#define BA1_OMNI_MEM 0x000E0000
-
-
-/*
- * The following define the offsets of the AC97 shadow registers, which appear
- * as a virtual extension to the base address register zero memory range.
- */
-#define AC97_REG_OFFSET_MASK 0x0000007EL
-#define AC97_CODEC_NUMBER_MASK 0x00003000L
-
-#define BA0_AC97_RESET 0x00001000L
-#define BA0_AC97_MASTER_VOLUME 0x00001002L
-#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L
-#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L
-#define BA0_AC97_MASTER_TONE 0x00001008L
-#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL
-#define BA0_AC97_PHONE_VOLUME 0x0000100CL
-#define BA0_AC97_MIC_VOLUME 0x0000100EL
-#define BA0_AC97_LINE_IN_VOLUME 0x00001010L
-#define BA0_AC97_CD_VOLUME 0x00001012L
-#define BA0_AC97_VIDEO_VOLUME 0x00001014L
-#define BA0_AC97_AUX_VOLUME 0x00001016L
-#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L
-#define BA0_AC97_RECORD_SELECT 0x0000101AL
-#define BA0_AC97_RECORD_GAIN 0x0000101CL
-#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL
-#define BA0_AC97_GENERAL_PURPOSE 0x00001020L
-#define BA0_AC97_3D_CONTROL 0x00001022L
-#define BA0_AC97_MODEM_RATE 0x00001024L
-#define BA0_AC97_POWERDOWN 0x00001026L
-#define BA0_AC97_EXT_AUDIO_ID 0x00001028L
-#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL
-#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL
-#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL
-#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L
-#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L
-#define BA0_AC97_MIC_ADC_RATE 0x00001034L
-#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L
-#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L
-#define BA0_AC97_RESERVED_3A 0x0000103AL
-#define BA0_AC97_EXT_MODEM_ID 0x0000103CL
-#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL
-#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L
-#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L
-#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L
-#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L
-#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L
-#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL
-#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL
-#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL
-#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L
-#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L
-#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L
-#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L
-#define BA0_AC97_RESERVED_58 0x00001058L
-#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL
-#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL
-#define BA0_AC97_AC_MODE 0x0000105EL
-#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L
-#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L
-#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L
-#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L
-#define BA0_AC97_SPDIF_CONTROL 0x00001068L
-#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL
-#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL
-#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL
-#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L
-#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L
-#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L
-#define BA0_AC97_CAL_ADDRESS 0x00001076L
-#define BA0_AC97_CAL_DATA 0x00001078L
-#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL
-#define BA0_AC97_VENDOR_ID1 0x0000107CL
-#define BA0_AC97_VENDOR_ID2 0x0000107EL
-
/*
* The following defines are for the flags in the host interrupt status
* register.
struct pci_dev *pci;
snd_card_t *card;
snd_pcm_t *pcm;
+
snd_rawmidi_t *rmidi;
snd_rawmidi_substream_t *midi_input;
snd_rawmidi_substream_t *midi_output;
struct pm_dev *pm_dev;
#endif
#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
- int current_gpio;
+ int current_gpio;
#endif
#ifdef CONFIG_SND_CS46XX_NEW_DSP
struct semaphore spos_mutex;
dsp_spos_instance_t * dsp_spos_instance;
+
+ snd_pcm_t *pcm_rear;
+ snd_pcm_t *pcm_iec958;
#else /* for compatibility */
cs46xx_pcm_t *playback_pcm;
unsigned int play_ctl;
cs46xx_t **rcodec);
int snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
+int snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
+int snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
int snd_cs46xx_mixer(cs46xx_t *chip);
int snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rmidi);
+int snd_cs46xx_start_dsp(cs46xx_t *chip);
void snd_cs46xx_gameport(cs46xx_t *chip);
#ifdef CONFIG_PM
#define SEGTYPE_SP_COEFFICIENT 0x00000004
#define DSP_SPOS_UU 0x0deadul /* unused */
-#define DSP_SPOS_DC 0x0badul /* dont care */
-#define DSP_SPOS_DC_DC 0x0bad0badul /* dont care */
+#define DSP_SPOS_DC 0x0badul /* dont care */
+#define DSP_SPOS_DC_DC 0x0bad0badul /* dont care */
#define DSP_SPOS_UUUU 0xdeadc0edul /* unused */
#define DSP_SPOS_UUHI 0xdeadul
#define DSP_SPOS_UULO 0xc0edul
-#define DSP_SPOS_DCDC 0x0badf1d0ul /* dont care */
+#define DSP_SPOS_DCDC 0x0badf1d0ul /* dont care */
#define DSP_SPOS_DCDCHI 0x0badul
#define DSP_SPOS_DCDCLO 0xf1d0ul
-#define DSP_MAX_TASK_NAME 60
+#define DSP_MAX_TASK_NAME 60
#define DSP_MAX_SYMBOL_NAME 100
-#define DSP_MAX_SCB_NAME 60
-#define DSP_MAX_SCB_DESC 200
-#define DSP_MAX_TASK_DESC 50
+#define DSP_MAX_SCB_NAME 60
+#define DSP_MAX_SCB_DESC 200
+#define DSP_MAX_TASK_DESC 50
#define DSP_MAX_PCM_CHANNELS 32
#define DSP_MAX_SRC_NR 6
+#define DSP_PCM_MAIN_CHANNEL 1
+#define DSP_PCM_REAR_CHANNEL 2
+#define DSP_PCM_CENTER_CHANNEL 3
+#define DSP_PCM_LFE_CHANNEL 4
+#define DSP_IEC958_CHANNEL 5
+
+#define DSP_SPDIF_STATUS_OUTPUT_ENABLED 1
+#define DSP_SPDIF_STATUS_PLAYBACK_OPEN 2
+#define DSP_SPDIF_STATUS_HW_ENABLED 4
+#define DSP_SPDIF_STATUS_AC3_MODE 8
+
struct _dsp_module_desc_t;
typedef struct _symbol_entry_t {
u32 unlinked;
dsp_scb_descriptor_t * pcm_reader_scb;
dsp_scb_descriptor_t * src_scb;
+ dsp_scb_descriptor_t * mixer_scb;
+ int pcm_channel_id;
void * private_data;
} pcm_channel_descriptor_t;
segment_desc_t code;
- /* PCM playback */
+ /* Main PCM playback mixer */
dsp_scb_descriptor_t * master_mix_scb;
+ u16 dac_volume_right;
+ u16 dac_volume_left;
+
+ /* Rear PCM playback mixer */
+ dsp_scb_descriptor_t * rear_mix_scb;
+
int npcm_channels;
int nsrc_scb;
pcm_channel_descriptor_t pcm_channels[DSP_MAX_PCM_CHANNELS];
/* SPDIF status */
int spdif_status_out;
int spdif_status_in;
- u32 spdif_input_volume;
+ u16 spdif_input_volume_right;
+ u16 spdif_input_volume_left;
/* SPDIF input sample rate converter */
dsp_scb_descriptor_t * spdif_in_src;
/* reference snooper */
dsp_scb_descriptor_t * ref_snoop_scb;
+ /* SPDIF output PCM reference */
+ dsp_scb_descriptor_t * spdif_pcm_input_scb;
+
+ /* asynch TX task */
+ dsp_scb_descriptor_t * asynch_tx_scb;
+
/* record sources */
dsp_scb_descriptor_t * pcm_input;
dsp_scb_descriptor_t * adc_input;
} dsp_spos_instance_t;
#endif /* __DSP_SPOS_H__ */
-
snd_card_free(card);
return err;
}
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ if ((err = snd_cs46xx_pcm_rear(chip,1, NULL)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ if ((err = snd_cs46xx_pcm_iec958(chip,2,NULL)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+#endif
if ((err = snd_cs46xx_mixer(chip)) < 0) {
snd_card_free(card);
return err;
snd_card_free(card);
return err;
}
+ if ((err = snd_cs46xx_start_dsp(chip)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+
snd_cs46xx_gameport(chip);
strcpy(card->driver, "CS46xx");
snd_card_free(card);
return err;
}
+
pci_set_drvdata(pci, chip);
dev++;
return 0;
* TODO:
* - Secondary CODEC on some soundcards
* - SPDIF input support for other sample rates then 48khz
- * - Independent PCM channels for rear output
* - Posibility to mix the SPDIF output with analog sources.
+ * - PCM channels for Center and LFE on secondary codec
*
* NOTE: with CONFIG_SND_CS46XX_NEW_DSP unset uses old DSP image (which
* is default configuration), no SPDIF, no secondary codec, no
unsigned short val)
{
cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return);
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
int val2 = 0;
+#endif
int codec_index = -1;
/* UGGLY: nr_ac97_codecs == 0 primery codec detection is in progress */
if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] || chip->nr_ac97_codecs == 0)
codec_index = CS46XX_PRIMARY_CODEC_INDEX;
- /* UGGLY: nr_ac97_codecs == 0 secondary codec detection is in progress */
+ /* UGGLY: nr_ac97_codecs == 1 secondary codec detection is in progress */
else if (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] || chip->nr_ac97_codecs == 1)
codec_index = CS46XX_SECONDARY_CODEC_INDEX;
else
snd_assert(0,return);
- chip->active_ctrl(chip, 1);
+
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
if (reg == AC97_CD)
val2 = snd_cs46xx_codec_read(chip, AC97_CD, codec_index);
+#endif
snd_cs46xx_codec_write(chip, reg, val, codec_index);
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
+ /* Benny: I've not found *one* soundcard where
+ this code below could do any sense, and
+ with the HW mixering it's anyway broken, with
+ more then 1 PCM stream the amplifier will not
+ be turned off by unmuting CD channel. So just
+ lets skip it.
+ */
/*
* Adjust power if the mixer is selected/deselected according
}
chip->active_ctrl(chip, -1);
+#endif
}
snd_cs46xx_poke(chip, BA1_FRMT, 0xadf);
}
+static int cs46xx_wait_for_fifo(cs46xx_t * chip,int retry_timeout)
+{
+ u32 i, status;
+ /*
+ * Make sure the previous FIFO write operation has completed.
+ */
+ for(i = 0; i < 50; i++){
+ status = snd_cs46xx_peekBA0(chip, BA0_SERBST);
+
+ if( !(status & SERBST_WBSY) )
+ break;
+
+ mdelay(retry_timeout);
+ }
+
+ if(status & SERBST_WBSY) {
+ snd_printk( KERN_ERR "cs46xx: failure waiting for FIFO command to complete\n");
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void snd_cs46xx_clear_serial_FIFOs(cs46xx_t *chip)
{
- int idx, loop, powerdown = 0;
+ int idx, powerdown = 0;
unsigned int tmp;
/*
* We want to clear out the serial port FIFOs so we don't end up playing
* whatever random garbage happens to be in them. We fill the sample FIFOS
* with zero (silence).
- */
+ */
snd_cs46xx_pokeBA0(chip, BA0_SERBWP, 0);
/*
* Fill all 256 sample FIFO locations.
*/
- for (idx = 0; idx < 256; idx++) {
+ for (idx = 0; idx < 0xFF; idx++) {
/*
* Make sure the previous FIFO write operation has completed.
*/
- for (loop = 0; loop < 5; loop++) {
- udelay(50);
- if (!(snd_cs46xx_peekBA0(chip, BA0_SERBST) & SERBST_WBSY))
- break;
- }
- if (snd_cs46xx_peekBA0(chip, BA0_SERBST) & SERBST_WBSY) {
+ if (cs46xx_wait_for_fifo(chip,1)) {
+ snd_printdd ("failed waiting for FIFO at addr (%02X)\n",idx);
+
if (powerdown)
snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);
+
+ break;
}
/*
* Write the serial port FIFO index.
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_sframes_t diff;
cs46xx_pcm_t * cpcm;
+ int buffer_size = runtime->period_size * CS46XX_FRAGS * 4;
+
cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
diff = runtime->control->appl_ptr - cpcm->appl_ptr;
}
cpcm->sw_ready += frames << cpcm->shift;
cpcm->appl_ptr = runtime->control->appl_ptr + frames;
- while (cpcm->hw_ready < CS46XX_BUFFER_SIZE &&
+ while (cpcm->hw_ready < buffer_size &&
cpcm->sw_ready > 0) {
- size_t hw_to_end = CS46XX_BUFFER_SIZE - cpcm->hw_data;
+ size_t hw_to_end = buffer_size - cpcm->hw_data;
size_t sw_to_end = cpcm->sw_bufsize - cpcm->sw_data;
- size_t bytes = CS46XX_BUFFER_SIZE - cpcm->hw_ready;
+ size_t bytes = buffer_size - cpcm->hw_ready;
if (cpcm->sw_ready < bytes)
bytes = cpcm->sw_ready;
if (hw_to_end < bytes)
runtime->dma_area + cpcm->sw_data,
bytes);
cpcm->hw_data += bytes;
- if (cpcm->hw_data == CS46XX_BUFFER_SIZE)
+ if (cpcm->hw_data == buffer_size)
cpcm->hw_data = 0;
cpcm->sw_data += bytes;
if (cpcm->sw_data == cpcm->sw_bufsize)
cs46xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_sframes_t diff = runtime->control->appl_ptr - chip->capt.appl_ptr;
+ int buffer_size = runtime->period_size * CS46XX_FRAGS * 4;
if (diff) {
if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
diff += runtime->boundary;
chip->capt.appl_ptr = runtime->control->appl_ptr + frames;
while (chip->capt.hw_ready > 0 &&
chip->capt.sw_ready < chip->capt.sw_bufsize) {
- size_t hw_to_end = CS46XX_BUFFER_SIZE - chip->capt.hw_data;
+ size_t hw_to_end = buffer_size - chip->capt.hw_data;
size_t sw_to_end = chip->capt.sw_bufsize - chip->capt.sw_data;
size_t bytes = chip->capt.sw_bufsize - chip->capt.sw_ready;
if (chip->capt.hw_ready < bytes)
chip->capt.hw_area + chip->capt.hw_data,
bytes);
chip->capt.hw_data += bytes;
- if (chip->capt.hw_data == CS46XX_BUFFER_SIZE)
+ if (chip->capt.hw_data == buffer_size)
chip->capt.hw_data = 0;
chip->capt.sw_data += bytes;
if (chip->capt.sw_data == chip->capt.sw_bufsize)
size_t ptr;
cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
ssize_t bytes;
+ int buffer_size = substream->runtime->period_size * CS46XX_FRAGS * 4;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
snd_assert (cpcm->pcm_channel,return -ENXIO);
bytes = ptr - cpcm->hw_io;
if (bytes < 0)
- bytes += CS46XX_BUFFER_SIZE;
+ bytes += buffer_size;
cpcm->hw_io = ptr;
cpcm->hw_ready -= bytes;
cpcm->sw_io += bytes;
cs46xx_t *chip = snd_pcm_substream_chip(substream);
size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_addr;
ssize_t bytes = ptr - chip->capt.hw_io;
+ int buffer_size = substream->runtime->period_size * CS46XX_FRAGS * 4;
+
if (bytes < 0)
- bytes += CS46XX_BUFFER_SIZE;
+ bytes += buffer_size;
chip->capt.hw_io = ptr;
chip->capt.hw_ready += bytes;
chip->capt.sw_io += bytes;
snd_cs46xx_playback_transfer(substream, 0);
/* raise playback volume */
- snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0x80008000);
+ cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,
+ chip->dsp_spos_instance->dac_volume_right,
+ chip->dsp_spos_instance->dac_volume_left);
#else
if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0);
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
#ifdef CONFIG_SND_CS46XX_NEW_DSP
- /* mute channel */
- snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0xffffffff);
+ /* mute channel */
+ cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,0,0);
+
if (!cpcm->pcm_channel->unlinked)
cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);
#else
return result;
}
+static int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm,
+ int sample_rate)
+{
+ /* if this is the only PCMReaderSCB child under current
+ SrcTask then there no need to re-create pcm-channel */
+ if ( cpcm->pcm_channel->src_scb->ref_count == 1 &&
+ cpcm->pcm_channel->sample_rate != sample_rate &&
+ /* never set a 0 khz sample rate */
+ sample_rate) {
+ /* sample rate not set or we can reuse
+ the same SRC*/
+ cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,sample_rate);
+ cpcm->pcm_channel->sample_rate = sample_rate;
+ }
+
+ /* if there is more then 1 PCMReaderSCB child's under current
+ SrcTask then we must recreate channel */
+ if (cpcm->pcm_channel->sample_rate != sample_rate &&
+ cpcm->pcm_channel->src_scb->ref_count != 1 &&
+ /* never set a 0 khz sample rate */
+ sample_rate) {
+ int unlinked = cpcm->pcm_channel->unlinked;
+ cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
+
+ if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm,
+ cpcm->hw_addr,
+ cpcm->pcm_channel->pcm_channel_id)) == NULL) {
+ snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
+ up (&chip->spos_mutex);
+ return -ENXIO;
+ }
+
+ if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel);
+ cpcm->pcm_channel->sample_rate = sample_rate;
+ }
+
+ return 0;
+}
static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
snd_pcm_runtime_t *runtime = substream->runtime;
cs46xx_pcm_t *cpcm;
int err;
-
+ cs46xx_t *chip = snd_pcm_substream_chip(substream);
+ int sample_rate = params_rate(hw_params);
+ int period_size = params_period_size(hw_params);
cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ down (&chip->spos_mutex);
+
+ snd_assert (cpcm->pcm_channel != NULL);
+
+ /* if IEC958 is opened in AC3 mode dont adjust SRCTask is not
+ used so dont adjust sample rate */
+ if (cpcm->pcm_channel->pcm_channel_id != DSP_IEC958_CHANNEL ||
+ !(chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)) {
+ if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
+ return -ENXIO;
+ }
+ }
+
+ if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size * 4)) {
+ up (&chip->spos_mutex);
+ return -EINVAL;
+ }
+ snd_printdd ("period_size (%d), periods (%d)\n",
+ period_size, params_periods(hw_params));
+#endif
+
if (params_periods(hw_params) == CS46XX_FRAGS) {
if (runtime->dma_area != cpcm->hw_area)
snd_pcm_lib_free_pages(substream);
runtime->dma_area = cpcm->hw_area;
runtime->dma_addr = cpcm->hw_addr;
runtime->dma_bytes = cpcm->hw_size;
+
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
+ substream->ops = &snd_cs46xx_playback_ops;
+ } else if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {
+ substream->ops = &snd_cs46xx_playback_rear_ops;
+ } else if (cpcm->pcm_channel->pcm_channel_id == DSP_IEC958_CHANNEL) {
+ substream->ops = &snd_cs46xx_playback_iec958_ops;
+ } else {
+ snd_assert(0);
+ }
+#else
substream->ops = &snd_cs46xx_playback_ops;
+#endif
+
} else {
if (runtime->dma_area == cpcm->hw_area) {
runtime->dma_area = NULL;
runtime->dma_addr = 0;
runtime->dma_bytes = 0;
}
- if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+ if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) {
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ up (&chip->spos_mutex);
+#endif
return err;
+ }
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
+ substream->ops = &snd_cs46xx_playback_indirect_ops;
+ } else if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {
+ substream->ops = &snd_cs46xx_playback_indirect_rear_ops;
+ } else if (cpcm->pcm_channel->pcm_channel_id == DSP_IEC958_CHANNEL) {
+ substream->ops = &snd_cs46xx_playback_indirect_iec958_ops;
+ } else {
+ snd_assert(0);
+ }
+#else
substream->ops = &snd_cs46xx_playback_indirect_ops;
+#endif
+
}
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ up (&chip->spos_mutex);
+#endif
+
return 0;
}
cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
- down (&chip->spos_mutex);
-
- if ( cpcm->pcm_channel->src_scb->ref_count == 1 &&
- cpcm->pcm_channel->sample_rate != runtime->rate) {
- /* sample rate not set or we can reuse
- the same SRC*/
-
- cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,runtime->rate);
- cpcm->pcm_channel->sample_rate = runtime->rate;
- }
-
- if (cpcm->pcm_channel->sample_rate != runtime->rate &&
- cpcm->pcm_channel->src_scb->ref_count != 1) {
- int unlinked = cpcm->pcm_channel->unlinked;
- cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
-
- if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr)) == NULL) {
- snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
- up (&chip->spos_mutex);
- return -ENXIO;
- }
-
- if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel);
- cpcm->pcm_channel->sample_rate = runtime->rate;
- }
+ snd_assert (cpcm->pcm_channel != NULL, return -ENXIO);
pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 );
pfie &= ~0x0000f03f;
- up (&chip->spos_mutex);
#else
/* old dsp */
pfie = snd_cs46xx_peek(chip, BA1_PFIE);
cpcm->appl_ptr = 0;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
+
tmp = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2);
tmp &= ~0x000003ff;
tmp |= (4 << cpcm->shift) - 1;
cs46xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
+ int period_size = params_period_size(hw_params);
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ snd_printdd ("capture period size (%d)\n",period_size);
+ cs46xx_dsp_pcm_ostream_set_period (chip,period_size * 4);
+#endif
if (runtime->periods == CS46XX_FRAGS) {
if (runtime->dma_area != chip->capt.hw_area)
snd_pcm_lib_free_pages(substream);
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (256 * 1024),
- .period_bytes_min = CS46XX_PERIOD_SIZE,
- .period_bytes_max = CS46XX_PERIOD_SIZE,
+ .period_bytes_min = CS46XX_MIN_PERIOD_SIZE,
+ .period_bytes_max = CS46XX_MAX_PERIOD_SIZE,
.periods_min = CS46XX_FRAGS,
.periods_max = 1024,
.fifo_size = 0,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = (256 * 1024),
- .period_bytes_min = CS46XX_PERIOD_SIZE,
- .period_bytes_max = CS46XX_PERIOD_SIZE,
+ .period_bytes_min = CS46XX_MIN_PERIOD_SIZE,
+ .period_bytes_max = CS46XX_MAX_PERIOD_SIZE,
.periods_min = CS46XX_FRAGS,
.periods_max = 1024,
.fifo_size = 0,
};
+static unsigned int period_sizes[] = { 8, 16, 32, 64, 128, 256, 512 };
+
+#define PERIOD_SIZES sizeof(period_sizes) / sizeof(period_sizes[0])
+
+static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = {
+ .count = PERIOD_SIZES,
+ .list = period_sizes,
+ .mask = 0
+};
+
static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return);
snd_magic_kfree(cpcm);
}
-static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream)
+static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id)
{
cs46xx_t *chip = snd_pcm_substream_chip(substream);
cs46xx_pcm_t * cpcm;
cpcm->substream = substream;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
down (&chip->spos_mutex);
- cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr);
+ cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr,pcm_channel_id);
if (cpcm->pcm_channel == NULL) {
snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
return -ENOMEM;
}
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ &hw_constraints_period_sizes);
up (&chip->spos_mutex);
#else
chip->playback_pcm = cpcm; /* HACK */
return 0;
}
+static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream)
+{
+ snd_printdd("open front channel\n");
+ return _cs46xx_playback_open_channel(substream,DSP_PCM_MAIN_CHANNEL);
+}
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+static int snd_cs46xx_playback_open_rear(snd_pcm_substream_t * substream)
+{
+ snd_printdd("open rear channel\n");
+
+ return _cs46xx_playback_open_channel(substream,DSP_PCM_REAR_CHANNEL);
+}
+
+static int snd_cs46xx_playback_open_iec958(snd_pcm_substream_t * substream)
+{
+ cs46xx_t *chip = snd_pcm_substream_chip(substream);
+
+ snd_printdd("open raw iec958 channel\n");
+
+ down (&chip->spos_mutex);
+ cs46xx_iec958_pre_open (chip);
+ up (&chip->spos_mutex);
+
+ return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL);
+}
+
+static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream);
+
+static int snd_cs46xx_playback_close_iec958(snd_pcm_substream_t * substream)
+{
+ int err;
+ cs46xx_t *chip = snd_pcm_substream_chip(substream);
+
+ snd_printdd("close raw iec958 channel\n");
+
+ err = snd_cs46xx_playback_close(substream);
+
+ down (&chip->spos_mutex);
+ cs46xx_iec958_post_close (chip);
+ up (&chip->spos_mutex);
+
+ return err;
+}
+#endif
+
static int snd_cs46xx_capture_open(snd_pcm_substream_t * substream)
{
cs46xx_t *chip = snd_pcm_substream_chip(substream);
substream->runtime->hw = snd_cs46xx_capture;
if (chip->accept_valid)
- substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
+ substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
chip->active_ctrl(chip, 1);
chip->amplifier_ctrl(chip, 1);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ &hw_constraints_period_sizes);
+#endif
return 0;
}
return 0;
}
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+snd_pcm_ops_t snd_cs46xx_playback_rear_ops = {
+ .open = snd_cs46xx_playback_open_rear,
+ .close = snd_cs46xx_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cs46xx_playback_hw_params,
+ .hw_free = snd_cs46xx_playback_hw_free,
+ .prepare = snd_cs46xx_playback_prepare,
+ .trigger = snd_cs46xx_playback_trigger,
+ .pointer = snd_cs46xx_playback_direct_pointer,
+};
+
+snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = {
+ .open = snd_cs46xx_playback_open_rear,
+ .close = snd_cs46xx_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cs46xx_playback_hw_params,
+ .hw_free = snd_cs46xx_playback_hw_free,
+ .prepare = snd_cs46xx_playback_prepare,
+ .trigger = snd_cs46xx_playback_trigger,
+ .copy = snd_cs46xx_playback_copy,
+ .pointer = snd_cs46xx_playback_indirect_pointer,
+};
+
+snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = {
+ .open = snd_cs46xx_playback_open_iec958,
+ .close = snd_cs46xx_playback_close_iec958,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cs46xx_playback_hw_params,
+ .hw_free = snd_cs46xx_playback_hw_free,
+ .prepare = snd_cs46xx_playback_prepare,
+ .trigger = snd_cs46xx_playback_trigger,
+ .pointer = snd_cs46xx_playback_direct_pointer,
+};
+
+snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = {
+ .open = snd_cs46xx_playback_open_iec958,
+ .close = snd_cs46xx_playback_close_iec958,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cs46xx_playback_hw_params,
+ .hw_free = snd_cs46xx_playback_hw_free,
+ .prepare = snd_cs46xx_playback_prepare,
+ .trigger = snd_cs46xx_playback_trigger,
+ .copy = snd_cs46xx_playback_copy,
+ .pointer = snd_cs46xx_playback_indirect_pointer,
+};
+
+#endif
+
snd_pcm_ops_t snd_cs46xx_playback_ops = {
.open = snd_cs46xx_playback_open,
.close = snd_cs46xx_playback_close,
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
+static void snd_cs46xx_pcm_rear_free(snd_pcm_t *pcm)
+{
+ cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return);
+ chip->pcm_rear = NULL;
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static void snd_cs46xx_pcm_iec958_free(snd_pcm_t *pcm)
+{
+ cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return);
+ chip->pcm_iec958 = NULL;
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
#define MAX_PLAYBACK_CHANNELS (DSP_MAX_PCM_CHANNELS - 1)
#else
#define MAX_PLAYBACK_CHANNELS 1
*rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0)
return err;
+
pcm->private_data = chip;
pcm->private_free = snd_cs46xx_pcm_free;
if (rpcm)
*rpcm = pcm;
+
+ return 0;
+}
+
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+int __devinit snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t ** rpcm)
+{
+ snd_pcm_t *pcm;
+ int err;
+
+ if (rpcm)
+ *rpcm = NULL;
+
+ if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0)
+ return err;
+
+ pcm->private_data = chip;
+ pcm->private_free = snd_cs46xx_pcm_rear_free;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs46xx_playback_rear_ops);
+
+ /* global setup */
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "CS46xx - Rear");
+ chip->pcm_rear = pcm;
+
+ snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+
+ if (rpcm)
+ *rpcm = pcm;
+
return 0;
}
+int __devinit snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t ** rpcm)
+{
+ snd_pcm_t *pcm;
+ int err;
+
+ if (rpcm)
+ *rpcm = NULL;
+
+ if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0)
+ return err;
+
+ pcm->private_data = chip;
+ pcm->private_free = snd_cs46xx_pcm_iec958_free;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs46xx_playback_iec958_ops);
+
+ /* global setup */
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "CS46xx - IEC958");
+ chip->pcm_rear = pcm;
+
+ snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+
+ if (rpcm)
+ *rpcm = pcm;
+
+ return 0;
+}
+#endif
+
/*
* Mixer routines
*/
-
static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97)
{
cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 32767;
+ uinfo->value.integer.max = 0x7fff;
return 0;
}
(0xffff - ucontrol->value.integer.value[1]));
unsigned int old = snd_cs46xx_peek(chip, reg);
int change = (old != val);
+
if (change) {
snd_cs46xx_poke(chip, reg, val);
-#ifdef CONFIG_SND_CS46XX_NEW_DSP
- /* NOTE: this updates the current left and right volume
- that should be automatically updated by the DSP and
- not touched by the host. But for some strange reason
- the DSP only updates the right channel volume, so with
- this dirty hack we force updating the right and left
- channel volume.
- */
- snd_cs46xx_poke(chip, reg + 4, val);
-
- /* shadow the SPDIF input volume */
- if (reg == (ASYNCRX_SCB_ADDR + 0xE) << 2) {
- /* FIXME: I known this is uggly ...
- any other suggestion ?
- */
- chip->dsp_spos_instance->spdif_input_volume = val;
- }
-#endif
}
return change;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
+static int snd_cs46xx_vol_dac_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_right;
+ ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_left;
+
+ return 0;
+}
+
+static int snd_cs46xx_vol_dac_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+ int change = 0;
+
+ if (chip->dsp_spos_instance->dac_volume_right != ucontrol->value.integer.value[0] ||
+ chip->dsp_spos_instance->dac_volume_left != ucontrol->value.integer.value[1]) {
+ cs46xx_dsp_set_dac_volume(chip,
+ ucontrol->value.integer.value[0],
+ ucontrol->value.integer.value[1]);
+ change = 1;
+ }
+
+ return change;
+}
+
+static int snd_cs46xx_vol_iec958_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_input_volume_right;
+ ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_left;
+ return 0;
+}
+
+static int snd_cs46xx_vol_iec958_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+ int change = 0;
+
+ if (chip->dsp_spos_instance->spdif_input_volume_right != ucontrol->value.integer.value[0] ||
+ chip->dsp_spos_instance->spdif_input_volume_left != ucontrol->value.integer.value[1]) {
+ cs46xx_dsp_set_iec958_volume (chip,
+ ucontrol->value.integer.value[0],
+ ucontrol->value.integer.value[1]);
+ change = 1;
+ }
+
+ return change;
+}
+
static int snd_mixer_boolean_info(snd_kcontrol_t *kcontrol,
snd_ctl_elem_info_t *uinfo)
{
int reg = kcontrol->private_value;
if (reg == CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT)
- ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_out;
+ ucontrol->value.integer.value[0] = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
else
ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_in;
switch (kcontrol->private_value) {
case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT:
- change = chip->dsp_spos_instance->spdif_status_out;
+ down (&chip->spos_mutex);
+ change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
if (ucontrol->value.integer.value[0] && !change)
cs46xx_dsp_enable_spdif_out(chip);
else if (change && !ucontrol->value.integer.value[0])
cs46xx_dsp_disable_spdif_out(chip);
- res = (change != chip->dsp_spos_instance->spdif_status_out);
+ res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED));
+ up (&chip->spos_mutex);
break;
case CS46XX_MIXER_SPDIF_INPUT_ELEMENT:
change = chip->dsp_spos_instance->spdif_status_in;
return 0;
}
+static int snd_cs46xx_iec958_ac3_mode_get(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *ucontrol)
+{
+ cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+ dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+ if (!ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ return 0;
+}
+
+static int snd_cs46xx_iec958_ac3_mode_put(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *ucontrol)
+{
+ cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+ dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+ int old = ins->spdif_status_out;
+
+ if (ucontrol->value.integer.value[0])
+ ins->spdif_status_out |= DSP_SPDIF_STATUS_AC3_MODE;
+ else
+ ins->spdif_status_out &= ~DSP_SPDIF_STATUS_AC3_MODE;
+
+ return (old != ins->spdif_status_out);
+}
+
static int snd_cs46xx_pcm_capture_put(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol)
{
}
/*
- * Game Theatre XP card - EGPIO[0] is used to select SDPIF input optical or coaxial.
+ * Game Theatre XP card - EGPIO[0] is used to select SPDIF input optical or coaxial.
*/
static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol,
snd_ctl_elem_value_t *ucontrol)
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "DAC Volume",
.info = snd_cs46xx_vol_info,
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
.get = snd_cs46xx_vol_get,
.put = snd_cs46xx_vol_put,
-
-#ifndef CONFIG_SND_CS46XX_NEW_DSP
.private_value = BA1_PVOL,
#else
- .private_value = (MASTERMIX_SCB_ADDR + 0xE) << 2,
+ .get = snd_cs46xx_vol_dac_get,
+ .put = snd_cs46xx_vol_dac_put,
#endif
},
.put = snd_cs46xx_iec958_put,
.private_value = CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT,
},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "IEC 958 AC3 Mode Switch",
+ .info = snd_mixer_boolean_info,
+ .get = snd_cs46xx_iec958_ac3_mode_get,
+ .put = snd_cs46xx_iec958_ac3_mode_put,
+},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 Input Switch",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC 958 Input Volume",
.info = snd_cs46xx_vol_info,
- .get = snd_cs46xx_vol_get,
- .put = snd_cs46xx_vol_put,
+ .get = snd_cs46xx_vol_iec958_get,
+ .put = snd_cs46xx_vol_iec958_put,
.private_value = (ASYNCRX_SCB_ADDR + 0xE) << 2,
},
#endif
.put = snd_herc_spdif_select_put,
},
};
+
+
+static void snd_cs46xx_sec_codec_reset (ac97_t * ac97)
+{
+ signed long end_time;
+ int err;
+
+ /* reset to defaults */
+ snd_ac97_write(ac97, AC97_RESET, 0);
+
+ /* set codec in extended mode */
+ snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3);
+
+ udelay(50);
+
+ /* it's necessary to wait awhile until registers are accessible after RESET */
+ /* because the PCM or MASTER volume registers can be modified, */
+ /* the REC_GAIN register is used for tests */
+ end_time = jiffies + HZ;
+ do {
+ unsigned short ext_mid;
+
+ /* use preliminary reads to settle the communication */
+ snd_ac97_read(ac97, AC97_RESET);
+ snd_ac97_read(ac97, AC97_VENDOR_ID1);
+ snd_ac97_read(ac97, AC97_VENDOR_ID2);
+ /* modem? */
+ ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);
+ if (ext_mid != 0xffff && (ext_mid & 1) != 0)
+ return;
+
+ /* test if we can write to the record gain volume register */
+ snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05);
+ if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05)
+ return;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/100);
+ } while (time_after_eq(end_time, jiffies));
+
+ snd_printk("CS46xx secondary codec dont respond!\n");
+}
#endif
int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
/* well, one codec only ... */
goto _end;
_ok2:
+ /* set secondary codec in extended mode */
+
+ /* use custom reset to set secondary codec in
+ extended mode */
+ ac97.reset = snd_cs46xx_sec_codec_reset;
+
if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0)
return err;
chip->nr_ac97_codecs = 2;
-
- /* add cs4630 mixer controls */
+
_end:
/* dosoundcard specific mixer setup */
#endif /* CONFIG_SND_CS46XX_NEW_DSP */
+ /* add cs4630 mixer controls */
for (idx = 0; idx < sizeof(snd_cs46xx_controls) /
sizeof(snd_cs46xx_controls[0]); idx++) {
snd_kcontrol_t *kctl;
/*
* initialize chip
*/
-
static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait)
{
- unsigned int tmp;
int timeout;
/*
*/
snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, CLKCR1_PLLP | CLKCR1_SWCE);
+ /*
+ * Enable FIFO Host Bypass
+ */
+ snd_cs46xx_pokeBA0(chip, BA0_SERBCF, SERBCF_HBP);
+
/*
* Fill the serial port FIFOs with silence.
*/
snd_cs46xx_pokeBA0(chip, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);
snd_cs46xx_pokeBA0(chip, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
+
#ifdef CONFIG_SND_CS46XX_NEW_DSP
snd_cs46xx_pokeBA0(chip, BA0_SERC7, SERC7_ASDI2EN);
snd_cs46xx_pokeBA0(chip, BA0_SERC3, 0);
mdelay(5);
+
/*
* Wait for the codec ready signal from the AC97 codec.
*/
snd_cs46xx_pokeBA0(chip, BA0_ACCTL2, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
#endif
+
/*
* Wait until we've sampled input slots 3 and 4 as valid, meaning that
* the codec is pumping ADC data across the AC-link.
* Now, assert valid frame and the slot 3 and 4 valid bits. This will
* commense the transfer of digital audio data to the AC97 codec.
*/
- snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4 | ACOSV_SLV7 | ACOSV_SLV8);
+
+ snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4 |
+ ACOSV_SLV7 | ACOSV_SLV8);
+
/*
* Power down the DAC and ADC. We will power them up (if) when we need
/* tmp = snd_cs46xx_peekBA0(chip, BA0_CLKCR1) & ~CLKCR1_SWCE; */
/* snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp); */
+ return 0;
+}
+
+/*
+ * start and load DSP
+ */
+int __devinit snd_cs46xx_start_dsp(cs46xx_t *chip)
+{
+ unsigned int tmp;
/*
- * Reset the processor.
- */
+ * Reset the processor.
+ */
snd_cs46xx_reset(chip);
-
/*
- * Download the image to the processor.
+ * Download the image to the processor.
*/
#ifdef CONFIG_SND_CS46XX_NEW_DSP
#if 0
if (cs46xx_dsp_scb_and_task_init(chip) < 0)
return -EIO;
- snd_printdd("[get here]\n");
#else
/* old image */
if (snd_cs46xx_download_image(chip) < 0) {
* Enable interrupts on the part.
*/
snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
-
+
tmp = snd_cs46xx_peek(chip, BA1_PFIE);
tmp &= ~0x0000f03f;
snd_cs46xx_poke(chip, BA1_PFIE, tmp); /* playback interrupt enable */
tmp |= 0x00000001;
snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
/* set the attenuation to 0dB */
- snd_cs46xx_poke(chip, BA1_PVOL, 0x80008000);
- snd_cs46xx_poke(chip, BA1_CVOL, 0x80008000);
+ snd_cs46xx_poke(chip, (MASTERMIX_SCB_ADDR + 0xE) << 2, 0x80008000);
+ snd_cs46xx_poke(chip, (VARIDECIMATE_SCB_ADDR + 0xE) << 2, 0x80008000);
+
+ /*
+ * Initialize cs46xx SPDIF controller
+ */
-#ifdef CONFIG_SND_CS46XX_NEW_DSP
/* time countdown enable */
cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000000);
-
+
/* SPDIF input MASTER ENABLE */
cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff);
-
- /* mute spdif out */
- cs46xx_dsp_disable_spdif_out(chip);
+#else
+ /* set the attenuation to 0dB */
+ snd_cs46xx_poke(chip, BA1_PVOL, 0x80008000);
+ snd_cs46xx_poke(chip, BA1_CVOL, 0x80008000);
#endif
return 0;
{
}
-
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static int voyetra_setup_eapd_slot(cs46xx_t *chip)
{
- int i;
- u32 idx;
- u16 modem_power,pin_config,logic_type,valid_slots,status;
+
+ u32 idx, valid_slots,tmp,powerdown = 0;
+ u16 modem_power,pin_config,logic_type;
+
+ snd_printdd ("cs46xx: cs46xx_setup_eapd_slot()+\n");
+
+ /*
+ * See if the devices are powered down. If so, we must power them up first
+ * or they will not respond.
+ */
+ tmp = snd_cs46xx_peekBA0(chip, BA0_CLKCR1);
+
+ if (!(tmp & CLKCR1_SWCE)) {
+ snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp | CLKCR1_SWCE);
+ powerdown = 1;
+ }
- snd_printd ("cs46xx: cs46xx_setup_eapd_slot()+\n");
/*
* Clear PRA. The Bonzo chip will be used for GPIO not for modem
* stuff.
}
modem_power = snd_cs46xx_codec_read (chip,
- BA0_AC97_EXT_MODEM_POWER,
+ AC97_EXTENDED_MSTATUS,
CS46XX_SECONDARY_CODEC_INDEX);
modem_power &=0xFEFF;
snd_cs46xx_codec_write(chip,
- BA0_AC97_EXT_MODEM_POWER, modem_power,
+ AC97_EXTENDED_MSTATUS, modem_power,
CS46XX_SECONDARY_CODEC_INDEX);
/*
* Set GPIO pin's 7 and 8 so that they are configured for output.
*/
pin_config = snd_cs46xx_codec_read (chip,
- BA0_AC97_GPIO_PIN_CONFIG,
+ AC97_GPIO_CFG,
CS46XX_SECONDARY_CODEC_INDEX);
pin_config &=0x27F;
snd_cs46xx_codec_write(chip,
- BA0_AC97_GPIO_PIN_CONFIG, pin_config,
+ AC97_GPIO_CFG, pin_config,
CS46XX_SECONDARY_CODEC_INDEX);
/*
* Set GPIO pin's 7 and 8 so that they are compatible with CMOS logic.
*/
- logic_type = snd_cs46xx_codec_read(chip, BA0_AC97_GPIO_PIN_TYPE,
+ logic_type = snd_cs46xx_codec_read(chip, AC97_GPIO_POLARITY,
CS46XX_SECONDARY_CODEC_INDEX);
logic_type &=0x27F;
- snd_cs46xx_codec_write (chip, BA0_AC97_GPIO_PIN_TYPE, logic_type,
+ snd_cs46xx_codec_write (chip, AC97_GPIO_POLARITY, logic_type,
CS46XX_SECONDARY_CODEC_INDEX);
valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
valid_slots |= 0x200;
snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
+ if ( cs46xx_wait_for_fifo(chip,1) ) {
+ snd_printdd("FIFO is busy\n");
+
+ return -EINVAL;
+ }
+
/*
* Fill slots 12 with the correct value for the GPIO pins.
*/
for(idx = 0x90; idx <= 0x9F; idx++) {
-
/*
* Initialize the fifo so that bits 7 and 8 are on.
*
* the left. 0x1800 corresponds to bits 7 and 8.
*/
snd_cs46xx_pokeBA0(chip, BA0_SERBWP, 0x1800);
-
+
/*
- * Make sure the previous FIFO write operation has completed.
+ * Wait for command to complete
*/
- for(i = 0; i < 5; i++){
- status = snd_cs46xx_peekBA0(chip, BA0_SERBST);
+ if ( cs46xx_wait_for_fifo(chip,200) ) {
+ snd_printdd("failed waiting for FIFO at addr (%02X)\n",idx);
- if( !(status & SERBST_WBSY) ) {
- break;
- }
- mdelay(100);
- }
-
- if(status & SERBST_WBSY) {
- snd_printk( KERN_ERR "cs46xx: cs46xx_setup_eapd_slot() " \
- "Failure to write the GPIO pins for slot 12.\n");
return -EINVAL;
}
-
+
/*
* Write the serial port FIFO index.
*/
snd_cs46xx_pokeBA0(chip, BA0_SERBCM, SERBCM_WRC);
}
+ /* wait for last command to complete */
+ cs46xx_wait_for_fifo(chip,200);
+
+ /*
+ * Now, if we powered up the devices, then power them back down again.
+ * This is kinda ugly, but should never happen.
+ */
+ if (powerdown)
+ snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);
+
return 0;
}
#endif
}
}
+static void voyetra_mixer_init (cs46xx_t *chip)
+{
+ snd_printdd ("initializing Voyetra mixer\n");
+
+ /* turnon Amplifier and leave it on */
+ chip->amplifier_ctrl(chip, 1);
+
+ /* Enable SPDIF out */
+ snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE0);
+ snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, EGPIODR_GPOE0);
+}
+
static void hercules_mixer_init (cs46xx_t *chip)
{
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static struct cs_card_type __initdata cards[] = {
{0x1489, 0x7001, "Genius Soundmaker 128 value", NULL, amp_none, NULL, NULL},
- {0x5053, 0x3357, "Voyetra", NULL, amp_voyetra, NULL, NULL},
+ {0x5053, 0x3357, "Voyetra", NULL, amp_voyetra, NULL, voyetra_mixer_init},
{0x1071, 0x6003, "Mitac MI6020/21", NULL, amp_voyetra, NULL, NULL},
{0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, amp_hercules, NULL, hercules_mixer_init},
{0x1681, 0x0050, "Hercules Game Theatre XP", NULL, amp_hercules, NULL, hercules_mixer_init},
for (cp = &cards[0]; cp->name; cp++) {
if (cp->vendor == ss_vendor && cp->id == ss_card) {
- snd_printd("hack for %s enabled\n", cp->name);
+ snd_printd ("hack for %s enabled\n", cp->name);
if (cp->init)
cp->init(chip);
chip->amplifier_ctrl = cp->amp;
snd_cs46xx_free(chip);
return err;
}
-
+
chip->active_ctrl(chip, -1);
*rchip = chip;
#define CS46XX_BA1_REG_SIZE 0x0100
-#define CS46XX_PERIOD_SIZE 2048
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+#define CS46XX_MIN_PERIOD_SIZE 1
+#define CS46XX_MAX_PERIOD_SIZE 1024*1024
+#else
+#define CS46XX_MIN_PERIOD_SIZE 2048
+#define CS46XX_MAX_PERIOD_SIZE 2048
+#endif
+
#define CS46XX_FRAGS 2
-#define CS46XX_BUFFER_SIZE CS46XX_PERIOD_SIZE * CS46XX_FRAGS
+/* #define CS46XX_BUFFER_SIZE CS46XX_MAX_PERIOD_SIZE * CS46XX_FRAGS */
#define SCB_NO_PARENT 0
#define SCB_ON_PARENT_NEXT_SCB 1
extern snd_pcm_ops_t snd_cs46xx_playback_indirect_ops;
extern snd_pcm_ops_t snd_cs46xx_capture_ops;
extern snd_pcm_ops_t snd_cs46xx_capture_indirect_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_rear_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_iec958_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops;
/*
unsigned long len);
int snd_cs46xx_clear_BA1(cs46xx_t *chip,unsigned long offset,unsigned long len);
int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip);
+int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip);
int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip);
int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip);
int cs46xx_dsp_disable_spdif_in (cs46xx_t *chip);
dsp_scb_descriptor_t * snoop_scb,
dsp_scb_descriptor_t * parent_scb,
int scb_child_type);
-pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr);
+pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr,
+ int pcm_channel_id);
void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,
pcm_channel_descriptor_t * pcm_channel);
void cs46xx_dsp_set_src_sample_rate(cs46xx_t * chip,dsp_scb_descriptor_t * src,
int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel);
dsp_scb_descriptor_t * cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
u16 addr,char * scb_name);
-int cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src);
-int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src);
+int cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src);
+int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src);
+int cs46xx_iec958_pre_open (cs46xx_t *chip);
+int cs46xx_iec958_post_close (cs46xx_t *chip);
+int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip,
+ pcm_channel_descriptor_t * pcm_channel,
+ int period_size);
+int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
+ int period_size);
+int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left);
+int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left);
#endif /* __CS46XX_LIB_H__ */
ins->spdif_in_sample_rate = 48000;
/* maximize volume */
- ins->spdif_input_volume = 0x80008000;
+ ins->dac_volume_right = 0x8000;
+ ins->dac_volume_left = 0x8000;
+ ins->spdif_input_volume_right = 0x8000;
+ ins->spdif_input_volume_left = 0x8000;
return ins;
}
dsp_scb_descriptor_t * codec_in_scb;
dsp_scb_descriptor_t * src_task_scb;
dsp_scb_descriptor_t * master_mix_scb;
+ dsp_scb_descriptor_t * rear_mix_scb;
dsp_scb_descriptor_t * record_mix_scb;
dsp_scb_descriptor_t * write_back_scb;
dsp_scb_descriptor_t * vari_decimate_scb;
- dsp_scb_descriptor_t * pcm_serial_input_task;
- dsp_scb_descriptor_t * asynch_tx_scb;
dsp_scb_descriptor_t * sec_codec_out_scb;
dsp_scb_descriptor_t * magic_snoop_scb;
ins->the_null_scb->sub_list_ptr = ins->the_null_scb;
ins->the_null_scb->next_scb_ptr = ins->the_null_scb;
ins->the_null_scb->parent_scb_ptr = NULL;
+ cs46xx_dsp_proc_register_scb_desc (chip,ins->the_null_scb);
}
{
/* create codec in */
codec_in_scb = cs46xx_dsp_create_codec_in_scb(chip,"CodecInSCB",0x0010,0x00A0,
- CODEC_INPUT_BUF1,
- CODECIN_SCB_ADDR,codec_out_scb,
- SCB_ON_PARENT_NEXT_SCB);
+ CODEC_INPUT_BUF1,
+ CODECIN_SCB_ADDR,codec_out_scb,
+ SCB_ON_PARENT_NEXT_SCB);
if (!codec_in_scb) goto _fail_end;
ins->codec_in_scb = codec_in_scb;
/* create secondary CODEC output */
sec_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_II",0x0010,0x0040,
- OUTPUTSNOOP_SCB_ADDR,
+ REAR_MIXER_SCB_ADDR,
SEC_CODECOUT_SCB_ADDR,codec_in_scb,
SCB_ON_PARENT_NEXT_SCB);
if (!sec_codec_out_scb) goto _fail_end;
+
+ /* create the rear PCM channel mixer SCB */
+ rear_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RearMixerSCB",
+ MIX_SAMPLE_BUF3,
+ REAR_MIXER_SCB_ADDR,
+ sec_codec_out_scb,
+ SCB_ON_PARENT_SUBLIST_SCB);
+ ins->rear_mix_scb = rear_mix_scb;
+ if (!rear_mix_scb) goto _fail_end;
+
/* the magic snooper */
magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_I",OUTPUTSNOOP_SCB_ADDR,
OUTPUT_SNOOP_BUFFER,
codec_out_scb,
sec_codec_out_scb,
- SCB_ON_PARENT_SUBLIST_SCB);
+ SCB_ON_PARENT_NEXT_SCB);
+
if (!magic_snoop_scb) goto _fail_end;
ins->ref_snoop_scb = magic_snoop_scb;
-
- /* The asynch. transfer task */
- asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
- SPDIFO_SCB_INST,
- SPDIFO_IP_OUTPUT_BUFFER1,
- magic_snoop_scb,
- SCB_ON_PARENT_NEXT_SCB);
-
- if (!asynch_tx_scb) goto _fail_end;
-
- /* pcm input */
- pcm_serial_input_task = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
- PCMSERIALINII_SCB_ADDR,
- magic_snoop_scb,asynch_tx_scb,
- SCB_ON_PARENT_SUBLIST_SCB);
-
- if (!pcm_serial_input_task) goto _fail_end;
-
/* SP IO access */
if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR,
- asynch_tx_scb,
+ magic_snoop_scb,
SCB_ON_PARENT_NEXT_SCB))
goto _fail_end;
-
/* SPDIF input sampel rate converter */
src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
SRC_OUTPUT_BUF1,
};
spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
+
snd_assert(spdifo_scb_desc, return -EIO);
spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
snd_assert(spdifi_scb_desc, return -EIO);
is the FG task tree */
fg_entry->parent_scb_ptr = spdifo_scb_desc;
+ /* for proc fs */
+ cs46xx_dsp_proc_register_scb_desc (chip,spdifo_scb_desc);
+ cs46xx_dsp_proc_register_scb_desc (chip,spdifi_scb_desc);
+ cs46xx_dsp_proc_register_scb_desc (chip,async_codec_scb_desc);
+
/* Async MASTER ENABLE, affects both SPDIF input and output */
snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 );
}
return 0;
}
-int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip)
+int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip)
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
/* SPDIF output MASTER ENABLE */
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
- /* right and left validate bit
- NOTE: 0x80000000 and enables the SCMC protection on stream
- */
+ /* right and left validate bit */
cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12));
/* monitor state */
- ins->spdif_status_out = 1;
-
- return 0;
-}
-
-int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
-{
- dsp_spos_instance_t * ins = chip->dsp_spos_instance;
-
- /* disable SPDIF output FIFO slot */
- snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0);
-
- /* SPDIF output MASTER DISABLE */
- cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x0);
-
- /* monitor state */
- ins->spdif_status_out = 0;
+ ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
return 0;
}
cs46xx_src_link(chip,ins->spdif_in_src);
/* restore SPDIF input volume */
- snd_cs46xx_poke(chip, (ASYNCRX_SCB_ADDR + 0xE) << 2, ins->spdif_input_volume);
- snd_cs46xx_poke(chip, (ASYNCRX_SCB_ADDR + 0xF) << 2, ins->spdif_input_volume);
+ cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,
+ ins->spdif_input_volume_right,
+ ins->spdif_input_volume_left);
+
spin_unlock_irq(&chip->reg_lock);
/* set SPDIF input sample rate and unmute
return 0;
}
+
+int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left)
+{
+ int i;
+ dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+ down(&chip->spos_mutex);
+
+ ins->dac_volume_right = right;
+ ins->dac_volume_left = left;
+
+ for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) {
+ if (ins->pcm_channels[i].active &&
+ !ins->pcm_channels[i].unlinked) {
+ cs46xx_dsp_scb_set_volume (chip,ins->pcm_channels[i].pcm_reader_scb,
+ right,left);
+
+ }
+ }
+
+ up(&chip->spos_mutex);
+
+ return 0;
+}
+
+int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left) {
+ dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+ down(&chip->spos_mutex);
+ cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,
+ right,left);
+
+ ins->spdif_input_volume_right = right;
+ ins->spdif_input_volume_left = left;
+ up(&chip->spos_mutex);
+
+ return 0;
+}
#define SPDIFI_IP_OUTPUT_BUFFER1 0x0E00
#define SPDIFO_IP_OUTPUT_BUFFER1 0x1000
#define MIX_SAMPLE_BUF1 0x1400
-#define MIX_SAMPLE_BUF2 0x3000
+#define MIX_SAMPLE_BUF2 0x2D00
+#define MIX_SAMPLE_BUF3 0x2E00
+#define MIX_SAMPLE_BUF4 0x2F00
+#define MIX_SAMPLE_BUF5 0x3000
/* Task stack address */
#define HFG_STACK 0x066A
#define OUTPUTSNOOPII_SCB_ADDR 0x150
#define PCMSERIALIN_PCM_SCB_ADDR 0x160
#define RECORD_MIXER_SCB_ADDR 0x170
+#define REAR_MIXER_SCB_ADDR 0x180
+#define SPDIF_MIXER_SCB_ADDR 0x190
/* hyperforground SCB's*/
#define HFG_TREE_SCB 0xBA0
#define SCBfuncEntryPtr 0xA
#define SRCCorPerGof 0x2
#define SRCPhiIncr6Int26Frac 0xd
+#define SCBVolumeCtrl 0xe
/* conf */
#define UseASER1Input 1
#define SP_SPDOUT_CONTROL 0x804D
#define SP_SPDOUT_CSUV 0x808E
+static inline void cs46xx_dsp_spos_update_scb (cs46xx_t * chip,dsp_scb_descriptor_t * scb)
+{
+ /* update nextSCB and subListPtr in SCB */
+ snd_cs46xx_poke(chip,
+ (scb->address + SCBsubListPtr) << 2,
+ (scb->sub_list_ptr->address << 0x10) |
+ (scb->next_scb_ptr->address));
+}
+
+static inline void cs46xx_dsp_scb_set_volume (cs46xx_t * chip,dsp_scb_descriptor_t * scb,
+ u16 right,u16 left) {
+ unsigned int val = ((0xffff - right) << 16 | (0xffff - left));
+
+ snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val);
+ snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val);
+}
+
#endif /* __DSP_SPOS_H__ */
#endif /* CONFIG_SND_CS46XX_NEW_DSP */
spin_lock_irqsave(&chip->reg_lock, flags);
/* update parent first entry in DSP RAM */
- snd_cs46xx_poke(chip,
- (scb->parent_scb_ptr->address + SCBsubListPtr) << 2,
- (scb->parent_scb_ptr->sub_list_ptr->address << 0x10) |
- (scb->parent_scb_ptr->next_scb_ptr->address));
+ cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
/* then update entry in DSP RAM */
- snd_cs46xx_poke(chip,
- (scb->address + SCBsubListPtr) << 2,
- (scb->sub_list_ptr->address << 0x10) |
- (scb->next_scb_ptr->address));
-
+ cs46xx_dsp_spos_update_scb(chip,scb);
+
scb->parent_scb_ptr = NULL;
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
for (i = 0; i < dword_count ; ++i ) {
writel(0, dst);
+ dst += 4;
}
}
}
spin_lock_irqsave(&chip->reg_lock, flags);
+
/* update entry in DSP RAM */
- snd_cs46xx_poke(chip,
- (scb->parent_scb_ptr->address + SCBsubListPtr) << 2,
- (scb->parent_scb_ptr->sub_list_ptr->address << 0x10) |
- (scb->parent_scb_ptr->next_scb_ptr->address));
+ cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
src_buffer_addr << 0x10,
0x04000000,
{
- 0xffff,0xffff,
+ 0x8000,0x8000,
0xffff,0xffff
}
};
/* D */ 0,
{
/* E */ 0x8000,0x8000,
- /* F */ 0x8000,0x8000
+ /* F */ 0xffff,0xffff
}
};
0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
/* : Max delta 25 dwords == 100 bytes */
0,hfg_scb_address, /* Point to HFG task SCB */
- 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
+ 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
0, /* Initialize accumulated Phi to 0 */
0,0x2aab, /* Const 1/3 */
RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
(asynch_buffer_address) << 0x10, /* This should be automagically synchronized
- to the producer pointer */
+ to the producer pointer */
/* There is no correct initial value, it will depend upon the detected
rate etc */
0x18000000, /* Phi increment for approx 32k operation */
0x8000,0x8000, /* Volume controls are unused at this time */
- 0x8000,0x8000
+ 0xffff,0xffff
};
scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
};
-pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr)
+pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
+ u32 sample_rate, void * private_data,
+ u32 hw_dma_addr,
+ int pcm_channel_id)
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
- dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb;
+ dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb, * mixer_scb = NULL;
/*dsp_scb_descriptor_t * pcm_parent_scb;*/
char scb_name[DSP_MAX_SCB_NAME];
int i,pcm_index = -1, insert_point, src_index = -1;
unsigned long flags;
+ switch (pcm_channel_id) {
+ case DSP_PCM_MAIN_CHANNEL:
+ mixer_scb = ins->master_mix_scb;
+ break;
+ case DSP_PCM_REAR_CHANNEL:
+ mixer_scb = ins->rear_mix_scb;
+ break;
+ case DSP_PCM_CENTER_CHANNEL:
+ /* TODO */
+ snd_assert(0);
+ break;
+ case DSP_PCM_LFE_CHANNEL:
+ /* TODO */
+ snd_assert(0);
+ break;
+ case DSP_IEC958_CHANNEL:
+ snd_assert (ins->asynch_tx_scb != NULL, return NULL);
+ mixer_scb = ins->asynch_tx_scb;
+ if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) {
+ snd_printdd ("IEC958 opened in AC3 mode\n");
+ /*src_scb = ins->asynch_tx_scb;
+ ins->asynch_tx_scb->ref_count ++;*/
+ }
+ break;
+ default:
+ snd_assert (0);
+ return NULL;
+ }
/* default sample rate is 44100 */
if (!sample_rate) sample_rate = 44100;
if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
if (ins->pcm_channels[i].active) {
- if (!src_scb && ins->pcm_channels[i].sample_rate == sample_rate) {
+ if (!src_scb &&
+ ins->pcm_channels[i].sample_rate == sample_rate &&
+ ins->pcm_channels[i].mixer_scb == mixer_scb) {
src_scb = ins->pcm_channels[i].src_scb;
ins->pcm_channels[i].src_scb->ref_count ++;
src_index = ins->pcm_channels[i].src_slot;
snd_assert (src_index != -1,return NULL);
/* we need to create a new SRC SCB */
- if (ins->master_mix_scb->sub_list_ptr == ins->the_null_scb) {
- src_parent_scb = ins->master_mix_scb;
+ if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
+ src_parent_scb = mixer_scb;
insert_point = SCB_ON_PARENT_SUBLIST_SCB;
} else {
- src_parent_scb = find_next_free_scb(chip,ins->master_mix_scb->sub_list_ptr);
+ src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
insert_point = SCB_ON_PARENT_NEXT_SCB;
}
return NULL;
}
- cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
+ if (pcm_channel_id != DSP_IEC958_CHANNEL ||
+ !(ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE))
+ cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
ins->nsrc_scb ++;
}
snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
- snd_printdd( "dsp_spos: creating PCM \"%s\"\n",scb_name);
+ snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
+ pcm_channel_id);
pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
pcm_reader_buffer_addr[pcm_index],
ins->pcm_channels[pcm_index].src_slot = src_index;
ins->pcm_channels[pcm_index].active = 1;
ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
+ ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
+ ins->pcm_channels[pcm_index].pcm_channel_id = pcm_channel_id;
ins->npcm_channels ++;
spin_unlock_irqrestore(&chip->reg_lock, flags);
return (ins->pcm_channels + pcm_index);
}
+int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip,
+ pcm_channel_descriptor_t * pcm_channel,
+ int period_size)
+{
+ u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
+ temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
+
+ switch (period_size) {
+ case 2048:
+ temp |= DMA_RQ_C1_SOURCE_MOD1024;
+ break;
+ case 1024:
+ temp |= DMA_RQ_C1_SOURCE_MOD512;
+ break;
+ case 512:
+ temp |= DMA_RQ_C1_SOURCE_MOD256;
+ break;
+ case 256:
+ temp |= DMA_RQ_C1_SOURCE_MOD128;
+ break;
+ case 128:
+ temp |= DMA_RQ_C1_SOURCE_MOD64;
+ break;
+ case 64:
+ temp |= DMA_RQ_C1_SOURCE_MOD32;
+ break;
+ case 32:
+ temp |= DMA_RQ_C1_SOURCE_MOD16;
+ break;
+ default:
+ snd_printdd ("period size (%d) not supported by HW\n");
+ return -EINVAL;
+ }
+
+ snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
+
+ return 0;
+}
+
+int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
+ int period_size)
+{
+ u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
+ temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
+
+ switch (period_size) {
+ case 2048:
+ temp |= DMA_RQ_C1_DEST_MOD1024;
+ break;
+ case 1024:
+ temp |= DMA_RQ_C1_DEST_MOD512;
+ break;
+ case 512:
+ temp |= DMA_RQ_C1_DEST_MOD256;
+ break;
+ case 256:
+ temp |= DMA_RQ_C1_DEST_MOD128;
+ break;
+ case 128:
+ temp |= DMA_RQ_C1_DEST_MOD64;
+ break;
+ case 64:
+ temp |= DMA_RQ_C1_DEST_MOD32;
+ break;
+ case 32:
+ temp |= DMA_RQ_C1_DEST_MOD16;
+ break;
+ default:
+ snd_printdd ("period size (%d) not supported by HW\n");
+ return -EINVAL;
+ }
+
+ snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
+
+ return 0;
+}
+
void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
{
dsp_spos_instance_t * ins = chip->dsp_spos_instance;
snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
- /* update entry in DSP RAM */
spin_lock_irqsave(&chip->reg_lock, flags);
- snd_cs46xx_poke(chip,
- (pcm_channel->pcm_reader_scb->address + SCBsubListPtr) << 2,
- (pcm_channel->pcm_reader_scb->sub_list_ptr->address << 0x10) |
- (pcm_channel->pcm_reader_scb->next_scb_ptr->address));
-
- snd_cs46xx_poke(chip,
- (parent_scb->address + SCBsubListPtr) << 2,
- (parent_scb->sub_list_ptr->address << 0x10) |
- (parent_scb->next_scb_ptr->address));
+
+ /* update SCB entry in DSP RAM */
+ cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
+
+ /* update parent SCB entry */
+ cs46xx_dsp_spos_update_scb(chip,parent_scb);
pcm_channel->unlinked = 0;
spin_unlock_irqrestore(&chip->reg_lock, flags);
spin_lock_irqsave(&chip->reg_lock, flags);
/* mute SCB */
- snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff);
+ /* cs46xx_dsp_scb_set_volume (chip,src,0,0); */
+
snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2,
((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
snd_cs46xx_poke(chip, (src->address + SRCPhiIncr6Int26Frac) << 2, phiIncr);
/* raise volume */
- snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0x80008000);
+ /* cs46xx_dsp_scb_set_volume (chip,src,0x7fff,0x7fff); */
+
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
snd_assert (src->parent_scb_ptr != NULL, return -EINVAL );
/* mute SCB */
- snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff);
+ cs46xx_dsp_scb_set_volume (chip,src,0,0);
_dsp_unlink_scb (chip,src);
src->parent_scb_ptr = parent_scb;
/* update entry in DSP RAM */
- snd_cs46xx_poke(chip,
- (parent_scb->address + SCBsubListPtr) << 2,
- (parent_scb->sub_list_ptr->address << 0x10) |
- (parent_scb->next_scb_ptr->address));
+ cs46xx_dsp_spos_update_scb(chip,parent_scb);
+
+ return 0;
+}
+
+int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip)
+{
+ dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+ if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
+ cs46xx_dsp_enable_spdif_hw (chip);
+ }
+
+ /* dont touch anything if SPDIF is open */
+ if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
+ /* when cs46xx_iec958_post_close(...) is called it
+ will call this function if necesary depending on
+ this bit */
+ ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+
+ return -EBUSY;
+ }
+
+ snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
+ snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
+
+ /* reset output snooper sample buffer pointer */
+ snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
+ (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
+
+ /* The asynch. transfer task */
+ ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
+ SPDIFO_SCB_INST,
+ SPDIFO_IP_OUTPUT_BUFFER1,
+ ins->master_mix_scb,
+ SCB_ON_PARENT_NEXT_SCB);
+ if (!ins->asynch_tx_scb) return -ENOMEM;
+
+ ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
+ PCMSERIALINII_SCB_ADDR,
+ ins->ref_snoop_scb,
+ ins->asynch_tx_scb,
+ SCB_ON_PARENT_SUBLIST_SCB);
+
+ if (!ins->spdif_pcm_input_scb) return -ENOMEM;
+
+ /* monitor state */
+ ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+
+ return 0;
+}
+
+int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
+{
+ dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+ /* dont touch anything if SPDIF is open */
+ if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
+ ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+ return -EBUSY;
+ }
+
+ /* check integrety */
+ snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
+ snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
+ snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
+ snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
+
+ cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
+ cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
+
+ ins->spdif_pcm_input_scb = NULL;
+ ins->asynch_tx_scb = NULL;
+
+ /* clear buffer to prevent any undesired noise */
+ _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
+
+ /* monitor state */
+ ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+
+
+ return 0;
+}
+
+int cs46xx_iec958_pre_open (cs46xx_t *chip)
+{
+ dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+ if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
+ /* remove AsynchFGTxSCB and and PCMSerialInput_II */
+ cs46xx_dsp_disable_spdif_out (chip);
+
+ /* save state */
+ ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+ }
+
+ /* if not enabled already */
+ if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
+ cs46xx_dsp_enable_spdif_hw (chip);
+ }
+
+ /* Create the asynch. transfer task for playback */
+ ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
+ SPDIFO_SCB_INST,
+ SPDIFO_IP_OUTPUT_BUFFER1,
+ ins->master_mix_scb,
+ SCB_ON_PARENT_NEXT_SCB);
+
+
+ if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)
+ /* set left (13), right validity bit (12) , and non-audio(1) and profsional bit (0) */
+ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12) | (1 << 1) | 1);
+
+ ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
+
+ return 0;
+}
+
+int cs46xx_iec958_post_close (cs46xx_t *chip)
+{
+ dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+ snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
+
+ ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
+
+ /* restore settings */
+ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12));
+
+ /* deallocate stuff */
+ cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
+ ins->asynch_tx_scb = NULL;
+
+ /* restore state */
+ if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
+ cs46xx_dsp_enable_spdif_out (chip);
+ }
+
return 0;
}
#endif
#define SNDRV_GET_ID
#include <sound/initval.h>
+#include <sound/asoundef.h>
#define chip_t ensoniq_t
#define ES_REG_CONTROL 0x00 /* R/W: Interrupt/Chip select control register */
#define ES_1370_ADC_STOP (1<<31) /* disable capture buffer transfers */
#define ES_1370_XCTL1 (1<<30) /* general purpose output bit */
-#define ES_1371_SPDIF_EN (1<<26) /* SPDIF enable */
-#define ES_1371_JOY_ASEL(o) (((o)&0x03)<<24) /* joystick port mapping */
+#define ES_1373_TEST_BIT (1<<29) /* should be set to 0 for normal operation */
+#define ES_1373_RECEN_B (1<<28) /* mix record with playback for I2S/SPDIF out */
+#define ES_1373_SPDIF_THRU (1<<26) /* 0 = SPDIF thru mode, 1 = SPDIF == dig out */
+#define ES_1371_JOY_ASEL(o) (((o)&0x03)<<24)/* joystick port mapping */
#define ES_1371_JOY_ASELM (0x03<<24) /* mask for above */
#define ES_1371_JOY_ASELI(i) (((i)>>24)&0x03)
-#define ES_1371_GPIO_IN(i) (((i)>>20)&0x0f) /* GPIO in [3:0] pins - R/O */
-#define ES_1370_PCLKDIVO(o) (((o)&0x1fff)<<16) /* clock divide ratio for DAC2 */
+#define ES_1371_GPIO_IN(i) (((i)>>20)&0x0f)/* GPIO in [3:0] pins - R/O */
+#define ES_1370_PCLKDIVO(o) (((o)&0x1fff)<<16)/* clock divide ratio for DAC2 */
#define ES_1370_PCLKDIVM ((0x1fff)<<16) /* mask for above */
-#define ES_1370_PCLKDIVI(i) (((i)>>16)&0x1fff) /* clock divide ratio for DAC2 */
-#define ES_1371_GPIO_OUT(o) (((o)&0x0f)<<16) /* GPIO out [3:0] pins - W/R */
+#define ES_1370_PCLKDIVI(i) (((i)>>16)&0x1fff)/* clock divide ratio for DAC2 */
+#define ES_1371_GPIO_OUT(o) (((o)&0x0f)<<16)/* GPIO out [3:0] pins - W/R */
#define ES_1371_GPIO_OUTM (0x0f<<16) /* mask for above */
#define ES_MSFMTSEL (1<<15) /* MPEG serial data format; 0 = SONY, 1 = I2S */
#define ES_1370_M_SBB (1<<14) /* clock source for DAC - 0 = clock generator; 1 = MPEG clocks */
#define ES_1371_SYNC_RES (1<<14) /* Warm AC97 reset */
-#define ES_1370_WTSRSEL(o) (((o)&0x03)<<12) /* fixed frequency clock for DAC1 */
+#define ES_1370_WTSRSEL(o) (((o)&0x03)<<12)/* fixed frequency clock for DAC1 */
#define ES_1370_WTSRSELM (0x03<<12) /* mask for above */
#define ES_1371_ADC_STOP (1<<13) /* disable CCB transfer capture information */
#define ES_1371_PWR_INTRM (1<<12) /* power level change interrupts enable */
#define ES_1370_DAC_SYNC (1<<11) /* DAC's are synchronous */
-#define ES_1371_M_CB (1<<11) /* capture clock source; 0 = ADC; 1 = I2S */
+#define ES_1371_M_CB (1<<11) /* capture clock source; 0 = AC'97 ADC; 1 = I2S */
#define ES_CCB_INTRM (1<<10) /* CCB voice interrupts enable */
-#define ES_1370_M_CB (1<<9) /* capture clock source; 0 = ADC; 1 = MPEG */
-#define ES_1370_XCTL0 (1<<8) /* generap purpose output bit */
-#define ES_1371_PDLEV(o) (((o)&0x03)<<8) /* current power down level */
+#define ES_1370_M_CB (1<<9) /* capture clock source; 0 = ADC; 1 = MPEG */
+#define ES_1370_XCTL0 (1<<8) /* generap purpose output bit */
+#define ES_1371_PDLEV(o) (((o)&0x03)<<8) /* current power down level */
#define ES_1371_PDLEVM (0x03<<8) /* mask for above */
-#define ES_BREQ (1<<7) /* memory bus request enable */
-#define ES_DAC1_EN (1<<6) /* DAC1 playback channel enable */
-#define ES_DAC2_EN (1<<5) /* DAC2 playback channel enable */
-#define ES_ADC_EN (1<<4) /* ADC capture channel enable */
-#define ES_UART_EN (1<<3) /* UART enable */
-#define ES_JYSTK_EN (1<<2) /* Joystick module enable */
-#define ES_1370_CDC_EN (1<<1) /* Codec interface enable */
-#define ES_1371_XTALCKDIS (1<<1) /* Xtal clock disable */
-#define ES_1370_SERR_DISABLE (1<<0) /* PCI serr signal disable */
-#define ES_1371_PCICLKDIS (1<<0) /* PCI clock disable */
+#define ES_BREQ (1<<7) /* memory bus request enable */
+#define ES_DAC1_EN (1<<6) /* DAC1 playback channel enable */
+#define ES_DAC2_EN (1<<5) /* DAC2 playback channel enable */
+#define ES_ADC_EN (1<<4) /* ADC capture channel enable */
+#define ES_UART_EN (1<<3) /* UART enable */
+#define ES_JYSTK_EN (1<<2) /* Joystick module enable */
+#define ES_1370_CDC_EN (1<<1) /* Codec interface enable */
+#define ES_1371_XTALCKDIS (1<<1) /* Xtal clock disable */
+#define ES_1370_SERR_DISABLE (1<<0) /* PCI serr signal disable */
+#define ES_1371_PCICLKDIS (1<<0) /* PCI clock disable */
#define ES_REG_STATUS 0x04 /* R/O: Interrupt/Chip select status register */
-#define ES_INTR (1<<31) /* Interrupt is pending */
-#define ES_1371_ST_AC97_RST (1<<29) /* CT5880 AC'97 Reset bit */
-#define ES_1371_ST_SPDIF_EN (1<<18) /* SPDIF enable */
-#define ES_1371_ST_SPDIF_TEST (1<<17) /* SPDIF test */
-#define ES_1371_TEST (1<<16) /* test ASIC */
-#define ES_1370_CSTAT (1<<10) /* CODEC is busy or register write in progress */
-#define ES_1370_CBUSY (1<<9) /* CODEC is busy */
-#define ES_1370_CWRIP (1<<8) /* CODEC register write in progress */
-#define ES_1371_SYNC_ERR (1<<8) /* CODEC synchronization error occured */
-#define ES_1371_VC(i) (((i)>>6)&0x03) /* voice code from CCB module */
-#define ES_1370_VC(i) (((i)>>5)&0x03) /* voice code from CCB module */
-#define ES_1371_MPWR (1<<5) /* power level interrupt pending */
-#define ES_MCCB (1<<4) /* CCB interrupt pending */
-#define ES_UART (1<<3) /* UART interrupt pending */
-#define ES_DAC1 (1<<2) /* DAC1 channel interrupt pending */
-#define ES_DAC2 (1<<1) /* DAC2 channel interrupt pending */
-#define ES_ADC (1<<0) /* ADC channel interrupt pending */
+#define ES_INTR (1<<31) /* Interrupt is pending */
+#define ES_1371_ST_AC97_RST (1<<29) /* CT5880 AC'97 Reset bit */
+#define ES_1373_GPIO_INT_EN(o)(((o)&0x0f)<<20)/* GPIO [3:0] pins - interrupt enable */
+#define ES_1373_SPDIF_EN (1<<18) /* SPDIF enable */
+#define ES_1373_SPDIF_TEST (1<<17) /* SPDIF test */
+#define ES_1371_TEST (1<<16) /* test ASIC */
+#define ES_1373_GPIO_INT(i) (((i)&0x0f)>>12)/* GPIO [3:0] pins - interrupt pending */
+#define ES_1370_CSTAT (1<<10) /* CODEC is busy or register write in progress */
+#define ES_1370_CBUSY (1<<9) /* CODEC is busy */
+#define ES_1370_CWRIP (1<<8) /* CODEC register write in progress */
+#define ES_1371_SYNC_ERR (1<<8) /* CODEC synchronization error occured */
+#define ES_1371_VC(i) (((i)>>6)&0x03) /* voice code from CCB module */
+#define ES_1370_VC(i) (((i)>>5)&0x03) /* voice code from CCB module */
+#define ES_1371_MPWR (1<<5) /* power level interrupt pending */
+#define ES_MCCB (1<<4) /* CCB interrupt pending */
+#define ES_UART (1<<3) /* UART interrupt pending */
+#define ES_DAC1 (1<<2) /* DAC1 channel interrupt pending */
+#define ES_DAC2 (1<<1) /* DAC2 channel interrupt pending */
+#define ES_ADC (1<<0) /* ADC channel interrupt pending */
#define ES_REG_UART_DATA 0x08 /* R/W: UART data register */
#define ES_REG_UART_STATUS 0x09 /* R/O: UART status register */
-#define ES_RXINT (1<<7) /* RX interrupt occured */
-#define ES_TXINT (1<<2) /* TX interrupt occured */
-#define ES_TXRDY (1<<1) /* transmitter ready */
-#define ES_RXRDY (1<<0) /* receiver ready */
+#define ES_RXINT (1<<7) /* RX interrupt occured */
+#define ES_TXINT (1<<2) /* TX interrupt occured */
+#define ES_TXRDY (1<<1) /* transmitter ready */
+#define ES_RXRDY (1<<0) /* receiver ready */
#define ES_REG_UART_CONTROL 0x09 /* W/O: UART control register */
-#define ES_RXINTEN (1<<7) /* RX interrupt enable */
+#define ES_RXINTEN (1<<7) /* RX interrupt enable */
#define ES_TXINTENO(o) (((o)&0x03)<<5) /* TX interrupt enable */
#define ES_TXINTENM (0x03<<5) /* mask for above */
#define ES_TXINTENI(i) (((i)>>5)&0x03)
#define ES_1371_CODEC_READ(i) (((i)>>0)&0xffff)
#define ES_REG_1371_SMPRATE 0x10 /* W/R: Codec rate converter interface register */
-#define ES_1371_SRC_RAM_ADDRO(o) (((o)&0x7f)<<25) /* address of the sample rate converter */
+#define ES_1371_SRC_RAM_ADDRO(o) (((o)&0x7f)<<25)/* address of the sample rate converter */
#define ES_1371_SRC_RAM_ADDRM (0x7f<<25) /* mask for above */
-#define ES_1371_SRC_RAM_ADDRI(i) (((i)>>25)&0x7f) /* address of the sample rate converter */
+#define ES_1371_SRC_RAM_ADDRI(i) (((i)>>25)&0x7f)/* address of the sample rate converter */
#define ES_1371_SRC_RAM_WE (1<<24) /* R/W: read/write control for sample rate converter */
#define ES_1371_SRC_RAM_BUSY (1<<23) /* R/O: sample rate memory is busy */
#define ES_1371_SRC_DISABLE (1<<22) /* sample rate converter disable */
#define ES_1371_DIS_P1 (1<<21) /* playback channel 1 accumulator update disable */
#define ES_1371_DIS_P2 (1<<20) /* playback channel 1 accumulator update disable */
#define ES_1371_DIS_R1 (1<<19) /* capture channel accumulator update disable */
-#define ES_1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0) /* current value of the sample rate converter */
+#define ES_1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0)/* current value of the sample rate converter */
#define ES_1371_SRC_RAM_DATAM (0xffff<<0) /* mask for above */
-#define ES_1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff) /* current value of the sample rate converter */
+#define ES_1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff)/* current value of the sample rate converter */
#define ES_REG_1371_LEGACY 0x18 /* W/R: Legacy control/status register */
#define ES_1371_JFAST (1<<31) /* fast joystick timing */
#define ES_1371_HIB (1<<30) /* host interrupt blocking enable */
#define ES_1371_VSB (1<<29) /* SB; 0 = addr 0x220xH, 1 = 0x22FxH */
-#define ES_1371_VMPUO(o) (((o)&0x03)<<27) /* base register address; 0 = 0x320xH; 1 = 0x330xH; 2 = 0x340xH; 3 = 0x350xH */
+#define ES_1371_VMPUO(o) (((o)&0x03)<<27)/* base register address; 0 = 0x320xH; 1 = 0x330xH; 2 = 0x340xH; 3 = 0x350xH */
#define ES_1371_VMPUM (0x03<<27) /* mask for above */
-#define ES_1371_VMPUI(i) (((i)>>27)&0x03) /* base register address */
-#define ES_1371_VCDCO(o) (((o)&0x03)<<25) /* CODEC; 0 = 0x530xH; 1 = undefined; 2 = 0xe80xH; 3 = 0xF40xH */
+#define ES_1371_VMPUI(i) (((i)>>27)&0x03)/* base register address */
+#define ES_1371_VCDCO(o) (((o)&0x03)<<25)/* CODEC; 0 = 0x530xH; 1 = undefined; 2 = 0xe80xH; 3 = 0xF40xH */
#define ES_1371_VCDCM (0x03<<25) /* mask for above */
-#define ES_1371_VCDCI(i) (((i)>>25)&0x03) /* CODEC address */
+#define ES_1371_VCDCI(i) (((i)>>25)&0x03)/* CODEC address */
#define ES_1371_FIRQ (1<<24) /* force an interrupt */
#define ES_1371_SDMACAP (1<<23) /* enable event capture for slave DMA controller */
#define ES_1371_SPICAP (1<<22) /* enable event capture for slave IRQ controller */
#define ES_1371_SVCAP (1<<18) /* enable event capture for SB registers */
#define ES_1371_CDCCAP (1<<17) /* enable event capture for CODEC registers */
#define ES_1371_BACAP (1<<16) /* enable event capture for SoundScape base address */
-#define ES_1371_EXI(i) (((i)>>8)&0x07) /* event number */
-#define ES_1371_AI(i) (((i)>>3)&0x1f) /* event significant I/O address */
+#define ES_1371_EXI(i) (((i)>>8)&0x07) /* event number */
+#define ES_1371_AI(i) (((i)>>3)&0x1f) /* event significant I/O address */
#define ES_1371_WR (1<<2) /* event capture; 0 = read; 1 = write */
#define ES_1371_LEGINT (1<<0) /* interrupt for legacy events; 0 = interrupt did occur */
+#define ES_REG_CHANNEL_STATUS 0x1c /* R/W: first 32-bits from S/PDIF channel status block, es1373 */
+
#define ES_REG_SERIAL 0x20 /* R/W: Serial interface control register */
#define ES_1371_DAC_TEST (1<<22) /* DAC test mode enable */
-#define ES_P2_END_INCO(o) (((o)&0x07)<<19) /* binary offset value to increment / loop end */
+#define ES_P2_END_INCO(o) (((o)&0x07)<<19)/* binary offset value to increment / loop end */
#define ES_P2_END_INCM (0x07<<19) /* mask for above */
-#define ES_P2_END_INCI(i) (((i)>>16)&0x07) /* binary offset value to increment / loop end */
-#define ES_P2_ST_INCO(o) (((o)&0x07)<<16) /* binary offset value to increment / start */
+#define ES_P2_END_INCI(i) (((i)>>16)&0x07)/* binary offset value to increment / loop end */
+#define ES_P2_ST_INCO(o) (((o)&0x07)<<16)/* binary offset value to increment / start */
#define ES_P2_ST_INCM (0x07<<16) /* mask for above */
-#define ES_P2_ST_INCI(i) (((i)<<16)&0x07) /* binary offset value to increment / start */
+#define ES_P2_ST_INCI(i) (((i)<<16)&0x07)/* binary offset value to increment / start */
#define ES_R1_LOOP_SEL (1<<15) /* ADC; 0 - loop mode; 1 = stop mode */
#define ES_P2_LOOP_SEL (1<<14) /* DAC2; 0 - loop mode; 1 = stop mode */
#define ES_P1_LOOP_SEL (1<<13) /* DAC1; 0 - loop mode; 1 = stop mode */
#define ES_P2_PAUSE (1<<12) /* DAC2; 0 - play mode; 1 = pause mode */
#define ES_P1_PAUSE (1<<11) /* DAC1; 0 - play mode; 1 = pause mode */
#define ES_R1_INT_EN (1<<10) /* ADC interrupt enable */
-#define ES_P2_INT_EN (1<<9) /* DAC2 interrupt enable */
-#define ES_P1_INT_EN (1<<8) /* DAC1 interrupt enable */
-#define ES_P1_SCT_RLD (1<<7) /* force sample counter reload for DAC1 */
-#define ES_P2_DAC_SEN (1<<6) /* when stop mode: 0 - DAC2 play back zeros; 1 = DAC2 play back last sample */
-#define ES_R1_MODEO(o) (((o)&0x03)<<4) /* ADC mode; 0 = 8-bit mono; 1 = 8-bit stereo; 2 = 16-bit mono; 3 = 16-bit stereo */
+#define ES_P2_INT_EN (1<<9) /* DAC2 interrupt enable */
+#define ES_P1_INT_EN (1<<8) /* DAC1 interrupt enable */
+#define ES_P1_SCT_RLD (1<<7) /* force sample counter reload for DAC1 */
+#define ES_P2_DAC_SEN (1<<6) /* when stop mode: 0 - DAC2 play back zeros; 1 = DAC2 play back last sample */
+#define ES_R1_MODEO(o) (((o)&0x03)<<4) /* ADC mode; 0 = 8-bit mono; 1 = 8-bit stereo; 2 = 16-bit mono; 3 = 16-bit stereo */
#define ES_R1_MODEM (0x03<<4) /* mask for above */
#define ES_R1_MODEI(i) (((i)>>4)&0x03)
-#define ES_P2_MODEO(o) (((o)&0x03)<<2) /* DAC2 mode; -- '' -- */
+#define ES_P2_MODEO(o) (((o)&0x03)<<2) /* DAC2 mode; -- '' -- */
#define ES_P2_MODEM (0x03<<2) /* mask for above */
#define ES_P2_MODEI(i) (((i)>>2)&0x03)
-#define ES_P1_MODEO(o) (((o)&0x03)<<0) /* DAC1 mode; -- '' -- */
+#define ES_P1_MODEO(o) (((o)&0x03)<<0) /* DAC1 mode; -- '' -- */
#define ES_P1_MODEM (0x03<<0) /* mask for above */
#define ES_P1_MODEI(i) (((i)>>0)&0x03)
snd_rawmidi_substream_t *midi_input;
snd_rawmidi_substream_t *midi_output;
+ unsigned int spdif;
+ unsigned int spdif_default;
+ unsigned int spdif_stream;
+
snd_info_entry_t *proc_entry;
#ifdef CHIP1370
ensoniq->playback1_substream = substream;
runtime->hw = snd_ensoniq_playback1;
snd_pcm_set_sync(substream);
+ spin_lock_irq(&ensoniq->reg_lock);
+ if (ensoniq->spdif && ensoniq->playback2_substream == NULL)
+ ensoniq->spdif_stream = ensoniq->spdif_default;
+ spin_unlock_irq(&ensoniq->reg_lock);
#ifdef CHIP1370
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&snd_es1370_hw_constraints_rates);
ensoniq->playback2_substream = substream;
runtime->hw = snd_ensoniq_playback2;
snd_pcm_set_sync(substream);
+ spin_lock_irq(&ensoniq->reg_lock);
+ if (ensoniq->spdif && ensoniq->playback1_substream == NULL)
+ ensoniq->spdif_stream = ensoniq->spdif_default;
+ spin_unlock_irq(&ensoniq->reg_lock);
#ifdef CHIP1370
snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&snd_es1370_hw_constraints_clock);
#ifdef CHIP1371
+
+static int snd_ens1373_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_ens1373_spdif_default_get(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
+ spin_lock_irq(&ensoniq->reg_lock);
+ ucontrol->value.iec958.status[0] = (ensoniq->spdif_default >> 0) & 0xff;
+ ucontrol->value.iec958.status[1] = (ensoniq->spdif_default >> 8) & 0xff;
+ ucontrol->value.iec958.status[2] = (ensoniq->spdif_default >> 16) & 0xff;
+ ucontrol->value.iec958.status[3] = (ensoniq->spdif_default >> 24) & 0xff;
+ spin_unlock_irq(&ensoniq->reg_lock);
+ return 0;
+}
+
+static int snd_ens1373_spdif_default_put(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change;
+
+ val = ((u32)ucontrol->value.iec958.status[0] << 0) |
+ ((u32)ucontrol->value.iec958.status[1] << 8) |
+ ((u32)ucontrol->value.iec958.status[2] << 16) |
+ ((u32)ucontrol->value.iec958.status[3] << 24);
+ spin_lock_irq(&ensoniq->reg_lock);
+ change = ensoniq->spdif_default != val;
+ ensoniq->spdif_default = val;
+ if (change && ensoniq->playback1_substream == NULL && ensoniq->playback2_substream == NULL)
+ outl(val, ES_REG(ensoniq, CHANNEL_STATUS));
+ spin_unlock_irq(&ensoniq->reg_lock);
+ return change;
+}
+
+static int snd_ens1373_spdif_mask_get(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ ucontrol->value.iec958.status[0] = 0xff;
+ ucontrol->value.iec958.status[1] = 0xff;
+ ucontrol->value.iec958.status[2] = 0xff;
+ ucontrol->value.iec958.status[3] = 0xff;
+ return 0;
+}
+
+static int snd_ens1373_spdif_stream_get(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
+ spin_lock_irq(&ensoniq->reg_lock);
+ ucontrol->value.iec958.status[0] = (ensoniq->spdif_stream >> 0) & 0xff;
+ ucontrol->value.iec958.status[1] = (ensoniq->spdif_stream >> 8) & 0xff;
+ ucontrol->value.iec958.status[2] = (ensoniq->spdif_stream >> 16) & 0xff;
+ ucontrol->value.iec958.status[3] = (ensoniq->spdif_stream >> 24) & 0xff;
+ spin_unlock_irq(&ensoniq->reg_lock);
+ return 0;
+}
+
+static int snd_ens1373_spdif_stream_put(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ int change;
+
+ val = ((u32)ucontrol->value.iec958.status[0] << 0) |
+ ((u32)ucontrol->value.iec958.status[1] << 8) |
+ ((u32)ucontrol->value.iec958.status[2] << 16) |
+ ((u32)ucontrol->value.iec958.status[3] << 24);
+ spin_lock_irq(&ensoniq->reg_lock);
+ change = ensoniq->spdif_stream != val;
+ ensoniq->spdif_stream = val;
+ if (change && (ensoniq->playback1_substream != NULL || ensoniq->playback2_substream != NULL))
+ outl(val, ES_REG(ensoniq, CHANNEL_STATUS));
+ spin_unlock_irq(&ensoniq->reg_lock);
+ return change;
+}
+
+static snd_kcontrol_new_t snd_ens1373_spdif_default __devinitdata =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+ .info = snd_ens1373_spdif_info,
+ .get = snd_ens1373_spdif_default_get,
+ .put = snd_ens1373_spdif_default_put,
+};
+
+static snd_kcontrol_new_t snd_ens1373_spdif_mask __devinitdata =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
+ .info = snd_ens1373_spdif_info,
+ .get = snd_ens1373_spdif_mask_get
+};
+
+static snd_kcontrol_new_t snd_ens1373_spdif_stream __devinitdata =
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
+ .info = snd_ens1373_spdif_info,
+ .get = snd_ens1373_spdif_stream_get,
+ .put = snd_ens1373_spdif_stream_put
+};
+
#define ES1371_SPDIF(xname) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_es1371_spdif_info, \
.get = snd_es1371_spdif_get, .put = snd_es1371_spdif_put }
static int snd_es1371_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
- spin_lock_irqsave(&ensoniq->reg_lock, flags);
- ucontrol->value.integer.value[0] = ensoniq->ctrl & ES_1371_SPDIF_EN ? 1 : 0;
- spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
+ spin_lock_irq(&ensoniq->reg_lock);
+ ucontrol->value.integer.value[0] = ensoniq->ctrl & ES_1373_SPDIF_THRU ? 1 : 0;
+ spin_unlock_irq(&ensoniq->reg_lock);
return 0;
}
static int snd_es1371_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
unsigned int nval1, nval2;
int change;
- nval1 = ucontrol->value.integer.value[0] ? ES_1371_SPDIF_EN : 0;
- nval2 = ucontrol->value.integer.value[0] ? ES_1371_ST_SPDIF_EN : 0;
- spin_lock_irqsave(&ensoniq->reg_lock, flags);
- change = (ensoniq->ctrl & ES_1371_SPDIF_EN) != nval1;
- ensoniq->ctrl &= ~ES_1371_SPDIF_EN;
+ nval1 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_THRU : 0;
+ nval2 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_EN : 0;
+ spin_lock_irq(&ensoniq->reg_lock);
+ change = (ensoniq->ctrl & ES_1373_SPDIF_THRU) != nval1;
+ ensoniq->ctrl &= ~ES_1373_SPDIF_THRU;
ensoniq->ctrl |= nval1;
- ensoniq->cssr &= ~ES_1371_ST_SPDIF_EN;
+ ensoniq->cssr &= ~ES_1373_SPDIF_EN;
ensoniq->cssr |= nval2;
outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
- spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
+ spin_unlock_irq(&ensoniq->reg_lock);
return change;
}
unsigned short vid; /* vendor ID */
unsigned short did; /* device ID */
unsigned char rev; /* revision */
-} es1371_spdif_present[] = {
+} __devinitdata es1371_spdif_present[] = {
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
if (ensoniq->pci->vendor == es1371_spdif_present[idx].vid &&
ensoniq->pci->device == es1371_spdif_present[idx].did &&
ensoniq->rev == es1371_spdif_present[idx].rev) {
- snd_kcontrol_t *kctl = snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq);
+ snd_kcontrol_t *kctl;
+ int index = 0;
+
+ ensoniq->spdif_default = ensoniq->spdif_stream = SNDRV_PCM_DEFAULT_CON_SPDIF;
+ outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
+
if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
- kctl->id.index = 1;
+ index++;
+
+ kctl = snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq);
+ kctl->id.index = index;
+ snd_ctl_add(card, kctl);
+
+ kctl = snd_ctl_new1(&snd_ens1373_spdif_default, ensoniq);
+ kctl->id.index = index;
+ snd_ctl_add(card, kctl);
+
+ kctl = snd_ctl_new1(&snd_ens1373_spdif_mask, ensoniq);
+ kctl->id.index = index;
+ snd_ctl_add(card, kctl);
+
+ kctl = snd_ctl_new1(&snd_ens1373_spdif_stream, ensoniq);
+ kctl->id.index = index;
snd_ctl_add(card, kctl);
break;
}