From c301098233bdbaae369bfdd98207db916df8cef2 Mon Sep 17 00:00:00 2001 From: ChenLi Tien Date: Thu, 24 Mar 2005 12:02:54 +0100 Subject: [ALSA] Show currectly selected widget in proc_read for hda driver HDA generic driver During debugging for cm9880 multi-channel playback, I added the * after the currently selected widget, mixer widget doesn't need this but other 3 widget types need it. Signed-off-by: ChenLi Tien Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 4d5db7faad8..8c703ff056f 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -266,13 +266,19 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) if (wid_caps & AC_WCAP_CONN_LIST) { hda_nid_t conn[HDA_MAX_CONNECTIONS]; - int c, conn_len; + int c, conn_len, curr = -1; conn_len = snd_hda_get_connections(codec, nid, conn, HDA_MAX_CONNECTIONS); + if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) + curr = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); snd_iprintf(buffer, " Connection: %d\n", conn_len); snd_iprintf(buffer, " "); - for (c = 0; c < conn_len; c++) + for (c = 0; c < conn_len; c++) { snd_iprintf(buffer, " 0x%02x", conn[c]); + if (c == curr) + snd_iprintf(buffer, "*"); + } snd_iprintf(buffer, "\n"); } } -- cgit v1.2.3-70-g09d2 From 36c4dc42249e96f0b0ddc90ca400bcb3981dbc62 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Mar 2005 17:48:30 +0100 Subject: [ALSA] Skip ac97 SPDIF controls CA0106 driver Skip building ac97 SPDIF controls via AC97_SCAP_NO_SPDIF. Clean up the code. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 1 + sound/pci/ca0106/ca0106_mixer.c | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 82533b45bc8..901e42bdc8b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -810,6 +810,7 @@ static int snd_ca0106_ac97(ca0106_t *chip) memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; + ac97.scaps = AC97_SCAP_NO_SPDIF; return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 97bed1b0899..231ecac8086 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -620,11 +620,6 @@ int __devinit snd_ca0106_mixer(ca0106_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; - if ((kctl = ctl_find(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT))) != NULL) { - /* already defined by ac97, remove it */ - /* FIXME: or do we need both controls? */ - remove_ctl(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT)); - } if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) -- cgit v1.2.3-70-g09d2 From d05b2817d859a2a2f2c3d5c056b688559fdbcc2b Mon Sep 17 00:00:00 2001 From: ChenLi Tien Date: Thu, 24 Mar 2005 20:47:35 +0100 Subject: [ALSA] fix multi-channel for model==full HDA Codec driver The patch_cm9880.c can't play side/C/B channels from front panel jacks. I fixed it by adding select pin. Signed-off-by: ChenLi Tien Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cmedia.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index b7cc8e4bffb..a44d64e828d 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -278,8 +278,10 @@ static struct hda_verb cmi9880_basic_init[] = { { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* port-G for CLFE (rear panel) */ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* port-H for side (rear panel) */ { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for line-in (rear panel) */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, /* port-B for mic-in (rear panel) with vref */ @@ -305,6 +307,10 @@ static struct hda_verb cmi9880_allout_init[] = { { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* port-G for CLFE (rear panel) */ { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for surround (rear panel) */ { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* port-B for mic-in (rear panel) with vref */ -- cgit v1.2.3-70-g09d2 From 6e4abc40fc125b1dcc2792eacac17606a4d86043 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 26 Mar 2005 19:35:29 +0100 Subject: [ALSA] Adds Capture to P16V chip. EMU10K1/EMU10K2 driver One can select which capture source, but one cannot yet set volumes. Signed-off-by: James Courtier-Dutton --- include/sound/emu10k1.h | 5 +- sound/pci/emu10k1/irq.c | 46 +++++---- sound/pci/emu10k1/p16v.c | 257 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 275 insertions(+), 33 deletions(-) (limited to 'sound/pci') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 43b6786abae..8221df88053 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -83,7 +83,8 @@ #define IPR 0x08 /* Global interrupt pending register */ /* Clear pending interrupts by writing a 1 to */ /* the relevant bits and zero to the other bits */ - +#define IPR_P16V 0x80000000 /* Bit set when the CA0151 P16V chip wishes + to interrupt */ #define IPR_GPIOMSG 0x20000000 /* GPIO message interrupt (RE'd, still not sure which INTE bits enable it) */ @@ -1109,7 +1110,9 @@ struct _snd_emu10k1 { emu10k1_voice_t voices[NUM_G]; emu10k1_voice_t p16v_voices[4]; + emu10k1_voice_t p16v_capture_voice; int p16v_device_offset; + u32 p16v_capture_source; emu10k1_pcm_mixer_t pcm_mixer[32]; emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK]; snd_kcontrol_t *ctl_send_routing; diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index b81a7cafff3..cd8460d5675 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -37,7 +37,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) int handled = 0; while ((status = inl(emu->port + IPR)) != 0) { - // printk("irq - status = 0x%x\n", status); + //printk("emu10k1 irq - status = 0x%x\n", status); orig_status = status; handled = 1; if (status & IPR_PCIERROR) { @@ -147,9 +147,36 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); status &= ~IPR_FXDSP; } + if (status & IPR_P16V) { + while ((status2 = inl(emu->port + IPR2)) != 0) { + u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ + emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); + emu10k1_voice_t *cvoice = &(emu->p16v_capture_voice); + + //printk(KERN_INFO "status2=0x%x\n", status2); + orig_status2 = status2; + if(status2 & mask) { + if(pvoice->use) { + snd_pcm_period_elapsed(pvoice->epcm->substream); + } else { + snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); + } + } + if(status2 & 0x110000) { + //printk(KERN_INFO "capture int found\n"); + if(cvoice->use) { + //printk(KERN_INFO "capture period_elapsed\n"); + snd_pcm_period_elapsed(cvoice->epcm->substream); + } + } + outl(orig_status2, emu->port + IPR2); /* ack all */ + } + status &= ~IPR_P16V; + } + if (status) { unsigned int bits; - //snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); + snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); //make sure any interrupts we don't handle are disabled: bits = INTE_FXDSPENABLE | INTE_PCIERRORENABLE | @@ -170,20 +197,5 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) } outl(orig_status, emu->port + IPR); /* ack all */ } - if (emu->audigy && emu->revision == 4) { /* P16V */ - while ((status2 = inl(emu->port + IPR2)) != 0) { - u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ - emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); - orig_status2 = status2; - if(status2 & mask) { - if(pvoice->use) { - snd_pcm_period_elapsed(pvoice->epcm->substream); - } else { - snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); - } - } - outl(orig_status2, emu->port + IPR2); /* ack all */ - } - } return IRQ_RETVAL(handled); } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index d03cb2fefc9..dd6ce9927e1 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -132,9 +132,29 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { .fifo_size = 0, }; +static snd_pcm_hardware_t snd_p16v_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = (32*1024), + .period_bytes_min = 64, + .period_bytes_max = (16*1024), + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0, +}; + + static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) { - snd_pcm_t *epcm = runtime->private_data; + emu10k1_pcm_t *epcm = runtime->private_data; if (epcm) { //snd_printk("epcm free: %p\n", epcm); @@ -178,15 +198,63 @@ static int snd_p16v_pcm_open_playback_channel(snd_pcm_substream_t *substream, in return 0; } +/* open_capture callback */ +static int snd_p16v_pcm_open_capture_channel(snd_pcm_substream_t *substream, int channel_id) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + emu10k1_voice_t *channel = &(emu->p16v_capture_voice); + emu10k1_pcm_t *epcm; + snd_pcm_runtime_t *runtime = substream->runtime; + int err; + + epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + //snd_printk("epcm kcalloc: %p\n", epcm); + + if (epcm == NULL) + return -ENOMEM; + epcm->emu = emu; + epcm->substream = substream; + //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); + + runtime->private_data = epcm; + runtime->private_free = snd_p16v_pcm_free_substream; + + runtime->hw = snd_p16v_capture_hw; + + channel->emu = emu; + channel->number = channel_id; + + channel->use=1; + //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use); + //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); + //channel->interrupt = snd_p16v_pcm_channel_interrupt; + channel->epcm=epcm; + if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + return err; + + return 0; +} + /* close callback */ static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream) { emu10k1_t *emu = snd_pcm_substream_chip(substream); //snd_pcm_runtime_t *runtime = substream->runtime; - //emu10k1_pcm_t *epcm = runtime->private_data; - emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; -/* FIXME: maybe zero others */ + //emu10k1_pcm_t *epcm = runtime->private_data; + emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; + /* FIXME: maybe zero others */ + return 0; +} + +/* close callback */ +static int snd_p16v_pcm_close_capture(snd_pcm_substream_t *substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + //emu10k1_pcm_t *epcm = runtime->private_data; + emu->p16v_capture_voice.use=0; + /* FIXME: maybe zero others */ return 0; } @@ -195,36 +263,55 @@ static int snd_p16v_pcm_open_playback_front(snd_pcm_substream_t *substream) return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); } +static int snd_p16v_pcm_open_capture(snd_pcm_substream_t *substream) +{ + // Only using channel 0 for now, but the card has 2 channels. + return snd_p16v_pcm_open_capture_channel(substream, 0); +} + /* hw_params callback */ static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream, snd_pcm_hw_params_t * hw_params) { int result; - //snd_printk("hw_params alloc: substream=%p\n", substream); result = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - //snd_printk("hw_params alloc: result=%d\n", result); - //dump_stack(); return result; } +/* hw_params callback */ +static int snd_p16v_pcm_hw_params_capture(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t * hw_params) +{ + int result; + result = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + return result; +} + + /* hw_free callback */ static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream) { int result; - //snd_printk("hw_params free: substream=%p\n", substream); result = snd_pcm_lib_free_pages(substream); - //snd_printk("hw_params free: result=%d\n", result); - //dump_stack(); return result; } +/* hw_free callback */ +static int snd_p16v_pcm_hw_free_capture(snd_pcm_substream_t *substream) +{ + int result; + result = snd_pcm_lib_free_pages(substream); + return result; +} + + /* prepare playback callback */ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - //emu10k1_pcm_t *epcm = runtime->private_data; int channel = substream->pcm->device - emu->p16v_device_offset; u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); @@ -253,7 +340,7 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ - for(i=0; i < runtime->periods; i++) { + for(i=0; i < runtime->periods; i++) { table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); table_base[(i*2)+1]=period_size_bytes<<16; } @@ -270,6 +357,23 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) return 0; } +/* prepare capture callback */ +static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int channel = substream->pcm->device - emu->p16v_device_offset; + //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); + snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); + snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); + snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes + snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); + //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ + //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<runtime; + emu10k1_pcm_t *epcm = runtime->private_data; + int channel = 0; + int result = 0; + u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + snd_p16v_intr_enable(emu, inte); + snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<running = 1; + break; + case SNDRV_PCM_TRIGGER_STOP: + snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<running = 0; + break; + default: + result = -EINVAL; + break; + } + return result; +} + /* pointer_playback callback */ static snd_pcm_uframes_t snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) @@ -370,6 +504,31 @@ snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) return ptr; } +/* pointer_capture callback */ +static snd_pcm_uframes_t +snd_p16v_pcm_pointer_capture(snd_pcm_substream_t *substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + emu10k1_pcm_t *epcm = runtime->private_data; + snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; + int channel = 0; + + if (!epcm->running) + return 0; + + ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel); + ptr2 = bytes_to_frames(runtime, ptr1); + ptr=ptr2; + if (ptr >= runtime->buffer_size) { + ptr -= runtime->buffer_size; + printk("buffer capture limited!\n"); + } + //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); + + return ptr; +} + /* operators */ static snd_pcm_ops_t snd_p16v_playback_front_ops = { .open = snd_p16v_pcm_open_playback_front, @@ -382,6 +541,18 @@ static snd_pcm_ops_t snd_p16v_playback_front_ops = { .pointer = snd_p16v_pcm_pointer_playback, }; +static snd_pcm_ops_t snd_p16v_capture_ops = { + .open = snd_p16v_pcm_open_capture, + .close = snd_p16v_pcm_close_capture, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_p16v_pcm_hw_params_capture, + .hw_free = snd_p16v_pcm_hw_free_capture, + .prepare = snd_p16v_pcm_prepare_capture, + .trigger = snd_p16v_pcm_trigger_capture, + .pointer = snd_p16v_pcm_pointer_capture, +}; + + int snd_p16v_free(emu10k1_t *chip) { // release the data @@ -405,20 +576,22 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) snd_pcm_t *pcm; snd_pcm_substream_t *substream; int err; - int capture=0; + int capture=1; //snd_printk("snd_p16v_pcm called. device=%d\n", device); emu->p16v_device_offset = device; if (rpcm) *rpcm = NULL; - //if (device == 0) capture=1; + if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) return err; pcm->private_data = emu; pcm->private_free = snd_p16v_pcm_free; - + // Single playback 8 channel device. + // Single capture 2 channel device. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_p16v_capture_ops); pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; @@ -694,6 +867,56 @@ static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear = .put = snd_p16v_volume_put_spdif_rear }; +static int snd_p16v_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[8] = { "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S", "CDIF", "FX", "AC97" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item > 7) + uinfo->value.enumerated.item = 7; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_p16v_capture_source_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->p16v_capture_source; + return 0; +} + +static int snd_p16v_capture_source_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + u32 mask; + u32 source; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->p16v_capture_source != val); + if (change) { + emu->p16v_capture_source = val; + source = (val << 28) | (val << 24) | (val << 20) | (val << 16); + mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & 0xffff; + snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, source | mask); + } + return change; +} + +static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HD Capture source", + .info = snd_p16v_capture_source_info, + .get = snd_p16v_capture_source_get, + .put = snd_p16v_capture_source_put +}; int snd_p16v_mixer(emu10k1_t *emu) { int err; @@ -731,6 +954,10 @@ int snd_p16v_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if ((kctl = snd_ctl_new1(&snd_p16v_capture_source, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; return 0; } -- cgit v1.2.3-70-g09d2 From 65f37647711bf6b0d09b499b9205a33b35ad4ad6 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 26 Mar 2005 22:10:36 +0100 Subject: [ALSA] Add's identification of the SB Live! Platinum [CT4760P] EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton --- sound/pci/emu10k1/emu10k1_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c3c96f9f2c7..e0068872cd9 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -684,6 +684,10 @@ static emu_chip_details_t emu_chip_details[] = { .driver = "EMU10K1", .name = "SB Live 5.1", .emu10k1_chip = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, + .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", + .emu10k1_chip = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .driver = "EMU10K1", .name = "SB Live [Unknown]", .emu10k1_chip = 1, -- cgit v1.2.3-70-g09d2 From 56f5ceed002db594500c1d2c2afc875be3d31fb5 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 27 Mar 2005 15:00:54 +0200 Subject: [ALSA] Added identification for the Audigy ES. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton --- sound/pci/emu10k1/emu10k1_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index e0068872cd9..ff220fc3142 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -671,6 +671,11 @@ static emu_chip_details_t emu_chip_details[] = { .spk71 = 1, .spdif_bug = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052, + .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", + .emu10k2_chip = 1, + .ca0102_chip = 1, + .spdif_bug = 1} , {.vendor = 0x1102, .device = 0x0004, .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", .emu10k2_chip = 1, -- cgit v1.2.3-70-g09d2 From a2142674b958d89e0806228a5f6cd22ec379d61d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 29 Mar 2005 16:33:28 +0200 Subject: [ALSA] Fix the detection of resolution of ac97 controls AC97 Codec Fixed the detection of bit resolution of ac97 mixer controls. This will fix the problem with TI ac97 codecs. Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 0b024ec1f70..7d2854de0c1 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1072,9 +1072,9 @@ static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max unsigned short val; snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8)); val = snd_ac97_read(ac97, reg); - if (! *lo_max && (val & cbit[i])) + if (! *lo_max && (val & 0x7f) == cbit[i]) *lo_max = max[i]; - if (! *hi_max && (val & (cbit[i] << 8))) + if (! *hi_max && ((val >> 8) & 0x7f) == cbit[i]) *hi_max = max[i]; if (*lo_max && *hi_max) break; -- cgit v1.2.3-70-g09d2 From 2b637da5a1bb3c128ecdadea6aee693f6ff3b786 Mon Sep 17 00:00:00 2001 From: Lee Revell Date: Wed, 30 Mar 2005 13:51:18 +0200 Subject: [ALSA] clean up card features EMU10K1/EMU10K2 driver This patch converts the emu10k1 driver to use the card capabilities structure for some more things. Not extensively tested but seems to work. Signed-off-by: Lee Revell Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 9 +++---- sound/pci/emu10k1/emu10k1_main.c | 29 +++++++++------------ sound/pci/emu10k1/emufx.c | 56 +++++++++++++++++++++------------------- sound/pci/emu10k1/emumixer.c | 10 +++---- sound/pci/emu10k1/emuproc.c | 2 +- 5 files changed, 51 insertions(+), 55 deletions(-) (limited to 'sound/pci') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 8221df88053..b1e8ee8e0fa 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1046,6 +1046,7 @@ typedef struct { unsigned char ca0108_chip; /* Audigy 2 Value */ unsigned char ca0151_chip; /* P16V */ unsigned char spk71; /* Has 7.1 speakers */ + unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ unsigned char spdif_bug; /* Has Spdif phasing bug */ unsigned char ac97_chip; /* Has an AC97 chip */ unsigned char ecard; /* APS EEPROM */ @@ -1057,11 +1058,8 @@ struct _snd_emu10k1 { int irq; unsigned long port; /* I/O port number */ - unsigned int APS: 1, /* APS flag */ - no_ac97: 1, /* no AC'97 */ - tos_link: 1, /* tos link detected */ - rear_ac97: 1, /* rear channels are on AC'97 */ - spk71:1; /* 7.1 configuration (Audigy 2 ZS) */ + unsigned int tos_link: 1, /* tos link detected */ + rear_ac97: 1; /* rear channels are on AC'97 */ const emu_chip_details_t *card_capabilities; /* Contains profile of card capabilities */ unsigned int audigy; /* is Audigy? */ unsigned int revision; /* chip revision */ @@ -1456,7 +1454,6 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, #endif typedef struct { - unsigned int card; /* card type */ unsigned int internal_tram_size; /* in samples */ unsigned int external_tram_size; /* in samples */ char fxbus_names[16][32]; /* names of FXBUSes */ diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index ff220fc3142..38be0f1b0e7 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -170,7 +170,7 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir) SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); - if (emu->audigy && emu->revision == 4) { /* audigy2 */ + if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ u32 tmp; @@ -600,7 +600,7 @@ static int snd_emu10k1_free(emu10k1_t *emu) if (emu->port) pci_release_regions(emu->pci); pci_disable_device(emu->pci); - if (emu->audigy && emu->revision == 4) /* P16V */ + if (emu->card_capabilities->ca0151_chip) /* P16V */ snd_p16v_free(emu); kfree(emu); return 0; @@ -612,8 +612,6 @@ static int snd_emu10k1_dev_free(snd_device_t *device) return snd_emu10k1_free(emu); } -/* vendor, device, subsystem, emu10k1_chip, emu10k2_chip, ca0102_chip, ca0108_chip, ca0151_chip, spk71, spdif_bug, ac97_chip, ecard, driver, name */ - static emu_chip_details_t emu_chip_details[] = { /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, @@ -688,15 +686,22 @@ static emu_chip_details_t emu_chip_details[] = { {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, .driver = "EMU10K1", .name = "SB Live 5.1", .emu10k1_chip = 1, - .ac97_chip = 1} , + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", .emu10k1_chip = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .driver = "EMU10K1", .name = "SB Live [Unknown]", .emu10k1_chip = 1, - .ac97_chip = 1} , + .ac97_chip = 1, + .sblive51 = 1} , { } /* terminator */ }; @@ -747,7 +752,6 @@ int __devinit snd_emu10k1_create(snd_card_t * card, emu->revision = revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); - emu->card_type = EMU10K1_CARD_CREATIVE; snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model); for (c = emu_chip_details; c->vendor; c++) { @@ -825,15 +829,6 @@ int __devinit snd_emu10k1_create(snd_card_t * card, pci_set_master(pci); - if (c->ecard) { - emu->card_type = EMU10K1_CARD_EMUAPS; - emu->APS = 1; - } - if (! c->ac97_chip) - emu->no_ac97 = 1; - - emu->spk71 = c->spk71; - emu->fx8010.fxbus_mask = 0x303f; if (extin_mask == 0) extin_mask = 0x3fcf; @@ -842,7 +837,7 @@ int __devinit snd_emu10k1_create(snd_card_t * card, emu->fx8010.extin_mask = extin_mask; emu->fx8010.extout_mask = extout_mask; - if (emu->APS) { + if (emu->card_capabilities->ecard) { if ((err = snd_emu10k1_ecard_init(emu)) < 0) { snd_emu10k1_free(emu); return err; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index b9fa2e887fe..0529fb28112 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1077,7 +1077,7 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) gpr += 2; /* PCM Side Playback (independent from stereo mix) */ - if (emu->spk71) { + if (emu->card_capabilities->spk71) { A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100); @@ -1145,14 +1145,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "CD Playback Volume" : "Audigy CD Playback Volume", + emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume", gpr, 0); gpr += 2; /* Audigy CD Capture Volume */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "CD Capture Volume" : "Audigy CD Capture Volume", + emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume", gpr, 0); gpr += 2; @@ -1171,14 +1171,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "Line Playback Volume" : "Line2 Playback Volume", + emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume", gpr, 0); gpr += 2; /* Line2 Capture Volume */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "Line Capture Volume" : "Line2 Capture Volume", + emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume", gpr, 0); gpr += 2; @@ -1197,14 +1197,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "Aux Playback Volume" : "Aux2 Playback Volume", + emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume", gpr, 0); gpr += 2; /* Aux2 Capture Volume */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->no_ac97 ? "Aux Capture Volume" : "Aux2 Capture Volume", + emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume", gpr, 0); gpr += 2; @@ -1232,7 +1232,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); gpr++; - if (emu->spk71) { + if (emu->card_capabilities->spk71) { /* Stereo Mix Side Playback */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1)); @@ -1266,7 +1266,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */ A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */ A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */ - if (emu->spk71) { + if (emu->card_capabilities->spk71) { A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 6), A_GPR(playback + 6), A_C_00000000, A_C_00000000); /* side left */ A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 7), A_GPR(playback + 7), A_C_00000000, A_C_00000000); /* side right */ } @@ -1359,7 +1359,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); - if (emu->spk71) + if (emu->card_capabilities->spk71) A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS); /* headphone */ @@ -1982,22 +1982,27 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000); /* EFX capture - capture the 16 EXTINS */ - OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0)); - OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1)); - OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2)); - OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3)); - /* Dont connect anything to FXBUS2 1 and 2. These are shared with - * Center/LFE on the SBLive 5.1. The kX driver only changes the - * routing when it detects an SBLive 5.1. - * - * Since only 14 of the 16 EXTINs are used, this is not a big problem. - * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture - * 0 and 3, then the rest of the EXTINs to the corresponding FX capture - * channel. - */ - for (z = 4; z < 14; z++) { - OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); + if (emu->card_capabilities->sblive51) { + /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER + * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording. + * + * Since only 14 of the 16 EXTINs are used, this is not a big problem. + * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture + * 0 and 3, then the rest of the EXTINs to the corresponding FX capture + * channel. Multitrack recorders will still see the center/lfe output signal + * on the second and third channels. + */ + OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0)); + OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1)); + OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2)); + OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3)); + for (z = 4; z < 14; z++) + OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); + } else { + for (z = 0; z < 16; z++) + OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); } + if (gpr > tmp) { snd_BUG(); @@ -2128,7 +2133,6 @@ static int snd_emu10k1_fx8010_info(emu10k1_t *emu, emu10k1_fx8010_info_t *info) int res; memset(info, 0, sizeof(info)); - info->card = emu->card_type; info->internal_tram_size = emu->fx8010.itram_size; info->external_tram_size = emu->fx8010.etram_pages.bytes / 2; fxbus = fxbuses; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 044663d31aa..d0b296587cc 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -791,7 +791,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) NULL }; - if (!emu->no_ac97) { + if (emu->card_capabilities->ac97_chip) { ac97_bus_t *pbus; ac97_template_t ac97; static ac97_bus_ops_t ops = { @@ -833,7 +833,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) for (; *c; c++) remove_ctl(card, *c); } else { - if (emu->APS) + if (emu->card_capabilities->ecard) strcpy(emu->card->mixername, "EMU APS"); else if (emu->audigy) strcpy(emu->card->mixername, "SB Audigy"); @@ -918,7 +918,7 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) mix->attn[0] = 0xffff; } - if (! emu->APS) { /* FIXME: APS has these controls? */ + if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ /* sb live! and audigy */ if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) return -ENOMEM; @@ -939,14 +939,14 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; - } else if (! emu->APS) { + } else if (! emu->card_capabilities->ecard) { /* sb live! */ if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; } - if (emu->audigy && emu->revision == 4) { /* P16V */ + if (emu->card_capabilities->ca0151_chip) { /* P16V */ if ((err = snd_p16v_mixer(emu))) return err; } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index d990d5eb45a..732d17d1307 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -182,7 +182,7 @@ static void snd_emu10k1_proc_read(snd_info_entry_t *entry, snd_iprintf(buffer, "EMU10K1\n\n"); snd_iprintf(buffer, "Card : %s\n", - emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative")); + emu->audigy ? "Audigy" : (emu->card_capabilities->ecard ? "EMU APS" : "Creative")); snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size); snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2); snd_iprintf(buffer, "\n"); -- cgit v1.2.3-70-g09d2 From aec72e0a4be407fb69fbee812cf0028d62e75152 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Mar 2005 14:22:25 +0200 Subject: [ALSA] Use old default id strings for compatibility EMU10K1/EMU10K2 driver Use expliciitly the old default id strings for backward compatibility. This will make 'alsactl restore' working again. Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 5 +++-- sound/pci/emu10k1/emu10k1_main.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index b1e8ee8e0fa..6647919768b 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1050,8 +1050,9 @@ typedef struct { unsigned char spdif_bug; /* Has Spdif phasing bug */ unsigned char ac97_chip; /* Has an AC97 chip */ unsigned char ecard; /* APS EEPROM */ - char * driver; - char * name; + const char *driver; + const char *name; + const char *id; /* for backward compatibility - can be NULL if not needed */ } emu_chip_details_t; struct _snd_emu10k1 { diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 38be0f1b0e7..a2fa5012c84 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -616,15 +616,18 @@ static emu_chip_details_t emu_chip_details[] = { /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1} , {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -633,6 +636,7 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -641,6 +645,7 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -649,6 +654,7 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102, .driver = "Audigy2", .name = "Audigy 2 [SB0240]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -657,12 +663,14 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, .driver = "Audigy2", .name = "Audigy 2 EX [1005]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, .spdif_bug = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", + .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, .ca0151_chip = 1, @@ -671,34 +679,41 @@ static emu_chip_details_t emu_chip_details[] = { .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052, .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", + .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .spdif_bug = 1} , {.vendor = 0x1102, .device = 0x0004, .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", + .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .spdif_bug = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, .driver = "EMU10K1", .name = "E-mu APS [4001]", + .id = "APS", .emu10k1_chip = 1, .ecard = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, .driver = "EMU10K1", .name = "SB Live 5.1", + .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", + .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", + .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .driver = "EMU10K1", .name = "SB Live [Unknown]", + .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , @@ -772,6 +787,9 @@ int __devinit snd_emu10k1_create(snd_card_t * card, else snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial); + if (!*card->id && c->id) + strlcpy(card->id, c->id, sizeof(card->id)); + is_audigy = emu->audigy = c->emu10k2_chip; /* set the DMA transfer mask */ -- cgit v1.2.3-70-g09d2 From 85a655d66b4d1672c7c6fee31297837556585f6b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Mar 2005 14:40:25 +0200 Subject: [ALSA] Fix the default id of multiple cards EMU10K1/EMU10K2 driver Fixed the default id string in case identical multiple cards exist. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index a2fa5012c84..c51a8ae464e 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -787,8 +787,22 @@ int __devinit snd_emu10k1_create(snd_card_t * card, else snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial); - if (!*card->id && c->id) + if (!*card->id && c->id) { + int i, n = 0; strlcpy(card->id, c->id, sizeof(card->id)); + for (;;) { + for (i = 0; i < snd_ecards_limit; i++) { + if (snd_cards[i] && !strcmp(snd_cards[i]->id, card->id)) + break; + } + if (i >= snd_ecards_limit) + break; + n++; + if (n >= SNDRV_CARDS) + break; + snprintf(card->id, sizeof(card->id), "%s_%d", c->id, n); + } + } is_audigy = emu->audigy = c->emu10k2_chip; -- cgit v1.2.3-70-g09d2 From 2668907a825702ba9c0e603f160a993b034572f5 Mon Sep 17 00:00:00 2001 From: Peter Zubaj Date: Fri, 1 Apr 2005 11:15:07 +0200 Subject: [ALSA] Audigy SB0090 identification EMU10K1/EMU10K2 driver This add identification of Audigy 1 model SB0090 and fixes problems with ac97 codec (mic not working). Signed-off-by: Peter Zubaj Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c51a8ae464e..a3a1a10fb0c 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -619,12 +619,14 @@ static emu_chip_details_t emu_chip_details[] = { .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, - .spk71 = 1} , + .spk71 = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", .id = "Audigy2", .emu10k2_chip = 1, - .ca0108_chip = 1} , + .ca0108_chip = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", .id = "Audigy2", @@ -682,13 +684,21 @@ static emu_chip_details_t emu_chip_details[] = { .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, - .spdif_bug = 1} , + .spdif_bug = 1, + .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102, + .driver = "Audigy", .name = "Audigy 1 [SB0090]", + .id = "Audigy", + .emu10k2_chip = 1, + .ca0102_chip = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, - .spdif_bug = 1} , + .spdif_bug = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, .driver = "EMU10K1", .name = "E-mu APS [4001]", .id = "APS", -- cgit v1.2.3-70-g09d2 From bdaed50292bea3e2b20c68c2ffe9dbde7c0d6910 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Apr 2005 15:48:42 +0200 Subject: [ALSA] Check revision for the proper detection of audigy 2 EMU10K1/EMU10K2 driver Check ther revision to detect non-listed audigy 2 boards. Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 1 + sound/pci/emu10k1/emu10k1_main.c | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 6647919768b..f5babd3f845 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1040,6 +1040,7 @@ typedef struct { u32 vendor; u32 device; u32 subsystem; + unsigned char revision; unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */ unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index a3a1a10fb0c..c6d53b45925 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -679,6 +679,14 @@ static emu_chip_details_t emu_chip_details[] = { .spk71 = 1, .spdif_bug = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, + .driver = "Audigy2", .name = "Audigy 2 [Unknown]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0102_chip = 1, + .ca0151_chip = 1, + .spdif_bug = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052, .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", .id = "Audigy", @@ -693,11 +701,10 @@ static emu_chip_details_t emu_chip_details[] = { .ca0102_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, - .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", + .driver = "Audigy", .name = "Audigy 1 [Unknown]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, - .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, .driver = "EMU10K1", .name = "E-mu APS [4001]", @@ -781,8 +788,11 @@ int __devinit snd_emu10k1_create(snd_card_t * card, for (c = emu_chip_details; c->vendor; c++) { if (c->vendor == pci->vendor && c->device == pci->device) { - if (c->subsystem == emu->serial) break; - if (c->subsystem == 0) break; + if (c->subsystem && c->subsystem != emu->serial) + continue; + if (c->revision && c->revision != emu->revision) + continue; + break; } } if (c->vendor == 0) { -- cgit v1.2.3-70-g09d2 From 55911694bf5edf15328dc6558fa3f432d52015ee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Apr 2005 15:50:13 +0200 Subject: [ALSA] Remove unused variables AC97 Codec Removed unused variables (the old control definitions). Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 7d2854de0c1..4ece2053bb1 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -658,11 +658,6 @@ AC97_SINGLE("LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 1, 1), AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1) }; -static const snd_kcontrol_new_t snd_ac97_controls_surround[2] = { -AC97_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), -AC97_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), -}; - static const snd_kcontrol_new_t snd_ac97_control_eapd = AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); -- cgit v1.2.3-70-g09d2 From 5f0dccf8500b0cc2ff247f626bc249bc184fd184 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 7 Apr 2005 15:53:20 +0200 Subject: [ALSA] Add CM9780 support, fix CM9761 SPDIF AC97 Codec - Added CM9780 patch - Fix the SPDIF support on CM9761/CM9780 - Allow the generic enum callback to pass any number (not power of 2) as the value mask Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 17 ++++-- sound/pci/ac97/ac97_patch.c | 143 ++++++++++++++++++++++++++++++++++++++------ sound/pci/ac97/ac97_patch.h | 1 + 3 files changed, 137 insertions(+), 24 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 4ece2053bb1..61549b1eb59 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -120,6 +120,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { { 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, { 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, +{ 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL }, { 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL }, { 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL }, { 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL }, @@ -462,12 +463,14 @@ int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; - unsigned short val; + unsigned short val, bitmask; + for (bitmask = 1; bitmask > e->mask; bitmask <<= 1) + ; val = snd_ac97_read_cache(ac97, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1); + ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); if (e->shift_l != e->shift_r) - ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1); + ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1); return 0; } @@ -477,17 +480,19 @@ int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u ac97_t *ac97 = snd_kcontrol_chip(kcontrol); struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; unsigned short val; - unsigned short mask; + unsigned short mask, bitmask; + for (bitmask = 1; bitmask > e->mask; bitmask <<= 1) + ; if (ucontrol->value.enumerated.item[0] > e->mask - 1) return -EINVAL; val = ucontrol->value.enumerated.item[0] << e->shift_l; - mask = (e->mask - 1) << e->shift_l; + mask = (bitmask - 1) << e->shift_l; if (e->shift_l != e->shift_r) { if (ucontrol->value.enumerated.item[1] > e->mask - 1) return -EINVAL; val |= ucontrol->value.enumerated.item[1] << e->shift_r; - mask |= (e->mask - 1) << e->shift_r; + mask |= (bitmask - 1) << e->shift_r; } return snd_ac97_update_bits(ac97, e->reg, mask, val); } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 13c34a5d820..473840d431b 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2087,12 +2087,13 @@ int patch_cm9739(ac97_t * ac97) } #define AC97_CM9761_MULTI_CHAN 0x64 +#define AC97_CM9761_FUNC 0x66 #define AC97_CM9761_SPDIF_CTRL 0x6c static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x0400) + if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x0400) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; @@ -2106,14 +2107,14 @@ static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_el { 0x0008, 0x0400 }, /* off, on */ { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ }; - return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x0408, + return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); } static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) + if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x1000) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; @@ -2129,7 +2130,7 @@ static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_ele { 0x2000, 0x1880 }, /* off, on */ { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ }; - return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3880, + return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); } @@ -2152,6 +2153,70 @@ static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { }, }; +static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item > 2) + uinfo->value.enumerated.item = 2; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int cm9761_spdif_out_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + if (ac97->regs[AC97_CM9761_FUNC] & 0x1) + ucontrol->value.enumerated.item[0] = 2; /* SPDIF-loopback */ + else if (ac97->regs[AC97_CM9761_SPDIF_CTRL] & 0x2) + ucontrol->value.enumerated.item[0] = 1; /* ADC loopback */ + else + ucontrol->value.enumerated.item[0] = 0; /* AC-link */ + return 0; +} + +static int cm9761_spdif_out_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + if (ucontrol->value.enumerated.item[0] == 2) + return snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0x1); + snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0); + return snd_ac97_update_bits(ac97, AC97_CM9761_SPDIF_CTRL, 0x2, + ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0); +} + +static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" }; +static const struct ac97_enum cm9761_dac_clock_enum = + AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock); + +static const snd_kcontrol_new_t snd_ac97_cm9761_controls_spdif[] = { + { /* BIT 1: SPDIFS */ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", + .info = cm9761_spdif_out_source_info, + .get = cm9761_spdif_out_source_get, + .put = cm9761_spdif_out_source_put, + }, + /* BIT 2: IG_SPIV */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9761_SPDIF_CTRL, 2, 1, 0), + /* BIT 3: SPI2F */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9761_SPDIF_CTRL, 3, 1, 0), + /* BIT 4: SPI2SDI */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9761_SPDIF_CTRL, 4, 1, 0), + /* BIT 9-10: DAC_CTL */ + AC97_ENUM("DAC Clock Source", cm9761_dac_clock_enum), +}; + +static int patch_cm9761_post_spdif(ac97_t * ac97) +{ + return patch_build_controls(ac97, snd_ac97_cm9761_controls_spdif, ARRAY_SIZE(snd_ac97_cm9761_controls_spdif)); +} + static int patch_cm9761_specific(ac97_t * ac97) { return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); @@ -2159,7 +2224,7 @@ static int patch_cm9761_specific(ac97_t * ac97) static struct snd_ac97_build_ops patch_cm9761_ops = { .build_specific = patch_cm9761_specific, - .build_post_spdif = patch_cm9739_post_spdif /* hope it's identical... */ + .build_post_spdif = patch_cm9761_post_spdif }; int patch_cm9761(ac97_t *ac97) @@ -2193,24 +2258,25 @@ int patch_cm9761(ac97_t *ac97) /* to be sure: we overwrite the ext status bits */ snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0); /* Don't set 0x0200 here. This results in the silent analog output */ - snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009); + snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0001); /* enable spdif-in */ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ /* set-up multi channel */ /* bit 15: pc master beep off - * bit 14: ?? + * bit 14: pin47 = EAPD/SPDIF * bit 13: vref ctl [= cm9739] - * bit 12: center/mic [= cm9739] (reverted on rev B) - * bit 11: ?? (mic/center/lfe) (reverted on rev B) - * bit 10: suddound/line [= cm9739] - * bit 9: mix 2 surround - * bit 8: ? - * bit 7: ?? (mic/center/lfe) - * bit 4: ?? (front) - * bit 3: ?? (line-in/rear share) (revereted with rev B) - * bit 2: ?? (surround) - * bit 1: front mic - * bit 0: mic boost + * bit 12: CLFE control (reverted on rev B) + * bit 11: Mic/center share (reverted on rev B) + * bit 10: suddound/line share + * bit 9: Analog-in mix -> surround + * bit 8: Analog-in mix -> CLFE + * bit 7: Mic/LFE share (mic/center/lfe) + * bit 5: vref select (9761A) + * bit 4: front control + * bit 3: surround control (revereted with rev B) + * bit 2: front mic + * bit 1: stereo mic + * bit 0: mic boost level (0=20dB, 1=30dB) */ #if 0 @@ -2230,6 +2296,47 @@ int patch_cm9761(ac97_t *ac97) return 0; } +#define AC97_CM9780_SIDE 0x60 +#define AC97_CM9780_JACK 0x62 +#define AC97_CM9780_MIXER 0x64 +#define AC97_CM9780_MULTI_CHAN 0x66 +#define AC97_CM9780_SPDIF 0x6c + +static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" }; +static const struct ac97_enum cm9780_ch_select_enum = + AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select); +static const snd_kcontrol_new_t cm9780_controls[] = { + AC97_DOUBLE("Side Playback Switch", AC97_CM9780_SIDE, 15, 7, 1, 1), + AC97_DOUBLE("Side Playback Volume", AC97_CM9780_SIDE, 8, 0, 31, 0), + AC97_ENUM("Side Playback Route", cm9780_ch_select_enum), +}; + +static int patch_cm9780_specific(ac97_t *ac97) +{ + return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls)); +} + +static struct snd_ac97_build_ops patch_cm9780_ops = { + .build_specific = patch_cm9780_specific, + .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */ +}; + +int patch_cm9780(ac97_t *ac97) +{ + unsigned short val; + + ac97->build_ops = &patch_cm9780_ops; + + /* enable spdif */ + if (ac97->ext_id & AC97_EI_SPDIF) { + ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ + val = snd_ac97_read(ac97, AC97_CM9780_SPDIF); + val |= 0x1; /* SPDI_EN */ + snd_ac97_write_cache(ac97, AC97_CM9780_SPDIF, val); + } + + return 0; +} /* * VIA VT1616 codec diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 6db51c96f5d..7b7377d0f2a 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -54,6 +54,7 @@ int patch_alc850(ac97_t * ac97); int patch_cm9738(ac97_t * ac97); int patch_cm9739(ac97_t * ac97); int patch_cm9761(ac97_t * ac97); +int patch_cm9780(ac97_t * ac97); int patch_vt1616(ac97_t * ac97); int patch_it2646(ac97_t * ac97); int mpatch_si3036(ac97_t * ac97); -- cgit v1.2.3-70-g09d2 From 2c56c47f678b0388290686d5a0988d8806ffe5cc Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Thu, 7 Apr 2005 20:21:21 +0200 Subject: [ALSA] Fix 'semaphore is not ready' problem with snd-intel8x0m Intel8x0-modem driver With some intel based ac97 modems codec access semaphore is not cleared after 0x54 AC97 register (GPIO_STATUS) reads. This may causes problems with newly applied modem mixer (Off-hook switch) and in other cases. Signed-off-by: Sasha Khapyorsky Signed-off-by: Takashi Iwai --- sound/pci/intel8x0m.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 67da096d659..f9972b20050 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -500,6 +500,8 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, res = 0xffff; } } + if (reg == AC97_GPIO_STATUS) + iagetword(chip, 0); /* clear semaphore */ return res; } -- cgit v1.2.3-70-g09d2 From 8e8311b0ac4dc8a2cf317e122a6f7dc4467e3254 Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Thu, 7 Apr 2005 20:22:58 +0200 Subject: [ALSA] Fix MC97 codec initialization AC97 Codec This (especially 12000 -> 8000 sample rate replace) fix popular 'MC97 converters.. not ready' error with modem codecs initializations. Signed-off-by: Sasha Khapyorsky Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 61549b1eb59..ab7114c51dc 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1964,21 +1964,21 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) /* note: it's important to set the rate at first */ tmp = AC97_MEA_GPIO; if (ac97->ext_mid & AC97_MEI_LINE1) { - snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 8000); tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; } if (ac97->ext_mid & AC97_MEI_LINE2) { - snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 8000); tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; } if (ac97->ext_mid & AC97_MEI_HANDSET) { - snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 8000); tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; } - snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); udelay(100); /* nothing should be in powerdown mode */ - snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); end_time = jiffies + (HZ / 10); do { if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) -- cgit v1.2.3-70-g09d2 From 23fea4dad67a665e8d359dbb39180422385f1dcc Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Thu, 7 Apr 2005 20:23:58 +0200 Subject: [ALSA] MC97 registers reset AC97 Codec Separated ac97 registers reset for audio and modem (or both) as recommended in AC97 spec. Signed-off-by: Sasha Khapyorsky Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index ab7114c51dc..1ad7f83a65e 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1872,7 +1872,11 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) goto __access_ok; } - snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */ + /* reset to defaults */ + if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO)) + snd_ac97_write(ac97, AC97_RESET, 0); + if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM)) + snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); if (bus->ops->wait) bus->ops->wait(ac97); else { -- cgit v1.2.3-70-g09d2 From f953eff29c1ea4c744afe3d50ff5ca33b44efcd2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Apr 2005 15:05:13 +0200 Subject: [ALSA] choose multi-channel jacks automatically HDA Codec driver Patch by C.L. Tien : The patch makes cm9880 to choose multi-channel jacks automatically. 1. I found the current code has basic_init, which already includes necessary controls for 6-stack initialization, so I don't need another model. 2. I add a new model 'auto' to let the driver find a. if there are option real panel/front panel, b. the jacks to be used for multichannel. Because the jack color are based on MS's channel sequence, so the 'auto' model will pick the same jacks for multichannel MS uses. I did this to hope to minimize users questions. These code can also be applied to other codecs but I don't have any to test. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cmedia.c | 233 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 3 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index a44d64e828d..e64e29dac82 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -29,6 +29,7 @@ #include #include "hda_codec.h" #include "hda_local.h" +#define NUM_PINS 11 /* board config type */ @@ -38,6 +39,7 @@ enum { CMI_FULL, /* back 6-jack + front-panel 2-jack */ CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ + CMI_AUTO, /* let driver guess it */ }; struct cmi_spec { @@ -48,6 +50,7 @@ struct cmi_spec { /* playback */ struct hda_multi_out multiout; + hda_nid_t dac_nids[4]; /* NID for each DAC */ /* capture */ hda_nid_t *adc_nids; @@ -63,6 +66,15 @@ struct cmi_spec { const struct cmi_channel_mode *channel_modes; struct hda_pcm pcm_rec[2]; /* PCM information */ + + /* pin deafault configuration */ + hda_nid_t pin_nid[NUM_PINS]; + unsigned int def_conf[NUM_PINS]; + unsigned int pin_def_confs; + + /* multichannel pins */ + hda_nid_t multich_pin[4]; /* max 8-channel */ + struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ }; /* @@ -353,6 +365,175 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } +#define AC_DEFCFG_ASSOC_SHIFT 4 +#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) +#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) +#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) + +/* get all pin default configuration in def_conf */ +static int cmi9880_get_pin_def_config(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + hda_nid_t nid, nid_start; + int i = 0, nodes; + + nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); + for (nid = nid_start; nid < nodes + nid_start; nid++) { + unsigned int wid_caps = snd_hda_param_read(codec, nid, + AC_PAR_AUDIO_WIDGET_CAP); + unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + /* read all default configuration for pin complex */ + if (wid_type == AC_WID_PIN) { + spec->pin_nid[i] = nid; + spec->def_conf[i] = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + i++; + } + } + spec->pin_def_confs = i; + return 0; +} + +/* get a pin default configuration of nid in def_conf */ +static unsigned int cmi9880_get_def_config(struct hda_codec *codec, hda_nid_t nid) +{ + struct cmi_spec *spec = codec->spec; + int i = 0; + + while (spec->pin_nid[i] != nid && i < spec->pin_def_confs) + i++; + if (i == spec->pin_def_confs) + return (unsigned int) -1; + else + return spec->def_conf[i]; +} + +/* decide what pins to use for multichannel playback */ +static int cmi9880_get_multich_pins(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + int i, j, pins, seq[4]; + int max_channel = 0; + unsigned int def_conf, sequence; + hda_nid_t nid; + + memset(spec->multich_pin, 0, sizeof(spec->multich_pin)); + for (pins = 0, i = 0; i < spec->pin_def_confs && pins < 4; i++) { + def_conf = spec->def_conf[i]; + /* skip pin not connected */ + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + continue; + /* get the sequence if association == 1 */ + /* the other pins have association = 0, incorrect in spec 1.0 */ + if (get_defcfg_association(def_conf) == 1) { + sequence = get_defcfg_sequence(def_conf); + seq[pins] = sequence; + spec->multich_pin[pins] = spec->pin_nid[i]; + pins++; // ready for next slot + max_channel += 2; + } + } + /* sort by sequence, data collected here will be for Windows */ + for (i = 0; i < pins; i++) { + for (j = i + 1; j < pins; j++) { + if (seq[j] < seq[i]) { + sequence = seq[j]; + nid = spec->multich_pin[j]; + seq[j] = seq[i]; + spec->multich_pin[j] = spec->multich_pin[i]; + seq[i] = sequence; + spec->multich_pin[i] = nid; + } + } + } + /* the pin assignment is for front, C/LFE, surround and back */ + if (max_channel >= 6) { + hda_nid_t temp; + /* exchange pin of C/LFE and surround */ + temp = spec->multich_pin[1]; + spec->multich_pin[1] = spec->multich_pin[2]; + spec->multich_pin[2] = temp; + } + return max_channel; +} + +/* fill in the multi_dac_nids table, which will decide + which audio widget to use for each channel */ +static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + hda_nid_t nid; + int assigned[4]; + int i, j; + + /* clear the table, only one c-media dac assumed here */ + memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); + memset(assigned, 0, sizeof(assigned)); + /* check the pins we found */ + for (i = 0; i < spec->multiout.max_channels / 2; i++) { + nid = spec->multich_pin[i]; + /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ + if (nid <= 0x0e && nid >= 0x0b) { + spec->dac_nids[i] = nid - 0x08; + assigned[nid - 0x0b] = 1; + } + } + /* left pin can be connect to any audio widget */ + for (i = 0; i < spec->multiout.max_channels / 2; i++) { + if (!assigned[i]) { + /* search for an empty channel */ + /* I should also check the pin type */ + for (j = 0; j < ARRAY_SIZE(spec->dac_nids); j++) + if (! spec->dac_nids[j]) { + spec->dac_nids[j] = i + 3; + assigned[i] = 1; + break; + } + } + } + return 0; +} + +/* create multi_init table, which is used for multichannel initialization */ +static int cmi9880_fill_multi_init(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + hda_nid_t nid; + int i, j, k, len; + + /* clear the table, only one c-media dac assumed here */ + memset(spec->multi_init, 0, sizeof(spec->multi_init)); + for (j = 0, i = 0; i < spec->multiout.max_channels / 2; i++) { + hda_nid_t conn[4]; + nid = spec->multich_pin[i]; + /* set as output */ + spec->multi_init[j].nid = nid; + spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; + spec->multi_init[j].param = 0xc0; + j++; + /* nid 0x0f,0x10,0x1f,0x20 are needed to set connection */ + switch (nid) { + case 0x0f: + case 0x10: + case 0x1f: + case 0x20: + /* set connection */ + spec->multi_init[j].nid = nid; + spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; + /* find the index in connect list */ + len = snd_hda_get_connections(codec, nid, conn, 4); + for (k = 0; k < len; k++) + if (conn[k] == spec->dac_nids[i]) + break; + spec->multi_init[j].param = k < len ? k : 0; + j++; + break; + } + } + return 0; +} + static int cmi9880_init(struct hda_codec *codec) { struct cmi_spec *spec = codec->spec; @@ -360,6 +541,8 @@ static int cmi9880_init(struct hda_codec *codec) snd_hda_sequence_write(codec, cmi9880_allout_init); else snd_hda_sequence_write(codec, cmi9880_basic_init); + if (spec->board_config == CMI_AUTO) + snd_hda_sequence_write(codec, spec->multi_init); return 0; } @@ -546,6 +729,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = { { .modelname = "full", .config = CMI_FULL }, { .modelname = "full_dig", .config = CMI_FULL_DIG }, { .modelname = "allout", .config = CMI_ALLOUT }, + { .modelname = "auto", .config = CMI_AUTO }, {} /* terminator */ }; @@ -570,10 +754,13 @@ static int patch_cmi9880(struct hda_codec *codec) codec->spec = spec; spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); if (spec->board_config < 0) { - snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); - spec->board_config = CMI_FULL_DIG; /* try everything */ + snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); + spec->board_config = CMI_AUTO; /* try everything */ } + /* copy default DAC NIDs */ + memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); + switch (spec->board_config) { case CMI_MINIMAL: case CMI_MIN_FP: @@ -605,10 +792,50 @@ static int patch_cmi9880(struct hda_codec *codec) spec->input_mux = &cmi9880_no_line_mux; spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; break; + case CMI_AUTO: + { + unsigned int port_e, port_f, port_g, port_h; + unsigned int port_spdifi, port_spdifo; + /* collect pin default configuration */ + cmi9880_get_pin_def_config(codec); + port_e = cmi9880_get_def_config(codec, 0x0f); + port_f = cmi9880_get_def_config(codec, 0x10); + port_g = cmi9880_get_def_config(codec, 0x1f); + port_h = cmi9880_get_def_config(codec, 0x20); + port_spdifi = cmi9880_get_def_config(codec, 0x13); + port_spdifo = cmi9880_get_def_config(codec, 0x12); + spec->front_panel = 1; + if ((get_defcfg_connect(port_e) == AC_JACK_PORT_NONE) + || (get_defcfg_connect(port_f) == AC_JACK_PORT_NONE)) { + spec->surr_switch = 1; + /* no front panel */ + if ((get_defcfg_connect(port_g) == AC_JACK_PORT_NONE) + || (get_defcfg_connect(port_h) == AC_JACK_PORT_NONE)) { + /* no optional rear panel */ + spec->board_config = CMI_MINIMAL; + spec->front_panel = 0; + spec->num_ch_modes = 2; + } else + spec->board_config = CMI_MIN_FP; + spec->num_ch_modes = 3; + spec->channel_modes = cmi9880_channel_modes; + spec->input_mux = &cmi9880_basic_mux; + } else { + spec->input_mux = &cmi9880_basic_mux; + if (get_defcfg_connect(port_spdifo) != 1) + spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; + if (get_defcfg_connect(port_spdifi) != 1) + spec->dig_in_nid = CMI_DIG_IN_NID; + } + spec->multiout.max_channels = cmi9880_get_multich_pins(codec); + cmi9880_fill_multi_dac_nids(codec); + cmi9880_fill_multi_init(codec); + } + break; } spec->multiout.num_dacs = 4; - spec->multiout.dac_nids = cmi9880_dac_nids; + spec->multiout.dac_nids = spec->dac_nids; spec->adc_nids = cmi9880_adc_nids; -- cgit v1.2.3-70-g09d2 From df34140a9c15d4be8833f7977dca277a03ab87b0 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 9 Apr 2005 16:57:09 +0200 Subject: [ALSA] Display SPDIF in status in proc fs 'spdif-in' file. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton --- sound/pci/emu10k1/emuproc.c | 61 ++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 732d17d1307..187a4e60a5f 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -44,28 +44,33 @@ static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, unsigned int status, rate = 0; status = snd_emu10k1_ptr_read(emu, status_reg, 0); - if (rate_reg > 0) - rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); snd_iprintf(buffer, "\n%s\n", title); - snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); - snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); - snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); - snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); - snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); - snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); - snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy"); - snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16); - snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]); - snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]); - snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]); - - if (rate_reg > 0) { - snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); - snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); - snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", rate & SRCS_ESTSAMPLERATE); + if (status != 0xffffffff) { + snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); + snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); + snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); + snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); + snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); + snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); + snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy"); + snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16); + snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]); + snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]); + snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]); + + if (rate_reg > 0) { + rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); + snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); + snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); + /* From ((Rate * 48000 ) / 262144); */ + snd_iprintf(buffer, "Estimated Sample Rate : %d\n", ((rate & 0xFFFFF ) * 375) >> 11); + } + } else { + snd_iprintf(buffer, "No signal detected.\n"); } + } static void snd_emu10k1_proc_read(snd_info_entry_t *entry, @@ -223,15 +228,20 @@ static void snd_emu10k1_proc_read(snd_info_entry_t *entry, snd_iprintf(buffer, "\nAll FX Outputs :\n"); for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++) snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); - snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 0", SPCS0, -1); - snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 1", SPCS1, -1); - snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 2/3", SPCS2, -1); - snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF", CDCS, CDSRCS); - snd_emu10k1_proc_spdif_status(emu, buffer, "General purpose S/PDIF", GPSCS, GPSRCS); +} + +static void snd_emu10k1_proc_spdif_read(snd_info_entry_t *entry, + snd_info_buffer_t * buffer) +{ + emu10k1_t *emu = entry->private_data; + snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); + snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); +#if 0 val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0); snd_iprintf(buffer, "\nZoomed Video\n"); snd_iprintf(buffer, "Rate Locked : %s\n", val & SRCS_RATELOCKED ? "on" : "off"); snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", val & SRCS_ESTSAMPLERATE); +#endif } static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry, @@ -526,6 +536,11 @@ int __devinit snd_emu10k1_proc_init(emu10k1_t * emu) if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read); + if (emu->card_capabilities->emu10k2_chip) { + if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) + snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read); + } + if (! snd_card_proc_new(emu->card, "voices", &entry)) snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); -- cgit v1.2.3-70-g09d2 From 001f758990d685e7023008763795f1970ef56614 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 9 Apr 2005 23:38:25 +0200 Subject: [ALSA] Improve SPDIF playback via the P16V/CA0151 chip. EMU10K1/EMU10K2 driver Although we can set 44100 as the output rate, the SPDIF can do it, but the Analog output cannot. The SPDIF has the bug, whereby the Left channel arrives one sample late, so although we don't do any resampling, it is not good for AC3 non-audio output. Signed-off-by: James Courtier-Dutton --- include/sound/emu10k1.h | 1 + sound/pci/emu10k1/emumixer.c | 2 ++ sound/pci/emu10k1/emuproc.c | 21 +++++++++++++++++++++ sound/pci/emu10k1/p16v.c | 16 +++++++--------- 4 files changed, 31 insertions(+), 9 deletions(-) (limited to 'sound/pci') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index f5babd3f845..61a3f418f30 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -747,6 +747,7 @@ /* Assumes sample lock */ /* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */ +#define SRCS_SPDIFVALID 0x04000000 /* SPDIF stream valid */ #define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */ #define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */ #define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */ diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index d0b296587cc..b544c258266 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -935,10 +935,12 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; +#if 0 if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; +#endif } else if (! emu->card_capabilities->ecard) { /* sb live! */ if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 187a4e60a5f..356fb710425 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -30,6 +30,7 @@ #include #include #include +#include "p16v.h" static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, snd_info_buffer_t * buffer, @@ -62,6 +63,7 @@ static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, if (rate_reg > 0) { rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); + snd_iprintf(buffer, "S/PDIF Valid : %s\n", rate & SRCS_SPDIFVALID ? "on" : "off"); snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); /* From ((Rate * 48000 ) / 262144); */ @@ -244,6 +246,21 @@ static void snd_emu10k1_proc_spdif_read(snd_info_entry_t *entry, #endif } +static void snd_emu10k1_proc_rates_read(snd_info_entry_t *entry, + snd_info_buffer_t * buffer) +{ + static int samplerate[8] = { 44100, 48000, 96000, 192000, 4, 5, 6, 7 }; + emu10k1_t *emu = entry->private_data; + unsigned int val, tmp, n; + val = snd_emu10k1_ptr20_read(emu, CAPTURE_RATE_STATUS, 0); + tmp = (val >> 16) & 0x8; + for (n=0;n<4;n++) { + tmp = val >> (16 + (n*4)); + if (tmp & 0x8) snd_iprintf(buffer, "Channel %d: Rate=%d\n", n, samplerate[tmp & 0x7]); + else snd_iprintf(buffer, "Channel %d: No input\n", n); + } +} + static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { @@ -540,6 +557,10 @@ int __devinit snd_emu10k1_proc_init(emu10k1_t * emu) if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read); } + if (emu->card_capabilities->ca0151_chip) { + if (! snd_card_proc_new(emu->card, "capture-rates", &entry)) + snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_rates_read); + } if (! snd_card_proc_new(emu->card, "voices", &entry)) snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index dd6ce9927e1..8dd87838fb2 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -119,8 +119,8 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ - .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 , - .rate_min = 48000, + .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, + .rate_min = 44100, .rate_max = 192000, .channels_min = 8, .channels_max = 8, @@ -324,19 +324,17 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); switch (runtime->rate) { case 44100: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x8000); /* FIXME: This will change the capture rate as well! */ - break; - case 48000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x0000); /* FIXME: This will change the capture rate as well! */ + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x8080); break; case 96000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x4000); /* FIXME: This will change the capture rate as well! */ + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x4040); break; case 192000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x2000); /* FIXME: This will change the capture rate as well! */ + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x2020); break; + case 48000: default: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, 0x0000); /* FIXME: This will change the capture rate as well! */ + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x0000); break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ -- cgit v1.2.3-70-g09d2 From 310bacd29230abf5f2a230159e48e983171e0f26 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 10 Apr 2005 00:00:24 +0200 Subject: [ALSA] Improve playback startup. Increase buffer size, and reduce xruns. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton --- sound/pci/emu10k1/p16v.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 8dd87838fb2..776761fe557 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -124,9 +124,9 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { .rate_max = 192000, .channels_min = 8, .channels_max = 8, - .buffer_bytes_max = (32*1024), + .buffer_bytes_max = ((65536 - 64) * 8), .period_bytes_min = 64, - .period_bytes_max = (16*1024), + .period_bytes_max = (65536 - 64), .periods_min = 2, .periods_max = 8, .fifo_size = 0, @@ -347,7 +347,8 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0); snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); - snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes + //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes + snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0); snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0); snd_emu10k1_ptr20_write(emu, 0x08, channel, 0); @@ -602,7 +603,7 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), - 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */ + ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0) return err; //snd_printk("preallocate playback substream: err=%d\n", err); } -- cgit v1.2.3-70-g09d2 From fd9a98ec0a7c8ce15928e3454d73533146d9d57c Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 10 Apr 2005 15:43:35 +0200 Subject: [ALSA] Fix typo in speaker routing. Now sound comes from the correct speakers EMU10K1/EMU10K2 driver when using the p16v HD device. Signed-off-by: James Courtier-Dutton --- sound/pci/emu10k1/emu10k1_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c6d53b45925..bf17db1fd24 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -189,7 +189,7 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir) /* Enabled Phased (8-channel) P16V playback */ outl(0x0201, emu->port + HCFG2); /* Set playback routing. */ - snd_emu10k1_ptr_write(emu, CAPTURE_P16V_SOURCE, 0, 78e4); + snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4); } if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ -- cgit v1.2.3-70-g09d2 From aed058e8713f76be9258011238670064ea3e69a8 Mon Sep 17 00:00:00 2001 From: Simone Zinanni Date: Mon, 11 Apr 2005 14:08:40 +0200 Subject: [ALSA] Provides preliminary support for the Terratec Phase 28 card ICE1712 driver Provides preliminary support for the Terratec Phase 28 card. Not extensively tested and probably buggy, but it seems to work. Signed-off-by: Simone Zinanni Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.h | 5 + sound/pci/ice1712/phase.c | 728 ++++++++++++++++++++++++++++++++++++++++++++ sound/pci/ice1712/phase.h | 19 +- 3 files changed, 751 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 8bb1c58c26a..5ad4728daa7 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -373,6 +373,11 @@ struct _snd_ice1712 { unsigned short master[2]; unsigned short vol[8]; } aureon; + /* AC97 register cache for Phase28 */ + struct phase28_spec { + unsigned short master[2]; + unsigned short vol[8]; + } phase28; /* Hoontech-specific setting */ struct hoontech_spec { unsigned char boxbits[4]; diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index d1f90832443..5bf734b04fa 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -45,6 +45,47 @@ #include "envy24ht.h" #include "phase.h" +/* WM8770 registers */ +#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ +#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ +#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ +#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */ +#define WM_PHASE_SWAP 0x12 /* DAC phase */ +#define WM_DAC_CTRL1 0x13 /* DAC control bits */ +#define WM_MUTE 0x14 /* mute controls */ +#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ +#define WM_INT_CTRL 0x16 /* interface control */ +#define WM_MASTER 0x17 /* master clock and mode */ +#define WM_POWERDOWN 0x18 /* power-down controls */ +#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ +#define WM_ADC_MUX 0x1b /* input MUX */ +#define WM_OUT_MUX1 0x1c /* output MUX */ +#define WM_OUT_MUX2 0x1e /* output MUX */ +#define WM_RESET 0x1f /* software reset */ + + +/* + * Logarithmic volume values for WM8770 + * Computed as 20 * Log10(255 / x) + */ +static unsigned char wm_vol[256] = { + 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, + 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, + 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, + 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 +}; + +#define WM_VOL_MAX (sizeof(wm_vol) - 1) +#define WM_VOL_MUTE 0x8000 + static akm4xxx_t akm_phase22 __devinitdata = { .type = SND_AK4524, .num_dacs = 2, @@ -124,6 +165,684 @@ static unsigned char phase22_eeprom[] __devinitdata = { 0x00, /* GPIO_STATE2 */ }; +static unsigned char phase28_eeprom[] __devinitdata = { + 0x0b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ + 0x80, /* ACLINK: I2S */ + 0xfc, /* I2S: vol, 96k, 24bit, 192k */ + 0xc3, /* SPDIF: out-en, out-int, spdif-in */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0x5f, /* GPIO_DIR2 */ + 0x00, /* GPIO_MASK */ + 0x00, /* GPIO_MASK1 */ + 0x00, /* GPIO_MASK2 */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; + +/* + * write data in the SPI mode + */ +static void phase28_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits) +{ + unsigned int tmp; + int i; + + tmp = snd_ice1712_gpio_read(ice); + + snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK| + PHASE28_WM_CS)); + tmp |= PHASE28_WM_RW; + tmp &= ~cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + for (i = bits - 1; i >= 0; i--) { + tmp &= ~PHASE28_SPI_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + if (data & (1 << i)) + tmp |= PHASE28_SPI_MOSI; + else + tmp &= ~PHASE28_SPI_MOSI; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PHASE28_SPI_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + + tmp &= ~PHASE28_SPI_CLK; + tmp |= cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PHASE28_SPI_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); +} + +/* + * get the current register value of WM codec + */ +static unsigned short wm_get(ice1712_t *ice, int reg) +{ + reg <<= 1; + return ((unsigned short)ice->akm[0].images[reg] << 8) | + ice->akm[0].images[reg + 1]; +} + +/* + * set the register value of WM codec + */ +static void wm_put_nocache(ice1712_t *ice, int reg, unsigned short val) +{ + phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16); +} + +/* + * set the register value of WM codec and remember it + */ +static void wm_put(ice1712_t *ice, int reg, unsigned short val) +{ + wm_put_nocache(ice, reg, val); + reg <<= 1; + ice->akm[0].images[reg] = val >> 8; + ice->akm[0].images[reg + 1] = val; +} + +static void wm_set_vol(ice1712_t *ice, unsigned int index, unsigned short vol, unsigned short master) +{ + unsigned char nvol; + + if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) + nvol = 0; + else + nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX]; + + wm_put(ice, index, nvol); + wm_put_nocache(ice, index, 0x180 | nvol); +} + +/* + * DAC mute control + */ +#define wm_pcm_mute_info phase28_mono_bool_info + +static int wm_pcm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + down(&ice->gpio_mutex); + ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_pcm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short nval, oval; + int change; + + snd_ice1712_save_gpio_status(ice); + oval = wm_get(ice, WM_MUTE); + nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10); + if ((change = (nval != oval))) + wm_put(ice, WM_MUTE, nval); + snd_ice1712_restore_gpio_status(ice); + + return change; +} + +/* + * Master volume attenuation mixer control + */ +static int wm_master_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = WM_VOL_MAX; + return 0; +} + +static int wm_master_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int i; + for (i=0; i<2; i++) + ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE; + return 0; +} + +static int wm_master_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int ch, change = 0; + + snd_ice1712_save_gpio_status(ice); + for (ch = 0; ch < 2; ch++) { + if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) { + int dac; + ice->spec.phase28.master[ch] &= WM_VOL_MUTE; + ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch]; + for (dac = 0; dac < ice->num_total_dacs; dac += 2) + wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, + ice->spec.phase28.vol[dac + ch], + ice->spec.phase28.master[ch]); + change = 1; + } + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +static int __devinit phase28_init(ice1712_t *ice) +{ + static unsigned short wm_inits_phase28[] = { + /* These come first to reduce init pop noise */ + 0x1b, 0x044, /* ADC Mux (AC'97 source) */ + 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ + 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */ + + 0x18, 0x000, /* All power-up */ + + 0x16, 0x122, /* I2S, normal polarity, 24bit */ + 0x17, 0x022, /* 256fs, slave mode */ + 0x00, 0, /* DAC1 analog mute */ + 0x01, 0, /* DAC2 analog mute */ + 0x02, 0, /* DAC3 analog mute */ + 0x03, 0, /* DAC4 analog mute */ + 0x04, 0, /* DAC5 analog mute */ + 0x05, 0, /* DAC6 analog mute */ + 0x06, 0, /* DAC7 analog mute */ + 0x07, 0, /* DAC8 analog mute */ + 0x08, 0x100, /* master analog mute */ + 0x09, 0xff, /* DAC1 digital full */ + 0x0a, 0xff, /* DAC2 digital full */ + 0x0b, 0xff, /* DAC3 digital full */ + 0x0c, 0xff, /* DAC4 digital full */ + 0x0d, 0xff, /* DAC5 digital full */ + 0x0e, 0xff, /* DAC6 digital full */ + 0x0f, 0xff, /* DAC7 digital full */ + 0x10, 0xff, /* DAC8 digital full */ + 0x11, 0x1ff, /* master digital full */ + 0x12, 0x000, /* phase normal */ + 0x13, 0x090, /* unmute DAC L/R */ + 0x14, 0x000, /* all unmute */ + 0x15, 0x000, /* no deemphasis, no ZFLG */ + 0x19, 0x000, /* -12dB ADC/L */ + 0x1a, 0x000, /* -12dB ADC/R */ + (unsigned short)-1 + }; + + unsigned int tmp; + akm4xxx_t *ak; + unsigned short *p; + int i; + + ice->num_total_dacs = 8; + ice->num_total_adcs = 2; + + // Initialize analog chips + ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + if (!ak) + return -ENOMEM; + ice->akm_codecs = 1; + + snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */ + + /* reset the wm codec as the SPI mode */ + snd_ice1712_save_gpio_status(ice); + snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL)); + + tmp = snd_ice1712_gpio_read(ice); + tmp &= ~PHASE28_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PHASE28_WM_CS; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PHASE28_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + p = wm_inits_phase28; + for (; *p != (unsigned short)-1; p += 2) + wm_put(ice, p[0], p[1]); + + snd_ice1712_restore_gpio_status(ice); + + ice->spec.phase28.master[0] = WM_VOL_MUTE; + ice->spec.phase28.master[1] = WM_VOL_MUTE; + for (i = 0; i < ice->num_total_dacs; i++) { + ice->spec.phase28.vol[i] = WM_VOL_MUTE; + wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]); + } + + return 0; +} + +/* + * DAC volume attenuation mixer control + */ +static int wm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + int voices = kcontrol->private_value >> 8; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = voices; + uinfo->value.integer.min = 0; /* mute (-101dB) */ + uinfo->value.integer.max = 0x7F; /* 0dB */ + return 0; +} + +static int wm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int i, ofs, voices; + + voices = kcontrol->private_value >> 8; + ofs = kcontrol->private_value & 0xff; + for (i = 0; i < voices; i++) + ucontrol->value.integer.value[i] = ice->spec.phase28.vol[ofs+i] & ~WM_VOL_MUTE; + return 0; +} + +static int wm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int i, idx, ofs, voices; + int change = 0; + + voices = kcontrol->private_value >> 8; + ofs = kcontrol->private_value & 0xff; + snd_ice1712_save_gpio_status(ice); + for (i = 0; i < voices; i++) { + idx = WM_DAC_ATTEN + ofs + i; + if (ucontrol->value.integer.value[i] != ice->spec.phase28.vol[ofs+i]) { + ice->spec.phase28.vol[ofs+i] &= WM_VOL_MUTE; + ice->spec.phase28.vol[ofs+i] |= ucontrol->value.integer.value[i]; + wm_set_vol(ice, idx, ice->spec.phase28.vol[ofs+i], + ice->spec.phase28.master[i]); + change = 1; + } + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + * WM8770 mute control + */ +static int wm_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = kcontrol->private_value >> 8; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int wm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int voices, ofs, i; + + voices = kcontrol->private_value >> 8; + ofs = kcontrol->private_value & 0xFF; + + for (i = 0; i < voices; i++) + ucontrol->value.integer.value[i] = (ice->spec.phase28.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; + return 0; +} + +static int wm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int change = 0, voices, ofs, i; + + voices = kcontrol->private_value >> 8; + ofs = kcontrol->private_value & 0xFF; + + snd_ice1712_save_gpio_status(ice); + for (i = 0; i < voices; i++) { + int val = (ice->spec.phase28.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; + if (ucontrol->value.integer.value[i] != val) { + ice->spec.phase28.vol[ofs + i] &= ~WM_VOL_MUTE; + ice->spec.phase28.vol[ofs + i] |= + ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; + wm_set_vol(ice, ofs + i, ice->spec.phase28.vol[ofs + i], + ice->spec.phase28.master[i]); + change = 1; + } + } + snd_ice1712_restore_gpio_status(ice); + + return change; +} + +/* + * WM8770 master mute control + */ +static int wm_master_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int wm_master_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = (ice->spec.phase28.master[0] & WM_VOL_MUTE) ? 0 : 1; + ucontrol->value.integer.value[1] = (ice->spec.phase28.master[1] & WM_VOL_MUTE) ? 0 : 1; + return 0; +} + +static int wm_master_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int change = 0, i; + + snd_ice1712_save_gpio_status(ice); + for (i = 0; i < 2; i++) { + int val = (ice->spec.phase28.master[i] & WM_VOL_MUTE) ? 0 : 1; + if (ucontrol->value.integer.value[i] != val) { + int dac; + ice->spec.phase28.master[i] &= ~WM_VOL_MUTE; + ice->spec.phase28.master[i] |= + ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; + for (dac = 0; dac < ice->num_total_dacs; dac += 2) + wm_set_vol(ice, WM_DAC_ATTEN + dac + i, + ice->spec.phase28.vol[dac + i], + ice->spec.phase28.master[i]); + change = 1; + } + } + snd_ice1712_restore_gpio_status(ice); + + return change; +} + +/* digital master volume */ +#define PCM_0dB 0xff +#define PCM_RES 128 /* -64dB */ +#define PCM_MIN (PCM_0dB - PCM_RES) +static int wm_pcm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* mute (-64dB) */ + uinfo->value.integer.max = PCM_RES; /* 0dB */ + return 0; +} + +static int wm_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short val; + + down(&ice->gpio_mutex); + val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; + val = val > PCM_MIN ? (val - PCM_MIN) : 0; + ucontrol->value.integer.value[0] = val; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short ovol, nvol; + int change = 0; + + snd_ice1712_save_gpio_status(ice); + nvol = ucontrol->value.integer.value[0]; + nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; + ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; + if (ovol != nvol) { + wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */ + wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */ + change = 1; + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + */ +static int phase28_mono_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +/* + * Deemphasis + */ +#define phase28_deemp_info phase28_mono_bool_info + +static int phase28_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf; + return 0; +} + +static int phase28_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int temp, temp2; + temp2 = temp = wm_get(ice, WM_DAC_CTRL2); + if (ucontrol->value.integer.value[0]) + temp |= 0xf; + else + temp &= ~0xf; + if (temp != temp2) { + wm_put(ice, WM_DAC_CTRL2, temp); + return 1; + } + return 0; +} + +/* + * ADC Oversampling + */ +static int phase28_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "128x", "64x" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int phase28_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8; + return 0; +} + +static int phase28_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + int temp, temp2; + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + temp2 = temp = wm_get(ice, WM_MASTER); + + if (ucontrol->value.enumerated.item[0]) + temp |= 0x8; + else + temp &= ~0x8; + + if (temp != temp2) { + wm_put(ice, WM_MASTER, temp); + return 1; + } + return 0; +} + +static snd_kcontrol_new_t phase28_dac_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = wm_master_mute_info, + .get = wm_master_mute_get, + .put = wm_master_mute_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = wm_master_vol_info, + .get = wm_master_vol_get, + .put = wm_master_vol_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Front Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (2 << 8) | 0 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Front Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (2 << 8) | 0 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Rear Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (2 << 8) | 2 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Rear Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (2 << 8) | 2 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Center Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (1 << 8) | 4 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Center Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (1 << 8) | 4 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "LFE Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (1 << 8) | 5 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "LFE Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (1 << 8) | 5 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Side Playback Switch", + .info = wm_mute_info, + .get = wm_mute_get, + .put = wm_mute_put, + .private_value = (2 << 8) | 6 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Side Playback Volume", + .info = wm_vol_info, + .get = wm_vol_get, + .put = wm_vol_put, + .private_value = (2 << 8) | 6 + } +}; + +static snd_kcontrol_new_t wm_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .info = wm_pcm_mute_info, + .get = wm_pcm_mute_get, + .put = wm_pcm_mute_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .info = wm_pcm_vol_info, + .get = wm_pcm_vol_get, + .put = wm_pcm_vol_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Deemphasis Switch", + .info = phase28_deemp_info, + .get = phase28_deemp_get, + .put = phase28_deemp_put + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Oversampling", + .info = phase28_oversampling_info, + .get = phase28_oversampling_get, + .put = phase28_oversampling_put + } +}; + +static int __devinit phase28_add_controls(ice1712_t *ice) +{ + unsigned int i, counts; + int err; + + counts = ARRAY_SIZE(phase28_dac_controls); + for (i = 0; i < counts; i++) { + err = snd_ctl_add(ice->card, snd_ctl_new1(&phase28_dac_controls[i], ice)); + if (err < 0) + return err; + } + + for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { + err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice)); + if (err < 0) + return err; + } + + return 0; +} + struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { { .subvendor = VT1724_SUBDEVICE_PHASE22, @@ -134,5 +853,14 @@ struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { .eeprom_size = sizeof(phase22_eeprom), .eeprom_data = phase22_eeprom, }, + { + .subvendor = VT1724_SUBDEVICE_PHASE28, + .name = "Terratec PHASE 28", + .model = "phase28", + .chip_init = phase28_init, + .build_controls = phase28_add_controls, + .eeprom_size = sizeof(phase28_eeprom), + .eeprom_data = phase28_eeprom, + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h index 6230cf16989..13e841b5548 100644 --- a/sound/pci/ice1712/phase.h +++ b/sound/pci/ice1712/phase.h @@ -24,11 +24,28 @@ * */ -#define PHASE_DEVICE_DESC "{Terratec,Phase 22}," +#define PHASE_DEVICE_DESC "{Terratec,Phase 22},"\ + "{Terratec,Phase 28}," #define VT1724_SUBDEVICE_PHASE22 0x3b155011 +#define VT1724_SUBDEVICE_PHASE28 0x3b154911 /* entry point */ extern struct snd_ice1712_card_info snd_vt1724_phase_cards[]; +/* PHASE28 GPIO bits */ +#define PHASE28_SPI_MISO (1 << 21) +#define PHASE28_WM_RESET (1 << 20) +#define PHASE28_SPI_CLK (1 << 19) +#define PHASE28_SPI_MOSI (1 << 18) +#define PHASE28_WM_RW (1 << 17) +#define PHASE28_AC97_RESET (1 << 16) +#define PHASE28_DIGITAL_SEL1 (1 << 15) +#define PHASE28_HP_SEL (1 << 14) +#define PHASE28_WM_CS (1 << 12) +#define PHASE28_AC97_COMMIT (1 << 11) +#define PHASE28_AC97_ADDR (1 << 10) +#define PHASE28_AC97_DATA_LOW (1 << 9) +#define PHASE28_AC97_DATA_HIGH (1 << 8) +#define PHASE28_AC97_DATA_MASK 0xFF #endif /* __SOUND_PHASE */ -- cgit v1.2.3-70-g09d2 From 467a8c2f41ab4b96a7c604619eb7465db403dda8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 11 Apr 2005 14:11:00 +0200 Subject: [ALSA] remove dead code YMFPCI driver This patch removes some dead code found by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai --- sound/pci/ymfpci/ymfpci_main.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 05f1629760b..997cf37cddd 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -1421,17 +1421,15 @@ static snd_kcontrol_new_t snd_ymfpci_drec_source __devinitdata = { static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - unsigned int mask = 1; - switch (kcontrol->private_value) { case YDSXGR_SPDIFOUTCTRL: break; case YDSXGR_SPDIFINCTRL: break; default: return -EINVAL; } - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; + uinfo->value.integer.max = 1; return 0; } @@ -1439,7 +1437,7 @@ static int snd_ymfpci_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; - unsigned int shift = 0, mask = 1, invert = 0; + unsigned int shift = 0, mask = 1; switch (kcontrol->private_value) { case YDSXGR_SPDIFOUTCTRL: break; @@ -1447,8 +1445,6 @@ static int snd_ymfpci_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t default: return -EINVAL; } ucontrol->value.integer.value[0] = (snd_ymfpci_readl(chip, reg) >> shift) & mask; - if (invert) - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0; } @@ -1456,7 +1452,7 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; - unsigned int shift = 0, mask = 1, invert = 0; + unsigned int shift = 0, mask = 1; int change; unsigned int val, oval; @@ -1466,8 +1462,6 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t default: return -EINVAL; } val = (ucontrol->value.integer.value[0] & mask); - if (invert) - val = mask - val; val <<= shift; spin_lock_irq(&chip->reg_lock); oval = snd_ymfpci_readl(chip, reg); @@ -1487,14 +1481,13 @@ static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t static int snd_ymfpci_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { unsigned int reg = kcontrol->private_value; - unsigned int mask = 16383; if (reg < 0x80 || reg >= 0xc0) return -EINVAL; - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; + uinfo->value.integer.max = 16383; return 0; } @@ -1502,7 +1495,7 @@ static int snd_ymfpci_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); unsigned int reg = kcontrol->private_value; - unsigned int shift_left = 0, shift_right = 16, mask = 16383, invert = 0; + unsigned int shift_left = 0, shift_right = 16, mask = 16383; unsigned int val; if (reg < 0x80 || reg >= 0xc0) @@ -1512,10 +1505,6 @@ static int snd_ymfpci_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t spin_unlock_irq(&chip->reg_lock); ucontrol->value.integer.value[0] = (val >> shift_left) & mask; ucontrol->value.integer.value[1] = (val >> shift_right) & mask; - if (invert) { - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; - } return 0; } @@ -1523,7 +1512,7 @@ static int snd_ymfpci_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); unsigned int reg = kcontrol->private_value; - unsigned int shift_left = 0, shift_right = 16, mask = 16383, invert = 0; + unsigned int shift_left = 0, shift_right = 16, mask = 16383; int change; unsigned int val1, val2, oval; @@ -1531,10 +1520,6 @@ static int snd_ymfpci_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t return -EINVAL; val1 = ucontrol->value.integer.value[0] & mask; val2 = ucontrol->value.integer.value[1] & mask; - if (invert) { - val1 = mask - val1; - val2 = mask - val2; - } val1 <<= shift_left; val2 <<= shift_right; spin_lock_irq(&chip->reg_lock); -- cgit v1.2.3-70-g09d2 From 26be865923ce9edefe8ddc007ddb1c098c29c449 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 11 Apr 2005 14:17:19 +0200 Subject: [ALSA] Add PCI ID for Gallant Odyssey Sound 4 FM801 driver The Gallant Odyssey Sound 4 card is based on the ForteMedia FM801 chip, but has a different PCI ID. Signed-off-by: Sergey Vlasov Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 08e7c5a296d..3291434f3e0 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -195,6 +195,7 @@ struct _snd_fm801 { static struct pci_device_id snd_fm801_ids[] = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ + { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ { 0, } }; -- cgit v1.2.3-70-g09d2 From 2d7eb7cb2bab1fbe8cfb610277b19ad40a9f7c75 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 11 Apr 2005 15:04:33 +0200 Subject: [ALSA] Support all sample rate conversion capabilities of DXS channels Documentation,VIA82xx driver Add support for full sample rate conversion capabilities of DXS channels present in VIA VT8233/5/7 controllers: - any sample rate in the 8000 ... 48000 Hz range is supported even if the AC'97 codec supports only 48000 Hz output; - different DXS channels can use different sample rates at the same time (the controller performs required sample rate conversion and mixing in hardware). Signed-off-by: Sergey Vlasov Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 21 +++++++++++++-------- sound/pci/via82xx.c | 20 +++++++++++++++++--- 2 files changed, 30 insertions(+), 11 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 71ef0498d5e..c69581ca2a3 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1211,16 +1211,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ------------------ Module for AC'97 motherboards based on VIA 82C686A/686B, 8233, - 8233A, 8233C, 8235 (south) bridge. + 8233A, 8233C, 8235, 8237 (south) bridge. mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup [VIA686A/686B only] joystick - Enable joystick (default off) [VIA686A/686B only] ac97_clock - AC'97 codec clock base (default 48000Hz) dxs_support - support DXS channels, - 0 = auto (defalut), 1 = enable, 2 = disable, - 3 = 48k only, 4 = no VRA - [VIA8233/C,8235 only] + 0 = auto (default), 1 = enable, 2 = disable, + 3 = 48k only, 4 = no VRA, 5 = enable any sample + rate and different sample rates on different + channels + [VIA8233/C, 8235, 8237 only] ac97_quirk - AC'97 workaround for strange hardware See the description of intel8x0 module for details. @@ -1232,18 +1234,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. default value 1.4. Then the interrupt number will be assigned under 15. You might also upgrade your BIOS. - Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound) + Note: VIA8233/5/7 (not VIA8233A) can support DXS (direct sound) channels as the first PCM. On these channels, up to 4 - streams can be played at the same time. + streams can be played at the same time, and the controller + can perform sample rate conversion with separate rates for + each channel. As default (dxs_support = 0), 48k fixed rate is chosen except for the known devices since the output is often noisy except for 48k on some mother boards due to the bug of BIOS. - Please try once dxs_support=1 and if it works on other + Please try once dxs_support=5 and if it works on other sample rates (e.g. 44.1kHz of mp3 playback), please let us know the PCI subsystem vendor/device id's (output of "lspci -nv"). - If it doesn't work, try dxs_support=4. If it still doesn't + If dxs_support=5 does not work, try dxs_support=1; if it + doesn't work too, try dxs_support=4. If it still doesn't work and the default setting is ok, dxs_support=3 is the right choice. If the default setting doesn't work at all, try dxs_support=2 to disable the DXS channels. diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 9b4d74d49f9..2f1e6ebd56a 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -101,7 +101,7 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); module_param_array(ac97_quirk, charp, NULL, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); module_param_array(dxs_support, int, NULL, 0444); -MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)"); +MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); /* pci ids */ @@ -302,6 +302,7 @@ DEFINE_VIA_REGSET(CAPTURE_8233, 0x60); #define VIA_DXS_DISABLE 2 #define VIA_DXS_48K 3 #define VIA_DXS_NO_VRA 4 +#define VIA_DXS_SRC 5 /* @@ -380,6 +381,7 @@ struct _snd_via82xx { struct via_rate_lock rates[2]; /* playback and capture */ unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ unsigned int no_vra: 1; /* no need to set VRA on DXS channels */ + unsigned int dxs_src: 1; /* use full SRC capabilities of DXS */ unsigned int spdif_on: 1; /* only spdif rates work to external DACs */ snd_pcm_t *pcms[2]; @@ -924,15 +926,16 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream) via82xx_t *chip = snd_pcm_substream_chip(substream); viadev_t *viadev = (viadev_t *)substream->runtime->private_data; snd_pcm_runtime_t *runtime = substream->runtime; + int ac97_rate = chip->dxs_src ? 48000 : runtime->rate; int rate_changed; u32 rbits; - if ((rate_changed = via_lock_rate(&chip->rates[0], runtime->rate)) < 0) + if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0) return rate_changed; if (rate_changed) { snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, chip->no_vra ? 48000 : runtime->rate); - snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); + snd_ac97_set_rate(chip->ac97, AC97_SPDIF, ac97_rate); } if (runtime->rate == 48000) rbits = 0xfffff; @@ -1074,6 +1077,12 @@ static int snd_via82xx_pcm_open(via82xx_t *chip, viadev_t *viadev, snd_pcm_subst /* fixed DXS playback rate */ runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; + } else if (chip->dxs_src && viadev->reg_offset < 0x40) { + /* use full SRC capabilities of DXS */ + runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_8000_48000); + runtime->hw.rate_min = 8000; + runtime->hw.rate_max = 48000; } else if (! ratep->rate) { int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; runtime->hw.rates = chip->ac97->rates[idx]; @@ -2149,6 +2158,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ + { .vendor = 0x1043, .device = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ @@ -2288,6 +2298,10 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, chip->dxs_fixed = 1; else if (dxs_support[dev] == VIA_DXS_NO_VRA) chip->no_vra = 1; + else if (dxs_support[dev] == VIA_DXS_SRC) { + chip->no_vra = 1; + chip->dxs_src = 1; + } } if ((err = snd_via8233_init_misc(chip, dev)) < 0) goto __error; -- cgit v1.2.3-70-g09d2 From 01ef355f0c34d6fbb451512e70e4cf336776b7fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Apr 2005 15:08:32 +0200 Subject: [ALSA] Fix SPDIF rate with dxs_support=4 VIA82xx driver Fix SPDIF rate setting with dxs_support=4. It should be 48k fixed. Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 2f1e6ebd56a..e6e746fa4bb 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -935,7 +935,8 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream) if (rate_changed) { snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, chip->no_vra ? 48000 : runtime->rate); - snd_ac97_set_rate(chip->ac97, AC97_SPDIF, ac97_rate); + snd_ac97_set_rate(chip->ac97, AC97_SPDIF, + chip->no_vra ? 48000 : runtime->rate); } if (runtime->rate == 48000) rbits = 0xfffff; -- cgit v1.2.3-70-g09d2 From 01d25d460a3b28aab537fab9a0038d1b5832ce28 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Apr 2005 16:58:24 +0200 Subject: [ALSA] Replace pci_module_init() with pci_register_driver() Documentation,ALS4000 driver,ATIIXP driver,ATIIXP-modem driver AZT3328 driver,BT87x driver,CMIPCI driver,CS4281 driver ENS1370/1+ driver,ES1938 driver,ES1968 driver,FM801 driver Intel8x0 driver,Intel8x0-modem driver,Maestro3 driver,RME32 driver RME96 driver,SonicVibes driver,VIA82xx driver,VIA82xx-modem driver ALI5451 driver,au88x0 driver,CA0106 driver,CS46xx driver EMU10K1/EMU10K2 driver,HDA Intel driver,ICE1712 driver,ICE1724 driver KORG1212 driver,MIXART driver,NM256 driver,RME HDSP driver RME9652 driver,Trident driver,Digigram VX222 driver,YMFPCI driver Replace the obsolete pci_module_init() with pci_register_driver(). Signed-off-by: Takashi Iwai --- .../sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 6 +- sound/pci/ali5451/ali5451.c | 2 +- sound/pci/als4000.c | 2 +- sound/pci/atiixp.c | 2 +- sound/pci/atiixp_modem.c | 2 +- sound/pci/au88x0/au88x0.c | 2 +- sound/pci/azt3328.c | 2 +- sound/pci/bt87x.c | 2 +- sound/pci/ca0106/ca0106_main.c | 2 +- sound/pci/cmipci.c | 159 ++++++++++++++++++--- sound/pci/cs4281.c | 2 +- sound/pci/cs46xx/cs46xx.c | 2 +- sound/pci/emu10k1/emu10k1.c | 2 +- sound/pci/emu10k1/emu10k1x.c | 2 +- sound/pci/ens1370.c | 2 +- sound/pci/es1938.c | 2 +- sound/pci/es1968.c | 2 +- sound/pci/fm801.c | 2 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/ice1712/ice1712.c | 2 +- sound/pci/ice1712/ice1724.c | 2 +- sound/pci/intel8x0.c | 2 +- sound/pci/intel8x0m.c | 2 +- sound/pci/korg1212/korg1212.c | 2 +- sound/pci/maestro3.c | 2 +- sound/pci/mixart/mixart.c | 2 +- sound/pci/nm256/nm256.c | 2 +- sound/pci/rme32.c | 2 +- sound/pci/rme96.c | 2 +- sound/pci/rme9652/hdsp.c | 2 +- sound/pci/rme9652/rme9652.c | 2 +- sound/pci/sonicvibes.c | 2 +- sound/pci/trident/trident.c | 2 +- sound/pci/via82xx.c | 2 +- sound/pci/via82xx_modem.c | 2 +- sound/pci/vx222/vx222.c | 2 +- sound/pci/ymfpci/ymfpci.c | 2 +- 37 files changed, 177 insertions(+), 58 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index e789475304b..db0b7d2dc47 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -371,7 +371,7 @@ create probe() callback. create remove() callback. create pci_driver table which contains the three pointers above. - create init() function just calling pci_module_init() to register the pci_driver table defined above. + create init() function just calling pci_register_driver() to register the pci_driver table defined above. create exit() function to call pci_unregister_driver() function. @@ -1198,7 +1198,7 @@ /* initialization of the module */ static int __init alsa_card_mychip_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } /* clean up the module */ @@ -1654,7 +1654,7 @@ 0) + if ((err = pci_register_driver(&driver)) > 0) return err; return 0; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 113208fbde1..b4503385ea6 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -519,40 +519,50 @@ inline static unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd) } /* bit operations for dword register */ -static void snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) +static int snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) { - unsigned int val; - val = inl(cm->iobase + cmd); + unsigned int val, oval; + val = oval = inl(cm->iobase + cmd); val |= flag; + if (val == oval) + return 0; outl(val, cm->iobase + cmd); + return 1; } -static void snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) +static int snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag) { - unsigned int val; - val = inl(cm->iobase + cmd); + unsigned int val, oval; + val = oval = inl(cm->iobase + cmd); val &= ~flag; + if (val == oval) + return 0; outl(val, cm->iobase + cmd); + return 1; } -#if 0 // not used /* bit operations for byte register */ -static void snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) +static int snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) { - unsigned char val; - val = inb(cm->iobase + cmd); + unsigned char val, oval; + val = oval = inb(cm->iobase + cmd); val |= flag; + if (val == oval) + return 0; outb(val, cm->iobase + cmd); + return 1; } -static void snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) +static int snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag) { - unsigned char val; - val = inb(cm->iobase + cmd); + unsigned char val, oval; + val = oval = inb(cm->iobase + cmd); val &= ~flag; + if (val == oval) + return 0; outb(val, cm->iobase + cmd); + return 1; } -#endif /* @@ -2250,8 +2260,8 @@ DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, 0, 0, 0); /* rever DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, CM_XCHGDAC, 0, 0); #endif DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0); -DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); -DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); +// DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); +// DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); // DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */ DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0); @@ -2300,10 +2310,114 @@ static int snd_cmipci_spdout_enable_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_v } +static int snd_cmipci_line_in_mode_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static inline unsigned int get_line_in_mode(cmipci_t *cm) +{ + unsigned int val; + if (cm->chip_version >= 39) { + val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL); + if (val & CM_LINE_AS_BASS) + return 2; + } + val = snd_cmipci_read_b(cm, CM_REG_MIXER1); + if (val & CM_SPK4) + return 1; + return 0; +} + +static int snd_cmipci_line_in_mode_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&cm->reg_lock); + ucontrol->value.enumerated.item[0] = get_line_in_mode(cm); + spin_unlock_irq(&cm->reg_lock); + return 0; +} + +static int snd_cmipci_line_in_mode_put(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + int change; + + spin_lock_irq(&cm->reg_lock); + if (ucontrol->value.enumerated.item[0] == 2) + change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); + else + change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); + if (ucontrol->value.enumerated.item[0] == 1) + change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_SPK4); + else + change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_SPK4); + spin_unlock_irq(&cm->reg_lock); + return change; +} + +static int snd_cmipci_mic_in_mode_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "Mic-In", "Center/LFE Output" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_cmipci_mic_in_mode_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + /* same bit as spdi_phase */ + spin_lock_irq(&cm->reg_lock); + ucontrol->value.enumerated.item[0] = + (snd_cmipci_read_b(cm, CM_REG_MISC) & CM_SPDIF_INVERSE) ? 1 : 0; + spin_unlock_irq(&cm->reg_lock); + return 0; +} + +static int snd_cmipci_mic_in_mode_put(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + cmipci_t *cm = snd_kcontrol_chip(kcontrol); + int change; + + spin_lock_irq(&cm->reg_lock); + if (ucontrol->value.enumerated.item[0]) + change = snd_cmipci_set_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE); + else + change = snd_cmipci_clear_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE); + spin_unlock_irq(&cm->reg_lock); + return change; +} + /* both for CM8338/8738 */ static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = { DEFINE_MIXER_SWITCH("Four Channel Mode", fourch), - DEFINE_MIXER_SWITCH("Line-In As Rear", line_rear), + { + .name = "Line-In Mode", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = snd_cmipci_line_in_mode_info, + .get = snd_cmipci_line_in_mode_get, + .put = snd_cmipci_line_in_mode_put, + }, }; /* for non-multichannel chips */ @@ -2341,10 +2455,15 @@ static snd_kcontrol_new_t snd_cmipci_old_mixer_switches[] __devinitdata = { /* only for model 039 or later */ static snd_kcontrol_new_t snd_cmipci_extra_mixer_switches[] __devinitdata = { - DEFINE_MIXER_SWITCH("Line-In As Bass", line_bass), DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel2), DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2), - DEFINE_MIXER_SWITCH("Mic As Center/LFE", spdi_phase), /* same bit as spdi_phase */ + { + .name = "Mic-In Mode", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = snd_cmipci_mic_in_mode_info, + .get = snd_cmipci_mic_in_mode_get, + .put = snd_cmipci_mic_in_mode_put, + } }; /* card control switches */ @@ -2944,7 +3063,7 @@ static struct pci_driver driver = { static int __init alsa_card_cmipci_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_cmipci_exit(void) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index d7e06b3caf9..8b42e8631f2 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -2124,7 +2124,7 @@ static struct pci_driver driver = { static int __init alsa_card_cs4281_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_cs4281_exit(void) diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 25d6466a867..db212ecd792 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -171,7 +171,7 @@ static struct pci_driver driver = { static int __init alsa_card_cs46xx_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_cs46xx_exit(void) diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 6446afe19d8..2085a998eae 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -228,7 +228,7 @@ static struct pci_driver driver = { static int __init alsa_card_emu10k1_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_emu10k1_exit(void) diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 27dfd8ddddf..04ba63762d3 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1627,7 +1627,7 @@ static int __init alsa_card_emu10k1x_init(void) { int err; - if ((err = pci_module_init(&driver)) > 0) + if ((err = pci_register_driver(&driver)) > 0) return err; return 0; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index f910399db5c..4e63498a58b 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -2401,7 +2401,7 @@ static struct pci_driver driver = { static int __init alsa_card_ens137x_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ens137x_exit(void) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index b4ca8adf393..b492777bc30 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1761,7 +1761,7 @@ static struct pci_driver driver = { static int __init alsa_card_es1938_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_es1938_exit(void) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index faf63ff19c4..da10d40b2d9 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2795,7 +2795,7 @@ static struct pci_driver driver = { static int __init alsa_card_es1968_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_es1968_exit(void) diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 3291434f3e0..ff10e637a95 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1469,7 +1469,7 @@ static struct pci_driver driver = { static int __init alsa_card_fm801_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_fm801_exit(void) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 959953ca320..cbc9ca73c2a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1439,7 +1439,7 @@ static struct pci_driver driver = { static int __init alsa_card_azx_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_azx_exit(void) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 79fba6be350..a2545a5b26c 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2748,7 +2748,7 @@ static struct pci_driver driver = { static int __init alsa_card_ice1712_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ice1712_exit(void) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 95500f06f0c..79b5f12e06f 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2328,7 +2328,7 @@ static struct pci_driver driver = { static int __init alsa_card_ice1724_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ice1724_exit(void) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 8b33b12fa5d..9c5710daed5 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2849,7 +2849,7 @@ static struct pci_driver driver = { static int __init alsa_card_intel8x0_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_intel8x0_exit(void) diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index f9972b20050..f655cf91406 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1452,7 +1452,7 @@ static struct pci_driver driver = { static int __init alsa_card_intel8x0m_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_intel8x0m_exit(void) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index bb1de200817..79d8eda54f0 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2541,7 +2541,7 @@ static struct pci_driver driver = { static int __init alsa_card_korg1212_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_korg1212_exit(void) diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 2cf33083d7c..9f184ea8a9d 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2702,7 +2702,7 @@ static struct pci_driver driver = { static int __init alsa_card_m3_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_m3_exit(void) diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 65bb0f47af2..082c0d0f73d 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1431,7 +1431,7 @@ static struct pci_driver driver = { static int __init alsa_card_mixart_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_mixart_exit(void) diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 356fbeac6f9..8a52091f855 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1645,7 +1645,7 @@ static struct pci_driver driver = { static int __init alsa_card_nm256_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_nm256_exit(void) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index b96acd5a57d..b7b554df670 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -2031,7 +2031,7 @@ static struct pci_driver driver = { static int __init alsa_card_rme32_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_rme32_exit(void) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 8e2666841d2..10c4f45a913 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -2437,7 +2437,7 @@ static struct pci_driver driver = { static int __init alsa_card_rme96_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_rme96_exit(void) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 12efbf0fab5..44ca7ddb68f 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -5194,7 +5194,7 @@ static struct pci_driver driver = { static int __init alsa_card_hdsp_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_hdsp_exit(void) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 69cd81eaa11..5861f234af2 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -2664,7 +2664,7 @@ static struct pci_driver driver = { static int __init alsa_card_hammerfall_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_hammerfall_exit(void) diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index cfd2c5fd6dd..60ecb2bdb65 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1522,7 +1522,7 @@ static struct pci_driver driver = { static int __init alsa_card_sonicvibes_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_sonicvibes_exit(void) diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index ad58e08d66e..5d21cb811c8 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -184,7 +184,7 @@ static struct pci_driver driver = { static int __init alsa_card_trident_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_trident_exit(void) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e6e746fa4bb..64cc40f97b5 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2349,7 +2349,7 @@ static struct pci_driver driver = { static int __init alsa_card_via82xx_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_via82xx_exit(void) diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index ea5c6f64015..098870aea26 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1233,7 +1233,7 @@ static struct pci_driver driver = { static int __init alsa_card_via82xx_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_via82xx_exit(void) diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 4ffbb25658a..dca6bd2c758 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -260,7 +260,7 @@ static struct pci_driver driver = { static int __init alsa_card_vx222_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_vx222_exit(void) diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 9f3ef22df08..5b5b624b47d 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -360,7 +360,7 @@ static struct pci_driver driver = { static int __init alsa_card_ymfpci_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ymfpci_exit(void) -- cgit v1.2.3-70-g09d2 From 0af68e5ed45e985b676edfbe4b8851dd46316502 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Apr 2005 17:03:03 +0200 Subject: [ALSA] Fix compile warning EMU10K1/EMU10K2 driver Fix compile warnings regarding the unused variables/functions. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index b544c258266..6be82c5fe13 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -68,6 +68,7 @@ static int snd_emu10k1_spdif_get_mask(snd_kcontrol_t * kcontrol, return 0; } +#if 0 static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[] = {"44100", "48000", "96000"}; @@ -152,6 +153,7 @@ static snd_kcontrol_new_t snd_audigy_spdif_output_rate = .get = snd_audigy_spdif_output_rate_get, .put = snd_audigy_spdif_output_rate_put }; +#endif static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -- cgit v1.2.3-70-g09d2 From bd7bf042e89941d4e693a0ec68c5093a2bb2adb3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Apr 2005 16:27:28 +0200 Subject: [ALSA] Fix permissions in some /proc files PCM Midlevel,CA0106 driver,EMU10K1/EMU10K2 driver Fix by Guillaume Chazarain : Some tunables in /proc have a write() function, but as their permission does not reflect it, it can be confusing to the user. So here is a patch that corrects the mode of those files. Note that I have only tested the 'xrun_debug' entry. Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 1 + sound/core/pcm_memory.c | 1 + sound/pci/ca0106/ca0106_proc.c | 2 ++ sound/pci/emu10k1/emu10k1x.c | 1 + sound/pci/emu10k1/emuproc.c | 5 +++++ 5 files changed, 10 insertions(+) (limited to 'sound/pci') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8d94325529a..a2757fcec1f 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -451,6 +451,7 @@ static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr) entry->c.text.read = snd_pcm_xrun_debug_read; entry->c.text.write_size = 64; entry->c.text.write = snd_pcm_xrun_debug_write; + entry->mode |= S_IWUSR; entry->private_data = pstr; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index f1d5f7a6ee0..9a174fb9656 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -204,6 +204,7 @@ static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream, entry->c.text.read = snd_pcm_lib_preallocate_proc_read; entry->c.text.write_size = 64; entry->c.text.write = snd_pcm_lib_preallocate_proc_write; + entry->mode |= S_IWUSR; entry->private_data = substream; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index afb711421e4..0bc1d783a84 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -418,6 +418,7 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32); entry->c.text.write_size = 64; entry->c.text.write = snd_ca0106_proc_reg_write32; + entry->mode |= S_IWUSR; } if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16); @@ -427,6 +428,7 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1); entry->c.text.write_size = 64; entry->c.text.write = snd_ca0106_proc_reg_write; + entry->mode |= S_IWUSR; // entry->private_data = emu; } if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 04ba63762d3..f8d92335a35 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1075,6 +1075,7 @@ static int __devinit snd_emu10k1x_proc_init(emu10k1x_t * emu) snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read); entry->c.text.write_size = 64; entry->c.text.write = snd_emu10k1x_proc_reg_write; + entry->mode |= S_IWUSR; entry->private_data = emu; } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 356fb710425..cc22707c91f 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -527,26 +527,31 @@ int __devinit snd_emu10k1_proc_init(emu10k1_t * emu) snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_io_reg_write; + entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_ptr_reg_write00; + entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_ptr_reg_write00; + entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_ptr_reg_write20; + entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b); entry->c.text.write_size = 64; entry->c.text.write = snd_emu_proc_ptr_reg_write20; + entry->mode |= S_IWUSR; } #endif -- cgit v1.2.3-70-g09d2 From eb8caf30f4c059ddfdfa32b6034549622953db6f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Apr 2005 14:32:57 +0200 Subject: [ALSA] Improve the shared-jack handling on ac97 AC97 Codec The handling of shared surround/clfe output jacks with line/mic-in on some AC97 codecs is improved. Instead of 'Line-In As Surround' or 'Mic As Center/LFE' switch, two new enum controls are introduced: 'Channel Mode' and 'Surround Jack Mode'. The formar changes the current output mode among 2, 4 and 6-channels. The latter controls whether the jacks are shared or independent. Signed-off-by: Takashi Iwai --- include/sound/ac97_codec.h | 4 + sound/pci/ac97/ac97_patch.c | 426 ++++++++++++++++++++++++-------------------- 2 files changed, 240 insertions(+), 190 deletions(-) (limited to 'sound/pci') diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 2433e279e07..996eeab683b 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -437,6 +437,7 @@ struct snd_ac97_build_ops { void (*suspend) (ac97_t *ac97); void (*resume) (ac97_t *ac97); #endif + void (*update_jacks) (ac97_t *ac97); /* for jack-sharing */ }; struct _snd_ac97_bus_ops { @@ -516,6 +517,9 @@ struct _snd_ac97 { } ad18xx; unsigned int dev_flags; /* device specific */ } spec; + /* jack-sharing info */ + unsigned char indep_surround; + unsigned char channel_mode; }; /* conditions */ diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 473840d431b..7f16c306165 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -64,6 +64,116 @@ static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned shor return ret; } +/* + * shared line-in/mic controls + */ +static int ac97_enum_text_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo, + const char **texts, unsigned int nums) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = nums; + if (uinfo->value.enumerated.item > nums - 1) + uinfo->value.enumerated.item = nums - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int ac97_surround_jack_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static const char *texts[] = { "Shared", "Independent" }; + return ac97_enum_text_info(kcontrol, uinfo, texts, 2); +} + +static int ac97_surround_jack_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = ac97->indep_surround; + return 0; +} + +static int ac97_surround_jack_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned char indep = !!ucontrol->value.enumerated.item[0]; + + if (indep != ac97->indep_surround) { + ac97->indep_surround = indep; + if (ac97->build_ops->update_jacks) + ac97->build_ops->update_jacks(ac97); + return 1; + } + return 0; +} + +static int ac97_channel_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static const char *texts[] = { "2ch", "4ch", "6ch" }; + if (kcontrol->private_value) + return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */ + return ac97_enum_text_info(kcontrol, uinfo, texts, 3); +} + +static int ac97_channel_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = ac97->channel_mode; + return 0; +} + +static int ac97_channel_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned char mode = ucontrol->value.enumerated.item[0]; + + if (mode != ac97->channel_mode) { + ac97->channel_mode = mode; + if (ac97->build_ops->update_jacks) + ac97->build_ops->update_jacks(ac97); + return 1; + } + return 0; +} + +#define AC97_SURROUND_JACK_MODE_CTL \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Surround Jack Mode", \ + .info = ac97_surround_jack_mode_info, \ + .get = ac97_surround_jack_mode_get, \ + .put = ac97_surround_jack_mode_put, \ + } +#define AC97_CHANNEL_MODE_CTL \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Channel Mode", \ + .info = ac97_channel_mode_info, \ + .get = ac97_channel_mode_get, \ + .put = ac97_channel_mode_put, \ + } +#define AC97_CHANNEL_MODE_4CH_CTL \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Channel Mode", \ + .info = ac97_channel_mode_info, \ + .get = ac97_channel_mode_get, \ + .put = ac97_channel_mode_put, \ + .private_value = 1, \ + } + +static inline int is_shared_linein(ac97_t *ac97) +{ + return ! ac97->indep_surround && ac97->channel_mode >= 1; +} + +static inline int is_shared_micin(ac97_t *ac97) +{ + return ! ac97->indep_surround && ac97->channel_mode >= 2; +} + + /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ @@ -1390,6 +1500,16 @@ static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); } +static void ad1888_update_jacks(ac97_t *ac97) +{ + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, + is_shared_linein(ac97) ? 0 : 1 << 12); + /* shared Mic */ + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, + is_shared_micin(ac97) ? 0 : 1 << 13); +} + static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1406,8 +1526,13 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { .get = snd_ac97_ad1888_downmix_get, .put = snd_ac97_ad1888_downmix_put }, +#if 0 AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), +#else + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, +#endif }; static int patch_ad1888_specific(ac97_t *ac97) @@ -1422,8 +1547,9 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1888_specific, #ifdef CONFIG_PM - .resume = ad18xx_resume + .resume = ad18xx_resume, #endif + .update_jacks = ad1888_update_jacks, }; int patch_ad1888(ac97_t * ac97) @@ -1521,31 +1647,25 @@ int patch_ad1985(ac97_t * ac97) /* * realtek ALC65x/850 codecs */ -static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; - return 0; -} - -static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +static void alc650_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - int change, val; - val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10)); - change = (ucontrol->value.integer.value[0] != val); - if (change) { - /* disable/enable vref */ - snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, - ucontrol->value.integer.value[0] ? (1 << 12) : 0); - /* turn on/off center-on-mic */ - snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, - ucontrol->value.integer.value[0] ? (1 << 10) : 0); - /* GPIO0 high for mic */ - snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, - ucontrol->value.integer.value[0] ? 0 : 0x100); - } - return change; + int shared; + + /* shared Line-In */ + shared = is_shared_linein(ac97); + snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, + shared ? (1 << 9) : 0); + /* update shared Mic */ + shared = is_shared_micin(ac97); + /* disable/enable vref */ + snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, + shared ? (1 << 12) : 0); + /* turn on/off center-on-mic */ + snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, + shared ? (1 << 10) : 0); + /* GPIO0 high for mic */ + snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, + shared ? 0 : 0x100); } static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { @@ -1558,8 +1678,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { /* 6: Independent Master Volume Right */ /* 7: Independent Master Volume Left */ /* 8: reserved */ - AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), - /* 10: mic, see below */ + /* 9: Line-In/Surround share */ + /* 10: Mic/CLFE share */ /* 11-13: in IEC958 controls */ AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), #if 0 /* always set in patch_alc650 */ @@ -1570,14 +1690,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), #endif - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = snd_ac97_alc650_mic_get, - .put = snd_ac97_alc650_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { @@ -1601,7 +1715,8 @@ static int patch_alc650_specific(ac97_t * ac97) } static struct snd_ac97_build_ops patch_alc650_ops = { - .build_specific = patch_alc650_specific + .build_specific = patch_alc650_specific, + .update_jacks = alc650_update_jacks }; int patch_alc650(ac97_t * ac97) @@ -1659,37 +1774,27 @@ int patch_alc650(ac97_t * ac97) return 0; } -static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; - return 0; -} - -static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +static void alc655_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - + int shared; + + /* shared Line-In */ + shared = is_shared_linein(ac97); + ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, + shared ? (1 << 9) : 0, 0); + /* update shared mic */ + shared = is_shared_micin(ac97); /* misc control; vrefout disable */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, - ucontrol->value.integer.value[0] ? (1 << 12) : 0); - return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, - ucontrol->value.integer.value[0] ? (1 << 10) : 0, - 0); + shared ? (1 << 12) : 0); + ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, + shared ? (1 << 10) : 0, 0); } - static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), - AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = snd_ac97_alc655_mic_get, - .put = snd_ac97_alc655_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -1759,7 +1864,8 @@ static int patch_alc655_specific(ac97_t * ac97) } static struct snd_ac97_build_ops patch_alc655_ops = { - .build_specific = patch_alc655_specific + .build_specific = patch_alc655_specific, + .update_jacks = alc655_update_jacks }; int patch_alc655(ac97_t * ac97) @@ -1798,63 +1904,32 @@ int patch_alc655(ac97_t * ac97) #define AC97_ALC850_JACK_SELECT 0x76 #define AC97_ALC850_MISC1 0x7a -static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +static void alc850_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2; - return 0; -} - -static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - + int shared; + + /* shared Line-In */ + shared = is_shared_linein(ac97); /* SURR 1kOhm (bit4), Amp (bit5) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), - ucontrol->value.integer.value[0] ? (1<<5) : (1<<4)); + shared ? (1<<5) : (1<<4)); /* LINE-IN = 0, SURROUND = 2 */ - return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, - ucontrol->value.integer.value[0] ? (2<<12) : (0<<12)); -} - -static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2; - return 0; -} - -static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - + snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, + shared ? (2<<12) : (0<<12)); + /* update shared mic */ + shared = is_shared_micin(ac97); /* Vref disable (bit12), 1kOhm (bit13) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), - ucontrol->value.integer.value[0] ? (1<<12) : (1<<13)); + shared ? (1<<12) : (1<<13)); /* MIC-IN = 1, CENTER-LFE = 2 */ - return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, - ucontrol->value.integer.value[0] ? (2<<4) : (1<<4)); + snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, + shared ? (2<<4) : (1<<4)); } static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line-In As Surround", - .info = snd_ac97_info_volsw, - .get = ac97_alc850_surround_get, - .put = ac97_alc850_surround_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = ac97_alc850_mic_get, - .put = ac97_alc850_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, - + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static int patch_alc850_specific(ac97_t *ac97) @@ -1871,7 +1946,8 @@ static int patch_alc850_specific(ac97_t *ac97) } static struct snd_ac97_build_ops patch_alc850_ops = { - .build_specific = patch_alc850_specific + .build_specific = patch_alc850_specific, + .update_jacks = alc850_update_jacks }; int patch_alc850(ac97_t *ac97) @@ -1911,9 +1987,17 @@ int patch_alc850(ac97_t *ac97) /* * C-Media CM97xx codecs */ +static void cm9738_update_jacks(ac97_t *ac97) +{ + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, + is_shared_linein(ac97) ? (1 << 10) : 0); +} + static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { - AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_4CH_CTL, }; static int patch_cm9738_specific(ac97_t * ac97) @@ -1922,7 +2006,8 @@ static int patch_cm9738_specific(ac97_t * ac97) } static struct snd_ac97_build_ops patch_cm9738_ops = { - .build_specific = patch_cm9738_specific + .build_specific = patch_cm9738_specific, + .update_jacks = cm9738_update_jacks }; int patch_cm9738(ac97_t * ac97) @@ -1986,34 +2071,19 @@ static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ }; -static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - return 0; -} - -static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static void cm9739_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, - ucontrol->value.integer.value[0] ? - 0x1000 : 0x2000); + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, + is_shared_linein(ac97) ? (1 << 10) : 0); + /* shared Mic */ + snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, + is_shared_micin(ac97) ? 0x1000 : 0x2000); } static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { - AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = snd_ac97_cm9739_center_mic_get, - .put = snd_ac97_cm9739_center_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static int patch_cm9739_specific(ac97_t * ac97) @@ -2028,7 +2098,8 @@ static int patch_cm9739_post_spdif(ac97_t * ac97) static struct snd_ac97_build_ops patch_cm9739_ops = { .build_specific = patch_cm9739_specific, - .build_post_spdif = patch_cm9739_post_spdif + .build_post_spdif = patch_cm9739_post_spdif, + .update_jacks = cm9739_update_jacks }; int patch_cm9739(ac97_t * ac97) @@ -2090,67 +2161,28 @@ int patch_cm9739(ac97_t * ac97) #define AC97_CM9761_FUNC 0x66 #define AC97_CM9761_SPDIF_CTRL 0x6c -static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static void cm9761_update_jacks(ac97_t *ac97) { - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x0400) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - return 0; -} - -static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short vals[2][2] = { + unsigned short surr_vals[2][2] = { { 0x0008, 0x0400 }, /* off, on */ { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ }; - return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, - vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); -} - -static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x1000) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - if (ac97->spec.dev_flags) /* 9761-82 rev.B */ - ucontrol->value.integer.value[0] = !ucontrol->value.integer.value[0]; - return 0; -} - -static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short vals[2][2] = { + unsigned short clfe_vals[2][2] = { { 0x2000, 0x1880 }, /* off, on */ { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ }; - return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, - vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); + + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, + surr_vals[ac97->spec.dev_flags][is_shared_linein(ac97)]); + /* shared Mic */ + snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, + clfe_vals[ac97->spec.dev_flags][is_shared_micin(ac97)]); } static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line-In As Surround", - .info = snd_ac97_info_volsw, - .get = snd_ac97_cm9761_linein_rear_get, - .put = snd_ac97_cm9761_linein_rear_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_volsw, - .get = snd_ac97_cm9761_center_mic_get, - .put = snd_ac97_cm9761_center_mic_put, - .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ - }, + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -2224,7 +2256,8 @@ static int patch_cm9761_specific(ac97_t * ac97) static struct snd_ac97_build_ops patch_cm9761_ops = { .build_specific = patch_cm9761_specific, - .build_post_spdif = patch_cm9761_post_spdif + .build_post_spdif = patch_cm9761_post_spdif, + .update_jacks = cm9761_update_jacks }; int patch_cm9761(ac97_t *ac97) @@ -2370,9 +2403,21 @@ int patch_vt1616(ac97_t * ac97) return 0; } +/* + */ +static void it2646_update_jacks(ac97_t *ac97) +{ + /* shared Line-In */ + snd_ac97_update_bits(ac97, 0x76, 1 << 9, + is_shared_linein(ac97) ? (1<<9) : 0); + /* shared Mic */ + snd_ac97_update_bits(ac97, 0x76, 1 << 10, + is_shared_micin(ac97) ? (1<<10) : 0); +} + static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { - AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0), - AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0), + AC97_SURROUND_JACK_MODE_CTL, + AC97_CHANNEL_MODE_CTL, }; static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { @@ -2392,7 +2437,8 @@ static int patch_it2646_specific(ac97_t * ac97) } static struct snd_ac97_build_ops patch_it2646_ops = { - .build_specific = patch_it2646_specific + .build_specific = patch_it2646_specific, + .update_jacks = it2646_update_jacks }; int patch_it2646(ac97_t * ac97) -- cgit v1.2.3-70-g09d2 From 1a12de1edf234b54ce94971d5604f85809c391b9 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 13 Apr 2005 14:37:50 +0200 Subject: [ALSA] hda: fix vref cap and ctl values HDA Codec driver,HDA generic driver Fix some vref defines so they are valid for the different bits in the pin cap and pin control registers. Please apply. Signed-off-by: Matt Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 20 +++++++++++++------- sound/pci/hda/hda_generic.c | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c9e9dc9c7c9..042bcfc6dbb 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -176,15 +176,21 @@ enum { #define AC_PINCAP_OUT (1<<4) /* output capable */ #define AC_PINCAP_IN (1<<5) /* input capable */ #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ -#define AC_PINCAP_VREF (7<<8) +#define AC_PINCAP_VREF (0x37<<8) #define AC_PINCAP_VREF_SHIFT 8 #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ -/* Vref status (used in pin cap and pin ctl) */ -#define AC_PIN_VREF_HIZ (1<<0) /* Hi-Z */ -#define AC_PIN_VREF_50 (1<<1) /* 50% */ -#define AC_PIN_VREF_GRD (1<<2) /* ground */ -#define AC_PIN_VREF_80 (1<<4) /* 80% */ -#define AC_PIN_VREF_100 (1<<5) /* 100% */ +/* Vref status (used in pin cap) */ +#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ +#define AC_PINCAP_VREF_50 (1<<1) /* 50% */ +#define AC_PINCAP_VREF_GRD (1<<2) /* ground */ +#define AC_PINCAP_VREF_80 (1<<4) /* 80% */ +#define AC_PINCAP_VREF_100 (1<<5) /* 100% */ +/* Vref setting (used in pin ctl) */ +#define AC_PINCTL_VREF_HIZ (0) /* Hi-Z */ +#define AC_PINCTL_VREF_50 (1) /* 50% */ +#define AC_PINCTL_VREF_GRD (2) /* ground */ +#define AC_PINCTL_VREF_80 (4) /* 80% */ +#define AC_PINCTL_VREF_100 (5) /* 100% */ /* Amplifier capabilities */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 69f7b6c4cf8..c233e7f1a74 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -426,7 +426,7 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) return "Line"; case AC_JACK_CD: if (pinctl) - *pinctl |= AC_PIN_VREF_GRD; + *pinctl |= AC_PINCTL_VREF_GRD; return "CD"; case AC_JACK_AUX: if ((location & 0x0f) == AC_JACK_LOC_FRONT) -- cgit v1.2.3-70-g09d2 From 2f2f4251c9b123b2ab04da9e78ab6158535c2e38 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 13 Apr 2005 14:45:30 +0200 Subject: [ALSA] add sigmatel codec support HDA generic driver,HDA Codec driver Add initial SigmaTel codec support for 9200 and 922x. Note that this hda patch relies on the configuration default registers to be set correctly (normally by BIOS/firmware) in order for it to set up pin widgets properly. There's a test switch in the patch so it will work with the SigmaTel reference boards that are usually plugged into a system that doesn't set the configuration default registers. It supports 2 channel analog out and line/mic in. I plan to add >2 channel support and spdif support shortly. Please apply. Signed-off-by: Matt Signed-off-by: Takashi Iwai --- sound/pci/hda/Makefile | 2 +- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/hda_patch.h | 3 + sound/pci/hda/patch_sigmatel.c | 560 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 565 insertions(+), 1 deletion(-) create mode 100644 sound/pci/hda/patch_sigmatel.c (limited to 'sound/pci') diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 570a59d33b4..bd8cb33c4fb 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,5 +1,5 @@ snd-hda-intel-objs := hda_intel.o -snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o +snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o ifdef CONFIG_PROC_FS snd-hda-codec-objs += hda_proc.o endif diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9ed117ac0c0..be6cba34939 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -51,6 +51,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x10ec, "Realtek" }, { 0x13f6, "C-Media" }, { 0x434d, "C-Media" }, + { 0x8384, "SigmaTel" }, {} /* terminator */ }; diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index cf6abce42bc..a5de684b694 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -8,10 +8,13 @@ extern struct hda_codec_preset snd_hda_preset_realtek[]; extern struct hda_codec_preset snd_hda_preset_cmedia[]; /* Analog Devices codecs */ extern struct hda_codec_preset snd_hda_preset_analog[]; +/* SigmaTel codecs */ +extern struct hda_codec_preset snd_hda_preset_sigmatel[]; static const struct hda_codec_preset *hda_preset_tables[] = { snd_hda_preset_realtek, snd_hda_preset_cmedia, snd_hda_preset_analog, + snd_hda_preset_sigmatel, NULL }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c new file mode 100644 index 00000000000..1534e20af63 --- /dev/null +++ b/sound/pci/hda/patch_sigmatel.c @@ -0,0 +1,560 @@ +/* + * Universal Interface for Intel High Definition Audio Codec + * + * HD audio interface patch for SigmaTel STAC92xx + * + * Copyright (c) 2005 Embedded Alley Solutions, Inc. + * + * + * Based on patch_cmedia.c and patch_realtek.c + * Copyright (c) 2004 Takashi Iwai + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +#undef STAC_TEST + +struct sigmatel_spec { + /* playback */ + struct hda_multi_out multiout; + hda_nid_t playback_nid; + + /* capture */ + hda_nid_t *adc_nids; + hda_nid_t *mux_nids; + unsigned int num_adcs; + hda_nid_t capture_nid; + + /* power management*/ + hda_nid_t *pstate_nids; + unsigned int num_pstates; + + /* pin widgets */ + hda_nid_t *pin_nids; + unsigned int num_pins; +#ifdef STAC_TEST + unsigned int *pin_configs; +#endif + + /* codec specific stuff */ + struct hda_verb *init; + snd_kcontrol_new_t *mixer; + + /* capture source */ + const struct hda_input_mux *input_mux; + unsigned int cur_mux[2]; + + /* channel mode */ + unsigned int num_ch_modes; + unsigned int cur_ch_mode; + const struct sigmatel_channel_mode *channel_modes; + + struct hda_pcm pcm_rec[1]; /* PCM information */ +}; + +static hda_nid_t stac9200_adc_nids[1] = { + 0x03, +}; + +static hda_nid_t stac9200_mux_nids[1] = { + 0x0c, +}; + +static hda_nid_t stac9200_dac_nids[1] = { + 0x02, +}; + +static hda_nid_t stac9200_pstate_nids[3] = { + 0x01, 0x02, 0x03, +}; + +static hda_nid_t stac9200_pin_nids[8] = { + 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, +}; + +static hda_nid_t stac922x_adc_nids[2] = { + 0x06, 0x07, +}; + +static hda_nid_t stac922x_mux_nids[2] = { + 0x12, 0x13, +}; + +static hda_nid_t stac922x_dac_nids[4] = { + 0x02, 0x03, 0x04, 0x05, +}; + +static hda_nid_t stac922x_pstate_nids[7] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +}; + +static hda_nid_t stac922x_pin_nids[10] = { + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x15, 0x1b, +}; + +static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->input_mux, uinfo); +} + +static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; + return 0; +} + +static int stac92xx_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); +} + +static struct hda_verb stac9200_ch2_init[] = { + /* set dac0mux for dac converter */ + { 0x07, 0x701, 0x00}, + {} +}; + +static struct hda_verb stac922x_ch2_init[] = { + /* set master volume and direct control */ + { 0x16, 0x70f, 0xff}, + {} +}; + +struct sigmatel_channel_mode { + unsigned int channels; + const struct hda_verb *sequence; +}; + +static snd_kcontrol_new_t stac9200_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 1, + .info = stac92xx_mux_enum_info, + .get = stac92xx_mux_enum_get, + .put = stac92xx_mux_enum_put, + }, + HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Input Mux Volume", 0x0c, 0, HDA_OUTPUT), + { } /* end */ +}; + +static snd_kcontrol_new_t stac922x_mixer[] = { + HDA_CODEC_VOLUME("PCM Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x2, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 1, + .info = stac92xx_mux_enum_info, + .get = stac92xx_mux_enum_get, + .put = stac92xx_mux_enum_put, + }, + HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static struct hda_input_mux stac9200_input_mux = { + .num_items = 5, + .items = { + { "Port B", 0x0 }, + { "Port C", 0x1 }, + { "Port D", 0x2 }, + { "Port A", 0x3 }, + { "CD", 0x4 }, + } +}; + +static struct hda_input_mux stac922x_input_mux = { + .num_items = 7, + .items = { + { "Port E", 0x0 }, + { "CD", 0x1 }, + { "Port F", 0x2 }, + { "Port B", 0x3 }, + { "Port C", 0x4 }, + { "Port D", 0x5 }, + { "Port A", 0x6 }, + } +}; + +static int stac92xx_build_controls(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + int err; + + err = snd_hda_add_new_ctls(codec, spec->mixer); + if (err < 0) + return err; + + return 0; +} + +#ifdef STAC_TEST +static unsigned int stac9200_pin_configs[8] = { + 0x40000100, 0x40000100, 0x0221401f, 0x01114010, + 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, +}; + +static unsigned int stac922x_pin_configs[14] = { + 0x40000100, 0x40000100, 0x40000100, 0x01114010, + 0x01813122, 0x40000100, 0x40000100, 0x40000100, + 0x40000100, 0x40000100, +}; + +static void stac92xx_set_config_regs(struct hda_codec *codec) +{ + int i; + struct sigmatel_spec *spec = codec->spec; + unsigned int pin_cfg; + + for (i=0; i < spec->num_pins; i++) { + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, + spec->pin_configs[i] & 0x000000ff); + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, + (spec->pin_configs[i] & 0x0000ff00) >> 8); + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, + (spec->pin_configs[i] & 0x00ff0000) >> 16); + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, + spec->pin_configs[i] >> 24); + pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0, + AC_VERB_GET_CONFIG_DEFAULT, + 0x00); + printk("pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg); + } +} +#endif + +static int stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, unsigned int value) +{ + unsigned int pin_ctl; + + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_ctl | value); + + return 0; +} + +static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int vref_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) >> AC_PINCAP_VREF_SHIFT; + unsigned int vref_ctl = AC_PINCTL_VREF_HIZ; + + if (vref_caps & AC_PINCAP_VREF_100) + vref_ctl = AC_PINCTL_VREF_100; + else if (vref_caps & AC_PINCAP_VREF_80) + vref_ctl = AC_PINCTL_VREF_80; + else if (vref_caps & AC_PINCAP_VREF_50) + vref_ctl = AC_PINCTL_VREF_50; + else if (vref_caps & AC_PINCAP_VREF_GRD) + vref_ctl = AC_PINCTL_VREF_GRD; + + stac92xx_set_pinctl(codec, nid, vref_ctl); + + return 0; +} + +static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg) +{ + switch((pin_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) { + case AC_JACK_HP_OUT: + /* Enable HP amp */ + stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN); + /* Fall through */ + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + /* Enable output */ + stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); + break; + case AC_JACK_MIC_IN: + /* Set vref */ + stac92xx_set_vref(codec, nid); + case AC_JACK_CD: + case AC_JACK_LINE_IN: + case AC_JACK_AUX: + /* Enable input */ + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; + } + + return 0; +} + +static int stac92xx_config_pins(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + unsigned int pin_cfg; + + for (i=0; i < spec->num_pins; i++) { + /* Default to disabled */ + snd_hda_codec_write(codec, spec->pin_nids[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + 0x00); + + pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0, + AC_VERB_GET_CONFIG_DEFAULT, + 0x00); + if (((pin_cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) == AC_JACK_PORT_NONE) + continue; /* Move on */ + + stac92xx_config_pin(codec, spec->pin_nids[i], pin_cfg); + } + + return 0; +} + +static int stac92xx_init(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + + for (i=0; i < spec->num_pstates; i++) + snd_hda_codec_write(codec, spec->pstate_nids[i], 0, + AC_VERB_SET_POWER_STATE, 0x00); + + mdelay(100); + + snd_hda_sequence_write(codec, spec->init); + +#ifdef STAC_TEST + stac92xx_set_config_regs(codec); +#endif + + stac92xx_config_pins(codec); + + return 0; +} + +/* + * Analog playback callbacks + */ +static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); +} + +static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, + format, substream); +} + +static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Analog capture callbacks + */ +static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + stream_tag, 0, format); + return 0; +} + +static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); + return 0; +} + +static struct hda_pcm_stream stac92xx_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0x02, /* NID to query formats and rates */ + .ops = { + .open = stac92xx_playback_pcm_open, + .prepare = stac92xx_playback_pcm_prepare, + .cleanup = stac92xx_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream stac92xx_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x06, /* NID to query formats and rates */ + .ops = { + .prepare = stac92xx_capture_pcm_prepare, + .cleanup = stac92xx_capture_pcm_cleanup + }, +}; + +static int stac92xx_build_pcms(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "STAC92xx"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->playback_nid; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid; + + return 0; +} + +static void stac92xx_free(struct hda_codec *codec) +{ + kfree(codec->spec); +} + +static struct hda_codec_ops stac92xx_patch_ops = { + .build_controls = stac92xx_build_controls, + .build_pcms = stac92xx_build_pcms, + .init = stac92xx_init, + .free = stac92xx_free, +}; + +static int patch_stac9200(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = stac9200_dac_nids; + spec->adc_nids = stac9200_adc_nids; + spec->mux_nids = stac9200_mux_nids; + spec->input_mux = &stac9200_input_mux; + spec->pstate_nids = stac9200_pstate_nids; + spec->num_pstates = 3; + spec->pin_nids = stac9200_pin_nids; +#ifdef STAC_TEST + spec->pin_configs = stac9200_pin_configs; +#endif + spec->num_pins = 8; + spec->init = stac9200_ch2_init; + spec->mixer = stac9200_mixer; + spec->playback_nid = 0x02; + spec->capture_nid = 0x03; + + codec->patch_ops = stac92xx_patch_ops; + + return 0; +} + +static int patch_stac922x(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 4; + spec->multiout.dac_nids = stac922x_dac_nids; + spec->adc_nids = stac922x_adc_nids; + spec->mux_nids = stac922x_mux_nids; + spec->input_mux = &stac922x_input_mux; + spec->pstate_nids = stac922x_pstate_nids; + spec->num_pstates = 7; + spec->pin_nids = stac922x_pin_nids; +#ifdef STAC_TEST + spec->pin_configs = stac922x_pin_configs; +#endif + spec->num_pins = 10; + spec->init = stac922x_ch2_init; + spec->mixer = stac922x_mixer; + spec->playback_nid = 0x02; + spec->capture_nid = 0x06; + + codec->patch_ops = stac92xx_patch_ops; + + return 0; +} + +/* + * patch entries + */ +struct hda_codec_preset snd_hda_preset_sigmatel[] = { + { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, + { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, + { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, + { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x }, + { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, + { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, + { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, + {} /* terminator */ +}; -- cgit v1.2.3-70-g09d2 From 4a3fdf3dba80f332e6233e72bdbccdc6031fc92e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Apr 2005 13:35:51 +0200 Subject: [ALSA] Add AD1981HD and AD1983 support HDA Codec driver Added the support of AD1981HD and AD1983 codecs. Including the fix for AD1986A. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 691 ++++++++++++++++++++++++++++++++----------- 1 file changed, 522 insertions(+), 169 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 75d23849f71..caa48699344 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1,5 +1,5 @@ /* - * HD audio interface patch for AD1986A + * HD audio interface patch for AD1981HD, AD1983, AD1986A * * Copyright (c) 2005 Takashi Iwai * @@ -27,13 +27,239 @@ #include "hda_codec.h" #include "hda_local.h" -struct ad1986a_spec { +struct ad198x_spec { struct semaphore amp_mutex; /* PCM volume/mute control mutex */ struct hda_multi_out multiout; /* playback */ + hda_nid_t adc_nid; + const struct hda_input_mux *input_mux; unsigned int cur_mux; /* capture source */ + unsigned int spdif_route; + snd_kcontrol_new_t *mixers; + const struct hda_verb *init_verbs; struct hda_pcm pcm_rec[2]; /* PCM information */ }; +/* + * input MUX handling (common part) + */ +static int ad198x_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + return snd_hda_input_mux_info(spec->input_mux, uinfo); +} + +static int ad198x_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->cur_mux; + return 0; +} + +static int ad198x_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->adc_nid, &spec->cur_mux); +} + +/* + * initialization (common callbacks) + */ +static int ad198x_init(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + snd_hda_sequence_write(codec, spec->init_verbs); + return 0; +} + +static int ad198x_build_controls(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + int err; + + err = snd_hda_add_new_ctls(codec, spec->mixers); + if (err < 0) + return err; + if (spec->multiout.dig_out_nid) + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + if (err < 0) + return err; + return 0; +} + +/* + * Analog playback callbacks + */ +static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); +} + +static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, + format, substream); +} + +static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + snd_hda_codec_setup_stream(codec, spec->adc_nid, stream_tag, 0, format); + return 0; +} + +static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct ad198x_spec *spec = codec->spec; + snd_hda_codec_setup_stream(codec, spec->adc_nid, 0, 0, 0); + return 0; +} + + +/* + */ +static struct hda_pcm_stream ad198x_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 6, + .nid = 0, /* fill later */ + .ops = { + .open = ad198x_playback_pcm_open, + .prepare = ad198x_playback_pcm_prepare, + .cleanup = ad198x_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream ad198x_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = ad198x_capture_pcm_prepare, + .cleanup = ad198x_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream ad198x_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .open = ad198x_dig_playback_pcm_open, + .close = ad198x_dig_playback_pcm_close + }, +}; + +static int ad198x_build_pcms(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "AD198x Analog"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nid; + + if (spec->multiout.dig_out_nid) { + info++; + codec->num_pcms++; + info->name = "AD198x Digital"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + + return 0; +} + +static void ad198x_free(struct hda_codec *codec) +{ + kfree(codec->spec); +} + +#ifdef CONFIG_PM +static int ad198x_resume(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + + ad198x_init(codec); + snd_hda_resume_ctls(codec, spec->mixers); + snd_hda_resume_spdif_out(codec); + return 0; +} +#endif + +static struct hda_codec_ops ad198x_patch_ops = { + .build_controls = ad198x_build_controls, + .build_pcms = ad198x_build_pcms, + .init = ad198x_init, + .free = ad198x_free, +#ifdef CONFIG_PM + .resume = ad198x_resume, +#endif +}; + + +/* + * AD1986A specific + */ + #define AD1986A_SPDIF_OUT 0x02 #define AD1986A_FRONT_DAC 0x03 #define AD1986A_SURR_DAC 0x04 @@ -68,7 +294,7 @@ static struct hda_input_mux ad1986a_capture_source = { static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *ad = codec->spec; + struct ad198x_spec *ad = codec->spec; down(&ad->amp_mutex); snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); @@ -79,7 +305,7 @@ static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *ad = codec->spec; + struct ad198x_spec *ad = codec->spec; int i, change = 0; down(&ad->amp_mutex); @@ -97,7 +323,7 @@ static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *ad = codec->spec; + struct ad198x_spec *ad = codec->spec; down(&ad->amp_mutex); snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); @@ -108,7 +334,7 @@ static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *ad = codec->spec; + struct ad198x_spec *ad = codec->spec; int i, change = 0; down(&ad->amp_mutex); @@ -121,32 +347,6 @@ static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t return change; } -/* - * input MUX handling - */ -static int ad1986a_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - return snd_hda_input_mux_info(&ad1986a_capture_source, uinfo); -} - -static int ad1986a_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->cur_mux; - return 0; -} - -static int ad1986a_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad1986a_spec *spec = codec->spec; - - return snd_hda_input_mux_put(codec, &ad1986a_capture_source, ucontrol, - AD1986A_ADC, &spec->cur_mux); -} - /* * mixers */ @@ -194,9 +394,9 @@ static snd_kcontrol_new_t ad1986a_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", - .info = ad1986a_mux_enum_info, - .get = ad1986a_mux_enum_get, - .put = ad1986a_mux_enum_put, + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, }, HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), { } /* end */ @@ -241,183 +441,328 @@ static struct hda_verb ad1986a_init_verbs[] = { {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* HP Pin */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* Front, Surround, CLFE Pins */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* Mono Pin */ + {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* Mic Pin */ + {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* Line, Aux, CD, Beep-In Pin */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, { } /* end */ }; -static int ad1986a_init(struct hda_codec *codec) +static int patch_ad1986a(struct hda_codec *codec) { - snd_hda_sequence_write(codec, ad1986a_init_verbs); - return 0; -} + struct ad198x_spec *spec; -static int ad1986a_build_controls(struct hda_codec *codec) -{ - int err; + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + init_MUTEX(&spec->amp_mutex); + codec->spec = spec; + + spec->multiout.max_channels = 6; + spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); + spec->multiout.dac_nids = ad1986a_dac_nids; + spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; + spec->adc_nid = AD1986A_ADC; + spec->input_mux = &ad1986a_capture_source; + spec->mixers = ad1986a_mixers; + spec->init_verbs = ad1986a_init_verbs; + + codec->patch_ops = ad198x_patch_ops; - err = snd_hda_add_new_ctls(codec, ad1986a_mixers); - if (err < 0) - return err; - err = snd_hda_create_spdif_out_ctls(codec, AD1986A_SPDIF_OUT); - if (err < 0) - return err; return 0; } /* - * Analog playback callbacks + * AD1983 specific */ -static int ad1986a_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) -{ - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); -} -static int ad1986a_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - snd_pcm_substream_t *substream) -{ - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} +#define AD1983_SPDIF_OUT 0x02 +#define AD1983_DAC 0x03 +#define AD1983_ADC 0x04 -static int ad1986a_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) -{ - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} +static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; + +static struct hda_input_mux ad1983_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x1 }, + { "Mix", 0x2 }, + { "Mix Mono", 0x3 }, + }, +}; /* - * Digital out + * SPDIF playback route */ -static int ad1986a_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) +static int ad1983_spdif_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); + static char *texts[] = { "PCM", "ADC" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; } -static int ad1986a_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) +static int ad1983_spdif_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - struct ad1986a_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; -/* - * Analog capture - */ -static int ad1986a_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - snd_pcm_substream_t *substream) -{ - snd_hda_codec_setup_stream(codec, AD1986A_ADC, stream_tag, 0, format); + ucontrol->value.enumerated.item[0] = spec->spdif_route; return 0; } -static int ad1986a_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - snd_pcm_substream_t *substream) +static int ad1983_spdif_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - snd_hda_codec_setup_stream(codec, AD1986A_ADC, 0, 0, 0); + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + + if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { + spec->spdif_route = ucontrol->value.enumerated.item[0]; + snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, + AC_VERB_SET_CONNECT_SEL, spec->spdif_route); + return 1; + } return 0; } - -/* - */ -static struct hda_pcm_stream ad1986a_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 6, - .nid = AD1986A_FRONT_DAC, /* NID to query formats and rates */ - .ops = { - .open = ad1986a_playback_pcm_open, - .prepare = ad1986a_playback_pcm_prepare, - .cleanup = ad1986a_playback_pcm_cleanup +static snd_kcontrol_new_t ad1983_mixers[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, }, -}; - -static struct hda_pcm_stream ad1986a_pcm_analog_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = AD1986A_ADC, /* NID to query formats and rates */ - .ops = { - .prepare = ad1986a_capture_pcm_prepare, - .cleanup = ad1986a_capture_pcm_cleanup + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Route", + .info = ad1983_spdif_route_info, + .get = ad1983_spdif_route_get, + .put = ad1983_spdif_route_put, }, + { } /* end */ }; -static struct hda_pcm_stream ad1986a_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = AD1986A_SPDIF_OUT, - .ops = { - .open = ad1986a_dig_playback_pcm_open, - .close = ad1986a_dig_playback_pcm_close - }, +static struct hda_verb ad1983_init_verbs[] = { + /* Front, HP, Mono; mute as default */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Beep, PCM, Mic, Line-In: mute */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Front, HP selectors; from Mix */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* Mono selector; from Mix */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic selector; Mic */ + {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Line-in selector: Line-in */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Mic boost: 0dB */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* Record selector: mic */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* SPDIF route: PCM */ + {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Front Pin */ + {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* HP Pin */ + {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* Mono Pin */ + {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* Mic Pin */ + {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* Line Pin */ + {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { } /* end */ }; -static int ad1986a_build_pcms(struct hda_codec *codec) +static int patch_ad1983(struct hda_codec *codec) { - struct ad1986a_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; + struct ad198x_spec *spec; - codec->num_pcms = 2; - codec->pcm_info = info; + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; - info->name = "AD1986A Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1986a_pcm_analog_capture; - info++; + init_MUTEX(&spec->amp_mutex); + codec->spec = spec; + + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); + spec->multiout.dac_nids = ad1983_dac_nids; + spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; + spec->adc_nid = AD1983_ADC; + spec->input_mux = &ad1983_capture_source; + spec->mixers = ad1983_mixers; + spec->init_verbs = ad1983_init_verbs; + spec->spdif_route = 0; - info->name = "AD1986A Digital"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_digital_playback; + codec->patch_ops = ad198x_patch_ops; return 0; } -static void ad1986a_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} -#ifdef CONFIG_PM -static int ad1986a_resume(struct hda_codec *codec) -{ - ad1986a_init(codec); - snd_hda_resume_ctls(codec, ad1986a_mixers); - snd_hda_resume_spdif_out(codec); - return 0; -} -#endif +/* + * AD1981 HD specific + */ -static struct hda_codec_ops ad1986a_patch_ops = { - .build_controls = ad1986a_build_controls, - .build_pcms = ad1986a_build_pcms, - .init = ad1986a_init, - .free = ad1986a_free, -#ifdef CONFIG_PM - .resume = ad1986a_resume, -#endif +#define AD1981_SPDIF_OUT 0x02 +#define AD1981_DAC 0x03 +#define AD1981_ADC 0x04 + +static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; + +/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ +static struct hda_input_mux ad1981_capture_source = { + .num_items = 7, + .items = { + { "Front Mic", 0x0 }, + { "Line", 0x1 }, + { "Mix", 0x2 }, + { "Mix Mono", 0x3 }, + { "CD", 0x4 }, + { "Mic", 0x6 }, + { "Aux", 0x7 }, + }, }; -static int patch_ad1986a(struct hda_codec *codec) +static snd_kcontrol_new_t ad1981_mixers[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + /* identical with AD1983 */ + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Route", + .info = ad1983_spdif_route_info, + .get = ad1983_spdif_route_get, + .put = ad1983_spdif_route_put, + }, + { } /* end */ +}; + +static struct hda_verb ad1981_init_verbs[] = { + /* Front, HP, Mono; mute as default */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Front, HP selectors; from Mix */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* Mono selector; from Mix */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Mic Mixer; select Front Mic */ + {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Mic boost: 0dB */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* Record selector: Front mic */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* SPDIF route: PCM */ + {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Front Pin */ + {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* HP Pin */ + {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* Mono Pin */ + {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* Front & Rear Mic Pins */ + {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* Line Pin */ + {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* Digital Beep */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Line-Out as Input: disabled */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + { } /* end */ +}; + +static int patch_ad1981(struct hda_codec *codec) { - struct ad1986a_spec *spec; + struct ad198x_spec *spec; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -426,20 +771,28 @@ static int patch_ad1986a(struct hda_codec *codec) init_MUTEX(&spec->amp_mutex); codec->spec = spec; - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); - spec->multiout.dac_nids = ad1986a_dac_nids; - spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); + spec->multiout.dac_nids = ad1981_dac_nids; + spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; + spec->adc_nid = AD1981_ADC; + spec->input_mux = &ad1981_capture_source; + spec->mixers = ad1981_mixers; + spec->init_verbs = ad1981_init_verbs; + spec->spdif_route = 0; - codec->patch_ops = ad1986a_patch_ops; + codec->patch_ops = ad198x_patch_ops; return 0; } + /* * patch entries */ struct hda_codec_preset snd_hda_preset_analog[] = { + { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, + { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, {} /* terminator */ }; -- cgit v1.2.3-70-g09d2 From 01f66d2ccf83ee3ddc8276346f4e1113b9de50d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Apr 2005 13:36:24 +0200 Subject: [ALSA] Remove dead code HDA Codec driver Removed the dead (duplicated) code. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index be6cba34939..890b7566154 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1449,10 +1449,6 @@ static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream snd_assert(info->nid, return -EINVAL); info->ops.prepare = hda_pcm_default_prepare; } - if (info->ops.prepare == NULL) { - snd_assert(info->nid, return -EINVAL); - info->ops.prepare = hda_pcm_default_prepare; - } if (info->ops.cleanup == NULL) { snd_assert(info->nid, return -EINVAL); info->ops.cleanup = hda_pcm_default_cleanup; -- cgit v1.2.3-70-g09d2 From 98f759a61639b40686e607ecc6fefacb4c249c82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Apr 2005 13:37:13 +0200 Subject: [ALSA] Misc clean up HDA Codec driver Misc clean up: move the definitions of constants for pinctl to a single place. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 042bcfc6dbb..263f5b698ba 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -185,13 +185,6 @@ enum { #define AC_PINCAP_VREF_GRD (1<<2) /* ground */ #define AC_PINCAP_VREF_80 (1<<4) /* 80% */ #define AC_PINCAP_VREF_100 (1<<5) /* 100% */ -/* Vref setting (used in pin ctl) */ -#define AC_PINCTL_VREF_HIZ (0) /* Hi-Z */ -#define AC_PINCTL_VREF_50 (1) /* 50% */ -#define AC_PINCTL_VREF_GRD (2) /* ground */ -#define AC_PINCTL_VREF_80 (4) /* 80% */ -#define AC_PINCTL_VREF_100 (5) /* 100% */ - /* Amplifier capabilities */ #define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ @@ -254,6 +247,11 @@ enum { /* Pin widget control - 8bit */ #define AC_PINCTL_VREFEN (0x7<<0) +#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ +#define AC_PINCTL_VREF_50 1 /* 50% */ +#define AC_PINCTL_VREF_GRD 2 /* ground */ +#define AC_PINCTL_VREF_80 4 /* 80% */ +#define AC_PINCTL_VREF_100 5 /* 100% */ #define AC_PINCTL_IN_EN (1<<5) #define AC_PINCTL_OUT_EN (1<<6) #define AC_PINCTL_HP_EN (1<<7) -- cgit v1.2.3-70-g09d2 From 7358036cc6cb139d70d2b1898d29ecedc087fceb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 15 Apr 2005 13:51:48 +0200 Subject: [ALSA] Add dxs_support=5 for Insight P4-ITX VIA82xx driver Added dxs_support=5 entry for Insight P4-ITX. Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 64cc40f97b5..881af1d11aa 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2165,6 +2165,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ + { .vendor = 0x1106, .device = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ -- cgit v1.2.3-70-g09d2 From fe5ac9dcfe3b219209cf8e08347cce47658267d0 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 20 Apr 2005 10:03:31 +0200 Subject: [ALSA] trivial warning fix for emu10k1 EMU10K1/EMU10K2 driver When building with gcc -W sound/pci/emu10k1/emupcm.c produces this little warning in 2.6.12-rc2-mm3 : sound/pci/emu10k1/emupcm.c:265: warning: 'inline' is not at beginning of declaration No big deal, but trivial to fix. Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emupcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index d1c2a02c486..fd7cc389f82 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -262,7 +262,7 @@ static unsigned int emu10k1_select_interprom(unsigned int pitch_target) * * returns: cache invalidate size in samples */ -static int inline emu10k1_ccis(int stereo, int w_16) +static inline int emu10k1_ccis(int stereo, int w_16) { if (w_16) { return stereo ? 24 : 26; -- cgit v1.2.3-70-g09d2 From c31329257522bf66df56e279e20df6fc7abd1ea7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Apr 2005 13:43:00 +0200 Subject: [ALSA] Fix a typo in comments HDA generic driver Fix a typo in comments. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index c233e7f1a74..bfbeff2e0d0 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -44,7 +44,7 @@ struct hda_gnode { struct list_head list; }; -/* pathc-specific record */ +/* patch-specific record */ struct hda_gspec { struct hda_gnode *dac_node; /* DAC node */ struct hda_gnode *out_pin_node; /* Output pin (Line-Out) node */ -- cgit v1.2.3-70-g09d2 From b0c95f514a4057720958c9ea0113229468c94b2b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Apr 2005 13:44:08 +0200 Subject: [ALSA] Show PIN jack type HDA generic driver Show the jack type of each PIN default configuration entry. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 8c703ff056f..15df7162f17 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -157,6 +157,7 @@ static const char *get_jack_color(u32 cfg) static void print_pin_caps(snd_info_buffer_t *buffer, struct hda_codec *codec, hda_nid_t nid) { + static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; static char *jack_types[16] = { "Line Out", "Speaker", "HP Out", "CD", "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", @@ -176,7 +177,8 @@ static void print_pin_caps(snd_info_buffer_t *buffer, snd_iprintf(buffer, " HP"); snd_iprintf(buffer, "\n"); caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - snd_iprintf(buffer, " Pin Default 0x%08x: %s at %s %s\n", caps, + snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, + jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], get_jack_location(caps)); -- cgit v1.2.3-70-g09d2 From d21b37ea134921f807ebdbd19ae3cd00bb8bf2fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Apr 2005 13:45:55 +0200 Subject: [ALSA] Fix and cleanup of CM9880 auto-configuration HDA Codec driver Fix and cleanup of CM9880 automatic PIN configuration. snd_hda_codec_setup_stream() doesn't do anything when NID is 0. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 3 +++ sound/pci/hda/hda_codec.h | 2 ++ sound/pci/hda/patch_cmedia.c | 31 +++++++++++++++++++------------ 3 files changed, 24 insertions(+), 12 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 890b7566154..44fac2182fc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -549,6 +549,9 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format) { + if (! nid) + return; + snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", nid, stream_tag, channel_id, format); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 263f5b698ba..43fc245d9a6 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -259,7 +259,9 @@ enum { /* configuration default - 32bit */ #define AC_DEFCFG_SEQUENCE (0xf<<0) #define AC_DEFCFG_DEF_ASSOC (0xf<<4) +#define AC_DEFCFG_ASSOC_SHIFT 4 #define AC_DEFCFG_MISC (0xf<<8) +#define AC_DEFCFG_MISC_SHIFT 8 #define AC_DEFCFG_COLOR (0xf<<12) #define AC_DEFCFG_COLOR_SHIFT 12 #define AC_DEFCFG_CONN_TYPE (0xf<<16) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index e64e29dac82..087230ca20a 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -365,7 +365,6 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } -#define AC_DEFCFG_ASSOC_SHIFT 4 #define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) #define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) #define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) @@ -796,6 +795,7 @@ static int patch_cmi9880(struct hda_codec *codec) { unsigned int port_e, port_f, port_g, port_h; unsigned int port_spdifi, port_spdifo; + int max_channels; /* collect pin default configuration */ cmi9880_get_pin_def_config(codec); port_e = cmi9880_get_def_config(codec, 0x0f); @@ -805,33 +805,40 @@ static int patch_cmi9880(struct hda_codec *codec) port_spdifi = cmi9880_get_def_config(codec, 0x13); port_spdifo = cmi9880_get_def_config(codec, 0x12); spec->front_panel = 1; - if ((get_defcfg_connect(port_e) == AC_JACK_PORT_NONE) - || (get_defcfg_connect(port_f) == AC_JACK_PORT_NONE)) { + if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || + get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { spec->surr_switch = 1; /* no front panel */ - if ((get_defcfg_connect(port_g) == AC_JACK_PORT_NONE) - || (get_defcfg_connect(port_h) == AC_JACK_PORT_NONE)) { + if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || + get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) { /* no optional rear panel */ spec->board_config = CMI_MINIMAL; spec->front_panel = 0; spec->num_ch_modes = 2; - } else + } else { spec->board_config = CMI_MIN_FP; spec->num_ch_modes = 3; + } spec->channel_modes = cmi9880_channel_modes; spec->input_mux = &cmi9880_basic_mux; + spec->multiout.max_channels = cmi9880_channel_modes[0].channels; } else { spec->input_mux = &cmi9880_basic_mux; - if (get_defcfg_connect(port_spdifo) != 1) + if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - if (get_defcfg_connect(port_spdifi) != 1) + if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) spec->dig_in_nid = CMI_DIG_IN_NID; + spec->multiout.max_channels = 8; } - spec->multiout.max_channels = cmi9880_get_multich_pins(codec); - cmi9880_fill_multi_dac_nids(codec); - cmi9880_fill_multi_init(codec); - } + max_channels = cmi9880_get_multich_pins(codec); + if (max_channels > 0) { + spec->multiout.max_channels = max_channels; + cmi9880_fill_multi_dac_nids(codec); + cmi9880_fill_multi_init(codec); + } else + snd_printd("patch_cmedia: cannot detect association in defcfg\n"); break; + } } spec->multiout.num_dacs = 4; -- cgit v1.2.3-70-g09d2 From 930fed517441310a80e269a193ee52f99dd58082 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Apr 2005 20:54:43 +0200 Subject: [ALSA] Add dxs_support entry for MSI K8T Neo-FIS2R VIA82xx driver Report by Ronny V. Vindenes Add dxs_support=5 for MSI K8T Neo-FIS2R. Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 881af1d11aa..4c41df05352 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2169,6 +2169,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ + { .vendor = 0x1462, .device = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ { .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ { .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ { .vendor = 0x1462, .device = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ -- cgit v1.2.3-70-g09d2 From b16760bbb9e3c63b6beef7e2c8f8db64ab5efe70 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 25 Apr 2005 11:22:20 +0200 Subject: [ALSA] fix behaviour of ac97_enum_mixer elements AC97 Codec ac97_enum mixer elements (e.g., 'Capture Source') did not work because of wrong bitmask calculation in snd_ac97_get_enum_double() and snd_ac97_put_enum_double(). https://bugtrack.alsa-project.org/alsa-bug/view.php?id=1072 Signed-off-by: Sergey Vlasov Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 1ad7f83a65e..36a33ae9ae0 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -465,7 +465,7 @@ int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; unsigned short val, bitmask; - for (bitmask = 1; bitmask > e->mask; bitmask <<= 1) + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ; val = snd_ac97_read_cache(ac97, e->reg); ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); @@ -482,7 +482,7 @@ int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u unsigned short val; unsigned short mask, bitmask; - for (bitmask = 1; bitmask > e->mask; bitmask <<= 1) + for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) ; if (ucontrol->value.enumerated.item[0] > e->mask - 1) return -EINVAL; -- cgit v1.2.3-70-g09d2 From 67e1b51e293cec9bbe8c9ad81680bceec1e3b7f9 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 25 Apr 2005 11:34:33 +0200 Subject: [ALSA] ac97 - add the 'Mic Front Input Switch' control (ALC850) AC97 Codec Add the 'Mic Front Input Switch' control to the mixer for ALC850. Enabling this input is required for using the front panel microphone connector with ASUS A8V motherboard. Signed-off-by: Sergey Vlasov Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_patch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 7f16c306165..737c4bb94d2 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1928,6 +1928,7 @@ static void alc850_update_jacks(ac97_t *ac97) static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), + AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1), AC97_SURROUND_JACK_MODE_CTL, AC97_CHANNEL_MODE_CTL, }; -- cgit v1.2.3-70-g09d2 From 7679a03099992d8e6c878d459e22b639ed8c10fa Mon Sep 17 00:00:00 2001 From: Thomas Charbonnel Date: Mon, 25 Apr 2005 11:35:29 +0200 Subject: [ALSA] hdsp - solved big endian problem RME HDSP driver ppc firmware upload fix Signed-off-by: Thomas Charbonnel Signed-off-by: Jaroslav Kysela --- sound/pci/rme9652/hdsp.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 44ca7ddb68f..b35ed5f0c04 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -4912,19 +4912,9 @@ static int __devinit hdsp_request_fw_loader(hdsp_t *hdsp) release_firmware(fw); return -EINVAL; } -#ifdef SNDRV_BIG_ENDIAN - { - int i; - u32 *src = (u32*)fw->data; - for (i = 0; i < ARRAY_SIZE(hdsp->firmware_cache); i++, src++) - hdsp->firmware_cache[i] = ((*src & 0x000000ff) << 16) | - ((*src & 0x0000ff00) << 8) | - ((*src & 0x00ff0000) >> 8) | - ((*src & 0xff000000) >> 16); - } -#else + memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache)); -#endif + release_firmware(fw); hdsp->state |= HDSP_FirmwareCached; -- cgit v1.2.3-70-g09d2 From c702563703b5680a7143f8ac66613d082a190ca2 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Wed, 4 May 2005 17:26:28 +0200 Subject: [ALSA] Support multiple capture rates on p16v. EMU10K1/EMU10K2 driver The capture rate does in fact vary, but it only captures anything if the HD Capture source is set to I2S or AC97. I have not tested if the sound is actually captured from an physical input of some type or not. TODO: Get SPDIF capture working. Signed-off-by: James Courtier-Dutton --- sound/pci/emu10k1/p16v.c | 53 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 18 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 776761fe557..13f7e62ee56 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -133,25 +133,24 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { }; static snd_pcm_hardware_t snd_p16v_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = (32*1024), - .period_bytes_min = 64, - .period_bytes_max = (16*1024), - .periods_min = 2, - .periods_max = 2, - .fifo_size = 0, + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, + .rate_min = 44100, + .rate_max = 192000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = (32*1024), + .period_bytes_min = 64, + .period_bytes_max = (16*1024), + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0, }; - static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) { emu10k1_pcm_t *epcm = runtime->private_data; @@ -362,7 +361,25 @@ static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream) emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int channel = substream->pcm->device - emu->p16v_device_offset; - //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); + u32 tmp; + //printk("prepare capture:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); + tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); + switch (runtime->rate) { + case 44100: + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0800); + break; + case 96000: + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0400); + break; + case 192000: + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0200); + break; + case 48000: + default: + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0000); + break; + } + /* FIXME: Check emu->buffer.size before actually writing to it. */ snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes -- cgit v1.2.3-70-g09d2 From f927c8fc648420ad8edd7e4699b4ba510c2e9c6b Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 7 May 2005 15:34:13 +0200 Subject: [ALSA] Implement different capture sources. EMU10K1/EMU10K2 driver e.g. When HD Capture source is set to SPDIF, setting HD Capture channel to 0 captures from CDROM digital input. setting HD Capture channel to 1 captures from SPDIF in. Signed-off-by: James Courtier-Dutton --- include/sound/emu10k1.h | 1 + sound/pci/emu10k1/p16v.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 23dabbceb4b..c50b91958ff 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1130,6 +1130,7 @@ struct _snd_emu10k1 { emu10k1_voice_t p16v_capture_voice; int p16v_device_offset; u32 p16v_capture_source; + u32 p16v_capture_channel; emu10k1_pcm_mixer_t pcm_mixer[32]; emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK]; snd_kcontrol_t *ctl_send_routing; diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 13f7e62ee56..93dff4c6b23 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -41,7 +41,13 @@ * Integrated with snd-emu10k1 driver. * 0.22 * Removed #if 0 ... #endif - * + * 0.23 + * Implement different capture rates. + * 0.24 + * Implement different capture source channels. + * e.g. When HD Capture source is set to SPDIF, + * setting HD Capture channel to 0 captures from CDROM digital input. + * setting HD Capture channel to 1 captures from SPDIF in. * * BUGS: * Some stability problems when unloading the snd-p16v kernel module. @@ -933,6 +939,56 @@ static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata = .get = snd_p16v_capture_source_get, .put = snd_p16v_capture_source_put }; + +static int snd_p16v_capture_channel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[4] = { "0", "1", "2", "3", }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item > 3) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_p16v_capture_channel_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->p16v_capture_channel; + return 0; +} + +static int snd_p16v_capture_channel_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + emu10k1_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + u32 tmp; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->p16v_capture_channel != val); + if (change) { + emu->p16v_capture_channel = val; + tmp = snd_emu10k1_ptr20_read(emu, CAPTURE_P16V_SOURCE, 0) & 0xfffc; + snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, tmp | val); + } + return change; +} + +static snd_kcontrol_new_t snd_p16v_capture_channel __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HD Capture channel", + .info = snd_p16v_capture_channel_info, + .get = snd_p16v_capture_channel_get, + .put = snd_p16v_capture_channel_put +}; + int snd_p16v_mixer(emu10k1_t *emu) { int err; @@ -974,6 +1030,10 @@ int snd_p16v_mixer(emu10k1_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if ((kctl = snd_ctl_new1(&snd_p16v_capture_channel, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; return 0; } -- cgit v1.2.3-70-g09d2 From 22bc30c84b4dc092deb2b14deb0603b257818e63 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 7 May 2005 16:13:40 +0200 Subject: [ALSA] Increase capture buffer sizes. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton --- sound/pci/emu10k1/p16v.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 93dff4c6b23..98f98018989 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -1,7 +1,7 @@ /* * Copyright (c) by James Courtier-Dutton * Driver p16v chips - * Version: 0.22 + * Version: 0.25 * * FEATURES currently supported: * Output fixed at S32_LE, 2 channel to hw:0,0 @@ -48,6 +48,8 @@ * e.g. When HD Capture source is set to SPDIF, * setting HD Capture channel to 0 captures from CDROM digital input. * setting HD Capture channel to 1 captures from SPDIF in. + * 0.25 + * Include capture buffer sizes. * * BUGS: * Some stability problems when unloading the snd-p16v kernel module. @@ -149,9 +151,9 @@ static snd_pcm_hardware_t snd_p16v_capture_hw = { .rate_max = 192000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = (32*1024), + .buffer_bytes_max = (65536 - 64), .period_bytes_min = 64, - .period_bytes_max = (16*1024), + .period_bytes_max = (65536 - 128) >> 1, /* size has to be N*64 bytes */ .periods_min = 2, .periods_max = 2, .fifo_size = 0, @@ -637,7 +639,7 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), - 64*1024, 64*1024)) < 0) + 65536 - 64, 65536 - 64)) < 0) return err; //snd_printk("preallocate capture substream: err=%d\n", err); } -- cgit v1.2.3-70-g09d2 From a488e033861363f64ed90d01622e0c30b382b753 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Sat, 7 May 2005 18:51:51 +0200 Subject: [ALSA] cs4281 - fix DLLRDY not seen problem CS4281 driver Reset the FPDN bit of the EPPMC register if needed. Signed-off-by: Arnaud Patard Signed-off-by: Jaroslav Kysela --- sound/pci/cs4281.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8b42e8631f2..b6e1854e938 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -206,7 +206,10 @@ MODULE_PARM_DESC(dual_codec, "Secondary Codec ID (0 = disabled)."); #define BA0_PMCS 0x0344 /* Power Management Control/Status */ #define BA0_CWPR 0x03e0 /* Configuration Write Protect */ + #define BA0_EPPMC 0x03e4 /* Extended PCI Power Management Control */ +#define BA0_EPPMC_FPDN (1<<14) /* Full Power DowN */ + #define BA0_GPIOR 0x03e8 /* GPIO Pin Interface Register */ #define BA0_SPMC 0x03ec /* Serial Port Power Management Control (& ASDIN2 enable) */ @@ -1461,6 +1464,11 @@ static int snd_cs4281_chip_init(cs4281_t *chip) int timeout; int retry_count = 2; + /* Having EPPMC.FPDN=1 prevent proper chip initialisation */ + tmp = snd_cs4281_peekBA0(chip, BA0_EPPMC); + if (tmp & BA0_EPPMC_FPDN) + snd_cs4281_pokeBA0(chip, BA0_EPPMC, tmp & ~BA0_EPPMC_FPDN); + __retry: tmp = snd_cs4281_peekBA0(chip, BA0_CFLR); if (tmp != BA0_CFLR_DEFAULT) { -- cgit v1.2.3-70-g09d2 From 3296480674e127601f453db6301bfbcbacb0d123 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:48:37 +0200 Subject: [ALSA] ac97 - fix Mic jack sharing on AD1888 codecs AC97 Codec The code for modifying the center/LFE disable bit on AD1888 codecs accidentally toggled the mute split bit instead. Signed-off-by: Clemens Ladisch --- sound/pci/ac97/ac97_patch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 737c4bb94d2..05efff08ddc 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1507,7 +1507,7 @@ static void ad1888_update_jacks(ac97_t *ac97) is_shared_linein(ac97) ? 0 : 1 << 12); /* shared Mic */ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, - is_shared_micin(ac97) ? 0 : 1 << 13); + is_shared_micin(ac97) ? 0 : 1 << 11); } static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { -- cgit v1.2.3-70-g09d2 From 462c4173509c5d1ebdc6cfd58f7236c2ac467e30 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:50:31 +0200 Subject: [ALSA] ac97 - enable multichannel output on AD198x codecs AC97 Codec The code for AD1980/AD1985/AD1986 codecs forgot to enable the code to switch the jack sharing bits on AD1888-compatible codecs. Signed-off-by: Clemens Ladisch --- sound/pci/ac97/ac97_patch.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 05efff08ddc..ce02e7091fc 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1585,8 +1585,9 @@ static struct snd_ac97_build_ops patch_ad1980_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1980_specific, #ifdef CONFIG_PM - .resume = ad18xx_resume + .resume = ad18xx_resume, #endif + .update_jacks = ad1888_update_jacks, }; int patch_ad1980(ac97_t * ac97) @@ -1614,8 +1615,9 @@ static struct snd_ac97_build_ops patch_ad1985_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1985_specific, #ifdef CONFIG_PM - .resume = ad18xx_resume + .resume = ad18xx_resume, #endif + .update_jacks = ad1888_update_jacks, }; int patch_ad1985(ac97_t * ac97) -- cgit v1.2.3-70-g09d2 From f7de9cfd25b6867a2854d98d734e03e1a9fc65fb Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Wed, 11 May 2005 11:13:26 +0200 Subject: [ALSA] emu10k1 - add SB0060 to emu_chip_details EMU10K1/EMU10K2 driver The following patch adds SB0060 to emu_chip_details. Signed-off-by: Mikael Magnusson Signed-off-by: Jaroslav Kysela --- sound/pci/emu10k1/emu10k1_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index bf17db1fd24..070be6af97b 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -711,6 +711,12 @@ static emu_chip_details_t emu_chip_details[] = { .id = "APS", .emu10k1_chip = 1, .ecard = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, + .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, .driver = "EMU10K1", .name = "SB Live 5.1", .id = "Live", -- cgit v1.2.3-70-g09d2 From 88491386be67f659e6b2c76c7463c997ce4c4ebb Mon Sep 17 00:00:00 2001 From: Ville Syrjala Date: Thu, 12 May 2005 14:14:28 +0200 Subject: [ALSA] maestro3: Fix interrupt ack and disable Maestro3 driver Due to a typo interrupts were never actually acked or disabled. Signed-off-by: Ville Syrjala Signed-off-by: Takashi Iwai --- sound/pci/maestro3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 9f184ea8a9d..293cc10e3cb 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1605,7 +1605,7 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif /* ack ints */ - snd_m3_outw(chip, HOST_INT_STATUS, status); + outb(status, chip->iobase + HOST_INT_STATUS); return IRQ_HANDLED; } @@ -2367,7 +2367,7 @@ static int snd_m3_free(m3_t *chip) kfree(chip->substreams); } if (chip->iobase) { - snd_m3_outw(chip, HOST_INT_CTRL, 0); /* disable ints */ + outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */ } #ifdef CONFIG_PM -- cgit v1.2.3-70-g09d2 From db68d15da00f64bef2c8c822baab42aff39ae774 Mon Sep 17 00:00:00 2001 From: Ville Syrjala Date: Thu, 12 May 2005 14:19:32 +0200 Subject: [ALSA] maestro3: Add HW volume button support Maestro3 driver Add support for hardware volume buttons. Signed-off-by: Ville Syrjala Signed-off-by: Takashi Iwai --- sound/pci/maestro3.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 293cc10e3cb..c1c7eeeb199 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -851,7 +851,12 @@ struct snd_m3 { m3_dma_t *substreams; spinlock_t reg_lock; + spinlock_t ac97_lock; + snd_kcontrol_t *master_switch; + snd_kcontrol_t *master_volume; + struct tasklet_struct hwvol_tq; + #ifdef CONFIG_PM u16 *suspend_mem; #endif @@ -1565,6 +1570,68 @@ static void snd_m3_update_ptr(m3_t *chip, m3_dma_t *s) } } +static void snd_m3_update_hw_volume(unsigned long private_data) +{ + m3_t *chip = (m3_t *) private_data; + int x, val; + unsigned long flags; + + /* Figure out which volume control button was pushed, + based on differences from the default register + values. */ + x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; + + /* Reset the volume control registers. */ + outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); + outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); + outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); + outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); + + if (!chip->master_switch || !chip->master_volume) + return; + + /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ + spin_lock_irqsave(&chip->ac97_lock, flags); + + val = chip->ac97->regs[AC97_MASTER_VOL]; + switch (x) { + case 0x88: + /* mute */ + val ^= 0x8000; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); + break; + case 0xaa: + /* volume up */ + if ((val & 0x7f) > 0) + val--; + if ((val & 0x7f00) > 0) + val -= 0x0100; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); + break; + case 0x66: + /* volume down */ + if ((val & 0x7f) < 0x1f) + val++; + if ((val & 0x7f00) < 0x1f00) + val += 0x0100; + chip->ac97->regs[AC97_MASTER_VOL] = val; + outw(val, chip->iobase + CODEC_DATA); + outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); + break; + } + spin_unlock_irqrestore(&chip->ac97_lock, flags); +} + static irqreturn_t snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -1576,7 +1643,10 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status == 0xff) return IRQ_NONE; - + + if (status & HV_INT_PENDING) + tasklet_hi_schedule(&chip->hwvol_tq); + /* * ack an assp int if its running * and has an int pending @@ -1842,24 +1912,32 @@ static unsigned short snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) { m3_t *chip = ac97->private_data; + unsigned long flags; + unsigned short data; if (snd_m3_ac97_wait(chip)) return 0xffff; + spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); if (snd_m3_ac97_wait(chip)) return 0xffff; - return snd_m3_inw(chip, CODEC_DATA); + data = snd_m3_inw(chip, CODEC_DATA); + spin_unlock_irqrestore(&chip->ac97_lock, flags); + return data; } static void snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { m3_t *chip = ac97->private_data; + unsigned long flags; if (snd_m3_ac97_wait(chip)) return; + spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outw(chip, val, CODEC_DATA); snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); + spin_unlock_irqrestore(&chip->ac97_lock, flags); } @@ -1968,6 +2046,7 @@ static int __devinit snd_m3_mixer(m3_t *chip) { ac97_bus_t *pbus; ac97_template_t ac97; + snd_ctl_elem_id_t id; int err; static ac97_bus_ops_t ops = { .write = snd_m3_ac97_write, @@ -1988,6 +2067,15 @@ static int __devinit snd_m3_mixer(m3_t *chip) schedule_timeout(HZ / 10); snd_ac97_write(chip->ac97, AC97_PCM, 0); + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Master Playback Switch"); + chip->master_switch = snd_ctl_find_id(chip->card, &id); + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Master Playback Volume"); + chip->master_volume = snd_ctl_find_id(chip->card, &id); + return 0; } @@ -2293,6 +2381,7 @@ static int snd_m3_chip_init(m3_t *chip) { struct pci_dev *pcidev = chip->pci; + unsigned long io = chip->iobase; u32 n; u16 w; u8 t; /* makes as much sense as 'n', no? */ @@ -2304,7 +2393,8 @@ snd_m3_chip_init(m3_t *chip) pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); - n &= REDUCED_DEBOUNCE; + n &= ~HV_BUTTON_FROM_GD; + n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE; n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); @@ -2332,6 +2422,12 @@ snd_m3_chip_init(m3_t *chip) outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); + outb(0x00, io + HARDWARE_VOL_CTRL); + outb(0x88, io + SHADOW_MIX_REG_VOICE); + outb(0x88, io + HW_VOL_COUNTER_VOICE); + outb(0x88, io + SHADOW_MIX_REG_MASTER); + outb(0x88, io + HW_VOL_COUNTER_MASTER); + return 0; } @@ -2341,7 +2437,7 @@ snd_m3_enable_ints(m3_t *chip) unsigned long io = chip->iobase; /* TODO: MPU401 not supported yet */ - outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); + outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, io + ASSP_CONTROL_C); } @@ -2593,6 +2689,9 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, return err; } + spin_lock_init(&chip->ac97_lock); + tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); + if ((err = snd_m3_mixer(chip)) < 0) return err; -- cgit v1.2.3-70-g09d2 From 091bf4dcab10b083f944d4eafbe0c734786485fe Mon Sep 17 00:00:00 2001 From: Ville Syrjala Date: Thu, 12 May 2005 14:20:57 +0200 Subject: [ALSA] maestro3: HP OmniBook HW volume button magic Maestro3 driver Some HP OmniBook laptops (500 and 6000 at least) require some GPIO magic before the HW volume buttons work. This patch makes them work mostly. Something is still missing to make them work perfectly. However I have been unable to figure out what exactly. Signed-off-by: Ville Syrjala Signed-off-by: Takashi Iwai --- sound/pci/maestro3.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index c1c7eeeb199..3690ea05b04 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2392,6 +2392,18 @@ snd_m3_chip_init(m3_t *chip) DISABLE_LEGACY); pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); + /* + * Volume buttons on some HP OmniBook laptops (500 and 6000 at least) + * don't work correctly. This makes them work for the most part. + * Volume up and down buttons on the laptop side work perfectly. + * Fn+cursor_up (volme up) works, Fn+cursor_down (volume down) doesn't, + * Fn+F8 (mute) works acts as volume up. + */ + outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); + outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); + outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); + outw(0xffff, io + GPIO_MASK); + pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); n &= ~HV_BUTTON_FROM_GD; n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE; -- cgit v1.2.3-70-g09d2 From c74db86bcf0897cdd4dc1f85ae0d76ef59aaeb20 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 14:26:27 +0200 Subject: [ALSA] Add position_fix module option Documentation,HDA Intel driver Added position_fix module option to HDA-intel driver for fixing up the DMA position (possibly hardware-) bugs. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 9 +++ sound/pci/hda/hda_intel.c | 85 ++++++++++++++----------- 2 files changed, 57 insertions(+), 37 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index c69581ca2a3..ef07506e583 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -618,6 +618,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for Intel HD Audio (ICH6, ICH6M, ICH7) model - force the model name + position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF) Module supports up to 8 cards. @@ -643,6 +644,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. full_dig 6-jack in back, 2-jack in front, SPDIF I/O allout 5-jack in back, 2-jack in front, SPDIF out + Note 2: If you get click noises on output, try the module option + position_fix=1 or 2. position_fix=1 will use the SD_LPIB + register value without FIFO size correction as the current + DMA pointer. position_fix=2 will make the driver to use + the position buffer instead of reading SD_LPIB register. + (Usually SD_LPLIB register is more accurate than the + position buffer.) + Module snd-hdsp --------------- diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cbc9ca73c2a..104593fa08e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -51,6 +51,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static char *model[SNDRV_CARDS]; +static int position_fix[SNDRV_CARDS]; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -60,6 +61,8 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); +module_param_array(position_fix, bool, NULL, 0444); +MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)."); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," @@ -183,6 +186,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define ICH6_MAX_CORB_ENTRIES 256 #define ICH6_MAX_RIRB_ENTRIES 256 +/* position fix mode */ +enum { + POS_FIX_FIFO, + POS_FIX_NONE, + POS_FIX_POSBUF +}; /* * Use CORB/RIRB for communication from/to codecs. @@ -190,12 +199,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; */ #define USE_CORB_RIRB -/* - * Define this if use the position buffer instead of reading SD_LPIB - * It's not used as default since SD_LPIB seems to give more accurate position - */ -/* #define USE_POSBUF */ - /* */ @@ -271,6 +274,9 @@ struct snd_azx { struct snd_dma_buffer bdl; struct snd_dma_buffer rb; struct snd_dma_buffer posbuf; + + /* flags */ + int position_fix; }; /* @@ -657,11 +663,11 @@ static void azx_init_chip(azx_t *chip) /* initialize the codec command I/O */ azx_init_cmd_io(chip); -#ifdef USE_POSBUF - /* program the position buffer */ - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); - azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); -#endif + if (chip->position_fix == POS_FIX_POSBUF) { + /* program the position buffer */ + azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); + azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); + } } @@ -791,11 +797,12 @@ static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev) /* upper BDL address */ azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); -#ifdef USE_POSBUF - /* enable the position buffer */ - if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); -#endif + if (chip->position_fix == POS_FIX_POSBUF) { + /* enable the position buffer */ + if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + } + /* set the interrupt enable bits in the descriptor control register */ azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); @@ -1036,16 +1043,20 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd) static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream) { + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + azx_t *chip = apcm->chip; azx_dev_t *azx_dev = get_azx_dev(substream); unsigned int pos; -#ifdef USE_POSBUF - /* use the position buffer */ - pos = *azx_dev->posbuf; -#else - /* read LPIB */ - pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size; -#endif + if (chip->position_fix == POS_FIX_POSBUF) { + /* use the position buffer */ + pos = *azx_dev->posbuf; + } else { + /* read LPIB */ + pos = azx_sd_readl(azx_dev, SD_LPIB); + if (chip->position_fix == POS_FIX_FIFO) + pos += azx_dev->fifo_size; + } if (pos >= azx_dev->bufsize) pos = 0; return bytes_to_frames(substream->runtime, pos); @@ -1155,9 +1166,8 @@ static int __devinit azx_init_stream(azx_t *chip) azx_dev_t *azx_dev = &chip->azx_dev[i]; azx_dev->bdl = (u32 *)(chip->bdl.area + off); azx_dev->bdl_addr = chip->bdl.addr + off; -#ifdef USE_POSBUF - azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); -#endif + if (chip->position_fix == POS_FIX_POSBUF) + azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ @@ -1237,10 +1247,8 @@ static int azx_free(azx_t *chip) snd_dma_free_pages(&chip->bdl); if (chip->rb.area) snd_dma_free_pages(&chip->rb); -#ifdef USE_POSBUF if (chip->posbuf.area) snd_dma_free_pages(&chip->posbuf); -#endif pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); @@ -1256,7 +1264,8 @@ static int azx_dev_free(snd_device_t *device) /* * constructor */ -static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip) +static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, + int posfix, azx_t **rchip) { azx_t *chip; int err = 0; @@ -1283,6 +1292,8 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r chip->pci = pci; chip->irq = -1; + chip->position_fix = posfix; + if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) { kfree(chip); pci_disable_device(pci); @@ -1314,14 +1325,14 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **r snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } -#ifdef USE_POSBUF - /* allocate memory for the position buffer */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) { - snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); - goto errout; + if (chip->position_fix == POS_FIX_POSBUF) { + /* allocate memory for the position buffer */ + if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) { + snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); + goto errout; + } } -#endif /* allocate CORB/RIRB */ if ((err = azx_alloc_cmd_io(chip)) < 0) goto errout; @@ -1372,7 +1383,7 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * return -ENOMEM; } - if ((err = azx_create(card, pci, &chip)) < 0) { + if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) { snd_card_free(card); return err; } -- cgit v1.2.3-70-g09d2 From dfc0ff62a1d24e987205b41fbf322a4377626481 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 14:31:49 +0200 Subject: [ALSA] Add ASUS Z71V support Documentation,HDA Codec driver Added the ASUS Z71V (or similar) laptop support. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 109 ++++++++++++++++++++++++ 2 files changed, 110 insertions(+) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index ef07506e583..d49325ed706 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -636,6 +636,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 5stack 5-jack in back, 2-jack in front 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out w810 3-jack + z71v 3-jack (HP shared SPDIF) CMI9880 minimal 3-jack in back diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 17c5062423a..c106e1fe01c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -39,6 +39,7 @@ enum { ALC880_5ST, ALC880_5ST_DIG, ALC880_W810, + ALC880_Z71V, }; struct alc_spec { @@ -90,6 +91,11 @@ static hda_nid_t alc880_w810_dac_nids[3] = { 0x02, 0x03, 0x04 }; +static hda_nid_t alc880_z71v_dac_nids[1] = { + /* front only? */ + 0x02 +}; + static hda_nid_t alc880_adc_nids[3] = { /* ADC0-2 */ 0x07, 0x08, 0x09, @@ -284,6 +290,10 @@ static struct alc_channel_mode alc880_w810_modes[1] = { { 6, NULL } }; +static struct alc_channel_mode alc880_z71v_modes[1] = { + { 2, NULL } +}; + /* */ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -475,6 +485,35 @@ static snd_kcontrol_new_t alc880_w810_base_mixer[] = { { } /* end */ }; +static snd_kcontrol_new_t alc880_z71v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + /* */ static int alc_build_controls(struct hda_codec *codec) @@ -719,6 +758,58 @@ static struct hda_verb alc880_w810_init_verbs[] = { { } }; +static struct hda_verb alc880_z71v_init_verbs[] = { + /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + /* front channel selector/amp: output 0: unmuted, max volume */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* front out pin: muted, (no volume selection) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* front out pin: NOT headphone enable, out enable, vref disabled */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* headphone channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* headphone channel selector/amp: input 1: capture mix: muted, (no volume selection) */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + /* headphone channel selector/amp: output 0: unmuted, max volume */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* headphone out pin: muted, (no volume selection) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* headpohne out pin: headphone enable, out enable, vref disabled */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + /* unmute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to line in (default select for this ADC) */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer + * widget(nid=0x0B) to support the input path of analog loopback + */ + /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ + /* unmute CD */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* unmute Line In */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + /* unmute Mic 1 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* unmute Line In 2 (for PASD boards Mic 2) */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + + { } +}; + static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -993,6 +1084,9 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .modelname = "w810", .config = ALC880_W810 }, { .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 }, + { .modelname = "z71v", .config = ALC880_Z71V }, + { .pci_vendor = 0x1043, .pci_device = 0x1964, .config = ALC880_Z71V }, + {} }; @@ -1023,6 +1117,10 @@ static int patch_alc880(struct hda_codec *codec) spec->mixers[spec->num_mixers] = alc880_five_stack_mixer; spec->num_mixers++; break; + case ALC880_Z71V: + spec->mixers[spec->num_mixers] = alc880_z71v_mixer; + spec->num_mixers++; + break; default: spec->mixers[spec->num_mixers] = alc880_base_mixer; spec->num_mixers++; @@ -1033,6 +1131,7 @@ static int patch_alc880(struct hda_codec *codec) case ALC880_3ST_DIG: case ALC880_5ST_DIG: case ALC880_W810: + case ALC880_Z71V: spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; break; default: @@ -1063,6 +1162,11 @@ static int patch_alc880(struct hda_codec *codec) spec->channel_mode = alc880_w810_modes; spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes); break; + case ALC880_Z71V: + spec->init_verbs = alc880_z71v_init_verbs; + spec->channel_mode = alc880_z71v_modes; + spec->num_channel_mode = ARRAY_SIZE(alc880_z71v_modes); + break; default: spec->init_verbs = alc880_init_verbs_three_stack; spec->channel_mode = alc880_threestack_modes; @@ -1086,6 +1190,11 @@ static int patch_alc880(struct hda_codec *codec) spec->multiout.dac_nids = alc880_w810_dac_nids; // No dedicated headphone socket - it's shared with built-in speakers. break; + case ALC880_Z71V: + spec->multiout.num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids); + spec->multiout.dac_nids = alc880_z71v_dac_nids; + spec->multiout.hp_nid = 0x03; + break; default: spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); spec->multiout.dac_nids = alc880_dac_nids; -- cgit v1.2.3-70-g09d2 From 2fa522bed875cf0bde9e9fdb8fdd852c9d74d67d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 14:51:12 +0200 Subject: [ALSA] Add test model for debugging ALC880 devices HDA Codec driver Added 'test' model for testing/debugging the devices with ALC880 codec. This model is built only when CONFIG_SND_DEBUG is set. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 271 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 270 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c106e1fe01c..75ec1970cc0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -40,6 +40,7 @@ enum { ALC880_5ST_DIG, ALC880_W810, ALC880_Z71V, + ALC880_TEST, }; struct alc_spec { @@ -1012,6 +1013,248 @@ static struct hda_codec_ops alc_patch_ops = { #endif }; + +/* + * Test configuration for debugging + * + * Almost all inputs/outputs are enabled. I/O pins can be configured via + * enum controls. + */ +#ifdef CONFIG_SND_DEBUG +static hda_nid_t alc880_test_dac_nids[4] = { + 0x02, 0x03, 0x04, 0x05 +}; + +static struct hda_input_mux alc880_test_capture_source = { + .num_items = 5, + .items = { + { "In-1", 0x0 }, + { "In-2", 0x1 }, + { "In-3", 0x2 }, + { "In-4", 0x3 }, + { "CD", 0x4 }, + }, +}; + +static struct alc_channel_mode alc880_test_modes[2] = { + { 2, NULL }, + { 6, NULL }, +}; + +static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { + "N/A", "Line Out", "HP Out", + "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item >= 8) + uinfo->value.enumerated.item = 7; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int pin_ctl, item = 0; + + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pin_ctl & AC_PINCTL_OUT_EN) { + if (pin_ctl & AC_PINCTL_HP_EN) + item = 2; + else + item = 1; + } else if (pin_ctl & AC_PINCTL_IN_EN) { + switch (pin_ctl & AC_PINCTL_VREFEN) { + case AC_PINCTL_VREF_HIZ: item = 3; break; + case AC_PINCTL_VREF_50: item = 4; break; + case AC_PINCTL_VREF_GRD: item = 5; break; + case AC_PINCTL_VREF_80: item = 6; break; + case AC_PINCTL_VREF_100: item = 7; break; + } + } + ucontrol->value.enumerated.item[0] = item; + return 0; +} + +static int alc_test_pin_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + static unsigned int ctls[] = { + 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_50, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_80, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_100, + }; + unsigned int old_ctl, new_ctl; + + old_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + new_ctl = ctls[ucontrol->value.enumerated.item[0]]; + if (old_ctl != new_ctl) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000); + return 1; + } + return 0; +} + +static int alc_test_pin_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { + "Front", "Surround", "CLFE", "Side" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item >= 4) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int alc_test_pin_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); + ucontrol->value.enumerated.item[0] = sel & 3; + return 0; +} + +static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = (hda_nid_t)kcontrol->private_value; + unsigned int sel; + + sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; + if (ucontrol->value.enumerated.item[0] != sel) { + sel = ucontrol->value.enumerated.item[0] & 3; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); + return 1; + } + return 0; +} + +#define PIN_CTL_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = alc_test_pin_ctl_info, \ + .get = alc_test_pin_ctl_get, \ + .put = alc_test_pin_ctl_put, \ + .private_value = nid \ + } + +#define PIN_SRC_TEST(xname,nid) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = alc_test_pin_src_info, \ + .get = alc_test_pin_src_get, \ + .put = alc_test_pin_src_put, \ + .private_value = nid \ + } + +static snd_kcontrol_new_t alc880_test_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + PIN_CTL_TEST("Front Pin Mode", 0x14), + PIN_CTL_TEST("Surround Pin Mode", 0x15), + PIN_CTL_TEST("CLFE Pin Mode", 0x16), + PIN_CTL_TEST("Side Pin Mode", 0x17), + PIN_CTL_TEST("In-1 Pin Mode", 0x18), + PIN_CTL_TEST("In-2 Pin Mode", 0x19), + PIN_CTL_TEST("In-3 Pin Mode", 0x1a), + PIN_CTL_TEST("In-4 Pin Mode", 0x1b), + PIN_SRC_TEST("In-1 Pin Source", 0x18), + PIN_SRC_TEST("In-2 Pin Source", 0x19), + PIN_SRC_TEST("In-3 Pin Source", 0x1a), + PIN_SRC_TEST("In-4 Pin Source", 0x1b), + HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; + +static struct hda_verb alc880_test_init_verbs[] = { + /* Unmute inputs of 0x0c - 0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + /* Vol output for 0x0c-0x0f */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* Set output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Unmute output pins 0x14-0x17 */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* Set input pins 0x18-0x1c */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* vref 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + /* Mute input pins 0x18-0x1b */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + { } +}; +#endif + /* */ @@ -1087,6 +1330,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .modelname = "z71v", .config = ALC880_Z71V }, { .pci_vendor = 0x1043, .pci_device = 0x1964, .config = ALC880_Z71V }, +#ifdef CONFIG_SND_DEBUG + { .modelname = "test", .config = ALC880_TEST }, +#endif + {} }; @@ -1121,6 +1368,12 @@ static int patch_alc880(struct hda_codec *codec) spec->mixers[spec->num_mixers] = alc880_z71v_mixer; spec->num_mixers++; break; +#ifdef CONFIG_SND_DEBUG + case ALC880_TEST: + spec->mixers[spec->num_mixers] = alc880_test_mixer; + spec->num_mixers++; + break; +#endif default: spec->mixers[spec->num_mixers] = alc880_base_mixer; spec->num_mixers++; @@ -1132,6 +1385,7 @@ static int patch_alc880(struct hda_codec *codec) case ALC880_5ST_DIG: case ALC880_W810: case ALC880_Z71V: + case ALC880_TEST: spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; break; default: @@ -1167,6 +1421,13 @@ static int patch_alc880(struct hda_codec *codec) spec->channel_mode = alc880_z71v_modes; spec->num_channel_mode = ARRAY_SIZE(alc880_z71v_modes); break; +#ifdef CONFIG_SND_DEBUG + case ALC880_TEST: + spec->init_verbs = alc880_test_init_verbs; + spec->channel_mode = alc880_test_modes; + spec->num_channel_mode = ARRAY_SIZE(alc880_test_modes); + break; +#endif default: spec->init_verbs = alc880_init_verbs_three_stack; spec->channel_mode = alc880_threestack_modes; @@ -1195,6 +1456,13 @@ static int patch_alc880(struct hda_codec *codec) spec->multiout.dac_nids = alc880_z71v_dac_nids; spec->multiout.hp_nid = 0x03; break; +#ifdef CONFIG_SND_DEBUG + case ALC880_TEST: + spec->multiout.num_dacs = ARRAY_SIZE(alc880_test_dac_nids); + spec->multiout.dac_nids = alc880_test_dac_nids; + spec->input_mux = &alc880_test_capture_source; + break; +#endif default: spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); spec->multiout.dac_nids = alc880_dac_nids; @@ -1202,7 +1470,8 @@ static int patch_alc880(struct hda_codec *codec) break; } - spec->input_mux = &alc880_capture_source; + if (! spec->input_mux) + spec->input_mux = &alc880_capture_source; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); spec->adc_nids = alc880_adc_nids; -- cgit v1.2.3-70-g09d2 From f5d40b30ed4daf09f1d43f9b2da1263b17a53c28 Mon Sep 17 00:00:00 2001 From: Frederick Li Date: Thu, 12 May 2005 14:55:20 +0200 Subject: [ALSA] Adding support for ATI IXP450 HD Audio device support Documentation,HDA Intel driver This patch changes the Intel HD Audio device driver to include the support of HD Audio device embedded in ATI south bridge IXP450. Because the design of ATI chipset follows intel HD Audio specification 1.0, the programming method is the same as that of intel HD Audio device exception one minor change which requires to enable snoop for DMA transport. There are 3 changes that have been made to hda_intel.c file. 1. Added device ID for ATI HD Audio device; 2. Increase maximum CODEC supported to 4; 3. Enable snoop during the driver initialization. Signed-off-by: Frederick Li Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 2 +- sound/pci/hda/hda_intel.c | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index d49325ed706..587eddcad91 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -615,7 +615,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-hda-intel -------------------- - Module for Intel HD Audio (ICH6, ICH6M, ICH7) + Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450 model - force the model name position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 104593fa08e..d8329a79bcd 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -68,7 +68,8 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH6M}," "{Intel, ICH7}," - "{Intel, ESB2}}"); + "{Intel, ESB2}," + "{ATI, SB450}}"); MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " @@ -153,7 +154,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* STATESTS int mask: SD2,SD1,SD0 */ #define STATESTS_INT_MASK 0x07 -#define AZX_MAX_CODECS 3 +#define AZX_MAX_CODECS 4 /* SD_CTL bits */ #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ @@ -193,6 +194,12 @@ enum { POS_FIX_POSBUF }; +/* Defines for ATI HD Audio support in SB450 south bridge */ +#define ATI_SB450_HDAUDIO_PCI_DEVICE_ID 0x437b +#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 +#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 + + /* * Use CORB/RIRB for communication from/to codecs. * This is the way recommended by Intel (see below). @@ -644,7 +651,7 @@ static void azx_stream_stop(azx_t *chip, azx_dev_t *azx_dev) */ static void azx_init_chip(azx_t *chip) { - unsigned char tcsel_reg; + unsigned char tcsel_reg, ati_misc_cntl2; /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS @@ -668,6 +675,15 @@ static void azx_init_chip(azx_t *chip) azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); } + + /* For ATI SB450 azalia HD audio, we need to enable snoop */ + if (chip->pci->vendor == PCI_VENDOR_ID_ATI && + chip->pci->device == ATI_SB450_HDAUDIO_PCI_DEVICE_ID) { + pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + &ati_misc_cntl2); + pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + (ati_misc_cntl2 & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); + } } @@ -1435,6 +1451,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */ { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */ { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ + { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v1.2.3-70-g09d2 From fc20a562ca1a3c22dc257b2e2d849cb1a9ab6420 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 15:00:41 +0200 Subject: [ALSA] Add support of VIA VT8251/VT8237A HD-Audio controllers Documentation,HDA Intel driver Added the support of VIA VT8251/VT8237A HD-Audio controllers. They are (almost) compatible with Intel ICH6/7. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 3 ++- sound/pci/hda/hda_intel.c | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 587eddcad91..5a7f7f5b3d5 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -615,7 +615,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-hda-intel -------------------- - Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450 + Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450, + VIA VT8251/VT8237A model - force the model name position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d8329a79bcd..87988da47bf 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -69,7 +69,9 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH6M}," "{Intel, ICH7}," "{Intel, ESB2}," - "{ATI, SB450}}"); + "{ATI, SB450}," + "{VIA, VT8251}," + "{VIA, VT8237A}}"); MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " @@ -1452,6 +1454,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */ { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ + { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v1.2.3-70-g09d2 From 7291548df69ab4e3a87ff6952449d1f05c3a5443 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 May 2005 16:49:45 +0200 Subject: [ALSA] Rename pci_vendor/pci_device to pci_subvendor/pci_subdevice HDA Codec driver,HDA generic driver Renamed pci_vendor/pci_device fields to pci_subvendor/pci_subdevice. They are really PCI subsystem IDs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 8 ++-- sound/pci/hda/hda_local.h | 4 +- sound/pci/hda/patch_realtek.c | 102 +++++++++++++++++++++--------------------- 3 files changed, 57 insertions(+), 57 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 44fac2182fc..87018dfd02f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1530,7 +1530,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config struct hda_board_config *c; if (codec->bus->modelname) { - for (c = tbl; c->modelname || c->pci_vendor; c++) { + for (c = tbl; c->modelname || c->pci_subvendor; c++) { if (c->modelname && ! strcmp(codec->bus->modelname, c->modelname)) { snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname); @@ -1543,9 +1543,9 @@ int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config u16 subsystem_vendor, subsystem_device; pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); - for (c = tbl; c->modelname || c->pci_vendor; c++) { - if (c->pci_vendor == subsystem_vendor && - c->pci_device == subsystem_device) + for (c = tbl; c->modelname || c->pci_subvendor; c++) { + if (c->pci_subvendor == subsystem_vendor && + c->pci_subdevice == subsystem_device) return c->config; } } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7c7b849875a..b8fbbc4901d 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -126,8 +126,8 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } struct hda_board_config { const char *modelname; int config; - unsigned short pci_vendor; - unsigned short pci_device; + unsigned short pci_subvendor; + unsigned short pci_subdevice; }; int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 75ec1970cc0..8a104827a95 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1261,74 +1261,74 @@ static struct hda_verb alc880_test_init_verbs[] = { static struct hda_board_config alc880_cfg_tbl[] = { /* Back 3 jack, front 2 jack */ { .modelname = "3stack", .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe200, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe201, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe202, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe204, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe205, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe206, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe208, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe209, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20a, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20c, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20d, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20e, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe210, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe211, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe214, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe302, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe303, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe304, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe306, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe307, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xe404, .config = ALC880_3ST }, - { .pci_vendor = 0x8086, .pci_device = 0xa101, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x3031, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4037, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4038, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4040, .config = ALC880_3ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, /* Back 3 jack, front 2 jack (Internal add Aux-In) */ - { .pci_vendor = 0x1025, .pci_device = 0xe310, .config = ALC880_3ST }, + { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe308, .config = ALC880_3ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ - { .pci_vendor = 0x8086, .pci_device = 0xe305, .config = ALC880_3ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xd402, .config = ALC880_3ST_DIG }, - { .pci_vendor = 0x1025, .pci_device = 0xe309, .config = ALC880_3ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG }, + { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG }, /* Back 5 jack, front 2 jack */ { .modelname = "5stack", .config = ALC880_5ST }, - { .pci_vendor = 0x107b, .pci_device = 0x3033, .config = ALC880_5ST }, - { .pci_vendor = 0x107b, .pci_device = 0x4039, .config = ALC880_5ST }, - { .pci_vendor = 0x107b, .pci_device = 0x3032, .config = ALC880_5ST }, - { .pci_vendor = 0x103c, .pci_device = 0x2a09, .config = ALC880_5ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, + { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, + { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe224, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe400, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe401, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xe402, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xd400, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xd401, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x8086, .pci_device = 0xa100, .config = ALC880_5ST_DIG }, - { .pci_vendor = 0x1565, .pci_device = 0x8202, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, { .modelname = "w810", .config = ALC880_W810 }, - { .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 }, + { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, { .modelname = "z71v", .config = ALC880_Z71V }, - { .pci_vendor = 0x1043, .pci_device = 0x1964, .config = ALC880_Z71V }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, #ifdef CONFIG_SND_DEBUG { .modelname = "test", .config = ALC880_TEST }, -- cgit v1.2.3-70-g09d2 From 10268b0c38333ede95bb59a7fa561519e6eb8251 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 May 2005 11:01:13 +0200 Subject: [ALSA] Remove obsolete mixer control AC97 Codec Removed the obsolete mixer control for AD1985. Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index ce02e7091fc..bcb1a20d75d 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1598,7 +1598,6 @@ int patch_ad1980(ac97_t * ac97) } static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { - AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0), AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) }; -- cgit v1.2.3-70-g09d2 From 89c87bf8c12e27fbbed971380e21895cace3a065 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 13 May 2005 15:28:08 +0200 Subject: [ALSA] make code static CA0106 driver,HDA Codec driver This patch makes needlessly global code static. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_proc.c | 2 +- sound/pci/hda/hda_codec.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 0bc1d783a84..3e5161a3236 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -95,7 +95,7 @@ static struct snd_ca0106_category_str snd_ca0106_con_category[] = { }; -void snd_ca0106_proc_dump_iec958( snd_info_buffer_t *buffer, u32 value) +static void snd_ca0106_proc_dump_iec958( snd_info_buffer_t *buffer, u32 value) { int i; u32 status[4]; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 87018dfd02f..70e3cb6dd25 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -662,7 +662,7 @@ static void put_vol_mute(struct hda_codec *codec, /* * read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. */ -int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) +static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); if (! info) @@ -671,7 +671,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int d return info->vol[ch]; } -int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) +static int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); if (! info) -- cgit v1.2.3-70-g09d2 From 680ff0ac6d0c84f14a2e540f64521a9fa80d8661 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 May 2005 16:06:14 +0200 Subject: [ALSA] Suppress error message HDA Codec driver Suppressing the error message regarding no AFG. This is often harmless (e.g. probing a modem codec). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 70e3cb6dd25..56941031ab0 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -509,7 +509,7 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, /* FIXME: support for multiple AFGs? */ codec->afg = look_for_afg_node(codec); if (! codec->afg) { - snd_printk(KERN_ERR "hda_codec: no AFG node found\n"); + snd_printdd("hda_codec: no AFG node found\n"); snd_hda_codec_free(codec); return -ENODEV; } -- cgit v1.2.3-70-g09d2 From 9bc533f58e8515cf346932fc84a58dd706342635 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 May 2005 16:44:27 +0200 Subject: [ALSA] Fix a typo in position_fix module option type HDA Intel driver Fixed a typo in the type of position_fix module option. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 87988da47bf..f05a6384b9c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -61,7 +61,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); -module_param_array(position_fix, bool, NULL, 0444); +module_param_array(position_fix, int, NULL, 0444); MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)."); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From fd2c326de8cd35a36514a887541426b1ef7c5516 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 May 2005 17:18:42 +0200 Subject: [ALSA] Allow more than 2 channel modes HDA Codec driver Allow 'Channel Mode' control to have more than 2 modes. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8a104827a95..9f12d1fd02d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -301,13 +301,14 @@ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *ui { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; + int items = kcontrol->private_value ? (int)kcontrol->private_value : 2; snd_assert(spec->channel_mode, return -ENXIO); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; + uinfo->value.enumerated.items = items; + if (uinfo->value.enumerated.item >= items) + uinfo->value.enumerated.item = items - 1; sprintf(uinfo->value.enumerated.name, "%dch", spec->channel_mode[uinfo->value.enumerated.item].channels); return 0; @@ -317,10 +318,16 @@ static int alc880_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; + int items = kcontrol->private_value ? (int)kcontrol->private_value : 2; + int i; snd_assert(spec->channel_mode, return -ENXIO); - ucontrol->value.enumerated.item[0] = - (spec->multiout.max_channels == spec->channel_mode[0].channels) ? 0 : 1; + for (i = 0; i < items; i++) { + if (spec->multiout.max_channels == spec->channel_mode[i].channels) { + ucontrol->value.enumerated.item[0] = i; + break; + } + } return 0; } @@ -1036,9 +1043,11 @@ static struct hda_input_mux alc880_test_capture_source = { }, }; -static struct alc_channel_mode alc880_test_modes[2] = { +static struct alc_channel_mode alc880_test_modes[4] = { { 2, NULL }, + { 4, NULL }, { 6, NULL }, + { 8, NULL }, }; static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -1211,6 +1220,7 @@ static snd_kcontrol_new_t alc880_test_mixer[] = { .info = alc880_ch_mode_info, .get = alc880_ch_mode_get, .put = alc880_ch_mode_put, + .private_value = ARRAY_SIZE(alc880_test_modes), }, { } /* end */ }; -- cgit v1.2.3-70-g09d2 From 54b903ec6e5a3194d86d8bb2f419c918efa4897f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 14:30:10 +0200 Subject: [ALSA] Add Analog Devices vendor name HDA Codec driver Added the missing vendor name entry for Analog Devices. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 56941031ab0..e6efaed4b46 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -49,6 +49,7 @@ struct hda_vendor_id { /* codec vendor labels */ static struct hda_vendor_id hda_vendor_ids[] = { { 0x10ec, "Realtek" }, + { 0x11d4, "Analog Devices" }, { 0x13f6, "C-Media" }, { 0x434d, "C-Media" }, { 0x8384, "SigmaTel" }, -- cgit v1.2.3-70-g09d2 From e5b3f45f5d442b57dd07dd4f914f7e6cf4d183f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 May 2005 17:17:57 +0200 Subject: [ALSA] Fix Mic/CLFE sharing on AD1985 AC97 Codec Fixed Mic/CLFE jack sharing on AD1985 codec. Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index bcb1a20d75d..5520f5d9749 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1526,13 +1526,8 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { .get = snd_ac97_ad1888_downmix_get, .put = snd_ac97_ad1888_downmix_put }, -#if 0 - AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), - AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), -#else AC97_SURROUND_JACK_MODE_CTL, AC97_CHANNEL_MODE_CTL, -#endif }; static int patch_ad1888_specific(ac97_t *ac97) @@ -1601,6 +1596,18 @@ static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) }; +static void ad1985_update_jacks(ac97_t *ac97) +{ + /* shared Line-In */ + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, + is_shared_linein(ac97) ? 0 : 1 << 12); + /* shared Mic */ + snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, + is_shared_micin(ac97) ? 0 : 1 << 11); + snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 9 << 11, + is_shared_micin(ac97) ? 0 : 9 << 11); +} + static int patch_ad1985_specific(ac97_t *ac97) { int err; @@ -1616,7 +1623,7 @@ static struct snd_ac97_build_ops patch_ad1985_build_ops = { #ifdef CONFIG_PM .resume = ad18xx_resume, #endif - .update_jacks = ad1888_update_jacks, + .update_jacks = ad1985_update_jacks, }; int patch_ad1985(ac97_t * ac97) -- cgit v1.2.3-70-g09d2 From 58c1f8acdeec4989e5dce1a3aec16926342d7f4b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 May 2005 16:13:00 +0200 Subject: [ALSA] Fix resume of via82xx-modem VIA82xx-modem driver Fix the resume of via82xx-modem, removing invalid __devinit. Signed-off-by: Takashi Iwai --- sound/pci/via82xx_modem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 098870aea26..276ce529968 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -938,7 +938,7 @@ static void __devinit snd_via82xx_proc_init(via82xx_t *chip) * */ -static int __devinit snd_via82xx_chip_init(via82xx_t *chip) +static int snd_via82xx_chip_init(via82xx_t *chip) { unsigned int val; int max_count; -- cgit v1.2.3-70-g09d2 From 82f008c2b651eefbf293546440fd226580b0c111 Mon Sep 17 00:00:00 2001 From: Ville Syrjala Date: Fri, 20 May 2005 18:40:38 +0200 Subject: [ALSA] maestro3: Add hardware volume control quirk list Maestro3 driver Add a hardware volume quirk list to the maestro3 driver. Details were taken from the Windows driver. Hardware volume control is enabled only for the systems in the list. Signed-off-by: Ville Syrjala Signed-off-by: Takashi Iwai --- sound/pci/maestro3.c | 127 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 106 insertions(+), 21 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 3690ea05b04..096f1513285 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -779,6 +779,12 @@ struct m3_quirk { (e.g. for IrDA on Dell Inspirons) */ }; +struct m3_hv_quirk { + u16 vendor, device, subsystem_vendor, subsystem_device; + u32 config; /* ALLEGRO_CONFIG hardware volume bits */ + int is_omnibook; /* Do HP OmniBook GPIO magic? */ +}; + struct m3_list { int curlen; int mem_addr; @@ -828,6 +834,7 @@ struct snd_m3 { struct pci_dev *pci; struct m3_quirk *quirk; + struct m3_hv_quirk *hv_quirk; int dacs_active; int timer_users; @@ -856,7 +863,7 @@ struct snd_m3 { snd_kcontrol_t *master_switch; snd_kcontrol_t *master_volume; struct tasklet_struct hwvol_tq; - + #ifdef CONFIG_PM u16 *suspend_mem; #endif @@ -973,6 +980,71 @@ static struct m3_quirk m3_quirk_list[] = { { NULL } }; +/* These values came from the Windows driver. */ +static struct m3_hv_quirk m3_hv_quirk_list[] = { + /* Allegro chips */ + { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 }, + { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */ + { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 }, + /* Maestro3 chips */ + { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */ + { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */ + { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 }, + { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, + { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 }, + { 0 } +}; /* * lowlevel functions @@ -2392,21 +2464,27 @@ snd_m3_chip_init(m3_t *chip) DISABLE_LEGACY); pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); - /* - * Volume buttons on some HP OmniBook laptops (500 and 6000 at least) - * don't work correctly. This makes them work for the most part. - * Volume up and down buttons on the laptop side work perfectly. - * Fn+cursor_up (volme up) works, Fn+cursor_down (volume down) doesn't, - * Fn+F8 (mute) works acts as volume up. - */ - outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); - outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); - outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); - outw(0xffff, io + GPIO_MASK); - + if (chip->hv_quirk && chip->hv_quirk->is_omnibook) { + /* + * Volume buttons on some HP OmniBook laptops don't work + * correctly. This makes them work for the most part. + * + * Volume up and down buttons on the laptop side work. + * Fn+cursor_up (volme up) works. + * Fn+cursor_down (volume down) doesn't work. + * Fn+F7 (mute) works acts as volume up. + */ + outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); + outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); + outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); + outw(0xffff, io + GPIO_MASK); + } pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); - n &= ~HV_BUTTON_FROM_GD; - n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE; + n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); + if (chip->hv_quirk) + n |= chip->hv_quirk->config; + /* For some reason we must always use reduced debounce. */ + n |= REDUCED_DEBOUNCE; n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); @@ -2594,7 +2672,7 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, m3_t *chip; int i, err; struct m3_quirk *quirk; - u16 subsystem_vendor, subsystem_device; + struct m3_hv_quirk *hv_quirk; static snd_device_ops_t ops = { .dev_free = snd_m3_dev_free, }; @@ -2632,18 +2710,25 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, chip->pci = pci; chip->irq = -1; - pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); - for (quirk = m3_quirk_list; quirk->vendor; quirk++) { - if (subsystem_vendor == quirk->vendor && - subsystem_device == quirk->device) { + if (pci->subsystem_vendor == quirk->vendor && + pci->subsystem_device == quirk->device) { printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name); chip->quirk = quirk; break; } } + for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) { + if (pci->vendor == hv_quirk->vendor && + pci->device == hv_quirk->device && + pci->subsystem_vendor == hv_quirk->subsystem_vendor && + pci->subsystem_device == hv_quirk->subsystem_device) { + chip->hv_quirk = hv_quirk; + break; + } + } + chip->external_amp = enable_amp; if (amp_gpio >= 0 && amp_gpio <= 0x0f) chip->amp_gpio = amp_gpio; -- cgit v1.2.3-70-g09d2 From 1f82941e82422fcb15d63431e163bf4f0b9389d9 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 21 May 2005 16:23:37 +0200 Subject: [ALSA] Implement surround71 outputs on SB Live 24bit. CA0106 driver Notes: Requires updated alsa-lib. Signed-off-by: James Courtier-Dutton --- sound/pci/ca0106/ca0106_mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 231ecac8086..48e24860824 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -113,7 +113,7 @@ static int snd_ca0106_shared_spdif_put(snd_kcontrol_t * kcontrol, } else { /* Analog */ snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000b0000); + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); mask = inl(emu->port + GPIO) | 0x101; @@ -437,7 +437,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_analog_center_lfe = static snd_kcontrol_new_t snd_ca0106_volume_control_analog_unknown = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Unknown Volume", + .name = "Analog Side Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_analog_unknown, .put = snd_ca0106_volume_put_analog_unknown -- cgit v1.2.3-70-g09d2 From 8f55fbb0fdb821023ff0a816ebf5056188891ff0 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 21 May 2005 16:45:58 +0200 Subject: [ALSA] When the alsamixer says 'SPDIF Out [Off]', SPDIF output should be off and Analog output should be on. CA0106 driver This fixes a bug whereby when the snd-ca0106 module first loads, alsamixer says 'SPDIF Out [Off]' but no analog sound comes from the speakers. This covers any bug reports that said things like 'mixer fails to remember analog output on, when the system is rebooted.' Signed-off-by: James Courtier-Dutton --- sound/pci/ca0106/ca0106_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index d4cb8edf708..90d493ca7c9 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1114,7 +1114,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ /* Analog or Digital output */ snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000b0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers */ + snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ chip->spdif_enable = 0; /* Set digital SPDIF output off */ chip->capture_source = 3; /* Set CAPTURE_SOURCE */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ @@ -1145,7 +1145,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ - outl(0x005f4300, chip->port+GPIO); /* Analog */ + outl(0x005f4301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ -- cgit v1.2.3-70-g09d2 From 1baa705b75124df7cfe3d5d2706f794a14d26ad0 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 21 May 2005 22:35:58 +0200 Subject: [ALSA] Tidy up card recognition. CA0106 driver Signed-off-by: James Courtier-Dutton --- sound/pci/ca0106/ca0106.h | 8 ++++++ sound/pci/ca0106/ca0106_main.c | 63 +++++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 28 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index deb02885105..c623858428c 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -508,9 +508,17 @@ struct snd_ca0106_pcm { unsigned short running; }; +typedef struct { + u32 serial; + char * name; + int ac97; + int gpio_type; +} ca0106_details_t; + // definition of the chip-specific record struct snd_ca0106 { snd_card_t *card; + ca0106_details_t *details; struct pci_dev *pci; unsigned long port; diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 90d493ca7c9..a56e68ea87b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -161,18 +161,29 @@ MODULE_PARM_DESC(enable, "Enable the CA0106 soundcard."); #include "ca0106.h" -typedef struct { - u32 serial; - char * name; -} ca0106_names_t; - -static ca0106_names_t ca0106_chip_names[] = { - { 0x10021102, "AudigyLS [SB0310]"} , - { 0x10051102, "AudigyLS [SB0310b]"} , /* Unknown AudigyLS that also says SB0310 on it */ - { 0x10061102, "Live! 7.1 24bit [SB0410]"} , /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ - { 0x10071102, "Live! 7.1 24bit [SB0413]"} , /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ - { 0x10091462, "MSI K8N Diamond MB [SB0438]"}, /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ - { 0, "AudigyLS [Unknown]" } +static ca0106_details_t ca0106_chip_details[] = { + /* AudigyLS[SB0310] */ + { .serial = 0x10021102, + .name = "AudigyLS [SB0310]", + .ac97 = 1 } , + /* Unknown AudigyLS that also says SB0310 on it */ + { .serial = 0x10051102, + .name = "AudigyLS [SB0310b]", + .ac97 = 1 } , + /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ + { .serial = 0x10061102, + .name = "Live! 7.1 24bit [SB0410]", + .gpio_type = 1 } , + /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ + { .serial = 0x10071102, + .name = "Live! 7.1 24bit [SB0413]", + .gpio_type = 1 } , + /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ + { .serial = 0x10091462, + .name = "MSI K8N Diamond MB [SB0438]", + .gpio_type = 1 } , + { .serial = 0, + .name = "AudigyLS [Unknown]" } }; /* hardware definition */ @@ -994,6 +1005,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, ca0106_t **rchip) { ca0106_t *chip; + ca0106_details_t *c; int err; int ch; static snd_device_ops_t ops = { @@ -1055,6 +1067,15 @@ static int __devinit snd_ca0106_create(snd_card_t *card, printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model, chip->revision, chip->serial); #endif + strcpy(card->driver, "CA0106"); + strcpy(card->shortname, "CA0106"); + + for (c=ca0106_chip_details; c->serial; c++) { + if (c->serial == chip->serial) break; + } + chip->details = c; + sprintf(card->longname, "%s at 0x%lx irq %i", + c->name, chip->port, chip->irq); outl(0, chip->port + INTE); @@ -1139,9 +1160,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ chip->capture_source = 3; /* Set CAPTURE_SOURCE */ - if ((chip->serial == 0x10061102) || - (chip->serial == 0x10071102) || - (chip->serial == 0x10091462)) { /* The SB0410 and SB0413 use GPIO differently. */ + if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ @@ -1173,7 +1192,6 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, static int dev; snd_card_t *card; ca0106_t *chip; - ca0106_names_t *c; int err; if (dev >= SNDRV_CARDS) @@ -1208,9 +1226,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_card_free(card); return err; } - if ((chip->serial != 0x10061102) && - (chip->serial != 0x10071102) && - (chip->serial != 0x10091462) ) { /* The SB0410 and SB0413 do not have an ac97 chip. */ + if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ if ((err = snd_ca0106_ac97(chip)) < 0) { snd_card_free(card); return err; @@ -1223,15 +1239,6 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_ca0106_proc_init(chip); - strcpy(card->driver, "CA0106"); - strcpy(card->shortname, "CA0106"); - - for (c=ca0106_chip_names; c->serial; c++) { - if (c->serial == chip->serial) break; - } - sprintf(card->longname, "%s at 0x%lx irq %i", - c->name, chip->port, chip->irq); - if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; -- cgit v1.2.3-70-g09d2 From e6e514fa825be7362a955ba43d6fd18896d375c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 May 2005 10:33:08 +0200 Subject: [ALSA] Add the vendor 0x1558 to PM whitelist of es1968 ES1968 driver Added the vendor id 0x1558 to the power management whitelist of es1968 driver. Signed-off-by: Takashi Iwai --- sound/pci/es1968.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index da10d40b2d9..ea889b31139 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2559,6 +2559,7 @@ static struct ess_device_list pm_whitelist[] __devinitdata = { { TYPE_MAESTRO2E, 0x103c }, { TYPE_MAESTRO2E, 0x1179 }, { TYPE_MAESTRO2E, 0x14c0 }, /* HP omnibook 4150 */ + { TYPE_MAESTRO2E, 0x1558 }, }; static struct ess_device_list mpu_blacklist[] __devinitdata = { -- cgit v1.2.3-70-g09d2 From b9cce37411edd668ae5dbc16aa9653800c8e0744 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 13:16:56 +0200 Subject: [ALSA] Add Shuttle SN25P support ICE1712 driver Added the support for Shuttle SN25P. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/vt1720_mobo.c | 9 +++++++++ sound/pci/ice1712/vt1720_mobo.h | 1 + 2 files changed, 10 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 3bd92627231..ab61e383024 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c @@ -110,6 +110,15 @@ struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { .eeprom_size = sizeof(k8x800_eeprom), .eeprom_data = k8x800_eeprom, }, + { + .subvendor = VT1720_SUBDEVICE_SN25P, + .name = "Shuttle SN25P", + /* identical with k8x800 */ + .chip_init = k8x800_init, + .build_controls = k8x800_add_controls, + .eeprom_size = sizeof(k8x800_eeprom), + .eeprom_data = k8x800_eeprom, + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h index f949eb804ca..e0b613c0f6a 100644 --- a/sound/pci/ice1712/vt1720_mobo.h +++ b/sound/pci/ice1712/vt1720_mobo.h @@ -33,6 +33,7 @@ #define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6 #define VT1720_SUBDEVICE_ZNF3_250 0x0f2745f6 #define VT1720_SUBDEVICE_9CJS 0x0f272327 +#define VT1720_SUBDEVICE_SN25P 0x97123650 extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; -- cgit v1.2.3-70-g09d2 From c9bce91f902737395c72d037d70effb5fcbc53b4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 13:41:03 +0200 Subject: [ALSA] Update documentation for ice1712 and ice1724 Documentation,ICE1712 driver Updated the documentation for ice1712 and ice1724 drivers. Added the device description for shuttle SN25P missing in the last patch. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 38 +++++++++++++++++++++---- sound/pci/ice1712/vt1720_mobo.h | 3 +- 2 files changed, 35 insertions(+), 6 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 5a7f7f5b3d5..bb31ae7698b 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -688,15 +688,19 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * TerraTec EWS 88D * TerraTec EWX 24/96 * TerraTec DMX 6Fire + * TerraTec Phase 88 * Hoontech SoundTrack DSP 24 * Hoontech SoundTrack DSP 24 Value * Hoontech SoundTrack DSP 24 Media 7.1 + * Event Electronics, EZ8 * Digigram VX442 + * Lionstracs, Mediastaton model - Use the given board model, one of the following: delta1010, dio2496, delta66, delta44, audiophile, delta410, delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d, - dmx6fire, dsp24, dsp24_value, dsp24_71, ez8 + dmx6fire, dsp24, dsp24_value, dsp24_71, ez8, + phase88, mediastation omni - Omni I/O support for MidiMan M-Audio Delta44/66 cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever) in msec resolution, default value is 500 (0.5 sec) @@ -705,20 +709,44 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. is not used with all Envy24 based cards (for example in the MidiMan Delta serie). + Note: The supported board is detected by reading EEPROM or PCI + SSID (if EEPROM isn't available). You can override the + model by passing "model" module option in case that the + driver isn't configured properly or you want to try another + type for testing. + Module snd-ice1724 ------------------ - Module for Envy24HT (VT/ICE1724) based PCI sound cards. + Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards. * MidiMan M Audio Revolution 7.1 * AMP Ltd AUDIO2000 - * TerraTec Aureon Sky-5.1, Space-7.1 + * TerraTec Aureon 5.1 Sky + * TerraTec Aureon 7.1 Space + * TerraTec Aureon 7.1 Universe + * TerraTec Phase 22 + * TerraTec Phase 28 + * AudioTrak Prodigy 7.1 + * AudioTrak Prodigy 192 + * Pontis MS300 + * Albatron K8X800 Pro II + * Chaintech ZNF3-150 + * Chaintech ZNF3-250 + * Chaintech 9CJS + * Shuttle SN25P model - Use the given board model, one of the following: - revo71, amp2000, prodigy71, aureon51, aureon71, - k8x800 + revo71, amp2000, prodigy71, prodigy192, aureon51, + aureon71, universe, k8x800, phase22, phase28, ms300 Module supports up to 8 cards and autoprobe. + Note: The supported board is detected by reading EEPROM or PCI + SSID (if EEPROM isn't available). You can override the + model by passing "model" module option in case that the + driver isn't configured properly or you want to try another + type for testing. + Module snd-intel8x0 ------------------- diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h index e0b613c0f6a..0b1b0ee1bea 100644 --- a/sound/pci/ice1712/vt1720_mobo.h +++ b/sound/pci/ice1712/vt1720_mobo.h @@ -27,7 +27,8 @@ #define VT1720_MOBO_DEVICE_DESC "{Albatron,K8X800 Pro II},"\ "{Chaintech,ZNF3-150},"\ "{Chaintech,ZNF3-250},"\ - "{Chaintech,9CJS}," + "{Chaintech,9CJS},"\ + "{Shuttle,SN25P}," #define VT1720_SUBDEVICE_K8X800 0xf217052c #define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6 -- cgit v1.2.3-70-g09d2 From 033a1f10923bdc3646750eef471a618f9d4c074b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 May 2005 16:41:43 +0200 Subject: [ALSA] hda-code: Fix the array size of codec list HDA Codec driver Fixed the wrong array size of the codec pointer list. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 43fc245d9a6..1b1203539ea 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -419,7 +419,7 @@ struct hda_bus { /* codec linked list */ struct list_head codec_list; - struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS]; /* caddr -> codec */ + struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ struct semaphore cmd_mutex; -- cgit v1.2.3-70-g09d2 From 71fe7b82db923e0f71b05deeb54fce75d5a4d08d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 May 2005 18:11:40 +0200 Subject: [ALSA] Fix ALC880 capture problems HDA Codec driver Fixed the capture on some ALC880 devices. The node 0x07 is sometimes invalid as an ADC. Also, the intialization of ADC nodes are fixed on some models. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 86 +++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 19 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9f12d1fd02d..ee1c4cd7f00 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -97,10 +97,20 @@ static hda_nid_t alc880_z71v_dac_nids[1] = { 0x02 }; +#if 0 +/* The datasheet says the node 0x07 is connected from inputs, + * but it shows zero connection in the real implementation. + */ static hda_nid_t alc880_adc_nids[3] = { /* ADC0-2 */ 0x07, 0x08, 0x09, }; +#else +static hda_nid_t alc880_adc_nids[2] = { + /* ADC1-2 */ + 0x08, 0x09, +}; +#endif #define ALC880_DIGOUT_NID 0x06 #define ALC880_DIGIN_NID 0x0a @@ -380,10 +390,11 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + /* We don't use NID 0x07 - see above */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -434,10 +445,11 @@ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + /* We don't use NID 0x07 - see above */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -506,6 +518,8 @@ static snd_kcontrol_new_t alc880_z71v_mixer[] = { HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -514,7 +528,7 @@ static snd_kcontrol_new_t alc880_z71v_mixer[] = { */ /* .name = "Capture Source", */ .name = "Input Source", - .count = 2, + .count = 3, .info = alc_mux_enum_info, .get = alc_mux_enum_get, .put = alc_mux_enum_put, @@ -564,8 +578,16 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* unmute amp left and right */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* set connection select to mic in */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute front mixer amp left (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, /* mute pin widget amp left and right (no gain on this amp) */ @@ -639,8 +661,16 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* unmute amp left and right */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* set connection select to mic in */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute front mixer amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, /* mute pin widget amp left and right (no gain on this amp) */ @@ -798,9 +828,16 @@ static struct hda_verb alc880_z71v_init_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* unmute amp left and right */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* set connection select to line in (default select for this ADC) */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, - + /* set connection select to mic in */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* unmute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* set connection select to mic in */ + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer * widget(nid=0x0B) to support the input path of analog loopback */ @@ -941,7 +978,9 @@ static struct hda_pcm_stream alc880_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, - .nid = 0x07, /* NID to query formats and rates */ + .nid = 0x08, /* NID to query formats and rates + * (0x07 might be broken on some devices) + */ .ops = { .prepare = alc880_capture_pcm_prepare, .cleanup = alc880_capture_pcm_cleanup @@ -1261,6 +1300,13 @@ static struct hda_verb alc880_test_init_verbs[] = { {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* ADC set up */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, { } }; #endif @@ -1822,11 +1868,13 @@ static struct hda_verb alc882_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, /* ADC1: unmute amp left and right */ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* ADC2: unmute amp left and right */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* ADC3: unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Unmute front loopback */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /* Unmute rear loopback */ -- cgit v1.2.3-70-g09d2 From fc232c6e8d618daae212f643587f33d202961861 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 10:42:45 +0200 Subject: [ALSA] Fix a wrong bit set in AC1985 code AC97 Codec Fixed a wrong bit set in AD1985 surround jack controls. Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 5520f5d9749..b81064133c6 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1604,8 +1604,8 @@ static void ad1985_update_jacks(ac97_t *ac97) /* shared Mic */ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, is_shared_micin(ac97) ? 0 : 1 << 11); - snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 9 << 11, - is_shared_micin(ac97) ? 0 : 9 << 11); + snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 1 << 9, + is_shared_micin(ac97) ? 0 : 1 << 9); } static int patch_ad1985_specific(ac97_t *ac97) -- cgit v1.2.3-70-g09d2 From 685c0dccadfe19233d414afd9f00b8d480a85953 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 11:10:18 +0200 Subject: [ALSA] Add dxs_support for a Twinhead mobo VIA82xx driver Added dxs_support=4 for a Twinhead mobo. Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 4c41df05352..bb322de4777 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2179,6 +2179,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x147b, .device = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ { .vendor = 0x147b, .device = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ + { .vendor = 0x14ff, .device = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */ { .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ { .vendor = 0x1584, .device = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ { .vendor = 0x161f, .device = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ -- cgit v1.2.3-70-g09d2 From 11ca9afcfee3e6667a498b702642b09ac7312a8a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 11:34:34 +0200 Subject: [ALSA] als4000 - Fix kernel panic with MPU401 ALS4000 driver Fix kernel panic with als4000 when MPU401 is accessed. Signed-off-by: Takashi Iwai --- sound/pci/als4000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index cdc1134cded..ca28b229c70 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -367,7 +367,7 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs * if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */ snd_pcm_period_elapsed(chip->capture_substream); if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */ - snd_mpu401_uart_interrupt(irq, chip->rmidi, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); /* release the gcr */ outb(gcr_status, chip->alt_port + 0xe); -- cgit v1.2.3-70-g09d2 From 8cfbbac6ad024c3dc749ff20d7c308794da6e370 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 12:10:40 +0200 Subject: [ALSA] ice1724 - Add support of Chaintech AV-710 Documentation,ICE1724 driver Add the support of Chaintech AV-710 to ice1724 driver. The patch includes the WM-codec initialization fix by Jaanus Kivistik . Since both AV-710 and AMP Audio2000 have the same SSID, initialize WM codecs as default for both devices. In case it breaks Audio2000, you can pass 'model=amp2000' option to avoid WM codec initialization. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 4 +++- sound/pci/ice1712/amp.c | 30 +++++++++++++++++++++++++ sound/pci/ice1712/amp.h | 16 ++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 97544ef265f..226013035d7 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -733,11 +733,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * Chaintech ZNF3-150 * Chaintech ZNF3-250 * Chaintech 9CJS + * Chaintech AV-710 * Shuttle SN25P model - Use the given board model, one of the following: revo71, amp2000, prodigy71, prodigy192, aureon51, - aureon71, universe, k8x800, phase22, phase28, ms300 + aureon71, universe, k8x800, phase22, phase28, ms300, + av710 Module supports up to 8 cards and autoprobe. diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 779951725e1..289b0b5711e 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -30,16 +30,39 @@ #include #include "ice1712.h" +#include "envy24ht.h" #include "amp.h" +static void wm_put(ice1712_t *ice, int reg, unsigned short val) +{ + unsigned short cval; + cval = (reg << 9) | val; + snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); +} static int __devinit snd_vt1724_amp_init(ice1712_t *ice) { + static unsigned short wm_inits[] = { + WM_ATTEN_L, 0x0000, /* 0 db */ + WM_ATTEN_R, 0x0000, /* 0 db */ + WM_DAC_CTRL, 0x0008, /* 24bit I2S */ + WM_INT_CTRL, 0x0001, /* 24bit I2S */ + }; + + unsigned int i; + /* only use basic functionality for now */ ice->num_total_dacs = 2; /* only PSDOUT0 is connected */ ice->num_total_adcs = 2; + /* Chaintech AV-710 has another codecs, which need initialization */ + /* initialize WM8728 codec */ + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AV710) { + for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) + wm_put(ice, wm_inits[i], wm_inits[i+1]); + } + return 0; } @@ -53,6 +76,13 @@ static int __devinit snd_vt1724_amp_add_controls(ice1712_t *ice) /* entry point */ struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_AV710, + .name = "Chaintech AV-710", + .model = "av710", + .chip_init = snd_vt1724_amp_init, + .build_controls = snd_vt1724_amp_add_controls, + }, { .subvendor = VT1724_SUBDEVICE_AUDIO2000, .name = "AMP Ltd AUDIO2000", diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h index d58d43383e8..a0fc89b4812 100644 --- a/sound/pci/ice1712/amp.h +++ b/sound/pci/ice1712/amp.h @@ -24,9 +24,23 @@ * */ -#define AMP_AUDIO2000_DEVICE_DESC "{AMP Ltd,AUDIO2000}," +#define AMP_AUDIO2000_DEVICE_DESC "{AMP Ltd,AUDIO2000},"\ + "{Chaintech,AV-710}," +#if 0 #define VT1724_SUBDEVICE_AUDIO2000 0x12142417 /* Advanced Micro Peripherals Ltd AUDIO2000 */ +#else +#define VT1724_SUBDEVICE_AUDIO2000 0x00030003 /* a dummy ID for AMP Audio2000 */ +#endif +#define VT1724_SUBDEVICE_AV710 0x12142417 /* AV710 - the same ID with Audio2000! */ + +/* WM8728 on I2C for AV710 */ +#define WM_DEV 0x36 + +#define WM_ATTEN_L 0x00 +#define WM_ATTEN_R 0x01 +#define WM_DAC_CTRL 0x02 +#define WM_INT_CTRL 0x03 extern struct snd_ice1712_card_info snd_vt1724_amp_cards[]; -- cgit v1.2.3-70-g09d2 From a6c17ec89d33a714b3e94a252c127f2ff63363c8 Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Fri, 27 May 2005 12:31:34 +0200 Subject: [ALSA] emu10k1: add details for the audigy player box version EMU10K1/EMU10K2 driver Add details for the audigy player box version. Signed-off-by: Arnaud Patard Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 070be6af97b..77be07283bb 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -700,6 +700,12 @@ static emu_chip_details_t emu_chip_details[] = { .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102, + .driver = "Audigy", .name = "Audigy 1 [SB0090]", + .id = "Audigy", + .emu10k2_chip = 1, + .ca0102_chip = 1, + .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .driver = "Audigy", .name = "Audigy 1 [Unknown]", .id = "Audigy", -- cgit v1.2.3-70-g09d2 From 7199acdc74dc16d2e75f83b8c65301ad19c40ef3 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Fri, 27 May 2005 22:07:23 +0200 Subject: [ALSA] Implement support for Line-in capture on SB Live 24bit. CA0106 driver Notes: MIC capture not tested yet. Signed-off-by: James Courtier-Dutton --- sound/pci/ca0106/ca0106.h | 61 +++++++++++++++++++++++++++++++++--- sound/pci/ca0106/ca0106_main.c | 70 +++++++++++++++++++++++++++++++++++++++--- sound/pci/ca0106/ca0106_proc.c | 27 ++++++++++++++-- 3 files changed, 148 insertions(+), 10 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index c623858428c..67e56a530b2 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.20 + * Version: 0.0.21 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -45,6 +45,8 @@ * Added I2C and SPI registers. Filled in interrupt enable. * 0.0.20 * Added GPIO info for SB Live 24bit. + * 0.0.21 + * Implement support for Line-in capture on SB Live 24bit. * * * This code was initally based on code from ALSA's emu10k1x.c which is: @@ -475,9 +477,56 @@ /* Causes interrupts based on timer intervals. */ #define SPI 0x7a /* SPI: Serial Interface Register */ #define I2C_A 0x7b /* I2C Address. 32 bit */ -#define I2C_0 0x7c /* I2C Data Port 0. 32 bit */ -#define I2C_1 0x7d /* I2C Data Port 1. 32 bit */ - +#define I2C_D0 0x7c /* I2C Data Port 0. 32 bit */ +#define I2C_D1 0x7d /* I2C Data Port 1. 32 bit */ +//I2C values +#define I2C_A_ADC_ADD_MASK 0x000000fe //The address is a 7 bit address +#define I2C_A_ADC_RW_MASK 0x00000001 //bit mask for R/W +#define I2C_A_ADC_TRANS_MASK 0x00000010 //Bit mask for I2c address DAC value +#define I2C_A_ADC_ABORT_MASK 0x00000020 //Bit mask for I2C transaction abort flag +#define I2C_A_ADC_LAST_MASK 0x00000040 //Bit mask for Last word transaction +#define I2C_A_ADC_BYTE_MASK 0x00000080 //Bit mask for Byte Mode + +#define I2C_A_ADC_ADD 0x00000034 //This is the Device address for ADC +#define I2C_A_ADC_READ 0x00000001 //To perform a read operation +#define I2C_A_ADC_START 0x00000100 //Start I2C transaction +#define I2C_A_ADC_ABORT 0x00000200 //I2C transaction abort +#define I2C_A_ADC_LAST 0x00000400 //I2C last transaction +#define I2C_A_ADC_BYTE 0x00000800 //I2C one byte mode + +#define I2C_D_ADC_REG_MASK 0xfe000000 //ADC address register +#define I2C_D_ADC_DAT_MASK 0x01ff0000 //ADC data register + +#define ADC_TIMEOUT 0x00000007 //ADC Timeout Clock Disable +#define ADC_IFC_CTRL 0x0000000b //ADC Interface Control +#define ADC_MASTER 0x0000000c //ADC Master Mode Control +#define ADC_POWER 0x0000000d //ADC PowerDown Control +#define ADC_ATTEN_ADCL 0x0000000e //ADC Attenuation ADCL +#define ADC_ATTEN_ADCR 0x0000000f //ADC Attenuation ADCR +#define ADC_ALC_CTRL1 0x00000010 //ADC ALC Control 1 +#define ADC_ALC_CTRL2 0x00000011 //ADC ALC Control 2 +#define ADC_ALC_CTRL3 0x00000012 //ADC ALC Control 3 +#define ADC_NOISE_CTRL 0x00000013 //ADC Noise Gate Control +#define ADC_LIMIT_CTRL 0x00000014 //ADC Limiter Control +#define ADC_MUX 0x00000015 //ADC Mux offset + +#if 0 +/* FIXME: Not tested yet. */ +#define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain +#define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB +#define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute +#define ADC_MUTE 0x000000c0 //Value to mute ADC +#define ADC_OSR 0x00000008 //Mask for ADC oversample rate select +#define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock +#define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter +#define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window +#endif + +#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux +#define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux +#define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux +#define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used) +#define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ #define PCM_FRONT_CHANNEL 0 @@ -513,6 +562,7 @@ typedef struct { char * name; int ac97; int gpio_type; + int i2c_adc; } ca0106_details_t; // definition of the chip-specific record @@ -555,3 +605,6 @@ void snd_ca0106_ptr_write(ca0106_t *emu, unsigned int chn, unsigned int data); +int snd_ca0106_i2c_write(ca0106_t *emu, u32 reg, u32 value); + + diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index a56e68ea87b..58d9026c8ca 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.22 + * Version: 0.0.23 * * FEATURES currently supported: * Front, Rear and Center/LFE. @@ -77,6 +77,8 @@ * Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) * 0.0.22 * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 + * 0.0.23 + * Implement support for Line-in capture on SB Live 24bit. * * BUGS: * Some stability problems when unloading the snd-ca0106 kernel module. @@ -173,15 +175,18 @@ static ca0106_details_t ca0106_chip_details[] = { /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ { .serial = 0x10061102, .name = "Live! 7.1 24bit [SB0410]", - .gpio_type = 1 } , + .gpio_type = 1, + .i2c_adc = 1 } , /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ { .serial = 0x10071102, .name = "Live! 7.1 24bit [SB0413]", - .gpio_type = 1 } , + .gpio_type = 1, + .i2c_adc = 1 } , /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ { .serial = 0x10091462, .name = "MSI K8N Diamond MB [SB0438]", - .gpio_type = 1 } , + .gpio_type = 1, + .i2c_adc = 1 } , { .serial = 0, .name = "AudigyLS [Unknown]" } }; @@ -257,6 +262,59 @@ void snd_ca0106_ptr_write(ca0106_t *emu, spin_unlock_irqrestore(&emu->emu_lock, flags); } +int snd_ca0106_i2c_write(ca0106_t *emu, + u32 reg, + u32 value) +{ + u32 tmp; + int timeout=0; + int status; + int retry; + if ((reg > 0x7f) || (value > 0x1ff)) + { + snd_printk("i2c_write: invalid values.\n"); + return -EINVAL; + } + + tmp = reg << 25 | value << 16; + snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); + snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); + + for(retry=0;retry<10;retry++) + { + /* Send the data to i2c */ + tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); + tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); + tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); + snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); + + /* Wait till the transaction ends */ + while(1) + { + status = snd_ca0106_ptr_read(emu, I2C_A, 0); + //snd_printk("I2C:status=0x%x\n", status); + timeout++; + if((status & I2C_A_ADC_START)==0) + break; + + if(timeout>1000) + break; + } + //Read back and see if the transaction is successful + if((status & I2C_A_ADC_ABORT)==0) + break; + } + + if(retry==10) + { + snd_printk("Writing to ADC failed!\n"); + return -EINVAL; + } + + return 0; +} + + static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) { unsigned long flags; @@ -1177,6 +1235,10 @@ static int __devinit snd_ca0106_create(snd_card_t *card, //outl(0x00000009, chip->port+HCFG); outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ + if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ + snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ + } + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_ca0106_free(chip); diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 3e5161a3236..1c9cc821d1b 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.17 + * Version: 0.0.18 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -39,7 +39,9 @@ * Modified Copyright message. * 0.0.17 * Add iec958 file in proc file system to show status of SPDIF in. - * + * 0.0.18 + * Implement support for Line-in capture on SB Live 24bit. + * * This code was initally based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes * @@ -407,6 +409,20 @@ static void snd_ca0106_proc_reg_write(snd_info_entry_t *entry, } } +static void snd_ca0106_proc_i2c_write(snd_info_entry_t *entry, + snd_info_buffer_t * buffer) +{ + ca0106_t *emu = entry->private_data; + char line[64]; + unsigned int reg, val; + while (!snd_info_get_line(buffer, line, sizeof(line))) { + if (sscanf(line, "%x %x", ®, &val) != 2) + continue; + if ((reg <= 0x7f) || (val <= 0x1ff)) { + snd_ca0106_i2c_write(emu, reg, val); + } + } +} int __devinit snd_ca0106_proc_init(ca0106_t * emu) { @@ -429,6 +445,13 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) entry->c.text.write_size = 64; entry->c.text.write = snd_ca0106_proc_reg_write; entry->mode |= S_IWUSR; +// entry->private_data = emu; + } + if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { + snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write); + entry->c.text.write_size = 64; + entry->c.text.write = snd_ca0106_proc_i2c_write; + entry->mode |= S_IWUSR; // entry->private_data = emu; } if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) -- cgit v1.2.3-70-g09d2 From ed144f3cdcf8f9b9280e04ca1a831c85a8fbb488 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Fri, 27 May 2005 23:28:27 +0200 Subject: [ALSA] Add Mic capture support. CA0106 driver Notes: This adds a new mixer item to switch between Mic and Line-in. Signed-off-by: James Courtier-Dutton --- sound/pci/ca0106/ca0106.h | 1 + sound/pci/ca0106/ca0106_mixer.c | 69 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 67e56a530b2..beac9dad2ed 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -589,6 +589,7 @@ struct snd_ca0106 { u32 spdif_bits[4]; /* s/pdif out setup */ int spdif_enable; int capture_source; + int capture_mic_line_in; struct snd_dma_buffer buffer; }; diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 48e24860824..0e5e9ce0ff2 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.16 + * Version: 0.0.17 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -37,6 +37,8 @@ * Separated ca0106.c into separate functional .c files. * 0.0.16 * Modified Copyright message. + * 0.0.17 + * Implement Mic and Line in Capture. * * This code was initally based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes @@ -183,6 +185,65 @@ static snd_kcontrol_new_t snd_ca0106_capture_source __devinitdata = .put = snd_ca0106_capture_source_put }; +static int snd_ca0106_capture_mic_line_in_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[2] = { "Line in", "Mic in" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_ca0106_capture_mic_line_in_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ca0106_t *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in; + return 0; +} + +static int snd_ca0106_capture_mic_line_in_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ca0106_t *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + u32 tmp; + + val = ucontrol->value.enumerated.item[0] ; + change = (emu->capture_mic_line_in != val); + if (change) { + emu->capture_mic_line_in = val; + if (val) { + snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + tmp = tmp | 0x400; + outl(tmp, emu->port+GPIO); + snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); + } else { + snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + outl(tmp, emu->port+GPIO); + snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); + } + } + return change; +} + +static snd_kcontrol_new_t snd_ca0106_capture_mic_line_in __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic/Line in Capture", + .info = snd_ca0106_capture_mic_line_in_info, + .get = snd_ca0106_capture_mic_line_in_get, + .put = snd_ca0106_capture_mic_line_in_put +}; + static int snd_ca0106_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; @@ -620,6 +681,12 @@ int __devinit snd_ca0106_mixer(ca0106_t *emu) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if (emu->details->i2c_adc == 1) { + if ((kctl = snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(card, kctl))) + return err; + } if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) -- cgit v1.2.3-70-g09d2 From 883130b476e7f8baa608dabe52c455ac351f7c39 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 28 May 2005 13:28:21 +0200 Subject: [ALSA] Implement S32_LE(24bit) and 96000 capture rates etc. CA0106 driver Signed-off-by: James Courtier-Dutton --- sound/pci/ca0106/ca0106_main.c | 63 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 58d9026c8ca..1c26206b4fb 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -216,10 +216,10 @@ static snd_pcm_hardware_t snd_ca0106_capture_hw = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, + .rate_min = 44100, + .rate_max = 192000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = ((65536 - 64) * 8), @@ -607,6 +607,61 @@ static int snd_ca0106_pcm_prepare_capture(snd_pcm_substream_t *substream) snd_pcm_runtime_t *runtime = substream->runtime; ca0106_pcm_t *epcm = runtime->private_data; int channel = epcm->channel_id; + u32 hcfg_mask = HCFG_CAPTURE_S32_LE; + u32 hcfg_set = 0x00000000; + u32 hcfg; + u32 over_sampling=0x2; + u32 reg71_mask = 0x0000c000 ; /* Global. Set ADC rate. */ + u32 reg71_set = 0; + u32 reg71; + + //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); + //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); + //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); + /* reg71 controls ADC rate. */ + switch (runtime->rate) { + case 44100: + reg71_set = 0x00004000; + break; + case 48000: + reg71_set = 0; + break; + case 96000: + reg71_set = 0x00008000; + over_sampling=0xa; + break; + case 192000: + reg71_set = 0x0000c000; + over_sampling=0xa; + break; + default: + reg71_set = 0; + break; + } + /* Format is a global setting */ + /* FIXME: Only let the first channel accessed set this. */ + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + hcfg_set = 0; + break; + case SNDRV_PCM_FORMAT_S32_LE: + hcfg_set = HCFG_CAPTURE_S32_LE; + break; + default: + hcfg_set = 0; + break; + } + hcfg = inl(emu->port + HCFG) ; + hcfg = (hcfg & ~hcfg_mask) | hcfg_set; + outl(hcfg, emu->port + HCFG); + reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); + reg71 = (reg71 & ~reg71_mask) | reg71_set; + snd_ca0106_ptr_write(emu, 0x71, 0, reg71); + if (emu->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ + snd_ca0106_i2c_write(emu, ADC_MASTER, over_sampling); /* Adjust the over sampler to better suit the capture rate. */ + } + + //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); snd_ca0106_ptr_write(emu, 0x13, channel, 0); snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); -- cgit v1.2.3-70-g09d2 From 8fabab15dc64d4aaed0e9dddf3482c128a0347a2 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 28 May 2005 16:35:49 +0200 Subject: [ALSA] Be more specific with which I2C channel to use. CA0106 driver Signed-off-by: James Courtier-Dutton --- sound/pci/ca0106/ca0106_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 1c26206b4fb..bfd558c9f3d 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -277,7 +277,10 @@ int snd_ca0106_i2c_write(ca0106_t *emu, } tmp = reg << 25 | value << 16; - snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); + /* Not sure what this I2C channel controls. */ + /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ + + /* This controls the I2C connected to the WM8775 ADC Codec */ snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); for(retry=0;retry<10;retry++) -- cgit v1.2.3-70-g09d2 From 87d61c290b5de63cc18ed5ec8103e30fe297373e Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Sun, 29 May 2005 15:08:23 +0200 Subject: [ALSA] MC97 modem mixer in sound/pci/ac97 AC97 Codec Simple MC97 modem mixer with two common controls: Off-hook and CID, and Si3056 MC specific control: Modem Speaker. Signed-off-by: Sasha Khapyorsky Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_codec.c | 21 +++++++++++++++++++-- sound/pci/ac97/ac97_patch.c | 21 +++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 36a33ae9ae0..996fcfb0953 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -150,7 +150,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, { 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, -{ 0x53494c20, 0xffffffe0, "Si3036,8", NULL, mpatch_si3036 }, +{ 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99] @@ -666,6 +666,11 @@ AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1) static const snd_kcontrol_new_t snd_ac97_control_eapd = AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); +static const snd_kcontrol_new_t snd_ac97_controls_modem_switches[2] = { +AC97_SINGLE("Off-hook Switch", AC97_GPIO_STATUS, 0, 1, 0), +AC97_SINGLE("Caller ID Switch", AC97_GPIO_STATUS, 2, 1, 0) +}; + /* change the existing EAPD control as inverted */ static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl) { @@ -1526,13 +1531,25 @@ static int snd_ac97_mixer_build(ac97_t * ac97) static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97) { - /* TODO */ + int err, idx; + //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG)); snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH)); snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH)); snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff); snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0); snd_ac97_write(ac97, AC97_MISC_AFE, 0x0); + + /* build modem switches */ + for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++) + if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_modem_switches[idx], ac97))) < 0) + return err; + + /* build chip specific controls */ + if (ac97->build_ops->build_specific) + if ((err = ac97->build_ops->build_specific(ac97)) < 0) + return err; + return 0; } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index b81064133c6..a15eb8522b7 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2459,12 +2459,29 @@ int patch_it2646(ac97_t * ac97) return 0; } -/* Si3036/8 specific registers */ +/* + * Si3036 codec + */ + #define AC97_SI3036_CHIP_ID 0x5a +#define AC97_SI3036_LINE_CFG 0x5c + +static const snd_kcontrol_new_t snd_ac97_controls_si3036[] = { +AC97_DOUBLE("Modem Speaker Volume", 0x5c, 14, 12, 3, 1) +}; + +static int patch_si3036_specific(ac97_t * ac97) +{ + return patch_build_controls(ac97, snd_ac97_controls_si3036, ARRAY_SIZE(snd_ac97_controls_si3036)); +} + +static struct snd_ac97_build_ops patch_si3036_ops = { + .build_specific = patch_si3036_specific, +}; int mpatch_si3036(ac97_t * ac97) { - //printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a)); + ac97->build_ops = &patch_si3036_ops; snd_ac97_write_cache(ac97, 0x5c, 0xf210 ); snd_ac97_write_cache(ac97, 0x68, 0); return 0; -- cgit v1.2.3-70-g09d2 From 83a5b72ad7c7cbd0d155d922733b2429f46801bf Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Sun, 29 May 2005 15:10:07 +0200 Subject: [ALSA] PCI modem drivers update ATIIXP-modem driver,Intel8x0-modem driver,VIA82xx-modem driver Modem drivers (atiixp-modem, intel8x0m, via82xx-modem) migration for using MC97 generic modem mixer for off-hook operation. Signed-off-by: Sasha Khapyorsky Signed-off-by: Jaroslav Kysela --- sound/pci/atiixp_modem.c | 40 +++++++++++-------------- sound/pci/intel8x0m.c | 76 ++--------------------------------------------- sound/pci/via82xx_modem.c | 28 ++++------------- 3 files changed, 25 insertions(+), 119 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 9220aae632b..a6b4b8d589f 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -463,6 +463,11 @@ static unsigned short snd_atiixp_ac97_read(ac97_t *ac97, unsigned short reg) static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { atiixp_t *chip = ac97->private_data; + if (reg == AC97_GPIO_STATUS) { + atiixp_write(chip, MODEM_OUT_GPIO, + (val << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN); + return; + } snd_atiixp_codec_write(chip, ac97->num, reg, val); } @@ -663,44 +668,33 @@ static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd) { atiixp_t *chip = snd_pcm_substream_chip(substream); atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; - unsigned int reg = 0; - int i; + int err = 0; snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL); - if (cmd != SNDRV_PCM_TRIGGER_START && cmd != SNDRV_PCM_TRIGGER_STOP) - return -EINVAL; - spin_lock(&chip->reg_lock); - - /* hook off/on: via GPIO_OUT */ - for (i = 0; i < NUM_ATI_CODECS; i++) { - if (chip->ac97[i]) { - reg = snd_ac97_read(chip->ac97[i], AC97_GPIO_STATUS); - break; - } - } - if(cmd == SNDRV_PCM_TRIGGER_START) - reg |= AC97_GPIO_LINE1_OH; - else - reg &= ~AC97_GPIO_LINE1_OH; - reg = (reg << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN ; - atiixp_write(chip, MODEM_OUT_GPIO, reg); - - if (cmd == SNDRV_PCM_TRIGGER_START) { + switch(cmd) { + case SNDRV_PCM_TRIGGER_START: dma->ops->enable_transfer(chip, 1); dma->running = 1; - } else { + break; + case SNDRV_PCM_TRIGGER_STOP: dma->ops->enable_transfer(chip, 0); dma->running = 0; + break; + default: + err = -EINVAL; + break; } + if (! err) { snd_atiixp_check_bus_busy(chip); if (cmd == SNDRV_PCM_TRIGGER_STOP) { dma->ops->flush_dma(chip); snd_atiixp_check_bus_busy(chip); } + } spin_unlock(&chip->reg_lock); - return 0; + return err; } diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index f655cf91406..bb758c77d21 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -35,7 +35,6 @@ #include #include #include -#include #include MODULE_AUTHOR("Jaroslav Kysela "); @@ -292,60 +291,9 @@ static struct pci_device_id snd_intel8x0m_ids[] = { #endif { 0, } }; -static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol, - snd_ctl_elem_value_t *ucontrol); -static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol, - snd_ctl_elem_value_t *ucontrol); -static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol, - snd_ctl_elem_info_t *uinfo); - -#define PRIVATE_VALUE_INITIALIZER(r,m) (((r) & 0xffff) << 16 | ((m) & 0xffff)) -#define PRIVATE_VALUE_MASK(control) ((control)->private_value & 0xffff) -#define PRIVATE_VALUE_REG(control) (((control)->private_value >> 16) & 0xffff) - -static snd_kcontrol_new_t snd_intel8x0m_mixer_switches[] __devinitdata = { - { .name = "Off-hook Switch", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = snd_intel8x0m_switch_default_info, - .get = snd_intel8x0m_switch_default_get, - .put = snd_intel8x0m_switch_default_put, - .private_value = PRIVATE_VALUE_INITIALIZER(AC97_GPIO_STATUS,AC97_GPIO_LINE1_OH) - } -}; MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids); -static int snd_intel8x0m_switch_default_info(snd_kcontrol_t *kcontrol, - snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_intel8x0m_switch_default_get(snd_kcontrol_t *kcontrol, - snd_ctl_elem_value_t *ucontrol) -{ - unsigned short mask = PRIVATE_VALUE_MASK(kcontrol); - unsigned short reg = PRIVATE_VALUE_REG(kcontrol); - intel8x0_t *chip = snd_kcontrol_chip(kcontrol); - unsigned int status; - status = snd_ac97_read(chip->ac97, reg) & mask ? 1 : 0; - ucontrol->value.integer.value[0] = status; - return 0; -} -static int snd_intel8x0m_switch_default_put(snd_kcontrol_t *kcontrol, - snd_ctl_elem_value_t *ucontrol) -{ - unsigned short mask = PRIVATE_VALUE_MASK(kcontrol); - unsigned short reg = PRIVATE_VALUE_REG(kcontrol); - intel8x0_t *chip = snd_kcontrol_chip(kcontrol); - unsigned short new_status = ucontrol->value.integer.value[0] ? mask : ~mask; - return snd_ac97_update_bits(chip->ac97, reg, - mask, new_status); -} /* * Lowlevel I/O - busmaster */ @@ -700,21 +648,6 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substrea return bytes_to_frames(substream->runtime, ptr); } -static int snd_intel8x0m_pcm_trigger(snd_pcm_substream_t *substream, int cmd) -{ - /* hook off/on on start/stop */ - /* Moved this to mixer control */ - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - break; - case SNDRV_PCM_TRIGGER_STOP: - break; - default: - return -EINVAL; - } - return snd_intel8x0_pcm_trigger(substream,cmd); -} - static int snd_intel8x0m_pcm_prepare(snd_pcm_substream_t * substream) { intel8x0_t *chip = snd_pcm_substream_chip(substream); @@ -810,7 +743,7 @@ static snd_pcm_ops_t snd_intel8x0m_playback_ops = { .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0m_pcm_prepare, - .trigger = snd_intel8x0m_pcm_trigger, + .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer, }; @@ -821,7 +754,7 @@ static snd_pcm_ops_t snd_intel8x0m_capture_ops = { .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0m_pcm_prepare, - .trigger = snd_intel8x0m_pcm_trigger, + .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer, }; @@ -949,7 +882,6 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ac97_t *x97; int err; unsigned int glob_sta = 0; - unsigned int idx; static ac97_bus_ops_t ops = { .write = snd_intel8x0_codec_write, .read = snd_intel8x0_codec_read, @@ -985,10 +917,6 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) chip->ichd[ICHD_MDMIN].ac97 = x97; chip->ichd[ICHD_MDMOUT].ac97 = x97; } - for (idx = 0; idx < ARRAY_SIZE(snd_intel8x0m_mixer_switches); idx++) { - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_intel8x0m_mixer_switches[idx], chip))) < 0) - goto __err; - } chip->in_ac97_init = 0; return 0; diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 276ce529968..e10fceb3ede 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -420,7 +420,10 @@ static void snd_via82xx_codec_write(ac97_t *ac97, { via82xx_t *chip = ac97->private_data; unsigned int xval; - + if(reg == AC97_GPIO_STATUS) { + outl(val, VIAREG(chip, GPI_STATUS)); + return; + } xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY; xval <<= VIA_REG_AC97_CODEC_ID_SHIFT; xval |= reg << VIA_REG_AC97_CMD_SHIFT; @@ -544,25 +547,6 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd) return 0; } -static int snd_via82xx_modem_pcm_trigger(snd_pcm_substream_t * substream, int cmd) -{ - via82xx_t *chip = snd_pcm_substream_chip(substream); - unsigned int val = 0; - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - val = snd_ac97_read(chip->ac97, AC97_GPIO_STATUS); - outl(val|AC97_GPIO_LINE1_OH, VIAREG(chip, GPI_STATUS)); - break; - case SNDRV_PCM_TRIGGER_STOP: - val = snd_ac97_read(chip->ac97, AC97_GPIO_STATUS); - outl(val&~AC97_GPIO_LINE1_OH, VIAREG(chip, GPI_STATUS)); - break; - default: - break; - } - return snd_via82xx_pcm_trigger(substream, cmd); -} - /* * pointer callbacks */ @@ -806,7 +790,7 @@ static snd_pcm_ops_t snd_via686_playback_ops = { .hw_params = snd_via82xx_hw_params, .hw_free = snd_via82xx_hw_free, .prepare = snd_via82xx_pcm_prepare, - .trigger = snd_via82xx_modem_pcm_trigger, + .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, .page = snd_pcm_sgbuf_ops_page, }; @@ -819,7 +803,7 @@ static snd_pcm_ops_t snd_via686_capture_ops = { .hw_params = snd_via82xx_hw_params, .hw_free = snd_via82xx_hw_free, .prepare = snd_via82xx_pcm_prepare, - .trigger = snd_via82xx_modem_pcm_trigger, + .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, .page = snd_pcm_sgbuf_ops_page, }; -- cgit v1.2.3-70-g09d2 From 299676b1d792ca643f37ff4f3275694a841739b7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 29 May 2005 15:21:02 +0200 Subject: [ALSA] sound/pci/ca0106: Use the DMA_32BIT_MASK constant CA0106 driver Use the DMA_32BIT_MASK constant from dma-mapping.h when calling pci_set_dma_mask() or pci_set_consistent_dma_mask() See http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for details Signed-off-by: Tobias Klauser Signed-off-by: Domen Puncer Signed-off-by: Jaroslav Kysela --- sound/pci/ca0106/ca0106_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index bfd558c9f3d..85caf1bbcc1 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -138,6 +138,7 @@ #include #include #include +#include #include #include #include @@ -1132,8 +1133,8 @@ static int __devinit snd_ca0106_create(snd_card_t *card, if ((err = pci_enable_device(pci)) < 0) return err; - if (pci_set_dma_mask(pci, 0xffffffffUL) < 0 || - pci_set_consistent_dma_mask(pci, 0xffffffffUL) < 0) { + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "error to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; -- cgit v1.2.3-70-g09d2 From 5cbff89cbc1087870c32ecb0b7f1965f93ec5401 Mon Sep 17 00:00:00 2001 From: Sasha Khapyorsky Date: Mon, 30 May 2005 08:09:56 +0200 Subject: [ALSA] Modem support for ALI5451 ALI5451 driver This patch adds modem support for ali5451. Since it is same pci device all is done in ali5451.c. Signed-off-by: Sasha Khapyorsky Signed-off-by: Jaroslav Kysela --- sound/pci/ali5451/ali5451.c | 281 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 218 insertions(+), 63 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 038f56ad42f..eb5c36d31a5 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -98,6 +98,8 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); #define ALI_LEF_CHANNEL 23 #define ALI_SURR_LEFT_CHANNEL 26 #define ALI_SURR_RIGHT_CHANNEL 25 +#define ALI_MODEM_IN_CHANNEL 21 +#define ALI_MODEM_OUT_CHANNEL 20 #define SNDRV_ALI_VOICE_TYPE_PCM 01 #define SNDRV_ALI_VOICE_TYPE_OTH 02 @@ -122,7 +124,15 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); #define ALI_SCTRL 0x48 #define ALI_SPDIF_OUT_ENABLE 0x20 +#define ALI_SCTRL_LINE_IN2 (1 << 9) +#define ALI_SCTRL_GPIO_IN2 (1 << 13) +#define ALI_SCTRL_LINE_OUT_EN (1 << 20) +#define ALI_SCTRL_GPIO_OUT_EN (1 << 23) +#define ALI_SCTRL_CODEC1_READY (1 << 24) +#define ALI_SCTRL_CODEC2_READY (1 << 25) #define ALI_AC97_GPIO 0x4c +#define ALI_AC97_GPIO_ENABLE 0x8000 +#define ALI_AC97_GPIO_DATA_SHIFT 16 #define ALI_SPDIF_CS 0x70 #define ALI_SPDIF_CTRL 0x74 #define ALI_SPDIF_IN_FUNC_ENABLE 0x02 @@ -143,6 +153,7 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); #define TARGET_REACHED 0x00008000 #define MIXER_OVERFLOW 0x00000800 #define MIXER_UNDERFLOW 0x00000400 + #define GPIO_IRQ 0x01000000 #define ALI_SBBL_SBCL 0xc0 #define ALI_SBCTRL_SBE2R_SBDD 0xc4 #define ALI_STIMER 0xc8 @@ -162,6 +173,9 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); #define ALI_REG(codec, x) ((codec)->port + x) +#define MAX_CODECS 2 + + typedef struct snd_stru_ali ali_t; typedef struct snd_ali_stru_voice snd_ali_voice_t; @@ -245,7 +259,7 @@ struct snd_stru_ali { struct pci_dev *pci_m7101; snd_card_t *card; - snd_pcm_t *pcm; + snd_pcm_t *pcm[MAX_CODECS]; alidev_t synth; snd_ali_channel_control_t chregs; @@ -255,8 +269,10 @@ struct snd_stru_ali { unsigned int spurious_irq_count; unsigned int spurious_irq_max_delta; + unsigned int num_of_codecs; + ac97_bus_t *ac97_bus; - ac97_t *ac97; + ac97_t *ac97[MAX_CODECS]; unsigned short ac97_ext_id; unsigned short ac97_ext_status; @@ -489,7 +505,12 @@ static void snd_ali_codec_write(ac97_t *ac97, ali_t *codec = ac97->private_data; snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val); - snd_ali_codec_poke(codec, 0, reg, val); + if(reg == AC97_GPIO_STATUS) { + outl((val << ALI_AC97_GPIO_DATA_SHIFT)|ALI_AC97_GPIO_ENABLE, + ALI_REG(codec, ALI_AC97_GPIO)); + return; + } + snd_ali_codec_poke(codec, ac97->num, reg, val); return ; } @@ -499,7 +520,7 @@ static unsigned short snd_ali_codec_read(ac97_t *ac97, unsigned short reg) ali_t *codec = ac97->private_data; snd_ali_printk("codec_read reg=%xh.\n", reg); - return (snd_ali_codec_peek(codec, 0, reg)); + return (snd_ali_codec_peek(codec, ac97->num, reg)); } /* @@ -1051,7 +1072,7 @@ static irqreturn_t snd_ali_card_interrupt(int irq, } -static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec) +static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec, int channel) { snd_ali_voice_t *pvoice = NULL; unsigned long flags; @@ -1061,7 +1082,8 @@ static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec) spin_lock_irqsave(&codec->voice_alloc, flags); if (type == SNDRV_ALI_VOICE_TYPE_PCM) { - idx = snd_ali_find_free_channel(codec,rec); + idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) : + snd_ali_find_free_channel(codec,rec); if(idx < 0) { snd_printk("ali_alloc_voice: err.\n"); spin_unlock_irqrestore(&codec->voice_alloc, flags); @@ -1297,7 +1319,7 @@ static int snd_ali_playback_hw_params(snd_pcm_substream_t * substream, if (params_buffer_size(hw_params)/2 != params_period_size(hw_params)) { if (evoice == NULL) { - evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); + evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0, -1); if (evoice == NULL) return -ENOMEM; pvoice->extra = evoice; @@ -1328,13 +1350,13 @@ static int snd_ali_playback_hw_free(snd_pcm_substream_t * substream) return 0; } -static int snd_ali_capture_hw_params(snd_pcm_substream_t * substream, +static int snd_ali_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } -static int snd_ali_capture_hw_free(snd_pcm_substream_t * substream) +static int snd_ali_hw_free(snd_pcm_substream_t * substream) { return snd_pcm_lib_free_pages(substream); } @@ -1428,7 +1450,7 @@ static int snd_ali_playback_prepare(snd_pcm_substream_t * substream) } -static int snd_ali_capture_prepare(snd_pcm_substream_t * substream) +static int snd_ali_prepare(snd_pcm_substream_t * substream) { ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1446,11 +1468,13 @@ static int snd_ali_capture_prepare(snd_pcm_substream_t * substream) spin_lock_irqsave(&codec->reg_lock, flags); - snd_ali_printk("capture_prepare...\n"); + snd_ali_printk("ali_prepare...\n"); snd_ali_enable_special_channel(codec,pvoice->number); - Delta = snd_ali_convert_rate(runtime->rate, 1); + Delta = (pvoice->number == ALI_MODEM_IN_CHANNEL || + pvoice->number == ALI_MODEM_OUT_CHANNEL) ? + 0x1000 : snd_ali_convert_rate(runtime->rate, pvoice->mode); // Prepare capture intr channel if (pvoice->number == ALI_SPDIF_IN_CHANNEL) { @@ -1534,7 +1558,7 @@ static snd_pcm_uframes_t snd_ali_playback_pointer(snd_pcm_substream_t *substream } -static snd_pcm_uframes_t snd_ali_capture_pointer(snd_pcm_substream_t *substream) +static snd_pcm_uframes_t snd_ali_pointer(snd_pcm_substream_t *substream) { ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1616,7 +1640,8 @@ static void snd_ali_pcm_free_substream(snd_pcm_runtime_t *runtime) } } -static int snd_ali_playback_open(snd_pcm_substream_t * substream) +static int snd_ali_open(snd_pcm_substream_t * substream, int rec, int channel, + snd_pcm_hardware_t *phw) { ali_t *codec = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1624,7 +1649,7 @@ static int snd_ali_playback_open(snd_pcm_substream_t * substream) unsigned long flags = 0; spin_lock_irqsave(&codec->reg_lock, flags); - pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); + pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, rec, channel); if (pvoice == NULL) { spin_unlock_irqrestore(&codec->reg_lock, flags); return -EAGAIN; @@ -1636,49 +1661,31 @@ static int snd_ali_playback_open(snd_pcm_substream_t * substream) runtime->private_data = pvoice; runtime->private_free = snd_ali_pcm_free_substream; - runtime->hw = snd_ali_playback; + runtime->hw = *phw; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); return 0; } +static int snd_ali_playback_open(snd_pcm_substream_t * substream) +{ + return snd_ali_open(substream, 0, -1, &snd_ali_playback); +} static int snd_ali_capture_open(snd_pcm_substream_t * substream) { - ali_t *codec = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_ali_voice_t *pvoice; - unsigned long flags; - - spin_lock_irqsave(&codec->reg_lock, flags); - pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 1); - if (pvoice == NULL) { - spin_unlock_irqrestore(&codec->reg_lock, flags); - return -EAGAIN; - } - pvoice->codec = codec; - spin_unlock_irqrestore(&codec->reg_lock, flags); - - pvoice->substream = substream; - runtime->private_data = pvoice; - runtime->private_free = snd_ali_pcm_free_substream; - runtime->hw = snd_ali_capture; - snd_pcm_set_sync(substream); - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); - return 0; + return snd_ali_open(substream, 1, -1, &snd_ali_capture); } - static int snd_ali_playback_close(snd_pcm_substream_t * substream) { return 0; } -static int snd_ali_capture_close(snd_pcm_substream_t * substream) +static int snd_ali_close(snd_pcm_substream_t * substream) { ali_t *codec = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data; + snd_ali_voice_t *pvoice = (snd_ali_voice_t *) substream->runtime->private_data; snd_ali_disable_special_channel(codec,pvoice->number); @@ -1698,29 +1705,121 @@ static snd_pcm_ops_t snd_ali_playback_ops = { static snd_pcm_ops_t snd_ali_capture_ops = { .open = snd_ali_capture_open, - .close = snd_ali_capture_close, + .close = snd_ali_close, .ioctl = snd_ali_ioctl, - .hw_params = snd_ali_capture_hw_params, - .hw_free = snd_ali_capture_hw_free, - .prepare = snd_ali_capture_prepare, + .hw_params = snd_ali_hw_params, + .hw_free = snd_ali_hw_free, + .prepare = snd_ali_prepare, + .trigger = snd_ali_trigger, + .pointer = snd_ali_pointer, +}; + +/* + * Modem PCM + */ + +static int snd_ali_modem_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + ali_t *chip = snd_pcm_substream_chip(substream); + unsigned int modem_num = chip->num_of_codecs - 1; + snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_RATE, params_rate(hw_params)); + snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_LEVEL, 0); + return snd_ali_hw_params(substream, hw_params); +} + +static snd_pcm_hardware_t snd_ali_modem = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_KNOT|SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000, + .rate_min = 8000, + .rate_max = 16000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = (256*1024), + .period_bytes_min = 64, + .period_bytes_max = (256*1024), + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +static int snd_ali_modem_open(snd_pcm_substream_t * substream, int rec, int channel) +{ + static unsigned int rates [] = {8000,9600,12000,16000}; + static snd_pcm_hw_constraint_list_t hw_constraint_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, + }; + int err = snd_ali_open(substream, rec, channel, &snd_ali_modem); + if (err) + return err; + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates); +} + +static int snd_ali_modem_playback_open(snd_pcm_substream_t * substream) +{ + return snd_ali_modem_open(substream, 0, ALI_MODEM_OUT_CHANNEL); +} + +static int snd_ali_modem_capture_open(snd_pcm_substream_t * substream) +{ + return snd_ali_modem_open(substream, 1, ALI_MODEM_IN_CHANNEL); +} + +static snd_pcm_ops_t snd_ali_modem_playback_ops = { + .open = snd_ali_modem_playback_open, + .close = snd_ali_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_ali_modem_hw_params, + .hw_free = snd_ali_hw_free, + .prepare = snd_ali_prepare, + .trigger = snd_ali_trigger, + .pointer = snd_ali_pointer, +}; + +static snd_pcm_ops_t snd_ali_modem_capture_ops = { + .open = snd_ali_modem_capture_open, + .close = snd_ali_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_ali_modem_hw_params, + .hw_free = snd_ali_hw_free, + .prepare = snd_ali_prepare, .trigger = snd_ali_trigger, - .pointer = snd_ali_capture_pointer, + .pointer = snd_ali_pointer, +}; + + +struct ali_pcm_description { + char *name; + unsigned int playback_num; + unsigned int capture_num; + snd_pcm_ops_t *playback_ops; + snd_pcm_ops_t *capture_ops; }; static void snd_ali_pcm_free(snd_pcm_t *pcm) { ali_t *codec = pcm->private_data; - codec->pcm = NULL; + codec->pcm[pcm->device] = NULL; } -static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm) + +static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_description *desc) { snd_pcm_t *pcm; int err; - if (rpcm) *rpcm = NULL; - err = snd_pcm_new(codec->card, "ALI 5451", device, ALI_CHANNELS, 1, &pcm); + err = snd_pcm_new(codec->card, desc->name, device, + desc->playback_num, desc->capture_num, &pcm); if (err < 0) { snd_printk("snd_ali_pcm: err called snd_pcm_new.\n"); return err; @@ -1728,20 +1827,36 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm) pcm->private_data = codec; pcm->private_free = snd_ali_pcm_free; pcm->info_flags = 0; - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ali_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ali_capture_ops); + if (desc->playback_ops) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, desc->playback_ops); + if (desc->capture_ops) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, desc->capture_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(codec->pci), 64*1024, 128*1024); pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strcpy(pcm->name, "ALI 5451"); - codec->pcm = pcm; - if (rpcm) *rpcm = pcm; + strcpy(pcm->name, desc->name); + codec->pcm[0] = pcm; return 0; } +struct ali_pcm_description ali_pcms[] = { + { "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops }, + { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops } +}; + +static int __devinit snd_ali_build_pcms(ali_t *codec) +{ + int i, err; + for(i = 0 ; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms) ; i++) + if((err = snd_ali_pcm(codec, i, &ali_pcms[i])) < 0) + return err; + return 0; +} + + #define ALI5451_SPDIF(xname, xindex, value) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ .info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \ @@ -1860,14 +1975,14 @@ static void snd_ali_mixer_free_ac97_bus(ac97_bus_t *bus) static void snd_ali_mixer_free_ac97(ac97_t *ac97) { ali_t *codec = ac97->private_data; - codec->ac97 = NULL; + codec->ac97[ac97->num] = NULL; } static int __devinit snd_ali_mixer(ali_t * codec) { ac97_template_t ac97; unsigned int idx; - int err; + int i, err; static ac97_bus_ops_t ops = { .write = snd_ali_codec_write, .read = snd_ali_codec_read, @@ -1880,10 +1995,16 @@ static int __devinit snd_ali_mixer(ali_t * codec) memset(&ac97, 0, sizeof(ac97)); ac97.private_data = codec; ac97.private_free = snd_ali_mixer_free_ac97; - if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97)) < 0) { - snd_printk("ali mixer creating error.\n"); + + for ( i = 0 ; i < codec->num_of_codecs ; i++) { + ac97.num = i; + if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i])) < 0) { + snd_printk("ali mixer %d creating error.\n", i); + if(i == 0) return err; } + } + if (codec->spdif_support) { for(idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) { err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec)); @@ -1904,8 +2025,12 @@ static int ali_suspend(snd_card_t *card, pm_message_t state) if (! im) return 0; - snd_pcm_suspend_all(chip->pcm); - snd_ac97_suspend(chip->ac97); + for(i = 0 ; i < chip->num_of_codecs ; i++) { + if (chip->pcm[i]) + snd_pcm_suspend_all(chip->pcm[i]); + if(chip->ac97[i]) + snd_ac97_suspend(chip->ac97[i]); + } spin_lock_irq(&chip->reg_lock); @@ -1969,7 +2094,9 @@ static int ali_resume(snd_card_t *card) spin_unlock_irq(&chip->reg_lock); - snd_ac97_resume(chip->ac97); + for(i = 0 ; i < chip->num_of_codecs ; i++) + if(chip->ac97[i]) + snd_ac97_resume(chip->ac97[i]); return 0; } @@ -2036,11 +2163,37 @@ static int snd_ali_chip_init(ali_t *codec) codec->spdif_mask = 0x00000002; } + codec->num_of_codecs = 1; + + /* secondary codec - modem */ + if (inl(ALI_REG(codec, ALI_SCTRL)) & ALI_SCTRL_CODEC2_READY) { + codec->num_of_codecs++; + outl(inl(ALI_REG(codec, ALI_SCTRL)) | + (ALI_SCTRL_LINE_IN2|ALI_SCTRL_GPIO_IN2|ALI_SCTRL_LINE_OUT_EN), + ALI_REG(codec, ALI_SCTRL)); + } + snd_ali_printk("chip initialize succeed.\n"); return 0; } +/* proc for register dump */ +static void snd_ali_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buf) +{ + ali_t *codec = entry->private_data; + int i; + for(i = 0 ; i < 256 ; i+= 4) + snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i))); +} + +static void __devinit snd_ali_proc_init(ali_t *codec) +{ + snd_info_entry_t *entry; + if(!snd_card_proc_new(codec->card, "ali5451", &entry)) + snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read); +} + static int __devinit snd_ali_resources(ali_t *codec) { int err; @@ -2233,11 +2386,13 @@ static int __devinit snd_ali_probe(struct pci_dev *pci, } snd_ali_printk("pcm building ...\n"); - if ((err = snd_ali_pcm(codec, 0, NULL)) < 0) { + if ((err = snd_ali_build_pcms(codec)) < 0) { snd_card_free(card); return err; } + snd_ali_proc_init(codec); + strcpy(card->driver, "ALI5451"); strcpy(card->shortname, "ALI 5451"); -- cgit v1.2.3-70-g09d2 From 745cac56ba6b0222d97a4bf0e347149f20518bf1 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 30 May 2005 11:49:05 +0200 Subject: [ALSA] via82xx - added 0x1071/0x8399 to while list VIA82xx driver - 0x1071, 0x8399 == VIA_DXS_ENABLE - Umax AB 595T (VIA K8N800A - VT8237) - reporter: Honza Machacek Signed-off-by: Jaroslav Kysela --- sound/pci/via82xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index bb322de4777..4c47fc83797 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2161,6 +2161,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ { .vendor = 0x1043, .device = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ + { .vendor = 0x1071, .device = 0x8399, .action = VIA_DXS_ENABLE }, /* Umax AB 595T (VIA K8N800A - VT8237) */ { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ -- cgit v1.2.3-70-g09d2 From 69ad07cf98d0ef65cac67bac2ea4381bb499bea8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 30 May 2005 14:48:16 +0200 Subject: [ALSA] AC97 - renamed vendor/device to subvendor/subdevice where appropriate AC97 Codec,ATIIXP driver,VIA82xx driver To avoid confusion, the structure members vendor/device were renamed to subvendor/subdevice, because we compare them with PCI subsystem vendor and subsystem device. Signed-off-by: Jaroslav Kysela --- include/sound/ac97_codec.h | 4 +- sound/pci/ac97/ac97_codec.c | 8 +-- sound/pci/atiixp.c | 4 +- sound/pci/via82xx.c | 118 ++++++++++++++++++++++---------------------- 4 files changed, 67 insertions(+), 67 deletions(-) (limited to 'sound/pci') diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 996eeab683b..1309c12b8f7 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -573,8 +573,8 @@ enum { }; struct ac97_quirk { - unsigned short vendor; /* PCI vendor id */ - unsigned short device; /* PCI device id */ + unsigned short subvendor; /* PCI subsystem vendor id */ + unsigned short subdevice; /* PCI sybsystem device id */ unsigned short mask; /* device id bit mask, 0 = accept all */ unsigned int codec_id; /* codec id (if any), 0 = accept all */ const char *name; /* name shown as info */ diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 996fcfb0953..a4b72cd2eea 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -2542,11 +2542,11 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o return result; } - for (; quirk->vendor; quirk++) { - if (quirk->vendor != ac97->subsystem_vendor) + for (; quirk->subvendor; quirk++) { + if (quirk->subvendor != ac97->subsystem_vendor) continue; - if ((! quirk->mask && quirk->device == ac97->subsystem_device) || - quirk->device == (quirk->mask & ac97->subsystem_device)) { + if ((! quirk->mask && quirk->subdevice == ac97->subsystem_device) || + quirk->subdevice == (quirk->mask & ac97->subsystem_device)) { if (quirk->codec_id && quirk->codec_id != ac97->id) continue; snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device); diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 06551a69fb4..cafab4af5c5 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1334,8 +1334,8 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *r static struct ac97_quirk ac97_quirks[] __devinitdata = { { - .vendor = 0x103c, - .device = 0x006b, + .subvendor = 0x103c, + .subdevice = 0x006b, .name = "HP Pavilion ZV5030US", .type = AC97_TUNE_MUTE_LED }, diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 4c47fc83797..52d1074f869 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1560,51 +1560,51 @@ static void snd_via82xx_mixer_free_ac97(ac97_t *ac97) static struct ac97_quirk ac97_quirks[] = { { - .vendor = 0x1106, - .device = 0x4161, + .subvendor = 0x1106, + .subdevice = 0x4161, .codec_id = 0x56494161, /* VT1612A */ .name = "Soltek SL-75DRV5", .type = AC97_TUNE_NONE }, { /* FIXME: which codec? */ - .vendor = 0x1106, - .device = 0x4161, + .subvendor = 0x1106, + .subdevice = 0x4161, .name = "ASRock K7VT2", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1019, - .device = 0x0a81, + .subvendor = 0x1019, + .subdevice = 0x0a81, .name = "ECS K7VTA3", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1019, - .device = 0x0a85, + .subvendor = 0x1019, + .subdevice = 0x0a85, .name = "ECS L7VMM2", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1849, - .device = 0x3059, + .subvendor = 0x1849, + .subdevice = 0x3059, .name = "ASRock K7VM2", .type = AC97_TUNE_HP_ONLY /* VT1616 */ }, { - .vendor = 0x14cd, - .device = 0x7002, + .subvendor = 0x14cd, + .subdevice = 0x7002, .name = "Unknown", .type = AC97_TUNE_ALC_JACK }, { - .vendor = 0x1071, - .device = 0x8590, + .subvendor = 0x1071, + .subdevice = 0x8590, .name = "Mitac Mobo", .type = AC97_TUNE_ALC_JACK }, { - .vendor = 0x161f, - .device = 0x202b, + .subvendor = 0x161f, + .subdevice = 0x202b, .name = "Arima Notebook", .type = AC97_TUNE_HP_ONLY, }, @@ -2142,8 +2142,8 @@ static struct via823x_info via823x_cards[] __devinitdata = { * auto detection of DXS channel supports. */ struct dxs_whitelist { - unsigned short vendor; - unsigned short device; + unsigned short subvendor; + unsigned short subdevice; unsigned short mask; short action; /* new dxs_support value */ }; @@ -2151,43 +2151,43 @@ struct dxs_whitelist { static int __devinit check_dxs_list(struct pci_dev *pci) { static struct dxs_whitelist whitelist[] = { - { .vendor = 0x1005, .device = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ - { .vendor = 0x1019, .device = 0x0996, .action = VIA_DXS_48K }, - { .vendor = 0x1019, .device = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */ - { .vendor = 0x1019, .device = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */ - { .vendor = 0x1025, .device = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */ - { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ - { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ - { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ - { .vendor = 0x1043, .device = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ - { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ - { .vendor = 0x1071, .device = 0x8399, .action = VIA_DXS_ENABLE }, /* Umax AB 595T (VIA K8N800A - VT8237) */ - { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ - { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ - { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ - { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ - { .vendor = 0x1106, .device = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ - { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ - { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ - { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ - { .vendor = 0x1462, .device = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ - { .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ - { .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ - { .vendor = 0x1462, .device = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ - { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ - { .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ - { .vendor = 0x147b, .device = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */ - { .vendor = 0x147b, .device = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ - { .vendor = 0x147b, .device = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ - { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ - { .vendor = 0x14ff, .device = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */ - { .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ - { .vendor = 0x1584, .device = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ - { .vendor = 0x161f, .device = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ - { .vendor = 0x161f, .device = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */ - { .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ - { .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ - { .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ + { .subvendor = 0x1005, .subdevice = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ + { .subvendor = 0x1019, .subdevice = 0x0996, .action = VIA_DXS_48K }, + { .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */ + { .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */ + { .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */ + { .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ + { .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ + { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ + { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ + { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ + { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_ENABLE }, /* Umax AB 595T (VIA K8N800A - VT8237) */ + { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ + { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ + { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ + { .subvendor = 0x1106, .subdevice = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ + { .subvendor = 0x1106, .subdevice = 0xc001, .action = VIA_DXS_SRC }, /* Insight P4-ITX */ + { .subvendor = 0x1297, .subdevice = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ + { .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ + { .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ + { .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */ + { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ + { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ + { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ + { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ + { .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ + { .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */ + { .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */ + { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ + { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ + { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */ + { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ + { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ + { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ + { .subvendor = 0x161f, .subdevice = 0x2032, .action = VIA_DXS_48K }, /* m680x machines */ + { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ + { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ + { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ { } /* terminator */ }; struct dxs_whitelist *w; @@ -2197,14 +2197,14 @@ static int __devinit check_dxs_list(struct pci_dev *pci) pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); - for (w = whitelist; w->vendor; w++) { - if (w->vendor != subsystem_vendor) + for (w = whitelist; w->subvendor; w++) { + if (w->subvendor != subsystem_vendor) continue; if (w->mask) { - if ((w->mask & subsystem_device) == w->device) + if ((w->mask & subsystem_device) == w->subdevice) return w->action; } else { - if (subsystem_device == w->device) + if (subsystem_device == w->subdevice) return w->action; } } -- cgit v1.2.3-70-g09d2 From 6fd8b87f0e1e5de436ba020bd5806fe9ad738269 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Mon, 30 May 2005 17:20:19 +0200 Subject: [ALSA] AC97 - renamed vendor/device to subvendor/subdevice where appropriate Intel8x0 driver To avoid confusion, the structure members vendor/device were renamed to subvendor/subdevice, because we compare them with PCI subsystem vendor and subsystem device. Signed-off-by: James Courtier-Dutton --- sound/pci/intel8x0.c | 148 +++++++++++++++++++++++++-------------------------- 1 file changed, 74 insertions(+), 74 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 9c5710daed5..53fa5d8d0c4 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1725,229 +1725,229 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { static struct ac97_quirk ac97_quirks[] __devinitdata = { { - .vendor = 0x0e11, - .device = 0x008a, + .subvendor = 0x0e11, + .subdevice = 0x008a, .name = "Compaq Evo W4000", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x0e11, - .device = 0x00b8, + .subvendor = 0x0e11, + .subdevice = 0x00b8, .name = "Compaq Evo D510C", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x0e11, - .device = 0x0860, + .subvendor = 0x0e11, + .subdevice = 0x0860, .name = "HP/Compaq nx7010", .type = AC97_TUNE_MUTE_LED }, { - .vendor = 0x1014, - .device = 0x1f00, + .subvendor = 0x1014, + .subdevice = 0x1f00, .name = "MS-9128", .type = AC97_TUNE_ALC_JACK }, { - .vendor = 0x1028, - .device = 0x00d8, + .subvendor = 0x1028, + .subdevice = 0x00d8, .name = "Dell Precision 530", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x010d, + .subvendor = 0x1028, + .subdevice = 0x010d, .name = "Dell", /* which model? AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x0126, + .subvendor = 0x1028, + .subdevice = 0x0126, .name = "Dell Optiplex GX260", /* AD1981A */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x012c, + .subvendor = 0x1028, + .subdevice = 0x012c, .name = "Dell Precision 650", /* AD1981A */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x012d, + .subvendor = 0x1028, + .subdevice = 0x012d, .name = "Dell Precision 450", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x0147, + .subvendor = 0x1028, + .subdevice = 0x0147, .name = "Dell", /* which model? AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x0163, + .subvendor = 0x1028, + .subdevice = 0x0163, .name = "Dell Unknown", /* STAC9750/51 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x006d, + .subvendor = 0x103c, + .subdevice = 0x006d, .name = "HP zv5000", .type = AC97_TUNE_MUTE_LED /*AD1981B*/ }, { /* FIXME: which codec? */ - .vendor = 0x103c, - .device = 0x00c3, + .subvendor = 0x103c, + .subdevice = 0x00c3, .name = "HP xw6000", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x088c, + .subvendor = 0x103c, + .subdevice = 0x088c, .name = "HP nc8000", .type = AC97_TUNE_MUTE_LED }, { - .vendor = 0x103c, - .device = 0x0890, + .subvendor = 0x103c, + .subdevice = 0x0890, .name = "HP nc6000", .type = AC97_TUNE_MUTE_LED }, { - .vendor = 0x103c, - .device = 0x129d, + .subvendor = 0x103c, + .subdevice = 0x129d, .name = "HP xw8000", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x12f1, + .subvendor = 0x103c, + .subdevice = 0x12f1, .name = "HP xw8200", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x12f2, + .subvendor = 0x103c, + .subdevice = 0x12f2, .name = "HP xw6200", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x3008, + .subvendor = 0x103c, + .subdevice = 0x3008, .name = "HP xw4200", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x104d, - .device = 0x8197, + .subvendor = 0x104d, + .subdevice = 0x8197, .name = "Sony S1XP", .type = AC97_TUNE_INV_EAPD }, { - .vendor = 0x1043, - .device = 0x80f3, + .subvendor = 0x1043, + .subdevice = 0x80f3, .name = "ASUS ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x10cf, - .device = 0x11c3, + .subvendor = 0x10cf, + .subdevice = 0x11c3, .name = "Fujitsu-Siemens E4010", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x10cf, - .device = 0x1253, + .subvendor = 0x10cf, + .subdevice = 0x1253, .name = "Fujitsu S6210", /* STAC9750/51 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x10f1, - .device = 0x2665, + .subvendor = 0x10f1, + .subdevice = 0x2665, .name = "Fujitsu-Siemens Celsius", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x10f1, - .device = 0x2885, + .subvendor = 0x10f1, + .subdevice = 0x2885, .name = "AMD64 Mobo", /* ALC650 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x110a, - .device = 0x0056, + .subvendor = 0x110a, + .subdevice = 0x0056, .name = "Fujitsu-Siemens Scenic", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x11d4, - .device = 0x5375, + .subvendor = 0x11d4, + .subdevice = 0x5375, .name = "ADI AD1985 (discrete)", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1462, - .device = 0x5470, + .subvendor = 0x1462, + .subdevice = 0x5470, .name = "MSI P4 ATX 645 Ultra", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1734, - .device = 0x0088, + .subvendor = 0x1734, + .subdevice = 0x0088, .name = "Fujitsu-Siemens D1522", /* AD1981 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x2000, + .subvendor = 0x8086, + .subdevice = 0x2000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0x4000, + .subvendor = 0x8086, + .subdevice = 0x4000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0x4856, + .subvendor = 0x8086, + .subdevice = 0x4856, .name = "Intel D845WN (82801BA)", .type = AC97_TUNE_SWAP_HP }, { - .vendor = 0x8086, - .device = 0x4d44, + .subvendor = 0x8086, + .subdevice = 0x4d44, .name = "Intel D850EMV2", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x4d56, + .subvendor = 0x8086, + .subdevice = 0x4d56, .name = "Intel ICH/AD1885", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x6000, + .subvendor = 0x8086, + .subdevice = 0x6000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0xe000, + .subvendor = 0x8086, + .subdevice = 0xe000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, #if 0 /* FIXME: this seems wrong on most boards */ { - .vendor = 0x8086, - .device = 0xa000, + .subvendor = 0x8086, + .subdevice = 0xa000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_HP_ONLY -- cgit v1.2.3-70-g09d2 From 4d572776d4dfa2d5385a2ec3acec3cc059149e13 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 30 May 2005 17:30:32 +0200 Subject: [ALSA] Remove redundant NULL checks before kfree Timer Midlevel,ALSA sequencer,ALSA<-OSS sequencer,Digigram VX core I2C tea6330t,GUS Library,VIA82xx driver,VIA82xx-modem driver CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,YMFPCI driver Digigram VX Pocket driver,Common EMU synth,USB generic driver,USB USX2Y Checking a pointer for NULL before calling kfree() on it is redundant, kfree() deals with NULL pointers just fine. This patch removes such checks from sound/ This patch also makes another, but closely related, change. It avoids casting pointers about to be kfree()'ed. Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_synth.c | 24 ++++++++---------------- sound/core/seq/seq_dummy.c | 5 +---- sound/core/timer.c | 12 ++++-------- sound/drivers/vx/vx_pcm.c | 12 ++++-------- sound/i2c/tea6330t.c | 3 +-- sound/isa/gus/gus_pcm.c | 3 +-- sound/pci/ca0106/ca0106_main.c | 6 +----- sound/pci/cs46xx/cs46xx_lib.c | 3 +-- sound/pci/emu10k1/emu10k1x.c | 5 +---- sound/pci/emu10k1/emupcm.c | 4 +--- sound/pci/via82xx.c | 6 ++---- sound/pci/via82xx_modem.c | 6 ++---- sound/pci/ymfpci/ymfpci_main.c | 4 +--- sound/pcmcia/vx/vx_entry.c | 3 +-- sound/synth/emux/emux_effect.c | 6 ++---- sound/usb/usbaudio.c | 12 ++++-------- sound/usb/usbmixer.c | 6 ++---- sound/usb/usx2y/usbusx2yaudio.c | 6 ++---- 18 files changed, 39 insertions(+), 87 deletions(-) (limited to 'sound/pci') diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 638cc148706..1a7736cbf3a 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -325,14 +325,10 @@ snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp) } snd_use_lock_free(&rec->use_lock); } - if (info->sysex) { - kfree(info->sysex); - info->sysex = NULL; - } - if (info->ch) { - kfree(info->ch); - info->ch = NULL; - } + kfree(info->sysex); + info->sysex = NULL; + kfree(info->ch); + info->ch = NULL; } dp->synth_opened = 0; dp->max_synthdev = 0; @@ -418,14 +414,10 @@ snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev) dp->file_mode) < 0) { midi_synth_dev.opened--; info->opened = 0; - if (info->sysex) { - kfree(info->sysex); - info->sysex = NULL; - } - if (info->ch) { - kfree(info->ch); - info->ch = NULL; - } + kfree(info->sysex); + info->sysex = NULL; + kfree(info->ch); + info->ch = NULL; } return; } diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index e88967c5b93..ea945a5d2a0 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -140,10 +140,7 @@ dummy_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int static void dummy_free(void *private_data) { - snd_seq_dummy_port_t *p; - - p = private_data; - kfree(p); + kfree(private_data); } /* diff --git a/sound/core/timer.c b/sound/core/timer.c index d67a5e91a10..b498e5482d7 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1469,14 +1469,10 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) goto __err; - if (tu->queue) { - kfree(tu->queue); - tu->queue = NULL; - } - if (tu->tqueue) { - kfree(tu->tqueue); - tu->tqueue = NULL; - } + kfree(tu->queue); + tu->queue = NULL; + kfree(tu->tqueue); + tu->tqueue = NULL; if (tu->tread) { tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); if (tu->tqueue == NULL) diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 98587176b32..af381b15fe5 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -1264,14 +1264,10 @@ static void snd_vx_pcm_free(snd_pcm_t *pcm) { vx_core_t *chip = pcm->private_data; chip->pcm[pcm->device] = NULL; - if (chip->playback_pipes) { - kfree(chip->playback_pipes); - chip->playback_pipes = NULL; - } - if (chip->capture_pipes) { - kfree(chip->capture_pipes); - chip->capture_pipes = NULL; - } + kfree(chip->playback_pipes); + chip->playback_pipes = NULL; + kfree(chip->capture_pipes); + chip->capture_pipes = NULL; } /* diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index bb503e70b66..2da8d7f157f 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c @@ -266,8 +266,7 @@ TEA6330T_TREBLE("Tone Control - Treble", 0) static void snd_tea6330_free(snd_i2c_device_t *device) { - tea6330t_t *tea = device->private_data; - kfree(tea); + kfree(device->private_data); } int snd_tea6330t_update_mixer(snd_card_t * card, diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 8995ad9c516..b75066ab46f 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -656,8 +656,7 @@ static snd_pcm_hardware_t snd_gf1_pcm_capture = static void snd_gf1_pcm_playback_free(snd_pcm_runtime_t *runtime) { - gus_pcm_private_t * pcmp = runtime->private_data; - kfree(pcmp); + kfree(runtime->private_data); } static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 85caf1bbcc1..0ec0c3ec220 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -332,11 +332,7 @@ static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime) { - ca0106_pcm_t *epcm = runtime->private_data; - - if (epcm) { - kfree(epcm); - } + kfree(runtime->private_data); } /* open_playback callback */ diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 5f2ffb7efa0..fd4c50c88bc 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1295,8 +1295,7 @@ static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime) { - cs46xx_pcm_t * cpcm = runtime->private_data; - kfree(cpcm); + kfree(runtime->private_data); } static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id) diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index f8d92335a35..e90c5ddd1d1 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -361,10 +361,7 @@ static void snd_emu10k1x_gpio_write(emu10k1x_t *emu, unsigned int value) static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime) { - emu10k1x_pcm_t *epcm = runtime->private_data; - - if (epcm) - kfree(epcm); + kfree(runtime->private_data); } static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index fd7cc389f82..520b99af5f5 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -991,9 +991,7 @@ static void snd_emu10k1_pcm_efx_mixer_notify(emu10k1_t *emu, int idx, int activa static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime) { - emu10k1_pcm_t *epcm = runtime->private_data; - - kfree(epcm); + kfree(runtime->private_data); } static int snd_emu10k1_efx_playback_close(snd_pcm_substream_t * substream) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 52d1074f869..e329e19b674 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -491,10 +491,8 @@ static int clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream, snd_dma_free_pages(&dev->table); dev->table.area = NULL; } - if (dev->idx_table) { - kfree(dev->idx_table); - dev->idx_table = NULL; - } + kfree(dev->idx_table); + dev->idx_table = NULL; return 0; } diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index e10fceb3ede..5896d289f9a 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -352,10 +352,8 @@ static int clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream, snd_dma_free_pages(&dev->table); dev->table.area = NULL; } - if (dev->idx_table) { - kfree(dev->idx_table); - dev->idx_table = NULL; - } + kfree(dev->idx_table); + dev->idx_table = NULL; return 0; } diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 997cf37cddd..2ae79610ecb 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -829,9 +829,7 @@ static snd_pcm_hardware_t snd_ymfpci_capture = static void snd_ymfpci_pcm_free_substream(snd_pcm_runtime_t *runtime) { - ymfpci_pcm_t *ypcm = runtime->private_data; - - kfree(ypcm); + kfree(runtime->private_data); } static int snd_ymfpci_playback_open_1(snd_pcm_substream_t * substream) diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c index 53d8172c52a..332bbca3dfc 100644 --- a/sound/pcmcia/vx/vx_entry.c +++ b/sound/pcmcia/vx/vx_entry.c @@ -68,8 +68,7 @@ static int snd_vxpocket_free(vx_core_t *chip) if (hw) hw->card_list[vxp->index] = NULL; chip->card = NULL; - if (chip->dev) - kfree(chip->dev); + kfree(chip->dev); snd_vx_free_firmware(chip); kfree(chip); diff --git a/sound/synth/emux/emux_effect.c b/sound/synth/emux/emux_effect.c index ec3fc1ba7fc..4764940f11a 100644 --- a/sound/synth/emux/emux_effect.c +++ b/sound/synth/emux/emux_effect.c @@ -291,10 +291,8 @@ snd_emux_create_effect(snd_emux_port_t *p) void snd_emux_delete_effect(snd_emux_port_t *p) { - if (p->effect) { - kfree(p->effect); - p->effect = NULL; - } + kfree(p->effect); + p->effect = NULL; } void diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a82412b8790..a75695045f2 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -859,10 +859,8 @@ static void release_urb_ctx(snd_urb_ctx_t *u) usb_free_urb(u->urb); u->urb = NULL; } - if (u->buf) { - kfree(u->buf); - u->buf = NULL; - } + kfree(u->buf); + u->buf = NULL; } /* @@ -880,10 +878,8 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force) release_urb_ctx(&subs->dataurb[i]); for (i = 0; i < SYNC_URBS; i++) release_urb_ctx(&subs->syncurb[i]); - if (subs->tmpbuf) { - kfree(subs->tmpbuf); - subs->tmpbuf = NULL; - } + kfree(subs->tmpbuf); + subs->tmpbuf = NULL; subs->nurbs = 0; } diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 83ba665e5c6..e73c1c9d3e7 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -623,10 +623,8 @@ static struct usb_feature_control_info audio_feature_info[] = { /* private_free callback */ static void usb_mixer_elem_free(snd_kcontrol_t *kctl) { - if (kctl->private_data) { - kfree(kctl->private_data); - kctl->private_data = NULL; - } + kfree(kctl->private_data); + kctl->private_data = NULL; } diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 4c292e09006..62dfd28b3b0 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -401,10 +401,8 @@ static void usX2Y_urbs_release(snd_usX2Y_substream_t *subs) for (i = 0; i < NRURBS; i++) usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]); - if (subs->tmpbuf) { - kfree(subs->tmpbuf); - subs->tmpbuf = NULL; - } + kfree(subs->tmpbuf); + subs->tmpbuf = NULL; } /* * initialize a substream's urbs -- cgit v1.2.3-70-g09d2 From b6a969155b04416185f368bd4e2f1d49b17c1ee1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 May 2005 18:27:03 +0200 Subject: [ALSA] Add write support to snd-page-alloc proc file Documentation,Memalloc module,RME HDSP driver,RME9652 driver Add the write support to snd-page-alloc proc file for buffer pre-allocation. Removed the pre-allocation codes via module options. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 36 ++++- sound/core/memalloc.c | 201 +++++++++++++----------- sound/pci/rme9652/hdsp.c | 14 +- sound/pci/rme9652/rme9652.c | 14 +- 4 files changed, 161 insertions(+), 104 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 226013035d7..812ed2b80b8 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -671,7 +671,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. module did formerly. It will allocate the buffers in advance when any HDSP cards are found. To make the buffer allocation sure, load snd-page-alloc module in the early - stage of boot sequence. + stage of boot sequence. See "Early Buffer Allocation" + section. Module snd-ice1712 ------------------ @@ -1067,7 +1068,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. module did formerly. It will allocate the buffers in advance when any RME9652 cards are found. To make the buffer allocation sure, load snd-page-alloc module in the early - stage of boot sequence. + stage of boot sequence. See "Early Buffer Allocation" + section. Module snd-sa11xx-uda1341 (on arm only) --------------------------------------- @@ -1545,6 +1547,36 @@ Proc interfaces (/proc/asound) echo "rvplayer 0 0 block" > /proc/asound/card0/pcm0p/oss +Early Buffer Allocation +======================= + +Some drivers (e.g. hdsp) require the large contiguous buffers, and +sometimes it's too late to find such spaces when the driver module is +actually loaded due to memory fragmentation. You can pre-allocate the +PCM buffers by loading snd-page-alloc module and write commands to its +proc file in prior, for example, in the early boot stage like +/etc/init.d/*.local scripts. + +Reading the proc file /proc/drivers/snd-page-alloc shows the current +usage of page allocation. In writing, you can send the following +commands to the snd-page-alloc driver: + + - add VENDOR DEVICE MASK SIZE BUFFERS + + VENDOR and DEVICE are PCI vendor and device IDs. They take + integer numbers (0x prefix is needed for the hex). + MASK is the PCI DMA mask. Pass 0 if not restricted. + SIZE is the size of each buffer to allocate. You can pass + k and m suffix for KB and MB. The max number is 16MB. + BUFFERS is the number of buffers to allocate. It must be greater + than 0. The max number is 4. + + - erase + + This will erase the all pre-allocated buffers which are not in + use. + + Links ===== diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 344a83fd7c2..dbc23e35fa0 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -46,13 +47,6 @@ MODULE_LICENSE("GPL"); #define SNDRV_CARDS 8 #endif -/* FIXME: so far only some PCI devices have the preallocation table */ -#ifdef CONFIG_PCI -static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); -#endif - /* */ @@ -451,9 +445,13 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) list_for_each(p, &mem_list_head) { mem = list_entry(p, struct snd_mem_list, list); if (mem->id == id && - ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) { + (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL || + ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) { + struct device *dev = dmab->dev.dev; list_del(p); *dmab = mem->buffer; + if (dmab->dev.dev == NULL) + dmab->dev.dev = dev; kfree(mem); up(&list_mutex); return dmab->bytes; @@ -508,91 +506,13 @@ static void free_all_reserved_pages(void) } - -/* - * allocation of buffers for pre-defined devices - */ - -#ifdef CONFIG_PCI -/* FIXME: for pci only - other bus? */ -struct prealloc_dev { - unsigned short vendor; - unsigned short device; - unsigned long dma_mask; - unsigned int size; - unsigned int buffers; -}; - -#define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000) - -static struct prealloc_dev prealloc_devices[] __initdata = { - { - /* hammerfall */ - .vendor = 0x10ee, - .device = 0x3fc4, - .dma_mask = 0xffffffff, - .size = HAMMERFALL_BUFFER_SIZE, - .buffers = 2 - }, - { - /* HDSP */ - .vendor = 0x10ee, - .device = 0x3fc5, - .dma_mask = 0xffffffff, - .size = HAMMERFALL_BUFFER_SIZE, - .buffers = 2 - }, - { }, /* terminator */ -}; - -static void __init preallocate_cards(void) -{ - struct pci_dev *pci = NULL; - int card; - - card = 0; - - while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { - struct prealloc_dev *dev; - unsigned int i; - if (card >= SNDRV_CARDS) - break; - for (dev = prealloc_devices; dev->vendor; dev++) { - if (dev->vendor == pci->vendor && dev->device == pci->device) - break; - } - if (! dev->vendor) - continue; - if (! enable[card++]) { - printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device); - continue; - } - - if (pci_set_dma_mask(pci, dev->dma_mask) < 0 || - pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) { - printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device); - continue; - } - for (i = 0; i < dev->buffers; i++) { - struct snd_dma_buffer dmab; - memset(&dmab, 0, sizeof(dmab)); - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - dev->size, &dmab) < 0) - printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size); - else - snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); - } - } -} -#else -#define preallocate_cards() /* NOP */ -#endif - - #ifdef CONFIG_PROC_FS /* * proc file interface */ +#define SND_MEM_PROC_FILE "driver/snd-page-alloc" +struct proc_dir_entry *snd_mem_proc; + static int snd_mem_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -621,6 +541,97 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, up(&list_mutex); return len; } + +/* FIXME: for pci only - other bus? */ +#ifdef CONFIG_PCI +#define gettoken(bufp) strsep(bufp, " \t\n") + +static int snd_mem_proc_write(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + char buf[128]; + char *token, *p; + + if (count > ARRAY_SIZE(buf) - 1) + count = ARRAY_SIZE(buf) - 1; + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + buf[ARRAY_SIZE(buf) - 1] = '\0'; + + p = buf; + token = gettoken(&p); + if (! token || *token == '#') + return (int)count; + if (strcmp(token, "add") == 0) { + char *endp; + int vendor, device, size, buffers; + long mask; + int i, alloced; + struct pci_dev *pci; + + if ((token = gettoken(&p)) == NULL || + (vendor = simple_strtol(token, NULL, 0)) <= 0 || + (token = gettoken(&p)) == NULL || + (device = simple_strtol(token, NULL, 0)) <= 0 || + (token = gettoken(&p)) == NULL || + (mask = simple_strtol(token, NULL, 0)) < 0 || + (token = gettoken(&p)) == NULL || + (size = memparse(token, &endp)) < 64*1024 || + size > 16*1024*1024 /* too big */ || + (token = gettoken(&p)) == NULL || + (buffers = simple_strtol(token, NULL, 0)) <= 0 || + buffers > 4) { + printk(KERN_ERR "snd-page-alloc: invalid proc write format\n"); + return (int)count; + } + vendor &= 0xffff; + device &= 0xffff; + + alloced = 0; + pci = NULL; + while ((pci = pci_find_device(vendor, device, pci)) != NULL) { + if (mask > 0 && mask < 0xffffffff) { + if (pci_set_dma_mask(pci, mask) < 0 || + pci_set_consistent_dma_mask(pci, mask) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); + return (int)count; + } + } + for (i = 0; i < buffers; i++) { + struct snd_dma_buffer dmab; + memset(&dmab, 0, sizeof(dmab)); + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + size, &dmab) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); + return (int)count; + } + snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); + } + alloced++; + } + if (! alloced) { + for (i = 0; i < buffers; i++) { + struct snd_dma_buffer dmab; + memset(&dmab, 0, sizeof(dmab)); + /* FIXME: We can allocate only in ZONE_DMA + * without a device pointer! + */ + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL, + size, &dmab) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); + break; + } + snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device)); + } + } + } else if (strcmp(token, "erase") == 0) + /* FIXME: need for releasing each buffer chunk? */ + free_all_reserved_pages(); + else + printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n"); + return (int)count; +} +#endif /* CONFIG_PCI */ #endif /* CONFIG_PROC_FS */ /* @@ -630,15 +641,21 @@ static int snd_mem_proc_read(char *page, char **start, off_t off, static int __init snd_mem_init(void) { #ifdef CONFIG_PROC_FS - create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL); + snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL); + if (snd_mem_proc) { + snd_mem_proc->read_proc = snd_mem_proc_read; +#ifdef CONFIG_PCI + snd_mem_proc->write_proc = snd_mem_proc_write; +#endif + } #endif - preallocate_cards(); return 0; } static void __exit snd_mem_exit(void) { - remove_proc_entry("driver/snd-page-alloc", NULL); + if (snd_mem_proc) + remove_proc_entry(SND_MEM_PROC_FILE, NULL); free_all_reserved_pages(); if (snd_allocated_pages > 0) printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index b35ed5f0c04..a673cc438b9 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -559,18 +559,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); - if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - size, dmab) < 0) - return -ENOMEM; + if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { + if (dmab->bytes >= size) + return 0; } + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + size, dmab) < 0) + return -ENOMEM; return 0; } static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) { - if (dmab->area) + if (dmab->area) { + dmab->dev.dev = NULL; /* make it anonymous */ snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); + } } diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 5861f234af2..f3037402d58 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -303,18 +303,22 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); - if (! snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - size, dmab) < 0) - return -ENOMEM; + if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { + if (dmab->bytes >= size) + return 0; } + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + size, dmab) < 0) + return -ENOMEM; return 0; } static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) { - if (dmab->area) + if (dmab->area) { + dmab->dev.dev = NULL; /* make it anonymous */ snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); + } } -- cgit v1.2.3-70-g09d2 From ce43fbaececc82196d321671159483b3287de128 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 May 2005 20:33:44 +0200 Subject: [ALSA] hda-intel - Fix Oops in the error path HDA Intel driver Fixed Oops in the error path from probe function of snd-hda-intel driver. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f05a6384b9c..0d546addc09 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -286,6 +286,7 @@ struct snd_azx { /* flags */ int position_fix; + unsigned int initialized: 1; }; /* @@ -1235,7 +1236,7 @@ static int azx_resume(snd_card_t *card) */ static int azx_free(azx_t *chip) { - if (chip->remap_addr) { + if (chip->initialized) { int i; for (i = 0; i < MAX_ICH6_DEV; i++) @@ -1361,6 +1362,8 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, /* initialize chip */ azx_init_chip(chip); + chip->initialized = 1; + /* codec detection */ if (! chip->codec_mask) { snd_printk(KERN_ERR SFX "no codecs found!\n"); -- cgit v1.2.3-70-g09d2 From 98c7f2121d4263867710df3b5124980e25261188 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 May 2005 16:52:58 +0200 Subject: [ALSA] Add FSC T3010 quirk Intel8x0 driver Added ac97_quirk for FSC T3010. Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 53fa5d8d0c4..cc16f95f9ce 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1856,6 +1856,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "Fujitsu-Siemens E4010", .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x10cf, + .subdevice = 0x1225, + .name = "Fujitsu-Siemens T3010", + .type = AC97_TUNE_HP_ONLY + }, { .subvendor = 0x10cf, .subdevice = 0x1253, -- cgit v1.2.3-70-g09d2 From 763f356cd8de9e158836d236b3fd9dd149d696f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 3 Jun 2005 11:25:34 +0200 Subject: [ALSA] Add HDSP MADI driver HDSPM driver,PCI drivers,RME9652 driver Added RME Hammerfall DSP MADI driver by Winfried Ritsch. (Moved from alsa-driver tree to mainline.) Signed-off-by: Takashi Iwai --- include/sound/hdspm.h | 131 ++ sound/pci/Kconfig | 13 + sound/pci/rme9652/Makefile | 2 + sound/pci/rme9652/hdspm.c | 3671 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 3817 insertions(+) create mode 100644 include/sound/hdspm.h create mode 100644 sound/pci/rme9652/hdspm.c (limited to 'sound/pci') diff --git a/include/sound/hdspm.h b/include/sound/hdspm.h new file mode 100644 index 00000000000..c34427ccd0b --- /dev/null +++ b/include/sound/hdspm.h @@ -0,0 +1,131 @@ +#ifndef __SOUND_HDSPM_H /* -*- linux-c -*- */ +#define __SOUND_HDSPM_H +/* + * Copyright (C) 2003 Winfried Ritsch (IEM) + * based on hdsp.h from Thomas Charbonnel (thomas@undata.org) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */ +#define HDSPM_MAX_CHANNELS 64 + +/* -------------------- IOCTL Peak/RMS Meters -------------------- */ + +typedef struct _snd_hdspm_peak_rms hdspm_peak_rms_t; + +/* peam rms level structure like we get from hardware + + maybe in future we can memory map it so I just copy it + to user on ioctl call now an dont change anything + rms are made out of low and high values + where (long) ????_rms = (????_rms_l >> 8) + ((????_rms_h & 0xFFFFFF00)<<24) + (i asume so from the code) +*/ + +struct _snd_hdspm_peak_rms { + + unsigned int level_offset[1024]; + + unsigned int input_peak[64]; + unsigned int playback_peak[64]; + unsigned int output_peak[64]; + unsigned int xxx_peak[64]; /* not used */ + + unsigned int reserved[256]; /* not used */ + + unsigned int input_rms_l[64]; + unsigned int playback_rms_l[64]; + unsigned int output_rms_l[64]; + unsigned int xxx_rms_l[64]; /* not used */ + + unsigned int input_rms_h[64]; + unsigned int playback_rms_h[64]; + unsigned int output_rms_h[64]; + unsigned int xxx_rms_h[64]; /* not used */ +}; + +struct sndrv_hdspm_peak_rms_ioctl { + hdspm_peak_rms_t *peak; +}; + +/* use indirect access due to the limit of ioctl bit size */ +#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, struct sndrv_hdspm_peak_rms_ioctl) + +/* ------------ CONFIG block IOCTL ---------------------- */ + +typedef struct _snd_hdspm_config_info hdspm_config_info_t; + +struct _snd_hdspm_config_info { + unsigned char pref_sync_ref; + unsigned char wordclock_sync_check; + unsigned char madi_sync_check; + unsigned int system_sample_rate; + unsigned int autosync_sample_rate; + unsigned char system_clock_mode; + unsigned char clock_source; + unsigned char autosync_ref; + unsigned char line_out; + unsigned int passthru; + unsigned int analog_out; +}; + +#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdspm_config_info_t) + + +/* get Soundcard Version */ + +typedef struct _snd_hdspm_version hdspm_version_t; + +struct _snd_hdspm_version { + unsigned short firmware_rev; +}; + +#define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x43, hdspm_version_t) + + +/* ------------- get Matrix Mixer IOCTL --------------- */ + +/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = 32768 Bytes */ + +/* organisation is 64 channelfader in a continous memory block */ +/* equivalent to hardware definition, maybe for future feature of mmap of them */ +/* each of 64 outputs has 64 infader and 64 outfader: + Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */ + +#define HDSPM_MIXER_CHANNELS HDSPM_MAX_CHANNELS + +typedef struct _snd_hdspm_channelfader snd_hdspm_channelfader_t; + +struct _snd_hdspm_channelfader { + unsigned int in[HDSPM_MIXER_CHANNELS]; + unsigned int pb[HDSPM_MIXER_CHANNELS]; +}; + +typedef struct _snd_hdspm_mixer hdspm_mixer_t; + +struct _snd_hdspm_mixer { + snd_hdspm_channelfader_t ch[HDSPM_MIXER_CHANNELS]; +}; + +struct sndrv_hdspm_mixer_ioctl { + hdspm_mixer_t *mixer; +}; + +/* use indirect access due to the limit of ioctl bit size */ +#define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct sndrv_hdspm_mixer_ioctl) + +#endif /* __SOUND_HDSPM_H */ diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 428efdbd70a..6d7a00f34d8 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -274,6 +274,19 @@ config SND_HDSP To compile this driver as a module, choose M here: the module will be called snd-hdsp. +config SND_HDSPM + tristate "RME Hammerfall DSP MADI" + depends on SND + select SND_HWDEP + select SND_RAWMIDI + select SND_PCM + help + Say Y here to include support for RME Hammerfall DSP MADI + soundcards. + + To compile this driver as a module, choose M here: the module + will be called snd-hdspm. + config SND_TRIDENT tristate "Trident 4D-Wave DX/NX; SiS 7018" depends on SND diff --git a/sound/pci/rme9652/Makefile b/sound/pci/rme9652/Makefile index 917374c9cd4..d2c294e136f 100644 --- a/sound/pci/rme9652/Makefile +++ b/sound/pci/rme9652/Makefile @@ -5,7 +5,9 @@ snd-rme9652-objs := rme9652.o snd-hdsp-objs := hdsp.o +snd-hdspm-objs := hdspm.o # Toplevel Module Dependency obj-$(CONFIG_SND_RME9652) += snd-rme9652.o obj-$(CONFIG_SND_HDSP) += snd-hdsp.o +obj-$(CONFIG_SND_HDSPM) +=snd-hdspm.o diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c new file mode 100644 index 00000000000..9e86d0eb41c --- /dev/null +++ b/sound/pci/rme9652/hdspm.c @@ -0,0 +1,3671 @@ +/* -*- linux-c -*- + * + * ALSA driver for RME Hammerfall DSP MADI audio interface(s) + * + * Copyright (c) 2003 Winfried Ritsch (IEM) + * code based on hdsp.c Paul Davis + * Marcus Andersson + * Thomas Charbonnel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ + +/* Disable precise pointer at start */ +static int precise_ptr[SNDRV_CARDS]; + +/* Send all playback to line outs */ +static int line_outs_monitor[SNDRV_CARDS]; + +/* Enable Analog Outs on Channel 63/64 by default */ +static int enable_monitor[SNDRV_CARDS]; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for RME HDSPM interface."); + +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for RME HDSPM interface."); + +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards."); + +module_param_array(precise_ptr, bool, NULL, 0444); +MODULE_PARM_DESC(precise_ptr, "Enable precise pointer, or disable."); + +module_param_array(line_outs_monitor, bool, NULL, 0444); +MODULE_PARM_DESC(line_outs_monitor, + "Send playback streams to analog outs by default."); + +module_param_array(enable_monitor, bool, NULL, 0444); +MODULE_PARM_DESC(enable_monitor, + "Enable Analog Out on Channel 63/64 by default."); + +MODULE_AUTHOR + ("Winfried Ritsch , Paul Davis , " + "Marcus Andersson, Thomas Charbonnel "); +MODULE_DESCRIPTION("RME HDSPM"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); + +/* --- Write registers. --- + These are defined as byte-offsets from the iobase value. */ + +#define HDSPM_controlRegister 64 +#define HDSPM_interruptConfirmation 96 +#define HDSPM_control2Reg 256 /* not in specs ???????? */ +#define HDSPM_midiDataOut0 352 /* just believe in old code */ +#define HDSPM_midiDataOut1 356 + +/* DMA enable for 64 channels, only Bit 0 is relevant */ +#define HDSPM_outputEnableBase 512 /* 512-767 input DMA */ +#define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */ + +/* 16 page addresses for each of the 64 channels DMA buffer in and out + (each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */ +#define HDSPM_pageAddressBufferOut 8192 +#define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4) + +#define HDSPM_MADI_mixerBase 32768 /* 32768-65535 for 2x64x64 Fader */ + +#define HDSPM_MATRIX_MIXER_SIZE 8192 /* = 2*64*64 * 4 Byte => 32kB */ + +/* --- Read registers. --- + These are defined as byte-offsets from the iobase value */ +#define HDSPM_statusRegister 0 +#define HDSPM_statusRegister2 96 + +#define HDSPM_midiDataIn0 360 +#define HDSPM_midiDataIn1 364 + +/* status is data bytes in MIDI-FIFO (0-128) */ +#define HDSPM_midiStatusOut0 384 +#define HDSPM_midiStatusOut1 388 +#define HDSPM_midiStatusIn0 392 +#define HDSPM_midiStatusIn1 396 + + +/* the meters are regular i/o-mapped registers, but offset + considerably from the rest. the peak registers are reset + when read; the least-significant 4 bits are full-scale counters; + the actual peak value is in the most-significant 24 bits. +*/ +#define HDSPM_MADI_peakrmsbase 4096 /* 4096-8191 2x64x32Bit Meters */ + +/* --- Control Register bits --------- */ +#define HDSPM_Start (1<<0) /* start engine */ + +#define HDSPM_Latency0 (1<<1) /* buffer size = 2^n */ +#define HDSPM_Latency1 (1<<2) /* where n is defined */ +#define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */ + +#define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Slave/Autosync */ + +#define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */ + +#define HDSPM_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ +#define HDSPM_Frequency1 (1<<7) /* 0=32kHz/64kHz */ +#define HDSPM_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ +#define HDSPM_QuadSpeed (1<<31) /* quad speed bit, not implemented now */ + +#define HDSPM_TX_64ch (1<<10) /* Output 64channel MODE=1, + 56channelMODE=0 */ + +#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode, + 0=off, 1=on */ + +#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ +#define HDSPM_InputSelect1 (1<<15) /* should be 0 */ + +#define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */ +#define HDSPM_SyncRef1 (1<<17) /* should be 0 */ + +#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use + AES additional bits in + lower 5 Audiodatabits ??? */ + +#define HDSPM_Midi0InterruptEnable (1<<22) +#define HDSPM_Midi1InterruptEnable (1<<23) + +#define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */ + + +/* --- bit helper defines */ +#define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) +#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1) +#define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) +#define HDSPM_InputOptical 0 +#define HDSPM_InputCoaxial (HDSPM_InputSelect0) +#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1) +#define HDSPM_SyncRef_Word 0 +#define HDSPM_SyncRef_MADI (HDSPM_SyncRef0) + +#define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */ +#define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */ + +#define HDSPM_Frequency32KHz HDSPM_Frequency0 +#define HDSPM_Frequency44_1KHz HDSPM_Frequency1 +#define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) +#define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) +#define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) +#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0) + +/* --- for internal discrimination */ +#define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */ +#define HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ 1 +#define HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ 2 +#define HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ 3 +#define HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ 4 +#define HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ 5 +#define HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ 6 +#define HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ 7 +#define HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ 8 +#define HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ 9 + +/* Synccheck Status */ +#define HDSPM_SYNC_CHECK_NO_LOCK 0 +#define HDSPM_SYNC_CHECK_LOCK 1 +#define HDSPM_SYNC_CHECK_SYNC 2 + +/* AutoSync References - used by "autosync_ref" control switch */ +#define HDSPM_AUTOSYNC_FROM_WORD 0 +#define HDSPM_AUTOSYNC_FROM_MADI 1 +#define HDSPM_AUTOSYNC_FROM_NONE 2 + +/* Possible sources of MADI input */ +#define HDSPM_OPTICAL 0 /* optical */ +#define HDSPM_COAXIAL 1 /* BNC */ + +#define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask) +#define hdspm_decode_latency(x) (((x) & HDSPM_LatencyMask)>>1) + +#define hdspm_encode_in(x) (((x)&0x3)<<14) +#define hdspm_decode_in(x) (((x)>>14)&0x3) + +/* --- control2 register bits --- */ +#define HDSPM_TMS (1<<0) +#define HDSPM_TCK (1<<1) +#define HDSPM_TDI (1<<2) +#define HDSPM_JTAG (1<<3) +#define HDSPM_PWDN (1<<4) +#define HDSPM_PROGRAM (1<<5) +#define HDSPM_CONFIG_MODE_0 (1<<6) +#define HDSPM_CONFIG_MODE_1 (1<<7) +/*#define HDSPM_VERSION_BIT (1<<8) not defined any more*/ +#define HDSPM_BIGENDIAN_MODE (1<<9) +#define HDSPM_RD_MULTIPLE (1<<10) + +/* --- Status Register bits --- */ +#define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ +#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */ +#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */ +#define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ + +#define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ + /* since 64byte accurate last 6 bits + are not used */ + +#define HDSPM_madiSync (1<<18) /* MADI is in sync */ +#define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */ + +#define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */ +#define HDSPM_madiFreq1 (1<<23) /* 1=32, 2=44.1 3=48 */ +#define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ +#define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ + +#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with Interrupt */ +#define HDSPM_midi0IRQPending (1<<30) /* MIDI IRQ is pending */ +#define HDSPM_midi1IRQPending (1<<31) /* and aktiv */ + +/* --- status bit helpers */ +#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2|HDSPM_madiFreq3) +#define HDSPM_madiFreq32 (HDSPM_madiFreq0) +#define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) +#define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) +#define HDSPM_madiFreq64 (HDSPM_madiFreq2) +#define HDSPM_madiFreq88_2 (HDSPM_madiFreq0|HDSPM_madiFreq2) +#define HDSPM_madiFreq96 (HDSPM_madiFreq1|HDSPM_madiFreq2) +#define HDSPM_madiFreq128 (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2) +#define HDSPM_madiFreq176_4 (HDSPM_madiFreq3) +#define HDSPM_madiFreq192 (HDSPM_madiFreq3|HDSPM_madiFreq0) + +/* Status2 Register bits */ + +#define HDSPM_version0 (1<<0) /* not realy defined but I guess */ +#define HDSPM_version1 (1<<1) /* in former cards it was ??? */ +#define HDSPM_version2 (1<<2) + +#define HDSPM_wcLock (1<<3) /* Wordclock is detected and locked */ +#define HDSPM_wcSync (1<<4) /* Wordclock is in sync with systemclock */ + +#define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ +#define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ +#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */ +/* missing Bit for 111=128, 1000=176.4, 1001=192 */ + +#define HDSPM_SelSyncRef0 (1<<8) /* Sync Source in slave mode */ +#define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */ +#define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */ + +#define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) + +#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreq32 (HDSPM_wc_freq0) +#define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) +#define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) +#define HDSPM_wcFreq64 (HDSPM_wc_freq2) +#define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) +#define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) + + +#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) +#define HDSPM_SelSyncRef_WORD 0 +#define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) +#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) + +/* Mixer Values */ +#define UNITY_GAIN 32768 /* = 65536/2 */ +#define MINUS_INFINITY_GAIN 0 + +/* PCI info */ +#ifndef PCI_VENDOR_ID_XILINX +#define PCI_VENDOR_ID_XILINX 0x10ee +#endif +#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 +#endif +#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 +#endif + + +/* Number of channels for different Speed Modes */ +#define MADI_SS_CHANNELS 64 +#define MADI_DS_CHANNELS 32 +#define MADI_QS_CHANNELS 16 + +/* the size of a substream (1 mono data stream) */ +#define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024) +#define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES) + +/* the size of the area we need to allocate for DMA transfers. the + size is the same regardless of the number of channels, and + also the latency to use. + for one direction !!! +*/ +#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES) +#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024) + +typedef struct _hdspm hdspm_t; +typedef struct _hdspm_midi hdspm_midi_t; + +struct _hdspm_midi { + hdspm_t *hdspm; + int id; + snd_rawmidi_t *rmidi; + snd_rawmidi_substream_t *input; + snd_rawmidi_substream_t *output; + char istimer; /* timer in use */ + struct timer_list timer; + spinlock_t lock; + int pending; +}; + +struct _hdspm { + spinlock_t lock; + snd_pcm_substream_t *capture_substream; /* only one playback */ + snd_pcm_substream_t *playback_substream; /* and/or capture stream */ + + char *card_name; /* for procinfo */ + unsigned short firmware_rev; /* dont know if relevant */ + + int precise_ptr; /* use precise pointers, to be tested */ + int monitor_outs; /* set up monitoring outs init flag */ + + u32 control_register; /* cached value */ + u32 control2_register; /* cached value */ + + hdspm_midi_t midi[2]; + struct tasklet_struct midi_tasklet; + + size_t period_bytes; + unsigned char ss_channels; /* channels of card in single speed */ + unsigned char ds_channels; /* Double Speed */ + unsigned char qs_channels; /* Quad Speed */ + + unsigned char *playback_buffer; /* suitably aligned address */ + unsigned char *capture_buffer; /* suitably aligned address */ + + pid_t capture_pid; /* process id which uses capture */ + pid_t playback_pid; /* process id which uses capture */ + int running; /* running status */ + + int last_external_sample_rate; /* samplerate mystic ... */ + int last_internal_sample_rate; + int system_sample_rate; + + char *channel_map; /* channel map for DS and Quadspeed */ + + int dev; /* Hardware vars... */ + int irq; + unsigned long port; + void __iomem *iobase; + + int irq_count; /* for debug */ + + snd_card_t *card; /* one card */ + snd_pcm_t *pcm; /* has one pcm */ + snd_hwdep_t *hwdep; /* and a hwdep for additional ioctl */ + struct pci_dev *pci; /* and an pci info */ + + /* Mixer vars */ + snd_kcontrol_t *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* fast alsa mixer */ + snd_kcontrol_t *input_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */ + hdspm_mixer_t *mixer; /* full mixer accessable over mixer ioctl or hwdep-device */ + +}; + +/* These tables map the ALSA channels 1..N to the channels that we + need to use in order to find the relevant channel buffer. RME + refer to this kind of mapping as between "the ADAT channel and + the DMA channel." We index it using the logical audio channel, + and the value is the DMA channel (i.e. channel buffer number) + where the data for that channel can be read/written from/to. +*/ + +static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63 +}; + +static char channel_map_madi_ds[HDSPM_MAX_CHANNELS] = { + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static char channel_map_madi_qs[HDSPM_MAX_CHANNELS] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60 + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + + +static struct pci_device_id snd_hdspm_ids[] = { + { + .vendor = PCI_VENDOR_ID_XILINX, + .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, snd_hdspm_ids); + +/* prototypes */ +static int __devinit snd_hdspm_create_alsa_devices(snd_card_t * card, + hdspm_t * hdspm); +static int __devinit snd_hdspm_create_pcm(snd_card_t * card, + hdspm_t * hdspm); + +static inline void snd_hdspm_initialize_midi_flush(hdspm_t * hdspm); +static int hdspm_update_simple_mixer_controls(hdspm_t * hdspm); +static int hdspm_autosync_ref(hdspm_t * hdspm); +static int snd_hdspm_set_defaults(hdspm_t * hdspm); +static void hdspm_set_sgbuf(hdspm_t * hdspm, struct snd_sg_buf *sgbuf, + unsigned int reg, int channels); + +/* Write/read to/from HDSPM with Adresses in Bytes + not words but only 32Bit writes are allowed */ + +static inline void hdspm_write(hdspm_t * hdspm, unsigned int reg, + unsigned int val) +{ + writel(val, hdspm->iobase + reg); +} + +static inline unsigned int hdspm_read(hdspm_t * hdspm, unsigned int reg) +{ + return readl(hdspm->iobase + reg); +} + +/* for each output channel (chan) I have an Input (in) and Playback (pb) Fader + mixer is write only on hardware so we have to cache him for read + each fader is a u32, but uses only the first 16 bit */ + +static inline int hdspm_read_in_gain(hdspm_t * hdspm, unsigned int chan, + unsigned int in) +{ + if (chan > HDSPM_MIXER_CHANNELS || in > HDSPM_MIXER_CHANNELS) + return 0; + + return hdspm->mixer->ch[chan].in[in]; +} + +static inline int hdspm_read_pb_gain(hdspm_t * hdspm, unsigned int chan, + unsigned int pb) +{ + if (chan > HDSPM_MIXER_CHANNELS || pb > HDSPM_MIXER_CHANNELS) + return 0; + return hdspm->mixer->ch[chan].pb[pb]; +} + +static inline int hdspm_write_in_gain(hdspm_t * hdspm, unsigned int chan, + unsigned int in, unsigned short data) +{ + if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) + return -1; + + hdspm_write(hdspm, + HDSPM_MADI_mixerBase + + ((in + 128 * chan) * sizeof(u32)), + (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF)); + return 0; +} + +static inline int hdspm_write_pb_gain(hdspm_t * hdspm, unsigned int chan, + unsigned int pb, unsigned short data) +{ + if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) + return -1; + + hdspm_write(hdspm, + HDSPM_MADI_mixerBase + + ((64 + pb + 128 * chan) * sizeof(u32)), + (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF)); + return 0; +} + + +/* enable DMA for specific channels, now available for DSP-MADI */ +static inline void snd_hdspm_enable_in(hdspm_t * hdspm, int i, int v) +{ + hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v); +} + +static inline void snd_hdspm_enable_out(hdspm_t * hdspm, int i, int v) +{ + hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v); +} + +/* check if same process is writing and reading */ +static inline int snd_hdspm_use_is_exclusive(hdspm_t * hdspm) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&hdspm->lock, flags); + if ((hdspm->playback_pid != hdspm->capture_pid) && + (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { + ret = 0; + } + spin_unlock_irqrestore(&hdspm->lock, flags); + return ret; +} + +/* check for external sample rate */ +static inline int hdspm_external_sample_rate(hdspm_t * hdspm) +{ + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); + unsigned int rate_bits; + int rate = 0; + + /* if wordclock has synced freq and wordclock is valid */ + if ((status2 & HDSPM_wcLock) != 0 && + (status & HDSPM_SelSyncRef0) == 0) { + + rate_bits = status2 & HDSPM_wcFreqMask; + + switch (rate_bits) { + case HDSPM_wcFreq32: + rate = 32000; + break; + case HDSPM_wcFreq44_1: + rate = 44100; + break; + case HDSPM_wcFreq48: + rate = 48000; + break; + case HDSPM_wcFreq64: + rate = 64000; + break; + case HDSPM_wcFreq88_2: + rate = 88200; + break; + case HDSPM_wcFreq96: + rate = 96000; + break; + /* Quadspeed Bit missing ???? */ + default: + rate = 0; + break; + } + } + + /* if rate detected and Syncref is Word than have it, word has priority to MADI */ + if (rate != 0 + && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) + return rate; + + /* maby a madi input (which is taken if sel sync is madi) */ + if (status & HDSPM_madiLock) { + rate_bits = status & HDSPM_madiFreqMask; + + switch (rate_bits) { + case HDSPM_madiFreq32: + rate = 32000; + break; + case HDSPM_madiFreq44_1: + rate = 44100; + break; + case HDSPM_madiFreq48: + rate = 48000; + break; + case HDSPM_madiFreq64: + rate = 64000; + break; + case HDSPM_madiFreq88_2: + rate = 88200; + break; + case HDSPM_madiFreq96: + rate = 96000; + break; + case HDSPM_madiFreq128: + rate = 128000; + break; + case HDSPM_madiFreq176_4: + rate = 176400; + break; + case HDSPM_madiFreq192: + rate = 192000; + break; + default: + rate = 0; + break; + } + } + return rate; +} + +/* Latency function */ +static inline void hdspm_compute_period_size(hdspm_t * hdspm) +{ + hdspm->period_bytes = + 1 << ((hdspm_decode_latency(hdspm->control_register) + 8)); +} + +static snd_pcm_uframes_t hdspm_hw_pointer(hdspm_t * hdspm) +{ + int position; + + position = hdspm_read(hdspm, HDSPM_statusRegister); + + if (!hdspm->precise_ptr) { + return (position & HDSPM_BufferID) ? (hdspm->period_bytes / + 4) : 0; + } + + /* hwpointer comes in bytes and is 64Bytes accurate (by docu since PCI Burst) + i have experimented that it is at most 64 Byte to much for playing + so substraction of 64 byte should be ok for ALSA, but use it only + for application where you know what you do since if you come to + near with record pointer it can be a disaster */ + + position &= HDSPM_BufferPositionMask; + position = ((position - 64) % (2 * hdspm->period_bytes)) / 4; + + return position; +} + + +static inline void hdspm_start_audio(hdspm_t * s) +{ + s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start); + hdspm_write(s, HDSPM_controlRegister, s->control_register); +} + +static inline void hdspm_stop_audio(hdspm_t * s) +{ + s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable); + hdspm_write(s, HDSPM_controlRegister, s->control_register); +} + +/* should I silence all or only opened ones ? doit all for first even is 4MB*/ +static inline void hdspm_silence_playback(hdspm_t * hdspm) +{ + int i; + int n = hdspm->period_bytes; + void *buf = hdspm->playback_buffer; + + snd_assert(buf != NULL, return); + + for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { + memset(buf, 0, n); + buf += HDSPM_CHANNEL_BUFFER_BYTES; + } +} + +static int hdspm_set_interrupt_interval(hdspm_t * s, unsigned int frames) +{ + int n; + + spin_lock_irq(&s->lock); + + frames >>= 7; + n = 0; + while (frames) { + n++; + frames >>= 1; + } + s->control_register &= ~HDSPM_LatencyMask; + s->control_register |= hdspm_encode_latency(n); + + hdspm_write(s, HDSPM_controlRegister, s->control_register); + + hdspm_compute_period_size(s); + + spin_unlock_irq(&s->lock); + + return 0; +} + + +/* dummy set rate lets see what happens */ +static int hdspm_set_rate(hdspm_t * hdspm, int rate, int called_internally) +{ + int reject_if_open = 0; + int current_rate; + int rate_bits; + int not_set = 0; + + /* ASSUMPTION: hdspm->lock is either set, or there is no need for + it (e.g. during module initialization). + */ + + if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { + + /* SLAVE --- */ + if (called_internally) { + + /* request from ctl or card initialization + just make a warning an remember setting + for future master mode switching */ + + snd_printk + (KERN_WARNING "HDSPM: Warning: device is not running as a clock master.\n"); + not_set = 1; + } else { + + /* hw_param request while in AutoSync mode */ + int external_freq = + hdspm_external_sample_rate(hdspm); + + if ((hdspm_autosync_ref(hdspm) == + HDSPM_AUTOSYNC_FROM_NONE)) { + + snd_printk(KERN_WARNING "HDSPM: Detected no Externel Sync \n"); + not_set = 1; + + } else if (rate != external_freq) { + + snd_printk + (KERN_WARNING "HDSPM: Warning: No AutoSync source for requested rate\n"); + not_set = 1; + } + } + } + + current_rate = hdspm->system_sample_rate; + + /* Changing between Singe, Double and Quad speed is not + allowed if any substreams are open. This is because such a change + causes a shift in the location of the DMA buffers and a reduction + in the number of available buffers. + + Note that a similar but essentially insoluble problem exists for + externally-driven rate changes. All we can do is to flag rate + changes in the read/write routines. + */ + + switch (rate) { + case 32000: + if (current_rate > 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency32KHz; + break; + case 44100: + if (current_rate > 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency44_1KHz; + break; + case 48000: + if (current_rate > 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency48KHz; + break; + case 64000: + if (current_rate <= 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency64KHz; + break; + case 88200: + if (current_rate <= 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency88_2KHz; + break; + case 96000: + if (current_rate <= 48000) { + reject_if_open = 1; + } + rate_bits = HDSPM_Frequency96KHz; + break; + default: + return -EINVAL; + } + + if (reject_if_open + && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { + snd_printk + (KERN_ERR "HDSPM: cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n", + hdspm->capture_pid, hdspm->playback_pid); + return -EBUSY; + } + + hdspm->control_register &= ~HDSPM_FrequencyMask; + hdspm->control_register |= rate_bits; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + if (rate > 64000) + hdspm->channel_map = channel_map_madi_qs; + else if (rate > 48000) + hdspm->channel_map = channel_map_madi_ds; + else + hdspm->channel_map = channel_map_madi_ss; + + hdspm->system_sample_rate = rate; + + if (not_set != 0) + return -1; + + return 0; +} + +/* mainly for init to 0 on load */ +static void all_in_all_mixer(hdspm_t * hdspm, int sgain) +{ + int i, j; + unsigned int gain = + (sgain > UNITY_GAIN) ? UNITY_GAIN : (sgain < 0) ? 0 : sgain; + + for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) + for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { + hdspm_write_in_gain(hdspm, i, j, gain); + hdspm_write_pb_gain(hdspm, i, j, gain); + } +} + +/*---------------------------------------------------------------------------- + MIDI + ----------------------------------------------------------------------------*/ + +static inline unsigned char snd_hdspm_midi_read_byte (hdspm_t *hdspm, int id) +{ + /* the hardware already does the relevant bit-mask with 0xff */ + if (id) + return hdspm_read(hdspm, HDSPM_midiDataIn1); + else + return hdspm_read(hdspm, HDSPM_midiDataIn0); +} + +static inline void snd_hdspm_midi_write_byte (hdspm_t *hdspm, int id, int val) +{ + /* the hardware already does the relevant bit-mask with 0xff */ + if (id) + return hdspm_write(hdspm, HDSPM_midiDataOut1, val); + else + return hdspm_write(hdspm, HDSPM_midiDataOut0, val); +} + +static inline int snd_hdspm_midi_input_available (hdspm_t *hdspm, int id) +{ + if (id) + return (hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff); + else + return (hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff); +} + +static inline int snd_hdspm_midi_output_possible (hdspm_t *hdspm, int id) +{ + int fifo_bytes_used; + + if (id) + fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xff; + else + fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xff; + + if (fifo_bytes_used < 128) + return 128 - fifo_bytes_used; + else + return 0; +} + +static inline void snd_hdspm_flush_midi_input (hdspm_t *hdspm, int id) +{ + while (snd_hdspm_midi_input_available (hdspm, id)) + snd_hdspm_midi_read_byte (hdspm, id); +} + +static int snd_hdspm_midi_output_write (hdspm_midi_t *hmidi) +{ + unsigned long flags; + int n_pending; + int to_write; + int i; + unsigned char buf[128]; + + /* Output is not interrupt driven */ + + spin_lock_irqsave (&hmidi->lock, flags); + if (hmidi->output) { + if (!snd_rawmidi_transmit_empty (hmidi->output)) { + if ((n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, hmidi->id)) > 0) { + if (n_pending > (int)sizeof (buf)) + n_pending = sizeof (buf); + + if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) { + for (i = 0; i < to_write; ++i) + snd_hdspm_midi_write_byte (hmidi->hdspm, hmidi->id, buf[i]); + } + } + } + } + spin_unlock_irqrestore (&hmidi->lock, flags); + return 0; +} + +static int snd_hdspm_midi_input_read (hdspm_midi_t *hmidi) +{ + unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */ + unsigned long flags; + int n_pending; + int i; + + spin_lock_irqsave (&hmidi->lock, flags); + if ((n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id)) > 0) { + if (hmidi->input) { + if (n_pending > (int)sizeof (buf)) { + n_pending = sizeof (buf); + } + for (i = 0; i < n_pending; ++i) { + buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); + } + if (n_pending) { + snd_rawmidi_receive (hmidi->input, buf, n_pending); + } + } else { + /* flush the MIDI input FIFO */ + while (n_pending--) { + snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); + } + } + } + hmidi->pending = 0; + if (hmidi->id) { + hmidi->hdspm->control_register |= HDSPM_Midi1InterruptEnable; + } else { + hmidi->hdspm->control_register |= HDSPM_Midi0InterruptEnable; + } + hdspm_write(hmidi->hdspm, HDSPM_controlRegister, hmidi->hdspm->control_register); + spin_unlock_irqrestore (&hmidi->lock, flags); + return snd_hdspm_midi_output_write (hmidi); +} + +static void snd_hdspm_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) +{ + hdspm_t *hdspm; + hdspm_midi_t *hmidi; + unsigned long flags; + u32 ie; + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + hdspm = hmidi->hdspm; + ie = hmidi->id ? HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable; + spin_lock_irqsave (&hdspm->lock, flags); + if (up) { + if (!(hdspm->control_register & ie)) { + snd_hdspm_flush_midi_input (hdspm, hmidi->id); + hdspm->control_register |= ie; + } + } else { + hdspm->control_register &= ~ie; + } + + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + spin_unlock_irqrestore (&hdspm->lock, flags); +} + +static void snd_hdspm_midi_output_timer(unsigned long data) +{ + hdspm_midi_t *hmidi = (hdspm_midi_t *) data; + unsigned long flags; + + snd_hdspm_midi_output_write(hmidi); + spin_lock_irqsave (&hmidi->lock, flags); + + /* this does not bump hmidi->istimer, because the + kernel automatically removed the timer when it + expired, and we are now adding it back, thus + leaving istimer wherever it was set before. + */ + + if (hmidi->istimer) { + hmidi->timer.expires = 1 + jiffies; + add_timer(&hmidi->timer); + } + + spin_unlock_irqrestore (&hmidi->lock, flags); +} + +static void snd_hdspm_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) +{ + hdspm_midi_t *hmidi; + unsigned long flags; + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irqsave (&hmidi->lock, flags); + if (up) { + if (!hmidi->istimer) { + init_timer(&hmidi->timer); + hmidi->timer.function = snd_hdspm_midi_output_timer; + hmidi->timer.data = (unsigned long) hmidi; + hmidi->timer.expires = 1 + jiffies; + add_timer(&hmidi->timer); + hmidi->istimer++; + } + } else { + if (hmidi->istimer && --hmidi->istimer <= 0) { + del_timer (&hmidi->timer); + } + } + spin_unlock_irqrestore (&hmidi->lock, flags); + if (up) + snd_hdspm_midi_output_write(hmidi); +} + +static int snd_hdspm_midi_input_open(snd_rawmidi_substream_t * substream) +{ + hdspm_midi_t *hmidi; + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irq (&hmidi->lock); + snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); + hmidi->input = substream; + spin_unlock_irq (&hmidi->lock); + + return 0; +} + +static int snd_hdspm_midi_output_open(snd_rawmidi_substream_t * substream) +{ + hdspm_midi_t *hmidi; + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irq (&hmidi->lock); + hmidi->output = substream; + spin_unlock_irq (&hmidi->lock); + + return 0; +} + +static int snd_hdspm_midi_input_close(snd_rawmidi_substream_t * substream) +{ + hdspm_midi_t *hmidi; + + snd_hdspm_midi_input_trigger (substream, 0); + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irq (&hmidi->lock); + hmidi->input = NULL; + spin_unlock_irq (&hmidi->lock); + + return 0; +} + +static int snd_hdspm_midi_output_close(snd_rawmidi_substream_t * substream) +{ + hdspm_midi_t *hmidi; + + snd_hdspm_midi_output_trigger (substream, 0); + + hmidi = (hdspm_midi_t *) substream->rmidi->private_data; + spin_lock_irq (&hmidi->lock); + hmidi->output = NULL; + spin_unlock_irq (&hmidi->lock); + + return 0; +} + +snd_rawmidi_ops_t snd_hdspm_midi_output = +{ + .open = snd_hdspm_midi_output_open, + .close = snd_hdspm_midi_output_close, + .trigger = snd_hdspm_midi_output_trigger, +}; + +snd_rawmidi_ops_t snd_hdspm_midi_input = +{ + .open = snd_hdspm_midi_input_open, + .close = snd_hdspm_midi_input_close, + .trigger = snd_hdspm_midi_input_trigger, +}; + +static int __devinit snd_hdspm_create_midi (snd_card_t *card, hdspm_t *hdspm, int id) +{ + int err; + char buf[32]; + + hdspm->midi[id].id = id; + hdspm->midi[id].rmidi = NULL; + hdspm->midi[id].input = NULL; + hdspm->midi[id].output = NULL; + hdspm->midi[id].hdspm = hdspm; + hdspm->midi[id].istimer = 0; + hdspm->midi[id].pending = 0; + spin_lock_init (&hdspm->midi[id].lock); + + sprintf (buf, "%s MIDI %d", card->shortname, id+1); + if ((err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi)) < 0) + return err; + + sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); + hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; + + snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdspm_midi_output); + snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdspm_midi_input); + + hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + + return 0; +} + + +static void hdspm_midi_tasklet(unsigned long arg) +{ + hdspm_t *hdspm = (hdspm_t *)arg; + + if (hdspm->midi[0].pending) + snd_hdspm_midi_input_read (&hdspm->midi[0]); + if (hdspm->midi[1].pending) + snd_hdspm_midi_input_read (&hdspm->midi[1]); +} + + +/*----------------------------------------------------------------------------- + Status Interface + ----------------------------------------------------------------------------*/ + +/* get the system sample rate which is set */ + +#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_system_sample_rate, \ + .get = snd_hdspm_get_system_sample_rate \ +} + +static int snd_hdspm_info_system_sample_rate(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + return 0; +} + +static int snd_hdspm_get_system_sample_rate(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * + ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm->system_sample_rate; + return 0; +} + +#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_autosync_sample_rate, \ + .get = snd_hdspm_get_autosync_sample_rate \ +} + +static int snd_hdspm_info_autosync_sample_rate(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "32000", "44100", "48000", + "64000", "88200", "96000", + "128000", "176400", "192000", + "None" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 10; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdspm_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * + ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + switch (hdspm_external_sample_rate(hdspm)) { + case 32000: + ucontrol->value.enumerated.item[0] = 0; + break; + case 44100: + ucontrol->value.enumerated.item[0] = 1; + break; + case 48000: + ucontrol->value.enumerated.item[0] = 2; + break; + case 64000: + ucontrol->value.enumerated.item[0] = 3; + break; + case 88200: + ucontrol->value.enumerated.item[0] = 4; + break; + case 96000: + ucontrol->value.enumerated.item[0] = 5; + break; + case 128000: + ucontrol->value.enumerated.item[0] = 6; + break; + case 176400: + ucontrol->value.enumerated.item[0] = 7; + break; + case 192000: + ucontrol->value.enumerated.item[0] = 8; + break; + + default: + ucontrol->value.enumerated.item[0] = 9; + } + return 0; +} + +#define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_system_clock_mode, \ + .get = snd_hdspm_get_system_clock_mode, \ +} + + + +static int hdspm_system_clock_mode(hdspm_t * hdspm) +{ + /* Always reflect the hardware info, rme is never wrong !!!! */ + + if (hdspm->control_register & HDSPM_ClockModeMaster) + return 0; + return 1; +} + +static int snd_hdspm_info_system_clock_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "Master", "Slave" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdspm_get_system_clock_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = + hdspm_system_clock_mode(hdspm); + return 0; +} + +#define HDSPM_CLOCK_SOURCE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_clock_source, \ + .get = snd_hdspm_get_clock_source, \ + .put = snd_hdspm_put_clock_source \ +} + +static int hdspm_clock_source(hdspm_t * hdspm) +{ + if (hdspm->control_register & HDSPM_ClockModeMaster) { + switch (hdspm->system_sample_rate) { + case 32000: + return 1; + case 44100: + return 2; + case 48000: + return 3; + case 64000: + return 4; + case 88200: + return 5; + case 96000: + return 6; + case 128000: + return 7; + case 176400: + return 8; + case 192000: + return 9; + default: + return 3; + } + } else { + return 0; + } +} + +static int hdspm_set_clock_source(hdspm_t * hdspm, int mode) +{ + int rate; + switch (mode) { + + case HDSPM_CLOCK_SOURCE_AUTOSYNC: + if (hdspm_external_sample_rate(hdspm) != 0) { + hdspm->control_register &= ~HDSPM_ClockModeMaster; + hdspm_write(hdspm, HDSPM_controlRegister, + hdspm->control_register); + return 0; + } + return -1; + case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ: + rate = 32000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ: + rate = 44100; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ: + rate = 48000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ: + rate = 64000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ: + rate = 88200; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ: + rate = 96000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ: + rate = 128000; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ: + rate = 176400; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ: + rate = 192000; + break; + + default: + rate = 44100; + } + hdspm->control_register |= HDSPM_ClockModeMaster; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + hdspm_set_rate(hdspm, rate, 1); + return 0; +} + +static int snd_hdspm_info_clock_source(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "AutoSync", + "Internal 32.0 kHz", "Internal 44.1 kHz", + "Internal 48.0 kHz", + "Internal 64.0 kHz", "Internal 88.2 kHz", + "Internal 96.0 kHz", + "Internal 128.0 kHz", "Internal 176.4 kHz", + "Internal 192.0 kHz" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 10; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int snd_hdspm_get_clock_source(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_clock_source(hdspm); + return 0; +} + +static int snd_hdspm_put_clock_source(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) + val = 0; + if (val > 6) + val = 6; + spin_lock_irq(&hdspm->lock); + if (val != hdspm_clock_source(hdspm)) + change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; + else + change = 0; + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_PREF_SYNC_REF(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_pref_sync_ref, \ + .get = snd_hdspm_get_pref_sync_ref, \ + .put = snd_hdspm_put_pref_sync_ref \ +} + +static int hdspm_pref_sync_ref(hdspm_t * hdspm) +{ + /* Notice that this looks at the requested sync source, + not the one actually in use. + */ + switch (hdspm->control_register & HDSPM_SyncRefMask) { + case HDSPM_SyncRef_Word: + return HDSPM_SYNC_FROM_WORD; + case HDSPM_SyncRef_MADI: + return HDSPM_SYNC_FROM_MADI; + } + + return HDSPM_SYNC_FROM_WORD; +} + +static int hdspm_set_pref_sync_ref(hdspm_t * hdspm, int pref) +{ + hdspm->control_register &= ~HDSPM_SyncRefMask; + + switch (pref) { + case HDSPM_SYNC_FROM_MADI: + hdspm->control_register |= HDSPM_SyncRef_MADI; + break; + case HDSPM_SYNC_FROM_WORD: + hdspm->control_register |= HDSPM_SyncRef_Word; + break; + default: + return -1; + } + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + return 0; +} + +static int snd_hdspm_info_pref_sync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "Word", "MADI" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdspm_get_pref_sync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm); + return 0; +} + +static int snd_hdspm_put_pref_sync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change, max; + unsigned int val; + + max = 2; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + + val = ucontrol->value.enumerated.item[0] % max; + + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_pref_sync_ref(hdspm); + hdspm_set_pref_sync_ref(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_AUTOSYNC_REF(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_autosync_ref, \ + .get = snd_hdspm_get_autosync_ref, \ +} + +static int hdspm_autosync_ref(hdspm_t * hdspm) +{ + /* This looks at the autosync selected sync reference */ + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + + switch (status2 & HDSPM_SelSyncRefMask) { + + case HDSPM_SelSyncRef_WORD: + return HDSPM_AUTOSYNC_FROM_WORD; + + case HDSPM_SelSyncRef_MADI: + return HDSPM_AUTOSYNC_FROM_MADI; + + case HDSPM_SelSyncRef_NVALID: + return HDSPM_AUTOSYNC_FROM_NONE; + + default: + return 0; + } + + return 0; +} + +static int snd_hdspm_info_autosync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "WordClock", "MADI", "None" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdspm_get_autosync_ref(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm); + return 0; +} + +#define HDSPM_LINE_OUT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_line_out, \ + .get = snd_hdspm_get_line_out, \ + .put = snd_hdspm_put_line_out \ +} + +static int hdspm_line_out(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_LineOut) ? 1 : 0; +} + + +static int hdspm_set_line_output(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_LineOut; + else + hdspm->control_register &= ~HDSPM_LineOut; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_line_out(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_line_out(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_line_out(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_line_out(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_line_out(hdspm); + hdspm_set_line_output(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_TX_64(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_tx_64, \ + .get = snd_hdspm_get_tx_64, \ + .put = snd_hdspm_put_tx_64 \ +} + +static int hdspm_tx_64(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_TX_64ch) ? 1 : 0; +} + +static int hdspm_set_tx_64(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_TX_64ch; + else + hdspm->control_register &= ~HDSPM_TX_64ch; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_tx_64(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_tx_64(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_tx_64(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_tx_64(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_tx_64(hdspm); + hdspm_set_tx_64(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_C_TMS(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_c_tms, \ + .get = snd_hdspm_get_c_tms, \ + .put = snd_hdspm_put_c_tms \ +} + +static int hdspm_c_tms(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_clr_tms) ? 1 : 0; +} + +static int hdspm_set_c_tms(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_clr_tms; + else + hdspm->control_register &= ~HDSPM_clr_tms; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_c_tms(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_c_tms(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_c_tms(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_c_tms(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_c_tms(hdspm); + hdspm_set_c_tms(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_SAFE_MODE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_safe_mode, \ + .get = snd_hdspm_get_safe_mode, \ + .put = snd_hdspm_put_safe_mode \ +} + +static int hdspm_safe_mode(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0; +} + +static int hdspm_set_safe_mode(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_AutoInp; + else + hdspm->control_register &= ~HDSPM_AutoInp; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_safe_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdspm_get_safe_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_safe_mode(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_safe_mode(hdspm); + hdspm_set_safe_mode(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_INPUT_SELECT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_input_select, \ + .get = snd_hdspm_get_input_select, \ + .put = snd_hdspm_put_input_select \ +} + +static int hdspm_input_select(hdspm_t * hdspm) +{ + return (hdspm->control_register & HDSPM_InputSelect0) ? 1 : 0; +} + +static int hdspm_set_input_select(hdspm_t * hdspm, int out) +{ + if (out) + hdspm->control_register |= HDSPM_InputSelect0; + else + hdspm->control_register &= ~HDSPM_InputSelect0; + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + + return 0; +} + +static int snd_hdspm_info_input_select(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "optical", "coaxial" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int snd_hdspm_get_input_select(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_input_select(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + unsigned int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irq(&hdspm->lock); + change = (int) val != hdspm_input_select(hdspm); + hdspm_set_input_select(hdspm, val); + spin_unlock_irq(&hdspm->lock); + return change; +} + +/* Simple Mixer + deprecated since to much faders ??? + MIXER interface says output (source, destination, value) + where source > MAX_channels are playback channels + on MADICARD + - playback mixer matrix: [channelout+64] [output] [value] + - input(thru) mixer matrix: [channelin] [output] [value] + (better do 2 kontrols for seperation ?) +*/ + +#define HDSPM_MIXER(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_mixer, \ + .get = snd_hdspm_get_mixer, \ + .put = snd_hdspm_put_mixer \ +} + +static int snd_hdspm_info_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 3; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 65535; + uinfo->value.integer.step = 1; + return 0; +} + +static int snd_hdspm_get_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int source; + int destination; + + source = ucontrol->value.integer.value[0]; + if (source < 0) + source = 0; + else if (source >= 2 * HDSPM_MAX_CHANNELS) + source = 2 * HDSPM_MAX_CHANNELS - 1; + + destination = ucontrol->value.integer.value[1]; + if (destination < 0) + destination = 0; + else if (destination >= HDSPM_MAX_CHANNELS) + destination = HDSPM_MAX_CHANNELS - 1; + + spin_lock_irq(&hdspm->lock); + if (source >= HDSPM_MAX_CHANNELS) + ucontrol->value.integer.value[2] = + hdspm_read_pb_gain(hdspm, destination, + source - HDSPM_MAX_CHANNELS); + else + ucontrol->value.integer.value[2] = + hdspm_read_in_gain(hdspm, destination, source); + + spin_unlock_irq(&hdspm->lock); + + return 0; +} + +static int snd_hdspm_put_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + int source; + int destination; + int gain; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + + source = ucontrol->value.integer.value[0]; + destination = ucontrol->value.integer.value[1]; + + if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS) + return -1; + if (destination < 0 || destination >= HDSPM_MAX_CHANNELS) + return -1; + + gain = ucontrol->value.integer.value[2]; + + spin_lock_irq(&hdspm->lock); + + if (source >= HDSPM_MAX_CHANNELS) + change = gain != hdspm_read_pb_gain(hdspm, destination, + source - + HDSPM_MAX_CHANNELS); + else + change = + gain != hdspm_read_in_gain(hdspm, destination, source); + + if (change) { + if (source >= HDSPM_MAX_CHANNELS) + hdspm_write_pb_gain(hdspm, destination, + source - HDSPM_MAX_CHANNELS, + gain); + else + hdspm_write_in_gain(hdspm, destination, source, + gain); + } + spin_unlock_irq(&hdspm->lock); + + return change; +} + +/* The simple mixer control(s) provide gain control for the + basic 1:1 mappings of playback streams to output + streams. +*/ + +#define HDSPM_PLAYBACK_MIXER \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_playback_mixer, \ + .get = snd_hdspm_get_playback_mixer, \ + .put = snd_hdspm_put_playback_mixer \ +} + +static int snd_hdspm_info_playback_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 65536; + uinfo->value.integer.step = 1; + return 0; +} + +static int snd_hdspm_get_playback_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int channel; + int mapped_channel; + + channel = ucontrol->id.index - 1; + + snd_assert(channel >= 0 + || channel < HDSPM_MAX_CHANNELS, return -EINVAL); + + if ((mapped_channel = hdspm->channel_map[channel]) < 0) + return -EINVAL; + + spin_lock_irq(&hdspm->lock); + ucontrol->value.integer.value[0] = + hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel); + spin_unlock_irq(&hdspm->lock); + + /* snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, value %d\n", + ucontrol->id.index, channel, mapped_channel, ucontrol->value.integer.value[0]); + */ + + return 0; +} + +static int snd_hdspm_put_playback_mixer(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + int change; + int channel; + int mapped_channel; + int gain; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + + channel = ucontrol->id.index - 1; + + snd_assert(channel >= 0 + || channel < HDSPM_MAX_CHANNELS, return -EINVAL); + + if ((mapped_channel = hdspm->channel_map[channel]) < 0) + return -EINVAL; + + gain = ucontrol->value.integer.value[0]; + + spin_lock_irq(&hdspm->lock); + change = + gain != hdspm_read_pb_gain(hdspm, mapped_channel, + mapped_channel); + if (change) + hdspm_write_pb_gain(hdspm, mapped_channel, mapped_channel, + gain); + spin_unlock_irq(&hdspm->lock); + return change; +} + +#define HDSPM_WC_SYNC_CHECK(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_sync_check, \ + .get = snd_hdspm_get_wc_sync_check \ +} + +static int snd_hdspm_info_sync_check(snd_kcontrol_t * kcontrol, + snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "No Lock", "Lock", "Sync" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int hdspm_wc_sync_check(hdspm_t * hdspm) +{ + int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + if (status2 & HDSPM_wcLock) { + if (status2 & HDSPM_wcSync) + return 2; + else + return 1; + } + return 0; +} + +static int snd_hdspm_get_wc_sync_check(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdspm_wc_sync_check(hdspm); + return 0; +} + + +#define HDSPM_MADI_SYNC_CHECK(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_sync_check, \ + .get = snd_hdspm_get_madisync_sync_check \ +} + +static int hdspm_madisync_sync_check(hdspm_t * hdspm) +{ + int status = hdspm_read(hdspm, HDSPM_statusRegister); + if (status & HDSPM_madiLock) { + if (status & HDSPM_madiSync) + return 2; + else + return 1; + } + return 0; +} + +static int snd_hdspm_get_madisync_sync_check(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * + ucontrol) +{ + hdspm_t *hdspm = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = + hdspm_madisync_sync_check(hdspm); + return 0; +} + + + + +static snd_kcontrol_new_t snd_hdspm_controls[] = { + + HDSPM_MIXER("Mixer", 0), +/* 'Sample Clock Source' complies with the alsa control naming scheme */ + HDSPM_CLOCK_SOURCE("Sample Clock Source", 0), + + HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), + HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), + HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), + HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), +/* 'External Rate' complies with the alsa control naming scheme */ + HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), + HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0), + HDSPM_MADI_SYNC_CHECK("MADI Sync Lock Status", 0), + HDSPM_LINE_OUT("Line Out", 0), + HDSPM_TX_64("TX 64 channels mode", 0), + HDSPM_C_TMS("Clear Track Marker", 0), + HDSPM_SAFE_MODE("Safe Mode", 0), + HDSPM_INPUT_SELECT("Input Select", 0), +}; + +static snd_kcontrol_new_t snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER; + + +static int hdspm_update_simple_mixer_controls(hdspm_t * hdspm) +{ + int i; + + for (i = hdspm->ds_channels; i < hdspm->ss_channels; ++i) { + if (hdspm->system_sample_rate > 48000) { + hdspm->playback_mixer_ctls[i]->vd[0].access = + SNDRV_CTL_ELEM_ACCESS_INACTIVE | + SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE; + } else { + hdspm->playback_mixer_ctls[i]->vd[0].access = + SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE; + } + snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO, + &hdspm->playback_mixer_ctls[i]->id); + } + + return 0; +} + + +static int snd_hdspm_create_controls(snd_card_t * card, hdspm_t * hdspm) +{ + unsigned int idx, limit; + int err; + snd_kcontrol_t *kctl; + + /* add control list first */ + + for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) { + if ((err = + snd_ctl_add(card, kctl = + snd_ctl_new1(&snd_hdspm_controls[idx], + hdspm))) < 0) { + return err; + } + } + + /* Channel playback mixer as default control + Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats to big for any alsamixer + they are accesible via special IOCTL on hwdep + and the mixer 2dimensional mixer control */ + + snd_hdspm_playback_mixer.name = "Chn"; + limit = HDSPM_MAX_CHANNELS; + + /* The index values are one greater than the channel ID so that alsamixer + will display them correctly. We want to use the index for fast lookup + of the relevant channel, but if we use it at all, most ALSA software + does the wrong thing with it ... + */ + + for (idx = 0; idx < limit; ++idx) { + snd_hdspm_playback_mixer.index = idx + 1; + if ((err = snd_ctl_add(card, + kctl = + snd_ctl_new1 + (&snd_hdspm_playback_mixer, + hdspm)))) { + return err; + } + hdspm->playback_mixer_ctls[idx] = kctl; + } + + return 0; +} + +/*------------------------------------------------------------ + /proc interface + ------------------------------------------------------------*/ + +static void +snd_hdspm_proc_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer) +{ + hdspm_t *hdspm = (hdspm_t *) entry->private_data; + unsigned int status; + unsigned int status2; + char *pref_sync_ref; + char *autosync_ref; + char *system_clock_mode; + char *clock_source; + char *insel; + char *syncref; + int x, x2; + + status = hdspm_read(hdspm, HDSPM_statusRegister); + status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + + snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", + hdspm->card_name, hdspm->card->number + 1, + hdspm->firmware_rev, + (status2 & HDSPM_version0) | + (status2 & HDSPM_version1) | (status2 & + HDSPM_version2)); + + snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", + hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); + + snd_iprintf(buffer, "--- System ---\n"); + + snd_iprintf(buffer, + "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", + status & HDSPM_audioIRQPending, + (status & HDSPM_midi0IRQPending) ? 1 : 0, + (status & HDSPM_midi1IRQPending) ? 1 : 0, + hdspm->irq_count); + snd_iprintf(buffer, + "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", + ((status & HDSPM_BufferID) ? 1 : 0), + (status & HDSPM_BufferPositionMask), + (status & HDSPM_BufferPositionMask) % (2 * + (int)hdspm-> + period_bytes), + ((status & HDSPM_BufferPositionMask) - + 64) % (2 * (int)hdspm->period_bytes), + (long) hdspm_hw_pointer(hdspm) * 4); + + snd_iprintf(buffer, + "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); + snd_iprintf(buffer, + "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x\n", + hdspm->control_register, hdspm->control2_register, + status, status2); + + snd_iprintf(buffer, "--- Settings ---\n"); + + x = 1 << (6 + + hdspm_decode_latency(hdspm-> + control_register & + HDSPM_LatencyMask)); + + snd_iprintf(buffer, + "Size (Latency): %d samples (2 periods of %lu bytes)\n", + x, (unsigned long) hdspm->period_bytes); + + snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n", + (hdspm-> + control_register & HDSPM_LineOut) ? "on " : "off", + (hdspm->precise_ptr) ? "on" : "off"); + + switch (hdspm->control_register & HDSPM_InputMask) { + case HDSPM_InputOptical: + insel = "Optical"; + break; + case HDSPM_InputCoaxial: + insel = "Coaxial"; + break; + default: + insel = "Unkown"; + } + + switch (hdspm->control_register & HDSPM_SyncRefMask) { + case HDSPM_SyncRef_Word: + syncref = "WordClock"; + break; + case HDSPM_SyncRef_MADI: + syncref = "MADI"; + break; + default: + syncref = "Unkown"; + } + snd_iprintf(buffer, "Inputsel = %s, SyncRef = %s\n", insel, + syncref); + + snd_iprintf(buffer, + "ClearTrackMarker = %s, Transmit in %s Channel Mode, Auto Input %s\n", + (hdspm-> + control_register & HDSPM_clr_tms) ? "on" : "off", + (hdspm-> + control_register & HDSPM_TX_64ch) ? "64" : "56", + (hdspm-> + control_register & HDSPM_AutoInp) ? "on" : "off"); + + switch (hdspm_clock_source(hdspm)) { + case HDSPM_CLOCK_SOURCE_AUTOSYNC: + clock_source = "AutoSync"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ: + clock_source = "Internal 32 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ: + clock_source = "Internal 44.1 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ: + clock_source = "Internal 48 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ: + clock_source = "Internal 64 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ: + clock_source = "Internal 88.2 kHz"; + break; + case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ: + clock_source = "Internal 96 kHz"; + break; + default: + clock_source = "Error"; + } + snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source); + if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { + system_clock_mode = "Slave"; + } else { + system_clock_mode = "Master"; + } + snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode); + + switch (hdspm_pref_sync_ref(hdspm)) { + case HDSPM_SYNC_FROM_WORD: + pref_sync_ref = "Word Clock"; + break; + case HDSPM_SYNC_FROM_MADI: + pref_sync_ref = "MADI Sync"; + break; + default: + pref_sync_ref = "XXXX Clock"; + break; + } + snd_iprintf(buffer, "Preferred Sync Reference: %s\n", + pref_sync_ref); + + snd_iprintf(buffer, "System Clock Frequency: %d\n", + hdspm->system_sample_rate); + + + snd_iprintf(buffer, "--- Status:\n"); + + x = status & HDSPM_madiSync; + x2 = status2 & HDSPM_wcSync; + + snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n", + (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") : + "NoLock", + (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") : + "NoLock"); + + switch (hdspm_autosync_ref(hdspm)) { + case HDSPM_AUTOSYNC_FROM_WORD: + autosync_ref = "Word Clock"; + break; + case HDSPM_AUTOSYNC_FROM_MADI: + autosync_ref = "MADI Sync"; + break; + case HDSPM_AUTOSYNC_FROM_NONE: + autosync_ref = "Input not valid"; + break; + default: + autosync_ref = "---"; + break; + } + snd_iprintf(buffer, + "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n", + autosync_ref, hdspm_external_sample_rate(hdspm), + (status & HDSPM_madiFreqMask) >> 22, + (status2 & HDSPM_wcFreqMask) >> 5); + + snd_iprintf(buffer, "Input: %s, Mode=%s\n", + (status & HDSPM_AB_int) ? "Coax" : "Optical", + (status & HDSPM_RX_64ch) ? "64 channels" : + "56 channels"); + + snd_iprintf(buffer, "\n"); +} + +static void __devinit snd_hdspm_proc_init(hdspm_t * hdspm) +{ + snd_info_entry_t *entry; + + if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) + snd_info_set_text_ops(entry, hdspm, 1024, + snd_hdspm_proc_read); +} + +/*------------------------------------------------------------ + hdspm intitialize + ------------------------------------------------------------*/ + +static int snd_hdspm_set_defaults(hdspm_t * hdspm) +{ + unsigned int i; + + /* ASSUMPTION: hdspm->lock is either held, or there is no need to + hold it (e.g. during module initalization). + */ + + /* set defaults: */ + + hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ + HDSPM_InputCoaxial | /* Input Coax not Optical */ + HDSPM_SyncRef_MADI | /* Madi is syncclock */ + HDSPM_LineOut | /* Analog output in */ + HDSPM_TX_64ch | /* transmit in 64ch mode */ + HDSPM_AutoInp; /* AutoInput chossing (takeover) */ + + /* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */ + /* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */ + /* ! HDSPM_clr_tms = do not clear bits in track marks */ + + hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + +#ifdef SNDRV_BIG_ENDIAN + hdspm->control2_register = HDSPM_BIGENDIAN_MODE; +#else + hdspm->control2_register = 0; +#endif + + hdspm_write(hdspm, HDSPM_control2Reg, hdspm->control2_register); + hdspm_compute_period_size(hdspm); + + /* silence everything */ + + all_in_all_mixer(hdspm, 0 * UNITY_GAIN); + + if (line_outs_monitor[hdspm->dev]) { + + snd_printk(KERN_INFO "HDSPM: sending all playback streams to line outs.\n"); + + for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) { + if (hdspm_write_pb_gain(hdspm, i, i, UNITY_GAIN)) + return -EIO; + } + } + + /* set a default rate so that the channel map is set up. */ + hdspm->channel_map = channel_map_madi_ss; + hdspm_set_rate(hdspm, 44100, 1); + + return 0; +} + + +/*------------------------------------------------------------ + interupt + ------------------------------------------------------------*/ + +static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + hdspm_t *hdspm = (hdspm_t *) dev_id; + unsigned int status; + int audio; + int midi0; + int midi1; + unsigned int midi0status; + unsigned int midi1status; + int schedule = 0; + + status = hdspm_read(hdspm, HDSPM_statusRegister); + + audio = status & HDSPM_audioIRQPending; + midi0 = status & HDSPM_midi0IRQPending; + midi1 = status & HDSPM_midi1IRQPending; + + if (!audio && !midi0 && !midi1) + return IRQ_NONE; + + hdspm_write(hdspm, HDSPM_interruptConfirmation, 0); + hdspm->irq_count++; + + midi0status = hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff; + midi1status = hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff; + + if (audio) { + + if (hdspm->capture_substream) + snd_pcm_period_elapsed(hdspm->pcm-> + streams + [SNDRV_PCM_STREAM_CAPTURE]. + substream); + + if (hdspm->playback_substream) + snd_pcm_period_elapsed(hdspm->pcm-> + streams + [SNDRV_PCM_STREAM_PLAYBACK]. + substream); + } + + if (midi0 && midi0status) { + /* we disable interrupts for this input until processing is done */ + hdspm->control_register &= ~HDSPM_Midi0InterruptEnable; + hdspm_write(hdspm, HDSPM_controlRegister, + hdspm->control_register); + hdspm->midi[0].pending = 1; + schedule = 1; + } + if (midi1 && midi1status) { + /* we disable interrupts for this input until processing is done */ + hdspm->control_register &= ~HDSPM_Midi1InterruptEnable; + hdspm_write(hdspm, HDSPM_controlRegister, + hdspm->control_register); + hdspm->midi[1].pending = 1; + schedule = 1; + } + if (schedule) + tasklet_hi_schedule(&hdspm->midi_tasklet); + return IRQ_HANDLED; +} + +/*------------------------------------------------------------ + pcm interface + ------------------------------------------------------------*/ + + +static snd_pcm_uframes_t snd_hdspm_hw_pointer(snd_pcm_substream_t * + substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + return hdspm_hw_pointer(hdspm); +} + +static char *hdspm_channel_buffer_location(hdspm_t * hdspm, + int stream, int channel) +{ + int mapped_channel; + + snd_assert(channel >= 0 + || channel < HDSPM_MAX_CHANNELS, return NULL); + + if ((mapped_channel = hdspm->channel_map[channel]) < 0) + return NULL; + + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + return hdspm->capture_buffer + + mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; + } else { + return hdspm->playback_buffer + + mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; + } +} + + +/* dont know why need it ??? */ +static int snd_hdspm_playback_copy(snd_pcm_substream_t * substream, + int channel, snd_pcm_uframes_t pos, + void __user *src, snd_pcm_uframes_t count) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + char *channel_buf; + + snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, + return -EINVAL); + + channel_buf = hdspm_channel_buffer_location(hdspm, + substream->pstr-> + stream, channel); + + snd_assert(channel_buf != NULL, return -EIO); + + return copy_from_user(channel_buf + pos * 4, src, count * 4); +} + +static int snd_hdspm_capture_copy(snd_pcm_substream_t * substream, + int channel, snd_pcm_uframes_t pos, + void __user *dst, snd_pcm_uframes_t count) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + char *channel_buf; + + snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, + return -EINVAL); + + channel_buf = hdspm_channel_buffer_location(hdspm, + substream->pstr-> + stream, channel); + snd_assert(channel_buf != NULL, return -EIO); + return copy_to_user(dst, channel_buf + pos * 4, count * 4); +} + +static int snd_hdspm_hw_silence(snd_pcm_substream_t * substream, + int channel, snd_pcm_uframes_t pos, + snd_pcm_uframes_t count) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + char *channel_buf; + + channel_buf = + hdspm_channel_buffer_location(hdspm, substream->pstr->stream, + channel); + snd_assert(channel_buf != NULL, return -EIO); + memset(channel_buf + pos * 4, 0, count * 4); + return 0; +} + +static int snd_hdspm_reset(snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + snd_pcm_substream_t *other; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + other = hdspm->capture_substream; + else + other = hdspm->playback_substream; + + if (hdspm->running) + runtime->status->hw_ptr = hdspm_hw_pointer(hdspm); + else + runtime->status->hw_ptr = 0; + if (other) { + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_runtime_t *oruntime = other->runtime; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + if (s == other) { + oruntime->status->hw_ptr = + runtime->status->hw_ptr; + break; + } + } + } + return 0; +} + +static int snd_hdspm_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * params) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + int err; + int i; + pid_t this_pid; + pid_t other_pid; + struct snd_sg_buf *sgbuf; + + + spin_lock_irq(&hdspm->lock); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { + this_pid = hdspm->playback_pid; + other_pid = hdspm->capture_pid; + } else { + this_pid = hdspm->capture_pid; + other_pid = hdspm->playback_pid; + } + + if ((other_pid > 0) && (this_pid != other_pid)) { + + /* The other stream is open, and not by the same + task as this one. Make sure that the parameters + that matter are the same. + */ + + if (params_rate(params) != hdspm->system_sample_rate) { + spin_unlock_irq(&hdspm->lock); + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_RATE); + return -EBUSY; + } + + if (params_period_size(params) != hdspm->period_bytes / 4) { + spin_unlock_irq(&hdspm->lock); + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + return -EBUSY; + } + + } + /* We're fine. */ + spin_unlock_irq(&hdspm->lock); + + /* how to make sure that the rate matches an externally-set one ? */ + + spin_lock_irq(&hdspm->lock); + if ((err = hdspm_set_rate(hdspm, params_rate(params), 0)) < 0) { + spin_unlock_irq(&hdspm->lock); + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_RATE); + return err; + } + spin_unlock_irq(&hdspm->lock); + + if ((err = + hdspm_set_interrupt_interval(hdspm, + params_period_size(params))) < + 0) { + _snd_pcm_hw_param_setempty(params, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + return err; + } + + /* Memory allocation, takashi's method, dont know if we should spinlock */ + /* malloc all buffer even if not enabled to get sure */ + /* malloc only needed bytes */ + err = + snd_pcm_lib_malloc_pages(substream, + HDSPM_CHANNEL_BUFFER_BYTES * + params_channels(params)); + if (err < 0) + return err; + + sgbuf = snd_pcm_substream_sgbuf(substream); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + + hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferOut, + params_channels(params)); + + for (i = 0; i < params_channels(params); ++i) + snd_hdspm_enable_out(hdspm, i, 1); + + hdspm->playback_buffer = + (unsigned char *) substream->runtime->dma_area; + } else { + hdspm_set_sgbuf(hdspm, sgbuf, HDSPM_pageAddressBufferIn, + params_channels(params)); + + for (i = 0; i < params_channels(params); ++i) + snd_hdspm_enable_in(hdspm, i, 1); + + hdspm->capture_buffer = + (unsigned char *) substream->runtime->dma_area; + } + return 0; +} + +static int snd_hdspm_hw_free(snd_pcm_substream_t * substream) +{ + int i; + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + + /* params_channels(params) should be enough, + but to get sure in case of error */ + for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) + snd_hdspm_enable_out(hdspm, i, 0); + + hdspm->playback_buffer = NULL; + } else { + for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) + snd_hdspm_enable_in(hdspm, i, 0); + + hdspm->capture_buffer = NULL; + + } + + snd_pcm_lib_free_pages(substream); + + return 0; +} + +static int snd_hdspm_channel_info(snd_pcm_substream_t * substream, + snd_pcm_channel_info_t * info) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + int mapped_channel; + + snd_assert(info->channel < HDSPM_MAX_CHANNELS, return -EINVAL); + + if ((mapped_channel = hdspm->channel_map[info->channel]) < 0) + return -EINVAL; + + info->offset = mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; + info->first = 0; + info->step = 32; + return 0; +} + +static int snd_hdspm_ioctl(snd_pcm_substream_t * substream, + unsigned int cmd, void *arg) +{ + switch (cmd) { + case SNDRV_PCM_IOCTL1_RESET: + { + return snd_hdspm_reset(substream); + } + + case SNDRV_PCM_IOCTL1_CHANNEL_INFO: + { + snd_pcm_channel_info_t *info = arg; + return snd_hdspm_channel_info(substream, info); + } + default: + break; + } + + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + +static int snd_hdspm_trigger(snd_pcm_substream_t * substream, int cmd) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + snd_pcm_substream_t *other; + int running; + + spin_lock(&hdspm->lock); + running = hdspm->running; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + running |= 1 << substream->stream; + break; + case SNDRV_PCM_TRIGGER_STOP: + running &= ~(1 << substream->stream); + break; + default: + snd_BUG(); + spin_unlock(&hdspm->lock); + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + other = hdspm->capture_substream; + else + other = hdspm->playback_substream; + + if (other) { + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + if (s == other) { + snd_pcm_trigger_done(s, substream); + if (cmd == SNDRV_PCM_TRIGGER_START) + running |= 1 << s->stream; + else + running &= ~(1 << s->stream); + goto _ok; + } + } + if (cmd == SNDRV_PCM_TRIGGER_START) { + if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) + && substream->stream == + SNDRV_PCM_STREAM_CAPTURE) + hdspm_silence_playback(hdspm); + } else { + if (running && + substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + hdspm_silence_playback(hdspm); + } + } else { + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + hdspm_silence_playback(hdspm); + } + _ok: + snd_pcm_trigger_done(substream, substream); + if (!hdspm->running && running) + hdspm_start_audio(hdspm); + else if (hdspm->running && !running) + hdspm_stop_audio(hdspm); + hdspm->running = running; + spin_unlock(&hdspm->lock); + + return 0; +} + +static int snd_hdspm_prepare(snd_pcm_substream_t * substream) +{ + return 0; +} + +static unsigned int period_sizes[] = + { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; + +static snd_pcm_hardware_t snd_hdspm_playback_subinfo = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_NONINTERLEAVED | + SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_DOUBLE), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = (SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), + .rate_min = 32000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = HDSPM_MAX_CHANNELS, + .buffer_bytes_max = + HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, + .period_bytes_min = (64 * 4), + .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0 +}; + +static snd_pcm_hardware_t snd_hdspm_capture_subinfo = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_NONINTERLEAVED | + SNDRV_PCM_INFO_SYNC_START), + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .rates = (SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), + .rate_min = 32000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = HDSPM_MAX_CHANNELS, + .buffer_bytes_max = + HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, + .period_bytes_min = (64 * 4), + .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS, + .periods_min = 2, + .periods_max = 2, + .fifo_size = 0 +}; + +static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { + .count = ARRAY_SIZE(period_sizes), + .list = period_sizes, + .mask = 0 +}; + + +static int snd_hdspm_hw_rule_channels_rate(snd_pcm_hw_params_t * params, + snd_pcm_hw_rule_t * rule) +{ + hdspm_t *hdspm = rule->private; + snd_interval_t *c = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_t *r = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + if (r->min > 48000) { + snd_interval_t t = { + .min = 1, + .max = hdspm->ds_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } else if (r->max < 64000) { + snd_interval_t t = { + .min = 1, + .max = hdspm->ss_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } + return 0; +} + +static int snd_hdspm_hw_rule_rate_channels(snd_pcm_hw_params_t * params, + snd_pcm_hw_rule_t * rule) +{ + hdspm_t *hdspm = rule->private; + snd_interval_t *c = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_t *r = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + if (c->min <= hdspm->ss_channels) { + snd_interval_t t = { + .min = 32000, + .max = 48000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } else if (c->max > hdspm->ss_channels) { + snd_interval_t t = { + .min = 64000, + .max = 96000, + .integer = 1, + }; + + return snd_interval_refine(r, &t); + } + return 0; +} + +static int snd_hdspm_playback_open(snd_pcm_substream_t * substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + snd_printdd("Open device substream %d\n", substream->stream); + + spin_lock_irq(&hdspm->lock); + + snd_pcm_set_sync(substream); + + runtime->hw = snd_hdspm_playback_subinfo; + + if (hdspm->capture_substream == NULL) + hdspm_stop_audio(hdspm); + + hdspm->playback_pid = current->pid; + hdspm->playback_substream = substream; + + spin_unlock_irq(&hdspm->lock); + + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes); + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + snd_hdspm_hw_rule_channels_rate, hdspm, + SNDRV_PCM_HW_PARAM_RATE, -1); + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + snd_hdspm_hw_rule_rate_channels, hdspm, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + + return 0; +} + +static int snd_hdspm_playback_release(snd_pcm_substream_t * substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + + spin_lock_irq(&hdspm->lock); + + hdspm->playback_pid = -1; + hdspm->playback_substream = NULL; + + spin_unlock_irq(&hdspm->lock); + + return 0; +} + + +static int snd_hdspm_capture_open(snd_pcm_substream_t * substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + spin_lock_irq(&hdspm->lock); + snd_pcm_set_sync(substream); + runtime->hw = snd_hdspm_capture_subinfo; + + if (hdspm->playback_substream == NULL) + hdspm_stop_audio(hdspm); + + hdspm->capture_pid = current->pid; + hdspm->capture_substream = substream; + + spin_unlock_irq(&hdspm->lock); + + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + &hw_constraints_period_sizes); + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + snd_hdspm_hw_rule_channels_rate, hdspm, + SNDRV_PCM_HW_PARAM_RATE, -1); + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + snd_hdspm_hw_rule_rate_channels, hdspm, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + return 0; +} + +static int snd_hdspm_capture_release(snd_pcm_substream_t * substream) +{ + hdspm_t *hdspm = snd_pcm_substream_chip(substream); + + spin_lock_irq(&hdspm->lock); + + hdspm->capture_pid = -1; + hdspm->capture_substream = NULL; + + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_hwdep_dummy_op(snd_hwdep_t * hw, struct file *file) +{ + /* we have nothing to initialize but the call is required */ + return 0; +} + + +static int snd_hdspm_hwdep_ioctl(snd_hwdep_t * hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + hdspm_t *hdspm = (hdspm_t *) hw->private_data; + struct sndrv_hdspm_mixer_ioctl mixer; + hdspm_config_info_t info; + hdspm_version_t hdspm_version; + struct sndrv_hdspm_peak_rms_ioctl rms; + + switch (cmd) { + + + case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: + if (copy_from_user(&rms, (void __user *)arg, sizeof(rms))) + return -EFAULT; + /* maybe there is a chance to memorymap in future so dont touch just copy */ + if(copy_to_user_fromio((void __user *)rms.peak, + hdspm->iobase+HDSPM_MADI_peakrmsbase, + sizeof(hdspm_peak_rms_t)) != 0 ) + return -EFAULT; + + break; + + + case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO: + + spin_lock_irq(&hdspm->lock); + info.pref_sync_ref = + (unsigned char) hdspm_pref_sync_ref(hdspm); + info.wordclock_sync_check = + (unsigned char) hdspm_wc_sync_check(hdspm); + + info.system_sample_rate = hdspm->system_sample_rate; + info.autosync_sample_rate = + hdspm_external_sample_rate(hdspm); + info.system_clock_mode = + (unsigned char) hdspm_system_clock_mode(hdspm); + info.clock_source = + (unsigned char) hdspm_clock_source(hdspm); + info.autosync_ref = + (unsigned char) hdspm_autosync_ref(hdspm); + info.line_out = (unsigned char) hdspm_line_out(hdspm); + info.passthru = 0; + spin_unlock_irq(&hdspm->lock); + if (copy_to_user((void __user *) arg, &info, sizeof(info))) + return -EFAULT; + break; + + case SNDRV_HDSPM_IOCTL_GET_VERSION: + hdspm_version.firmware_rev = hdspm->firmware_rev; + if (copy_to_user((void __user *) arg, &hdspm_version, + sizeof(hdspm_version))) + return -EFAULT; + break; + + case SNDRV_HDSPM_IOCTL_GET_MIXER: + if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) + return -EFAULT; + if (copy_to_user + ((void __user *)mixer.mixer, hdspm->mixer, sizeof(hdspm_mixer_t))) + return -EFAULT; + break; + + default: + return -EINVAL; + } + return 0; +} + +static snd_pcm_ops_t snd_hdspm_playback_ops = { + .open = snd_hdspm_playback_open, + .close = snd_hdspm_playback_release, + .ioctl = snd_hdspm_ioctl, + .hw_params = snd_hdspm_hw_params, + .hw_free = snd_hdspm_hw_free, + .prepare = snd_hdspm_prepare, + .trigger = snd_hdspm_trigger, + .pointer = snd_hdspm_hw_pointer, + .copy = snd_hdspm_playback_copy, + .silence = snd_hdspm_hw_silence, + .page = snd_pcm_sgbuf_ops_page, +}; + +static snd_pcm_ops_t snd_hdspm_capture_ops = { + .open = snd_hdspm_capture_open, + .close = snd_hdspm_capture_release, + .ioctl = snd_hdspm_ioctl, + .hw_params = snd_hdspm_hw_params, + .hw_free = snd_hdspm_hw_free, + .prepare = snd_hdspm_prepare, + .trigger = snd_hdspm_trigger, + .pointer = snd_hdspm_hw_pointer, + .copy = snd_hdspm_capture_copy, + .page = snd_pcm_sgbuf_ops_page, +}; + +static int __devinit snd_hdspm_create_hwdep(snd_card_t * card, + hdspm_t * hdspm) +{ + snd_hwdep_t *hw; + int err; + + if ((err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw)) < 0) + return err; + + hdspm->hwdep = hw; + hw->private_data = hdspm; + strcpy(hw->name, "HDSPM hwdep interface"); + + hw->ops.open = snd_hdspm_hwdep_dummy_op; + hw->ops.ioctl = snd_hdspm_hwdep_ioctl; + hw->ops.release = snd_hdspm_hwdep_dummy_op; + + return 0; +} + + +/*------------------------------------------------------------ + memory interface + ------------------------------------------------------------*/ +static int __devinit snd_hdspm_preallocate_memory(hdspm_t * hdspm) +{ + int err; + snd_pcm_t *pcm; + size_t wanted; + + pcm = hdspm->pcm; + + wanted = HDSPM_DMA_AREA_BYTES + 4096; /* dont know why, but it works */ + + if ((err = + snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(hdspm->pci), + wanted, + wanted)) < 0) { + snd_printdd("Could not preallocate %d Bytes\n", wanted); + + return err; + } else + snd_printdd(" Preallocated %d Bytes\n", wanted); + + return 0; +} + +static int snd_hdspm_memory_free(hdspm_t * hdspm) +{ + snd_printdd("memory_free_for_all %p\n", hdspm->pcm); + + snd_pcm_lib_preallocate_free_for_all(hdspm->pcm); + return 0; +} + + +static void hdspm_set_sgbuf(hdspm_t * hdspm, struct snd_sg_buf *sgbuf, + unsigned int reg, int channels) +{ + int i; + for (i = 0; i < (channels * 16); i++) + hdspm_write(hdspm, reg + 4 * i, + snd_pcm_sgbuf_get_addr(sgbuf, + (size_t) 4096 * i)); +} + +/* ------------- ALSA Devices ---------------------------- */ +static int __devinit snd_hdspm_create_pcm(snd_card_t * card, + hdspm_t * hdspm) +{ + snd_pcm_t *pcm; + int err; + + if ((err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm)) < 0) + return err; + + hdspm->pcm = pcm; + pcm->private_data = hdspm; + strcpy(pcm->name, hdspm->card_name); + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_hdspm_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_hdspm_capture_ops); + + pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; + + if ((err = snd_hdspm_preallocate_memory(hdspm)) < 0) + return err; + + return 0; +} + +static inline void snd_hdspm_initialize_midi_flush(hdspm_t * hdspm) +{ + snd_hdspm_flush_midi_input(hdspm, 0); + snd_hdspm_flush_midi_input(hdspm, 1); +} + +static int __devinit snd_hdspm_create_alsa_devices(snd_card_t * card, + hdspm_t * hdspm) +{ + int err; + + snd_printdd("Create card...\n"); + if ((err = snd_hdspm_create_pcm(card, hdspm)) < 0) + return err; + + if ((err = snd_hdspm_create_midi(card, hdspm, 0)) < 0) + return err; + + if ((err = snd_hdspm_create_midi(card, hdspm, 1)) < 0) + return err; + + if ((err = snd_hdspm_create_controls(card, hdspm)) < 0) + return err; + + if ((err = snd_hdspm_create_hwdep(card, hdspm)) < 0) + return err; + + snd_printdd("proc init...\n"); + snd_hdspm_proc_init(hdspm); + + hdspm->system_sample_rate = -1; + hdspm->last_external_sample_rate = -1; + hdspm->last_internal_sample_rate = -1; + hdspm->playback_pid = -1; + hdspm->capture_pid = -1; + hdspm->capture_substream = NULL; + hdspm->playback_substream = NULL; + + snd_printdd("Set defaults...\n"); + if ((err = snd_hdspm_set_defaults(hdspm)) < 0) + return err; + + snd_printdd("Update mixer controls...\n"); + hdspm_update_simple_mixer_controls(hdspm); + + snd_printdd("Initializeing complete ???\n"); + + if ((err = snd_card_register(card)) < 0) { + snd_printk(KERN_ERR "HDSPM: error registering card\n"); + return err; + } + + snd_printdd("... yes now\n"); + + return 0; +} + +static int __devinit snd_hdspm_create(snd_card_t * card, hdspm_t * hdspm, + int precise_ptr, int enable_monitor) +{ + struct pci_dev *pci = hdspm->pci; + int err; + int i; + + unsigned long io_extent; + + hdspm->irq = -1; + hdspm->irq_count = 0; + + hdspm->midi[0].rmidi = NULL; + hdspm->midi[1].rmidi = NULL; + hdspm->midi[0].input = NULL; + hdspm->midi[1].input = NULL; + hdspm->midi[0].output = NULL; + hdspm->midi[1].output = NULL; + spin_lock_init(&hdspm->midi[0].lock); + spin_lock_init(&hdspm->midi[1].lock); + hdspm->iobase = NULL; + hdspm->control_register = 0; + hdspm->control2_register = 0; + + hdspm->playback_buffer = NULL; + hdspm->capture_buffer = NULL; + + for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) + hdspm->playback_mixer_ctls[i] = NULL; + hdspm->mixer = NULL; + + hdspm->card = card; + + spin_lock_init(&hdspm->lock); + + tasklet_init(&hdspm->midi_tasklet, + hdspm_midi_tasklet, (unsigned long) hdspm); + + pci_read_config_word(hdspm->pci, + PCI_CLASS_REVISION, &hdspm->firmware_rev); + + strcpy(card->driver, "HDSPM"); + strcpy(card->mixername, "Xilinx FPGA"); + hdspm->card_name = "RME HDSPM MADI"; + + if ((err = pci_enable_device(pci)) < 0) + return err; + + pci_set_master(hdspm->pci); + + if ((err = pci_request_regions(pci, "hdspm")) < 0) + return err; + + hdspm->port = pci_resource_start(pci, 0); + io_extent = pci_resource_len(pci, 0); + + snd_printdd("grabbed memory region 0x%lx-0x%lx\n", + hdspm->port, hdspm->port + io_extent - 1); + + + if ((hdspm->iobase = ioremap_nocache(hdspm->port, io_extent)) == NULL) { + snd_printk(KERN_ERR "HDSPM: unable to remap region 0x%lx-0x%lx\n", + hdspm->port, hdspm->port + io_extent - 1); + return -EBUSY; + } + snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n", + (unsigned long)hdspm->iobase, hdspm->port, + hdspm->port + io_extent - 1); + + if (request_irq(pci->irq, snd_hdspm_interrupt, + SA_INTERRUPT | SA_SHIRQ, "hdspm", + (void *) hdspm)) { + snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); + return -EBUSY; + } + + snd_printdd("use IRQ %d\n", pci->irq); + + hdspm->irq = pci->irq; + hdspm->precise_ptr = precise_ptr; + + hdspm->monitor_outs = enable_monitor; + + snd_printdd("kmalloc Mixer memory of %d Bytes\n", + sizeof(hdspm_mixer_t)); + if ((hdspm->mixer = + (hdspm_mixer_t *) kmalloc(sizeof(hdspm_mixer_t), GFP_KERNEL)) + == NULL) { + snd_printk(KERN_ERR "HDSPM: unable to kmalloc Mixer memory of %d Bytes\n", + (int)sizeof(hdspm_mixer_t)); + return err; + } + + hdspm->ss_channels = MADI_SS_CHANNELS; + hdspm->ds_channels = MADI_DS_CHANNELS; + hdspm->qs_channels = MADI_QS_CHANNELS; + + snd_printdd("create alsa devices.\n"); + if ((err = snd_hdspm_create_alsa_devices(card, hdspm)) < 0) + return err; + + snd_hdspm_initialize_midi_flush(hdspm); + + return 0; +} + +static int snd_hdspm_free(hdspm_t * hdspm) +{ + + if (hdspm->port) { + + /* stop th audio, and cancel all interrupts */ + hdspm->control_register &= + ~(HDSPM_Start | HDSPM_AudioInterruptEnable + | HDSPM_Midi0InterruptEnable | + HDSPM_Midi1InterruptEnable); + hdspm_write(hdspm, HDSPM_controlRegister, + hdspm->control_register); + } + + if (hdspm->irq >= 0) + free_irq(hdspm->irq, (void *) hdspm); + + + if (hdspm->mixer) + kfree(hdspm->mixer); + + if (hdspm->iobase) + iounmap(hdspm->iobase); + + snd_hdspm_memory_free(hdspm); + + if (hdspm->port) + pci_release_regions(hdspm->pci); + + pci_disable_device(hdspm->pci); + return 0; +} + +static void snd_hdspm_card_free(snd_card_t * card) +{ + hdspm_t *hdspm = (hdspm_t *) card->private_data; + + if (hdspm) + snd_hdspm_free(hdspm); +} + +static int __devinit snd_hdspm_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + hdspm_t *hdspm; + snd_card_t *card; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + if (!(card = snd_card_new(index[dev], id[dev], + THIS_MODULE, sizeof(hdspm_t)))) + return -ENOMEM; + + hdspm = (hdspm_t *) card->private_data; + card->private_free = snd_hdspm_card_free; + hdspm->dev = dev; + hdspm->pci = pci; + + if ((err = + snd_hdspm_create(card, hdspm, precise_ptr[dev], + enable_monitor[dev])) < 0) { + snd_card_free(card); + return err; + } + + strcpy(card->shortname, "HDSPM MADI"); + sprintf(card->longname, "%s at 0x%lx, irq %d", hdspm->card_name, + hdspm->port, hdspm->irq); + + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } + + pci_set_drvdata(pci, card); + + dev++; + return 0; +} + +static void __devexit snd_hdspm_remove(struct pci_dev *pci) +{ + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + +static struct pci_driver driver = { + .name = "RME Hammerfall DSP MADI", + .id_table = snd_hdspm_ids, + .probe = snd_hdspm_probe, + .remove = __devexit_p(snd_hdspm_remove), +}; + + +static int __init alsa_card_hdspm_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_hdspm_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_hdspm_init) +module_exit(alsa_card_hdspm_exit) -- cgit v1.2.3-70-g09d2 From c82bf829c01079e77286481884eacb229310b4f0 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 4 Jun 2005 15:03:06 +0200 Subject: [ALSA] ca0106: Fix 96000 Hz audio playback. CA0106 driver Signed-off-by: James Courtier-Dutton --- sound/pci/ca0106/ca0106.h | 2 +- sound/pci/ca0106/ca0106_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index beac9dad2ed..da09cab405a 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -154,7 +154,7 @@ * bit 9 0 = Mute / 1 = Analog out. * bit 10 0 = Line-in / 1 = Mic-in. * bit 11 0 = ? / 1 = ? - * bit 12 0 = ? / 1 = ? + * bit 12 0 = 48 Khz / 1 = 96 Khz Analog out on SB Live 24bit. * bit 13 0 = ? / 1 = ? * bit 14 0 = Mute / 1 = Analog out * bit 15 0 = ? / 1 = ? diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 0ec0c3ec220..95c28928426 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1277,7 +1277,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ - outl(0x005f4301, chip->port+GPIO); /* Analog */ + outl(0x005f5301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ -- cgit v1.2.3-70-g09d2 From 96d078154bca743512102e370a03fb71d56478f5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 7 Jun 2005 08:56:24 +0200 Subject: [ALSA] via82xx - fixed entry for Umax AB 595T (VIA K8N800A - VT8237) VIA82xx driver As the original reporter noted, the NO_VRA must be used for loud volumes. Signed-off-by: Jaroslav Kysela --- sound/pci/via82xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e329e19b674..e861a011002 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2159,7 +2159,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ { .subvendor = 0x1043, .subdevice = 0x812a, .action = VIA_DXS_SRC }, /* ASUS A8V Deluxe */ { .subvendor = 0x1071, .subdevice = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ - { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_ENABLE }, /* Umax AB 595T (VIA K8N800A - VT8237) */ + { .subvendor = 0x1071, .subdevice = 0x8399, .action = VIA_DXS_NO_VRA }, /* Umax AB 595T (VIA K8N800A - VT8237) */ { .subvendor = 0x10cf, .subdevice = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .subvendor = 0x1106, .subdevice = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ { .subvendor = 0x1106, .subdevice = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */ -- cgit v1.2.3-70-g09d2 From 4a19faee6332fad8f81eaa98cf0e3be15a2366c4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jun 2005 14:43:58 +0200 Subject: [ALSA] Fix the handling of amp cache in hda-codec HDA Codec driver Fixed the handling of amp cache in hda-codec driver. The confliction of cache values with different indices should be fixed now. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 74 ++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 40 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e6efaed4b46..cb3a7613934 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -566,9 +566,10 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre * amp access functions */ -#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64) +/* FIXME: more better hash key? */ +#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) #define INFO_AMP_CAPS (1<<0) -#define INFO_AMP_VOL (1<<1) +#define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ static void init_amp_hash(struct hda_codec *codec) @@ -627,28 +628,29 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) /* * read the current volume to info - * if the cache exists, read from the cache. + * if the cache exists, read the cache value. */ -static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, +static unsigned int get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, hda_nid_t nid, int ch, int direction, int index) { u32 val, parm; - if (info->status & (INFO_AMP_VOL << ch)) - return; + if (info->status & INFO_AMP_VOL(ch)) + return info->vol[ch]; parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; parm |= index; val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); info->vol[ch] = val & 0xff; - info->status |= INFO_AMP_VOL << ch; + info->status |= INFO_AMP_VOL(ch); + return info->vol[ch]; } /* - * write the current volume in info to the h/w + * write the current volume in info to the h/w and update the cache */ -static void put_vol_mute(struct hda_codec *codec, +static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, hda_nid_t nid, int ch, int direction, int index, int val) { u32 parm; @@ -658,30 +660,34 @@ static void put_vol_mute(struct hda_codec *codec, parm |= index << AC_AMP_SET_INDEX_SHIFT; parm |= val; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); + info->vol[ch] = val; } /* - * read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. + * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. */ static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); if (! info) return 0; - get_vol_mute(codec, info, nid, ch, direction, index); - return info->vol[ch]; + return get_vol_mute(codec, info, nid, ch, direction, index); } -static int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) +/* + * update the AMP value, mask = bit mask to set, val = the value + */ +static int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val) { struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); + if (! info) return 0; - get_vol_mute(codec, info, nid, ch, direction, idx); + val &= mask; + val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; if (info->vol[ch] == val && ! codec->in_resume) return 0; - put_vol_mute(codec, nid, ch, direction, idx, val); - info->vol[ch] = val; + put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } @@ -740,21 +746,15 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); - int val; long *valp = ucontrol->value.integer.value; int change = 0; - if (chs & 1) { - val = *valp & 0x7f; - val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80; - change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); - valp++; - } - if (chs & 2) { - val = *valp & 0x7f; - val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80; - change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val); - } + if (chs & 1) + change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, + 0x7f, *valp); + if (chs & 2) + change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, + 0x7f, valp[1]); return change; } @@ -793,21 +793,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t int chs = get_amp_channels(kcontrol); int dir = get_amp_direction(kcontrol); int idx = get_amp_index(kcontrol); - int val; long *valp = ucontrol->value.integer.value; int change = 0; - if (chs & 1) { - val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; - val |= *valp ? 0 : 0x80; - change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); - valp++; - } - if (chs & 2) { - val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; - val |= *valp ? 0 : 0x80; - change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val); - } + if (chs & 1) + change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, + 0x80, *valp ? 0 : 0x80); + if (chs & 2) + change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, + 0x80, valp[1] ? 0 : 0x80); return change; } -- cgit v1.2.3-70-g09d2 From ead9b7c39984f509dc42d81200109c01a0b689c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jun 2005 14:48:19 +0200 Subject: [ALSA] Fix the PCM mixer switch for AD1986A HDA Codec driver Fix the PCM mixer switch for AD1986a (it was a typo). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index caa48699344..2fd05bb8413 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -318,7 +318,7 @@ static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_ return change; } -#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_volume_info +#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { -- cgit v1.2.3-70-g09d2 From 41e41f1f3495c6a7443977d2842d6911e3dcf31c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jun 2005 14:48:49 +0200 Subject: [ALSA] Fix the analog loopback volumes of ALC codecs HDA Codec driver Fix the analog loopback volumes of ALC codecs. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 122 +++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 25 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ee1c4cd7f00..0ca5151908d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -78,6 +78,8 @@ struct alc_spec { /* PCM information */ struct hda_pcm pcm_rec[2]; + + struct semaphore bind_mutex; }; /* DAC/ADC assignment */ @@ -362,6 +364,73 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc } +/* + * bound volume controls + * + * bind multiple volumes (# indices, from 0) + */ + +#define AMP_VAL_IDX_SHIFT 19 +#define AMP_VAL_IDX_MASK (0x0f<<19) + +static int alc_bind_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned long pval; + + down(&spec->bind_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ + snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + kcontrol->private_value = pval; + up(&spec->bind_mutex); + return 0; +} + +static int alc_bind_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned long pval; + + down(&spec->bind_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ + snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); + kcontrol->private_value = pval; + up(&spec->bind_mutex); + return 0; +} + +static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned long pval; + int i, indices, change = 0; + + down(&spec->bind_mutex); + pval = kcontrol->private_value; + indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; + for (i = 0; i < indices; i++) { + kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); + change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + } + kcontrol->private_value = pval; + up(&spec->bind_mutex); + return change; +} + +#define ALC_BIND_VOL_MONO(xname, nid, channel, indices, direction) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = alc_bind_vol_info, \ + .get = alc_bind_vol_get, \ + .put = alc_bind_vol_put, \ + .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } + +#define ALC_BIND_VOL(xname,nid,indices,dir) ALC_BIND_VOL_MONO(xname,nid,3,indices,dir) + /* */ @@ -370,12 +439,12 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc * HP=0x19 */ static snd_kcontrol_new_t alc880_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), + ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -388,7 +457,7 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), /* We don't use NID 0x07 - see above */ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), @@ -423,15 +492,15 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19 */ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), + ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Side Playback Volume", 0x0d, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -443,7 +512,7 @@ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), */ HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), /* We don't use NID 0x07 - see above */ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), @@ -506,9 +575,9 @@ static snd_kcontrol_new_t alc880_w810_base_mixer[] = { }; static snd_kcontrol_new_t alc880_z71v_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -1215,10 +1284,10 @@ static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * } static snd_kcontrol_new_t alc880_test_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), + ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT), + ALC_BIND_VOL("CLFE Playback Volume", 0x0e, 2, HDA_OUTPUT), + ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT), PIN_CTL_TEST("Front Pin Mode", 0x14), PIN_CTL_TEST("Surround Pin Mode", 0x15), PIN_CTL_TEST("CLFE Pin Mode", 0x16), @@ -1402,6 +1471,7 @@ static int patch_alc880(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + init_MUTEX(&spec->bind_mutex); codec->spec = spec; board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); @@ -1551,7 +1621,7 @@ static struct alc_channel_mode alc260_modes[1] = { }; snd_kcontrol_new_t alc260_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x08, 2, HDA_OUTPUT), /* use LINE2 for the output */ /* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */ HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), @@ -1565,9 +1635,9 @@ snd_kcontrol_new_t alc260_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Headphone Playback Volume", 0x09, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + ALC_BIND_VOL_MONO("Mono Playback Volume", 0x0a, 1, 2, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), @@ -1660,6 +1730,7 @@ static int patch_alc260(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + init_MUTEX(&spec->bind_mutex); codec->spec = spec; spec->mixers[spec->num_mixers] = alc260_base_mixer; @@ -1757,15 +1828,15 @@ static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ static snd_kcontrol_new_t alc882_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), + ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT), HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), @@ -1895,6 +1966,7 @@ static int patch_alc882(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + init_MUTEX(&spec->bind_mutex); codec->spec = spec; spec->mixers[spec->num_mixers] = alc882_base_mixer; -- cgit v1.2.3-70-g09d2 From 1ccc67d692c52dcc02e70206338ff36ac145a939 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Jun 2005 14:49:31 +0200 Subject: [ALSA] Disable MPU401 on SIS7018 Trident driver Disable MPU401 support on SIS7018 since it results in kernel freeze. Signed-off-by: Takashi Iwai --- sound/pci/trident/trident.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 5d21cb811c8..940d531575c 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -143,7 +143,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, return err; } } - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, + if (trident->device != TRIDENT_DEVICE_ID_SI7018 && + (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, trident->midi_port, 1, trident->irq, 0, &trident->rmidi)) < 0) { snd_card_free(card); -- cgit v1.2.3-70-g09d2 From 3e289f16ec2e08bbb37ce57a31386ed135887da4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:45:09 +0200 Subject: [ALSA] hda-codec - Print all AMP IN values HDA generic driver Print all AMP IN values when multiple nodes are connected. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 15df7162f17..de1217bd8e6 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -68,21 +68,27 @@ static void print_amp_caps(snd_info_buffer_t *buffer, static void print_amp_vals(snd_info_buffer_t *buffer, struct hda_codec *codec, hda_nid_t nid, - int dir, int stereo) + int dir, int stereo, int indices) { unsigned int val; - if (stereo) { + int i; + + if (dir == HDA_OUTPUT) + dir = AC_AMP_GET_OUTPUT; + else + dir = AC_AMP_GET_INPUT; + for (i = 0; i < indices; i++) { + snd_iprintf(buffer, " ["); + if (stereo) { + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_LEFT | dir | i); + snd_iprintf(buffer, "0x%02x ", val); + } val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_LEFT | - (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : - AC_AMP_GET_INPUT)); - snd_iprintf(buffer, "0x%02x ", val); + AC_AMP_GET_RIGHT | dir | i); + snd_iprintf(buffer, "0x%02x]", val); } - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_RIGHT | - (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : - AC_AMP_GET_INPUT)); - snd_iprintf(buffer, "0x%02x\n", val); + snd_iprintf(buffer, "\n"); } static void print_pcm_caps(snd_info_buffer_t *buffer, @@ -217,6 +223,9 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) unsigned int wid_caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + int conn_len = 0; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; + snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, get_wid_type_name(wid_type), wid_caps); if (wid_caps & AC_WCAP_STEREO) @@ -231,19 +240,23 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) snd_iprintf(buffer, " Amp-Out"); snd_iprintf(buffer, "\n"); + if (wid_caps & AC_WCAP_CONN_LIST) + conn_len = snd_hda_get_connections(codec, nid, conn, + HDA_MAX_CONNECTIONS); + if (wid_caps & AC_WCAP_IN_AMP) { snd_iprintf(buffer, " Amp-In caps: "); print_amp_caps(buffer, codec, nid, HDA_INPUT); snd_iprintf(buffer, " Amp-In vals: "); print_amp_vals(buffer, codec, nid, HDA_INPUT, - wid_caps & AC_WCAP_STEREO); + wid_caps & AC_WCAP_STEREO, conn_len); } if (wid_caps & AC_WCAP_OUT_AMP) { snd_iprintf(buffer, " Amp-Out caps: "); print_amp_caps(buffer, codec, nid, HDA_OUTPUT); snd_iprintf(buffer, " Amp-Out vals: "); print_amp_vals(buffer, codec, nid, HDA_OUTPUT, - wid_caps & AC_WCAP_STEREO); + wid_caps & AC_WCAP_STEREO, 1); } if (wid_type == AC_WID_PIN) { @@ -267,10 +280,7 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) } if (wid_caps & AC_WCAP_CONN_LIST) { - hda_nid_t conn[HDA_MAX_CONNECTIONS]; - int c, conn_len, curr = -1; - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); + int c, curr = -1; if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) curr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0); -- cgit v1.2.3-70-g09d2 From 4b3acaf5b56f53ef259a6ddf8e17dcb529631d9b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:48:10 +0200 Subject: [ALSA] hda-codec - Feed front signals to all surrounds HDA Codec driver Feed front signals to all surround channels if no data is given for surround channels. It seems that CLFE works as expected (only center outputs) even if connected from the front line - at least on my test system. If this change causes problems on other system (e.g. only the left channel is transferred to the center channel), please let me know... Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index cb3a7613934..8805928167f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1682,11 +1682,12 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); /* surrounds */ for (i = 1; i < mout->num_dacs; i++) { - if (i == HDA_REAR && chs == 2) /* copy front to rear */ - snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, format); - else if (chs >= (i + 1) * 2) /* independent out */ + if (chs >= (i + 1) * 2) /* independent out */ snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2, format); + else /* copy front */ + snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, + format); } return 0; } -- cgit v1.2.3-70-g09d2 From 05acb863a27e7f82d81c422b977415fa80b99f96 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:50:25 +0200 Subject: [ALSA] hda-codec - Clean up and fix ALC-codec support code HDA Codec driver Clean up and fix ALC-codec support code. The last addition of bound volume is fixed now to handle correctly the bound 'mute switches'. The analog loopback should work better. The init verbs are fixed together with this change. The numbers are replaced with macros for better readability. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 636 ++++++++++++++++++++++-------------------- 1 file changed, 328 insertions(+), 308 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0ca5151908d..84ae90cc111 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -101,7 +101,7 @@ static hda_nid_t alc880_z71v_dac_nids[1] = { #if 0 /* The datasheet says the node 0x07 is connected from inputs, - * but it shows zero connection in the real implementation. + * but it shows zero connection in the real implementation on some devices. */ static hda_nid_t alc880_adc_nids[3] = { /* ADC0-2 */ @@ -373,7 +373,7 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc #define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_MASK (0x0f<<19) -static int alc_bind_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +static int alc_bind_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; @@ -382,13 +382,13 @@ static int alc_bind_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinf down(&spec->bind_mutex); pval = kcontrol->private_value; kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ - snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + snd_hda_mixer_amp_switch_info(kcontrol, uinfo); kcontrol->private_value = pval; up(&spec->bind_mutex); return 0; } -static int alc_bind_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int alc_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; @@ -397,13 +397,13 @@ static int alc_bind_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon down(&spec->bind_mutex); pval = kcontrol->private_value; kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ - snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); + snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); kcontrol->private_value = pval; up(&spec->bind_mutex); return 0; } -static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; @@ -415,21 +415,21 @@ static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; for (i = 0; i < indices; i++) { kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); - change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); } kcontrol->private_value = pval; up(&spec->bind_mutex); return change; } -#define ALC_BIND_VOL_MONO(xname, nid, channel, indices, direction) \ +#define ALC_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = alc_bind_vol_info, \ - .get = alc_bind_vol_get, \ - .put = alc_bind_vol_put, \ + .info = alc_bind_switch_info, \ + .get = alc_bind_switch_get, \ + .put = alc_bind_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } -#define ALC_BIND_VOL(xname,nid,indices,dir) ALC_BIND_VOL_MONO(xname,nid,3,indices,dir) +#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) /* */ @@ -439,14 +439,14 @@ static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon * HP=0x19 */ static snd_kcontrol_new_t alc880_base_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), - ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x1a, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -457,8 +457,8 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), /* We don't use NID 0x07 - see above */ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), @@ -492,16 +492,16 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19 */ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT), - ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), - ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Side Playback Volume", 0x0d, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -575,10 +575,10 @@ static snd_kcontrol_new_t alc880_w810_base_mixer[] = { }; static snd_kcontrol_new_t alc880_z71v_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -636,51 +636,66 @@ static int alc_build_controls(struct hda_codec *codec) * initialize the codec volumes, etc */ +#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) +#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 +#define PIN_IN 0x20 +#define PIN_VREF 0x24 +#define PIN_OUT 0x40 +#define PIN_HP 0xc0 + static struct hda_verb alc880_init_verbs_three_stack[] = { + /* Set pin widgets for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + /* unmute capture amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* unmute capture1 amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* unmute capture2 amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute front mixer amp left (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute rear mixer amp left and right (volume = 0) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute rear mixer amp left and right (volume = 0) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* set vol=0 front mixer amp */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute front-out pin widget amp (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 rear mixer amp */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* mute line-in pin widget amp left and right (no gain on this amp) */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* set vol=0 clfe mixer amp */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* mute mic pin widget amp left and right (no gain on this amp) */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* using rear surround as the path for headphone output */ - /* unmute rear surround mixer amp left and right (volume = 0) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* set vol=0 rear surround mixer amp */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* PASD 3 stack boards use the Mic 2 as the headphone output */ /* need to program the selector associated with the Mic 2 pin widget to * surround path (index 0x01) for headphone output */ {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* need to retask the Mic 2 pin widget to output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B) * to support the input path of analog loopback @@ -688,14 +703,14 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { * mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ - /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + /* mute CD */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + /* mute Mic 1 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* mute Line In 2 (for PASD boards Mic 2) */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* Unmute input amps for the line out paths to support the output path of * analog loopback @@ -704,66 +719,70 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { */ /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute rear Surround out path */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; static struct hda_verb alc880_init_verbs_five_stack[] = { + /* Set pin widgets for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + /* mute capture amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* mute amp1 left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute front mixer amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* five rear and clfe */ - /* unmute rear mixer amp left and right (volume = 0) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, - /* unmute clfe mixer amp left and right (volume = 0) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + /* set vol=0 front mixer amp */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute front-out pin widget amp (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 rear mixer amp */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute rear-out pin widget (no gain on this amp) */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 clfe mixer amp */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute clfe-pin widget amp (no gain on this amp) */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* using rear surround as the path for headphone output */ - /* unmute rear surround mixer amp left and right (volume = 0) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + /* set vol=0 rear surround mixer amp */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* PASD 3 stack boards use the Mic 2 as the headphone output */ /* need to program the selector associated with the Mic 2 pin widget to * surround path (index 0x01) for headphone output */ {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, /* mute pin widget amp left and right (no gain on this amp) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* need to retask the Mic 2 pin widget to output */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, @@ -773,13 +792,13 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* Unmute input amps for the line out paths to support the output path of * analog loopback @@ -788,123 +807,121 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { */ /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Unmute rear Surround out path */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; static struct hda_verb alc880_w810_init_verbs[] = { /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* front channel selector/amp: output 0: unmuted, max volume */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* front out pin: muted, (no volume selection) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* front out pin: NOT headphone enable, out enable, vref disabled */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* surround channel selector/amp: output 0: unmuted, max volume */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* surround out pin: muted, (no volume selection) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* surround out pin: NOT headphone enable, out enable, vref disabled */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* c/lfe channel selector/amp: output 0: unmuted, max volume */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* c/lfe out pin: muted, (no volume selection) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* c/lfe out pin: NOT headphone enable, out enable, vref disabled */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* hphone/speaker input selector: front DAC */ {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* hphone/speaker out pin: muted, (no volume selection) */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, { } }; static struct hda_verb alc880_z71v_init_verbs[] = { - /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, - /* front channel selector/amp: output 0: unmuted, max volume */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* front out pin: muted, (no volume selection) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* front channel selector/amp: muted, DAC and mix (no vol) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* front channel selector/amp: output 0: vol=0 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* front out pin: unmuted, (no volume selection) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* front out pin: NOT headphone enable, out enable, vref disabled */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* headphone channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - /* headphone channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, - /* headphone channel selector/amp: output 0: unmuted, max volume */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* headphone out pin: muted, (no volume selection) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* headphone channel selector/amp: muted, DAC and mix (no vol) */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* headphone channel selector/amp: output 0: vol=0 */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* headphone out pin: muted, (no volume selection) */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* headpohne out pin: headphone enable, out enable, vref disabled */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer @@ -913,13 +930,13 @@ static struct hda_verb alc880_z71v_init_verbs[] = { /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, { } }; @@ -1284,10 +1301,14 @@ static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * } static snd_kcontrol_new_t alc880_test_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT), - ALC_BIND_VOL("CLFE Playback Volume", 0x0e, 2, HDA_OUTPUT), - ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + ALC_BIND_MUTE("CLFE Playback Volume", 0x0e, 2, HDA_INPUT), + ALC_BIND_MUTE("Side Playback Volume", 0x0f, 2, HDA_INPUT), PIN_CTL_TEST("Front Pin Mode", 0x14), PIN_CTL_TEST("Surround Pin Mode", 0x15), PIN_CTL_TEST("CLFE Pin Mode", 0x16), @@ -1310,10 +1331,10 @@ static snd_kcontrol_new_t alc880_test_mixer[] = { HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", @@ -1328,54 +1349,59 @@ static snd_kcontrol_new_t alc880_test_mixer[] = { .info = alc880_ch_mode_info, .get = alc880_ch_mode_get, .put = alc880_ch_mode_put, - .private_value = ARRAY_SIZE(alc880_test_modes), }, { } /* end */ }; static struct hda_verb alc880_test_init_verbs[] = { /* Unmute inputs of 0x0c - 0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0x7100}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* Vol output for 0x0c-0x0f */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* Set output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Unmute output pins 0x14-0x17 */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Set input pins 0x18-0x1c */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, /* vref 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mute input pins 0x18-0x1b */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* ADC set up */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Analog input/passthru */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, { } }; #endif @@ -1621,10 +1647,8 @@ static struct alc_channel_mode alc260_modes[1] = { }; snd_kcontrol_new_t alc260_base_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x08, 2, HDA_OUTPUT), - /* use LINE2 for the output */ - /* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), @@ -1635,10 +1659,10 @@ snd_kcontrol_new_t alc260_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), - ALC_BIND_VOL("Headphone Playback Volume", 0x09, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), - ALC_BIND_VOL_MONO("Mono Playback Volume", 0x0a, 1, 2, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), { @@ -1653,58 +1677,58 @@ snd_kcontrol_new_t alc260_base_mixer[] = { static struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* LINE-2 is used for line-out in rear */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* select line-out */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* LINE-OUT pin */ - {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* enable HP */ - {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* enable Mono */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - /* unmute amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* set connection select to line in (default select for this ADC) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* unmute Line-Out mixer amp left and right (volume = 0) */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* unmute HP mixer amp left and right (volume = 0) */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* unmute Mono mixer amp left and right (volume = 0) */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* mute LINE-2 out */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, + /* set vol=0 Line-Out mixer amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 HP mixer amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* set vol=0 Mono mixer amp left and right */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* unmute pin widget amp left and right (no gain on this amp) */ + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* unmute LINE-2 out pin */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* mute CD */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* mute Line In */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + /* mute Mic */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Headphone out path */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute Mono out path */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, + /* mute Front out path */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Headphone out path */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* mute Mono out path */ + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; @@ -1828,16 +1852,16 @@ static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ static snd_kcontrol_new_t alc882_base_mixer[] = { - ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT), - ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT), - HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -1869,91 +1893,87 @@ static snd_kcontrol_new_t alc882_base_mixer[] = { static struct hda_verb alc882_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Front Pin: to output mode */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Front Pin: mute amp left and right (no volume) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select Front mixer (0x0c, index 0) */ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Rear Pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Rear Pin: mute amp left and right (no volume) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select Rear mixer (0x0d, index 1) */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE Pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* CLFE Pin: mute amp left and right (no volume) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select CLFE mixer (0x0e, index 2) */ {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Side Pin */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Side Pin: mute amp left and right (no volume) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select Side mixer (0x0f, index 3) */ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Headphone Pin */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, /* Headphone Pin: mute amp left and right (no volume) */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* select Front mixer (0x0c, index 0) */ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Mic (rear) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Front Mic pin widget for input and vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* FIXME: use matrix-type input source selection */ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* ADC1: unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC3: unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Unmute front loopback */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Unmute rear loopback */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, - /* Mute CLFE loopback */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - /* Unmute side loopback */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, { } }; -- cgit v1.2.3-70-g09d2 From 5ecd7022f52872db32eddf85a527064ed7b522a3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:54:23 +0200 Subject: [ALSA] hda-codec - Allow sub_device=0 in board config check HDA Codec driver Allow sub_device=0 in board config check. This means that every device with the given sub vendor ID will match. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8805928167f..f62d1d5eb7f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1540,7 +1540,8 @@ int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); for (c = tbl; c->modelname || c->pci_subvendor; c++) { if (c->pci_subvendor == subsystem_vendor && - c->pci_subdevice == subsystem_device) + (! c->pci_subdevice /* all match */|| + (c->pci_subdevice == subsystem_device))) return c->config; } } -- cgit v1.2.3-70-g09d2 From 16ded525389c31256bcc9fd44352ab799b60b7fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2005 19:58:24 +0200 Subject: [ALSA] hda-codec - Add support of more models with ALC codecs HDA Codec driver,HDA Intel driver Merged the work of pshou for the support of more models with ALC codecs: ALC880 ASUS, Uniwill, FSC1734, generic 6-stack, and ALC260 HP. Tests with the real hardwares are appreciated. The codec patch is cleaned up: The preset configuration of codecs are stored in the table and copied to the spec instance. Added/fixed comments. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 6 + sound/pci/hda/hda_intel.c | 1 + sound/pci/hda/patch_realtek.c | 878 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 723 insertions(+), 162 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1b1203539ea..59991560d49 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -75,6 +75,9 @@ enum { #define AC_VERB_GET_DIGI_CONVERT 0x0f0d #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f /* f10-f1a: GPIO */ +#define AC_VERB_GET_GPIO_DATA 0x0f15 +#define AC_VERB_GET_GPIO_MASK 0x0f16 +#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c /* @@ -97,6 +100,9 @@ enum { #define AC_VERB_SET_DIGI_CONVERT_1 0x70d #define AC_VERB_SET_DIGI_CONVERT_2 0x70e #define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f +#define AC_VERB_SET_GPIO_DATA 0x715 +#define AC_VERB_SET_GPIO_MASK 0x716 +#define AC_VERB_SET_GPIO_DIRECTION 0x717 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0d546addc09..d8984919742 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1458,6 +1458,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */ + { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ULI */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 84ae90cc111..ce280c006be 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -33,7 +33,6 @@ /* ALC880 board config type */ enum { - ALC880_MINIMAL, ALC880_3ST, ALC880_3ST_DIG, ALC880_5ST, @@ -41,32 +40,54 @@ enum { ALC880_W810, ALC880_Z71V, ALC880_TEST, + ALC880_6ST_DIG, + ALC880_F1734, + ALC880_ASUS, + ALC880_ASUS_DIG, + ALC880_ASUS_W1V, + ALC880_UNIWILL_DIG, + ALC880_MODEL_LAST /* last tag */ +}; + +/* ALC260 models */ +enum { + ALC260_BASIC, + ALC260_HP, + ALC260_MODEL_LAST /* last tag */ }; struct alc_spec { /* codec parameterization */ - unsigned int front_panel: 1; - - snd_kcontrol_new_t* mixers[2]; + unsigned int front_panel: 1; /* indicates the board has a front panel; + * not referred currently for any purpose, + * though... + */ + + snd_kcontrol_new_t *mixers[2]; /* mixer arrays */ unsigned int num_mixers; - struct hda_verb *init_verbs; + struct hda_verb *init_verbs; /* initialization verbs + * don't forget NULL termination! + */ - char* stream_name_analog; + char *stream_name_analog; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; struct hda_pcm_stream *stream_analog_capture; - char* stream_name_digital; + char *stream_name_digital; /* digital PCM stream */ struct hda_pcm_stream *stream_digital_playback; struct hda_pcm_stream *stream_digital_capture; /* playback */ - struct hda_multi_out multiout; + struct hda_multi_out multiout; /* playback set-up + * max_channels, dacs must be set + * dig_out_nid and hp_nid are optional + */ /* capture */ unsigned int num_adc_nids; hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; + hda_nid_t dig_in_nid; /* digital-in NID; optional */ /* capture source */ const struct hda_input_mux *input_mux; @@ -77,9 +98,9 @@ struct alc_spec { int num_channel_mode; /* PCM information */ - struct hda_pcm pcm_rec[2]; + struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ - struct semaphore bind_mutex; + struct semaphore bind_mutex; /* for bound controls */ }; /* DAC/ADC assignment */ @@ -89,6 +110,11 @@ static hda_nid_t alc880_dac_nids[4] = { 0x02, 0x05, 0x04, 0x03 }; +static hda_nid_t alc880_6st_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; + static hda_nid_t alc880_w810_dac_nids[3] = { /* front, rear/surround, clfe */ 0x02, 0x03, 0x04 @@ -122,9 +148,14 @@ static hda_nid_t alc260_dac_nids[1] = { 0x02, }; -static hda_nid_t alc260_adc_nids[2] = { - /* ADC0-1 */ - 0x04, 0x05, +static hda_nid_t alc260_adc_nids[1] = { + /* ADC0 */ + 0x04, +}; + +static hda_nid_t alc260_hp_adc_nids[1] = { + /* ADC1 */ + 0x05, }; #define ALC260_DIGOUT_NID 0x03 @@ -140,6 +171,17 @@ static struct hda_input_mux alc880_capture_source = { }, }; +//pshou 05/24/05 +static struct hda_input_mux alc880_6stack_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + static struct hda_input_mux alc260_capture_source = { .num_items = 4, .items = { @@ -307,6 +349,11 @@ static struct alc_channel_mode alc880_z71v_modes[1] = { { 2, NULL } }; +//pshou 05/19/05 +static struct alc_channel_mode alc880_sixstack_modes[1] = { + { 8, NULL }, +}; + /* */ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -605,6 +652,172 @@ static snd_kcontrol_new_t alc880_z71v_mixer[] = { { } /* end */ }; +//pshou 05/24/05 +static snd_kcontrol_new_t alc880_six_stack_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), */ + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; + +// 03/08/05 Fujitsu +static snd_kcontrol_new_t alc880_2_jack_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + +//pshou 04/24/05 +static snd_kcontrol_new_t alc880_asus_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; + +// pshou 05/03/05 +static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; /* */ static int alc_build_controls(struct hda_codec *codec) @@ -642,7 +855,8 @@ static int alc_build_controls(struct hda_codec *codec) #define AMP_OUT_UNMUTE 0xb000 #define AMP_OUT_ZERO 0xb000 #define PIN_IN 0x20 -#define PIN_VREF 0x24 +#define PIN_VREF80 0x24 +#define PIN_VREF50 0x21 #define PIN_OUT 0x40 #define PIN_HP 0xc0 @@ -657,19 +871,19 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* unmute capture amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute capture1 amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute capture2 amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set vol=0 front mixer amp */ @@ -704,11 +918,11 @@ static struct hda_verb alc880_init_verbs_three_stack[] = { */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ /* mute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, /* mute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* mute Line In 2 (for PASD boards Mic 2) */ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, @@ -745,19 +959,19 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* mute capture amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* mute amp1 left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set vol=0 front mixer amp */ @@ -792,13 +1006,13 @@ static struct hda_verb alc880_init_verbs_five_stack[] = { /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, /* Unmute input amps for the line out paths to support the output path of * analog loopback @@ -909,19 +1123,19 @@ static struct hda_verb alc880_z71v_init_verbs[] = { /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to mic in */ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer @@ -930,17 +1144,150 @@ static struct hda_verb alc880_z71v_init_verbs[] = { /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + + { } +}; + +//pshou 05/24/05 +static struct hda_verb alc880_six_stack_init_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* unmute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer + * widget(nid=0x0B) to support the input path of analog loopback + */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* unmute Line In */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + /* unmute Mic 1 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* unmute Mic 2 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Unmute Front out path */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Unmute Surround (used as HP) out path */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Unmute C/LFE out path */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mute */ + /* Unmute rear Surround out path */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + { } +}; + +static struct hda_verb alc880_2_jack_init_verbs[] = { + /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x0C, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1B, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, { } }; +static struct hda_verb alc880_asus_init_verbs[] = { + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ + /* unmute CD */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* unmute Line In */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + /* unmute Mic 1 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* unmute Line In 2 (for PASD boards Mic 2) */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ + /* Unmute Front out path */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Unmute Surround (used as HP) out path */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Unmute C/LFE out path */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + + { } +}; + + static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1379,8 +1726,8 @@ static struct hda_verb alc880_test_init_verbs[] = { {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Set input pins 0x18-0x1c */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -1447,6 +1794,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { /* Back 3 jack, front 2 jack (Internal add Aux-In) */ { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, + { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, @@ -1463,6 +1811,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST }, { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST }, { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST }, /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, @@ -1474,6 +1823,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG }, { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG }, { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG }, + { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, { .modelname = "w810", .config = ALC880_W810 }, { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 }, @@ -1481,6 +1834,30 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .modelname = "z71v", .config = ALC880_Z71V }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, + { .modelname = "6statack-digout", .config = ALC880_6ST_DIG }, + { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG }, + { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, + { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, + { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, + + { .modelname = "asua", .config = ALC880_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, + + { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, + { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, + + { .modelname = "F1734", .config = ALC880_F1734 }, + { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, + #ifdef CONFIG_SND_DEBUG { .modelname = "test", .config = ALC880_TEST }, #endif @@ -1488,10 +1865,207 @@ static struct hda_board_config alc880_cfg_tbl[] = { {} }; +/* + * configuration template - to be copied to the spec instance + */ +struct alc_config_preset { + snd_kcontrol_new_t *mixers; + unsigned int front_panel: 1; /* optional */ + unsigned int gpio_payload; /* optional */ + struct hda_verb *init_verbs; + unsigned int num_dacs; + hda_nid_t *dac_nids; + hda_nid_t dig_out_nid; /* optional */ + hda_nid_t hp_nid; /* optional */ + unsigned int num_adc_nids; + hda_nid_t *adc_nids; + unsigned int num_channel_mode; + const struct alc_channel_mode *channel_mode; + const struct hda_input_mux *input_mux; +}; + +static struct alc_config_preset alc880_presets[] = { + [ALC880_3ST] = { + .mixers = alc880_base_mixer, + .init_verbs = alc880_init_verbs_three_stack, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .front_panel = 1, + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_3ST_DIG] = { + .mixers = alc880_base_mixer, + .init_verbs = alc880_init_verbs_three_stack, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .front_panel = 1, + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST] = { + .mixers = alc880_five_stack_mixer, + .init_verbs = alc880_init_verbs_five_stack, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_5ST_DIG] = { + .mixers = alc880_five_stack_mixer, + .init_verbs = alc880_init_verbs_five_stack, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), + .channel_mode = alc880_fivestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_6ST_DIG] = { + .mixers = alc880_six_stack_mixer, + .init_verbs = alc880_six_stack_init_verbs, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), + .dac_nids = alc880_6st_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), + .channel_mode = alc880_sixstack_modes, + .input_mux = &alc880_6stack_capture_source, + }, + [ALC880_W810] = { + .mixers = alc880_w810_base_mixer, + .init_verbs = alc880_w810_init_verbs, + .gpio_payload = 0x2, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + // No dedicated headphone socket - it's shared with built-in speakers. + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), + .channel_mode = alc880_w810_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_Z71V] = { + .mixers = alc880_z71v_mixer, + .init_verbs = alc880_z71v_init_verbs, + .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), + .dac_nids = alc880_z71v_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_z71v_modes), + .channel_mode = alc880_z71v_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_F1734] = { + .mixers = alc880_2_jack_mixer, + .init_verbs = alc880_2_jack_init_verbs, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_z71v_modes), + .channel_mode = alc880_z71v_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS] = { + .mixers = alc880_asus_mixer, + .init_verbs = alc880_asus_init_verbs, + .gpio_payload = 0x1, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_DIG] = { + .mixers = alc880_asus_mixer, + .init_verbs = alc880_asus_init_verbs, + .gpio_payload = 0x1, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_ASUS_W1V] = { + .mixers = alc880_asus_w1v_mixer, + .init_verbs = alc880_asus_init_verbs, + .gpio_payload = 0x1, + .front_panel = 1, + .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), + .dac_nids = alc880_w810_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, + [ALC880_UNIWILL_DIG] = { + .mixers = alc880_asus_mixer, + .init_verbs = alc880_asus_init_verbs, + .num_dacs = ARRAY_SIZE(alc880_dac_nids), + .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .hp_nid = 0x03, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .input_mux = &alc880_capture_source, + }, +#ifdef CONFIG_SND_DEBUG + [ALC880_TEST] = { + .mixers = alc880_test_mixer, + .init_verbs = alc880_test_init_verbs, + .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), + .dac_nids = alc880_test_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), + .adc_nids = alc880_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc880_test_modes), + .channel_mode = alc880_test_modes, + .input_mux = &alc880_test_capture_source, + }, +#endif +}; + static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; int board_config; + const struct alc_config_preset *preset; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -1501,91 +2075,31 @@ static int patch_alc880(struct hda_codec *codec) codec->spec = spec; board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); - if (board_config < 0) { + if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n"); - board_config = ALC880_MINIMAL; + board_config = ALC880_3ST; } + preset = &alc880_presets[board_config]; - switch (board_config) { - case ALC880_W810: - spec->mixers[spec->num_mixers] = alc880_w810_base_mixer; - spec->num_mixers++; - break; - case ALC880_5ST: - case ALC880_5ST_DIG: - spec->mixers[spec->num_mixers] = alc880_five_stack_mixer; - spec->num_mixers++; - break; - case ALC880_Z71V: - spec->mixers[spec->num_mixers] = alc880_z71v_mixer; - spec->num_mixers++; - break; -#ifdef CONFIG_SND_DEBUG - case ALC880_TEST: - spec->mixers[spec->num_mixers] = alc880_test_mixer; - spec->num_mixers++; - break; -#endif - default: - spec->mixers[spec->num_mixers] = alc880_base_mixer; - spec->num_mixers++; - break; - } - - switch (board_config) { - case ALC880_3ST_DIG: - case ALC880_5ST_DIG: - case ALC880_W810: - case ALC880_Z71V: - case ALC880_TEST: - spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; - break; - default: - break; - } + spec->mixers[spec->num_mixers] = preset->mixers; + snd_assert(spec->mixers[0], kfree(spec);return -EINVAL); + spec->num_mixers++; - switch (board_config) { - case ALC880_3ST: - case ALC880_3ST_DIG: - case ALC880_5ST: - case ALC880_5ST_DIG: - case ALC880_W810: - spec->front_panel = 1; - break; - default: - break; + /* some MBs need GPIO setup */ + if (preset->gpio_payload) { + /* Enable mask and set output */ + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, preset->gpio_payload); + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, preset->gpio_payload); + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, preset->gpio_payload); } - switch (board_config) { - case ALC880_5ST: - case ALC880_5ST_DIG: - spec->init_verbs = alc880_init_verbs_five_stack; - spec->channel_mode = alc880_fivestack_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes); - break; - case ALC880_W810: - spec->init_verbs = alc880_w810_init_verbs; - spec->channel_mode = alc880_w810_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes); - break; - case ALC880_Z71V: - spec->init_verbs = alc880_z71v_init_verbs; - spec->channel_mode = alc880_z71v_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_z71v_modes); - break; -#ifdef CONFIG_SND_DEBUG - case ALC880_TEST: - spec->init_verbs = alc880_test_init_verbs; - spec->channel_mode = alc880_test_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_test_modes); - break; -#endif - default: - spec->init_verbs = alc880_init_verbs_three_stack; - spec->channel_mode = alc880_threestack_modes; - spec->num_channel_mode = ARRAY_SIZE(alc880_threestack_modes); - break; - } + spec->front_panel = preset->front_panel; + spec->init_verbs = preset->init_verbs; + spec->channel_mode = preset->channel_mode; + spec->num_channel_mode = preset->num_channel_mode; spec->stream_name_analog = "ALC880 Analog"; spec->stream_analog_playback = &alc880_pcm_analog_playback; @@ -1597,35 +2111,14 @@ static int patch_alc880(struct hda_codec *codec) spec->multiout.max_channels = spec->channel_mode[0].channels; - switch (board_config) { - case ALC880_W810: - spec->multiout.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids); - spec->multiout.dac_nids = alc880_w810_dac_nids; - // No dedicated headphone socket - it's shared with built-in speakers. - break; - case ALC880_Z71V: - spec->multiout.num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids); - spec->multiout.dac_nids = alc880_z71v_dac_nids; - spec->multiout.hp_nid = 0x03; - break; -#ifdef CONFIG_SND_DEBUG - case ALC880_TEST: - spec->multiout.num_dacs = ARRAY_SIZE(alc880_test_dac_nids); - spec->multiout.dac_nids = alc880_test_dac_nids; - spec->input_mux = &alc880_test_capture_source; - break; -#endif - default: - spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); - spec->multiout.dac_nids = alc880_dac_nids; - spec->multiout.hp_nid = 0x03; /* rear-surround NID */ - break; - } + spec->multiout.num_dacs = preset->num_dacs; + spec->multiout.dac_nids = preset->adc_nids; + spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.hp_nid = preset->hp_nid; - if (! spec->input_mux) - spec->input_mux = &alc880_capture_source; - spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); - spec->adc_nids = alc880_adc_nids; + spec->input_mux = preset->input_mux; + spec->num_adc_nids = preset->num_adc_nids; + spec->adc_nids = preset->adc_nids; codec->patch_ops = alc_patch_ops; @@ -1675,15 +2168,42 @@ snd_kcontrol_new_t alc260_base_mixer[] = { { } /* end */ }; +snd_kcontrol_new_t alc260_hp_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + static struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* LINE-2 is used for line-out in rear */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* select line-out */ @@ -1695,9 +2215,13 @@ static struct hda_verb alc260_init_verbs[] = { /* enable Mono */ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* mute capture amp left and right */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* set connection select to line in (default select for this ADC) */ {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* mute capture amp left and right */ + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* set connection select to line in (default select for this ADC) */ + {0x05, AC_VERB_SET_CONNECT_SEL, 0x02}, /* set vol=0 Line-Out mixer amp left and right */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* unmute pin widget amp left and right (no gain on this amp) */ @@ -1714,11 +2238,11 @@ static struct hda_verb alc260_init_verbs[] = { {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ /* mute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* mute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, /* mute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* mute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -1746,9 +2270,16 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = { .nid = 0x4, }; +static struct hda_board_config alc260_cfg_tbl[] = { + { .modelname = "hp", .config = ALC260_HP }, + { .pci_subvendor = 0x103c, .config = ALC260_HP }, + {} +}; + static int patch_alc260(struct hda_codec *codec) { struct alc_spec *spec; + int board_config; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -1757,8 +2288,22 @@ static int patch_alc260(struct hda_codec *codec) init_MUTEX(&spec->bind_mutex); codec->spec = spec; - spec->mixers[spec->num_mixers] = alc260_base_mixer; - spec->num_mixers++; + board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); + if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { + snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); + board_config = ALC260_BASIC; + } + + switch (board_config) { + case ALC260_HP: + spec->mixers[spec->num_mixers] = alc260_base_mixer; + spec->num_mixers++; + break; + default: + spec->mixers[spec->num_mixers] = alc260_base_mixer; + spec->num_mixers++; + break; + } spec->init_verbs = alc260_init_verbs; spec->channel_mode = alc260_modes; @@ -1773,8 +2318,17 @@ static int patch_alc260(struct hda_codec *codec) spec->multiout.dac_nids = alc260_dac_nids; spec->input_mux = &alc260_capture_source; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); - spec->adc_nids = alc260_adc_nids; + switch (board_config) { + case ALC260_HP: + spec->stream_analog_capture->nid = 5; + spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); + spec->adc_nids = alc260_hp_adc_nids; + break; + default: + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); + spec->adc_nids = alc260_adc_nids; + break; + } codec->patch_ops = alc_patch_ops; @@ -1940,9 +2494,9 @@ static struct hda_verb alc882_init_verbs[] = { /* select Front mixer (0x0c, index 0) */ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Mic (rear) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Front Mic pin widget for input and vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Line In pin widget for input */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* CD pin widget for input */ -- cgit v1.2.3-70-g09d2 From e9edcee061a80181f0d6e7cada07e1898c14718e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 13 Jun 2005 14:16:38 +0200 Subject: [ALSA] hda-codec - More fix of ALC880 codec support Documentation,HDA Codec driver,HDA generic driver,HDA Intel driver - Fix some invalid configurations, typos in the last patch - Make init_verbs chainable, so that different configs can share the same init_verbs - Reorder and clean up the source codes in patch_realtek.c - Add the pin default configuration parser, used commonly in cmedia and realtek patch codes. - Add 'auto' model to ALC880 for auto-configuration from BIOS Use this model as default, and 3-stack as fallback Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 4 + sound/pci/hda/hda_codec.c | 103 +- sound/pci/hda/hda_generic.c | 10 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/hda/hda_local.h | 33 +- sound/pci/hda/patch_cmedia.c | 236 +-- sound/pci/hda/patch_realtek.c | 1935 ++++++++++++----------- 7 files changed, 1218 insertions(+), 1105 deletions(-) (limited to 'sound/pci') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index ced9a6eac56..104a994b828 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -638,6 +638,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out w810 3-jack z71v 3-jack (HP shared SPDIF) + asus 3-jack + uniwill 3-jack + F1734 2-jack CMI9880 minimal 3-jack in back @@ -645,6 +648,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. full 6-jack in back, 2-jack in front full_dig 6-jack in back, 2-jack in front, SPDIF I/O allout 5-jack in back, 2-jack in front, SPDIF out + auto auto-config reading BIOS (default) Note 2: If you get click noises on output, try the module option position_fix=1 or 2. position_fix=1 will use the SD_LPIB diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f62d1d5eb7f..e2cf0238728 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1520,9 +1520,9 @@ int snd_hda_build_pcms(struct hda_bus *bus) * * If no entries are matching, the function returns a negative value. */ -int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl) +int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl) { - struct hda_board_config *c; + const struct hda_board_config *c; if (codec->bus->modelname) { for (c = tbl; c->modelname || c->pci_subvendor; c++) { @@ -1714,6 +1714,105 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_o return 0; } +/* + * Helper for automatic ping configuration + */ +/* parse all pin widgets and store the useful pin nids to cfg */ +int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg) +{ + hda_nid_t nid, nid_start; + int i, j, nodes; + short seq, sequences[4], assoc_line_out; + + memset(cfg, 0, sizeof(*cfg)); + + memset(sequences, 0, sizeof(sequences)); + assoc_line_out = 0; + + nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); + for (nid = nid_start; nid < nodes + nid_start; nid++) { + unsigned int wid_caps = snd_hda_param_read(codec, nid, + AC_PAR_AUDIO_WIDGET_CAP); + unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + unsigned int def_conf; + short assoc, loc; + + /* read all default configuration for pin complex */ + if (wid_type != AC_WID_PIN) + continue; + def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + continue; + loc = get_defcfg_location(def_conf); + switch (get_defcfg_device(def_conf)) { + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + seq = get_defcfg_sequence(def_conf); + assoc = get_defcfg_association(def_conf); + if (! assoc) + continue; + if (! assoc_line_out) + assoc_line_out = assoc; + else if (assoc_line_out != assoc) + continue; + if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) + continue; + cfg->line_out_pins[cfg->line_outs] = nid; + sequences[cfg->line_outs] = seq; + cfg->line_outs++; + break; + case AC_JACK_HP_OUT: + cfg->hp_pin = nid; + break; + case AC_JACK_MIC_IN: + if (loc == AC_JACK_LOC_FRONT) + cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid; + else + cfg->input_pins[AUTO_PIN_MIC] = nid; + break; + case AC_JACK_LINE_IN: + if (loc == AC_JACK_LOC_FRONT) + cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; + else + cfg->input_pins[AUTO_PIN_LINE] = nid; + break; + case AC_JACK_CD: + cfg->input_pins[AUTO_PIN_CD] = nid; + break; + case AC_JACK_AUX: + cfg->input_pins[AUTO_PIN_AUX] = nid; + break; + case AC_JACK_SPDIF_OUT: + cfg->dig_out_pin = nid; + break; + case AC_JACK_SPDIF_IN: + cfg->dig_in_pin = nid; + break; + } + } + + /* sort by sequence */ + for (i = 0; i < cfg->line_outs; i++) + for (j = i + 1; j < cfg->line_outs; j++) + if (sequences[i] > sequences[j]) { + seq = sequences[i]; + sequences[i] = sequences[j]; + sequences[j] = seq; + nid = cfg->line_out_pins[i]; + cfg->line_out_pins[i] = cfg->line_out_pins[j]; + cfg->line_out_pins[j] = nid; + } + + /* Swap surround and CLFE: the association order is front/CLFE/surr/back */ + if (cfg->line_outs >= 3) { + nid = cfg->line_out_pins[1]; + cfg->line_out_pins[1] = cfg->line_out_pins[2]; + cfg->line_out_pins[2] = nid; + } + + return 0; +} + #ifdef CONFIG_PM /* * power management diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index bfbeff2e0d0..2d046abb591 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -68,8 +68,8 @@ struct hda_gspec { /* * retrieve the default device type from the default config value */ -#define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) -#define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) +#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) /* * destructor @@ -323,7 +323,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, if (! (node->pin_caps & AC_PINCAP_OUT)) continue; if (jack_type >= 0) { - if (jack_type != get_defcfg_type(node)) + if (jack_type != defcfg_type(node)) continue; if (node->wid_caps & AC_WCAP_DIGITAL) continue; /* skip SPDIF */ @@ -418,8 +418,8 @@ static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc */ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) { - unsigned int location = get_defcfg_location(node); - switch (get_defcfg_type(node)) { + unsigned int location = defcfg_location(node); + switch (defcfg_type(node)) { case AC_JACK_LINE_IN: if ((location & 0x0f) == AC_JACK_LOC_FRONT) return "Front Line"; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d8984919742..5e0cca36ed5 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1458,7 +1458,7 @@ static struct pci_device_id azx_ids[] = { { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */ - { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ULI */ + { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index b8fbbc4901d..810cfd2d9bb 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -130,7 +130,7 @@ struct hda_board_config { unsigned short pci_subdevice; }; -int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl); +int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_config *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew); /* @@ -158,4 +158,35 @@ struct hda_bus_unsolicited { struct work_struct work; }; +/* + * Helper for automatic ping configuration + */ + +enum { + AUTO_PIN_MIC, + AUTO_PIN_FRONT_MIC, + AUTO_PIN_LINE, + AUTO_PIN_FRONT_LINE, + AUTO_PIN_CD, + AUTO_PIN_AUX, + AUTO_PIN_LAST +}; + +struct auto_pin_cfg { + int line_outs; + hda_nid_t line_out_pins[4]; /* sorted in the order of Front/Surr/CLFE/Side */ + hda_nid_t hp_pin; + hda_nid_t input_pins[AUTO_PIN_LAST]; + hda_nid_t dig_out_pin; + hda_nid_t dig_in_pin; +}; + +#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) +#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) +#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) +#define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) + +int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg); + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 087230ca20a..2d6e3e3d0a3 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -51,6 +51,7 @@ struct cmi_spec { /* playback */ struct hda_multi_out multiout; hda_nid_t dac_nids[4]; /* NID for each DAC */ + int num_dacs; /* capture */ hda_nid_t *adc_nids; @@ -77,6 +78,19 @@ struct cmi_spec { struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ }; +/* amp values */ +#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) +#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 +/* pinctl values */ +#define PIN_IN 0x20 +#define PIN_VREF80 0x24 +#define PIN_VREF50 0x21 +#define PIN_OUT 0x40 +#define PIN_HP 0xc0 + /* * input MUX */ @@ -114,9 +128,9 @@ static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon /* 3-stack / 2 channel */ static struct hda_verb cmi9880_ch2_init[] = { /* set line-in PIN for input */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* set mic PIN for input, also enable vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* route front PCM (DAC1) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, {} @@ -125,9 +139,9 @@ static struct hda_verb cmi9880_ch2_init[] = { /* 3-stack / 6 channel */ static struct hda_verb cmi9880_ch6_init[] = { /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* route front PCM (DAC1) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, {} @@ -136,9 +150,9 @@ static struct hda_verb cmi9880_ch6_init[] = { /* 3-stack+front / 8 channel */ static struct hda_verb cmi9880_ch8_init[] = { /* set line-in PIN for output */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* set mic PIN for output */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* route rear-surround PCM (DAC4) to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, {} @@ -281,27 +295,27 @@ static hda_nid_t cmi9880_adc_nids[2] = { */ static struct hda_verb cmi9880_basic_init[] = { /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* route front PCM to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-A for surround (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for line-in (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* route front mic to ADC1/2 */ { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, @@ -310,27 +324,27 @@ static struct hda_verb cmi9880_basic_init[] = { static struct hda_verb cmi9880_allout_init[] = { /* port-D for line out (rear panel) */ - { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-E for HP out (front panel) */ - { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* route front PCM to HP */ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, /* port-A for side (rear panel) */ - { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-G for CLFE (rear panel) */ - { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* port-H for side (rear panel) */ - { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, /* port-C for surround (rear panel) */ - { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* port-B for mic-in (rear panel) with vref */ - { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* port-F for mic-in (front panel) with vref */ - { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* CD-in */ - { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* route front mic to ADC1/2 */ { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, @@ -365,101 +379,9 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } -#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) -#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) -#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) - -/* get all pin default configuration in def_conf */ -static int cmi9880_get_pin_def_config(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid, nid_start; - int i = 0, nodes; - - nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); - for (nid = nid_start; nid < nodes + nid_start; nid++) { - unsigned int wid_caps = snd_hda_param_read(codec, nid, - AC_PAR_AUDIO_WIDGET_CAP); - unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - /* read all default configuration for pin complex */ - if (wid_type == AC_WID_PIN) { - spec->pin_nid[i] = nid; - spec->def_conf[i] = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - i++; - } - } - spec->pin_def_confs = i; - return 0; -} - -/* get a pin default configuration of nid in def_conf */ -static unsigned int cmi9880_get_def_config(struct hda_codec *codec, hda_nid_t nid) -{ - struct cmi_spec *spec = codec->spec; - int i = 0; - - while (spec->pin_nid[i] != nid && i < spec->pin_def_confs) - i++; - if (i == spec->pin_def_confs) - return (unsigned int) -1; - else - return spec->def_conf[i]; -} - -/* decide what pins to use for multichannel playback */ -static int cmi9880_get_multich_pins(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - int i, j, pins, seq[4]; - int max_channel = 0; - unsigned int def_conf, sequence; - hda_nid_t nid; - - memset(spec->multich_pin, 0, sizeof(spec->multich_pin)); - for (pins = 0, i = 0; i < spec->pin_def_confs && pins < 4; i++) { - def_conf = spec->def_conf[i]; - /* skip pin not connected */ - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - continue; - /* get the sequence if association == 1 */ - /* the other pins have association = 0, incorrect in spec 1.0 */ - if (get_defcfg_association(def_conf) == 1) { - sequence = get_defcfg_sequence(def_conf); - seq[pins] = sequence; - spec->multich_pin[pins] = spec->pin_nid[i]; - pins++; // ready for next slot - max_channel += 2; - } - } - /* sort by sequence, data collected here will be for Windows */ - for (i = 0; i < pins; i++) { - for (j = i + 1; j < pins; j++) { - if (seq[j] < seq[i]) { - sequence = seq[j]; - nid = spec->multich_pin[j]; - seq[j] = seq[i]; - spec->multich_pin[j] = spec->multich_pin[i]; - seq[i] = sequence; - spec->multich_pin[i] = nid; - } - } - } - /* the pin assignment is for front, C/LFE, surround and back */ - if (max_channel >= 6) { - hda_nid_t temp; - /* exchange pin of C/LFE and surround */ - temp = spec->multich_pin[1]; - spec->multich_pin[1] = spec->multich_pin[2]; - spec->multich_pin[2] = temp; - } - return max_channel; -} - /* fill in the multi_dac_nids table, which will decide which audio widget to use for each channel */ -static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) +static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct cmi_spec *spec = codec->spec; hda_nid_t nid; @@ -470,32 +392,34 @@ static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); memset(assigned, 0, sizeof(assigned)); /* check the pins we found */ - for (i = 0; i < spec->multiout.max_channels / 2; i++) { - nid = spec->multich_pin[i]; + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ - if (nid <= 0x0e && nid >= 0x0b) { - spec->dac_nids[i] = nid - 0x08; + if (nid >= 0x0b && nid <= 0x0e) { + spec->dac_nids[i] = (nid - 0x0b) + 0x03; assigned[nid - 0x0b] = 1; } } /* left pin can be connect to any audio widget */ - for (i = 0; i < spec->multiout.max_channels / 2; i++) { - if (!assigned[i]) { - /* search for an empty channel */ - /* I should also check the pin type */ - for (j = 0; j < ARRAY_SIZE(spec->dac_nids); j++) - if (! spec->dac_nids[j]) { - spec->dac_nids[j] = i + 3; - assigned[i] = 1; - break; - } + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (nid <= 0x0e) + continue; + /* search for an empty channel */ + for (j = 0; j < cfg->line_outs; j++) { + if (! assigned[j]) { + spec->dac_nids[i] = i + 0x03; + assigned[j] = 1; + break; + } } } + spec->num_dacs = cfg->line_outs; return 0; } /* create multi_init table, which is used for multichannel initialization */ -static int cmi9880_fill_multi_init(struct hda_codec *codec) +static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct cmi_spec *spec = codec->spec; hda_nid_t nid; @@ -503,29 +427,26 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec) /* clear the table, only one c-media dac assumed here */ memset(spec->multi_init, 0, sizeof(spec->multi_init)); - for (j = 0, i = 0; i < spec->multiout.max_channels / 2; i++) { + for (j = 0, i = 0; i < cfg->line_outs; i++) { hda_nid_t conn[4]; - nid = spec->multich_pin[i]; + nid = cfg->line_out_pins[i]; /* set as output */ spec->multi_init[j].nid = nid; spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; - spec->multi_init[j].param = 0xc0; + spec->multi_init[j].param = PIN_OUT; j++; - /* nid 0x0f,0x10,0x1f,0x20 are needed to set connection */ - switch (nid) { - case 0x0f: - case 0x10: - case 0x1f: - case 0x20: + if (nid > 0x0e) { /* set connection */ spec->multi_init[j].nid = nid; spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; + spec->multi_init[j].param = 0; /* find the index in connect list */ len = snd_hda_get_connections(codec, nid, conn, 4); for (k = 0; k < len; k++) - if (conn[k] == spec->dac_nids[i]) + if (conn[k] == spec->dac_nids[i]) { + spec->multi_init[j].param = j; break; - spec->multi_init[j].param = k < len ? k : 0; + } j++; break; } @@ -759,6 +680,7 @@ static int patch_cmi9880(struct hda_codec *codec) /* copy default DAC NIDs */ memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); + spec->num_dacs = 4; switch (spec->board_config) { case CMI_MINIMAL: @@ -795,18 +717,16 @@ static int patch_cmi9880(struct hda_codec *codec) { unsigned int port_e, port_f, port_g, port_h; unsigned int port_spdifi, port_spdifo; - int max_channels; + struct auto_pin_cfg cfg; + /* collect pin default configuration */ - cmi9880_get_pin_def_config(codec); - port_e = cmi9880_get_def_config(codec, 0x0f); - port_f = cmi9880_get_def_config(codec, 0x10); - port_g = cmi9880_get_def_config(codec, 0x1f); - port_h = cmi9880_get_def_config(codec, 0x20); - port_spdifi = cmi9880_get_def_config(codec, 0x13); - port_spdifo = cmi9880_get_def_config(codec, 0x12); + port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); spec->front_panel = 1; if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { + port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); spec->surr_switch = 1; /* no front panel */ if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || @@ -824,24 +744,26 @@ static int patch_cmi9880(struct hda_codec *codec) spec->multiout.max_channels = cmi9880_channel_modes[0].channels; } else { spec->input_mux = &cmi9880_basic_mux; + port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) spec->dig_in_nid = CMI_DIG_IN_NID; spec->multiout.max_channels = 8; } - max_channels = cmi9880_get_multich_pins(codec); - if (max_channels > 0) { - spec->multiout.max_channels = max_channels; - cmi9880_fill_multi_dac_nids(codec); - cmi9880_fill_multi_init(codec); + snd_hda_parse_pin_def_config(codec, &cfg); + if (cfg.line_outs) { + spec->multiout.max_channels = cfg.line_outs * 2; + cmi9880_fill_multi_dac_nids(codec, &cfg); + cmi9880_fill_multi_init(codec, &cfg); } else snd_printd("patch_cmedia: cannot detect association in defcfg\n"); break; } } - spec->multiout.num_dacs = 4; + spec->multiout.num_dacs = spec->num_dacs; spec->multiout.dac_nids = spec->dac_nids; spec->adc_nids = cmi9880_adc_nids; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ce280c006be..9edd558d6bd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -39,13 +39,16 @@ enum { ALC880_5ST_DIG, ALC880_W810, ALC880_Z71V, - ALC880_TEST, + ALC880_AUTO, ALC880_6ST_DIG, ALC880_F1734, ALC880_ASUS, ALC880_ASUS_DIG, ALC880_ASUS_W1V, ALC880_UNIWILL_DIG, +#ifdef CONFIG_SND_DEBUG + ALC880_TEST, +#endif ALC880_MODEL_LAST /* last tag */ }; @@ -56,19 +59,28 @@ enum { ALC260_MODEL_LAST /* last tag */ }; +/* amp values */ +#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) +#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 +/* pinctl values */ +#define PIN_IN 0x20 +#define PIN_VREF80 0x24 +#define PIN_VREF50 0x21 +#define PIN_OUT 0x40 +#define PIN_HP 0xc0 + struct alc_spec { /* codec parameterization */ - unsigned int front_panel: 1; /* indicates the board has a front panel; - * not referred currently for any purpose, - * though... - */ - - snd_kcontrol_new_t *mixers[2]; /* mixer arrays */ + snd_kcontrol_new_t *mixers[3]; /* mixer arrays */ unsigned int num_mixers; - struct hda_verb *init_verbs; /* initialization verbs - * don't forget NULL termination! - */ + const struct hda_verb *init_verbs[3]; /* initialization verbs + * don't forget NULL termination! + */ + unsigned int num_init_verbs; char *stream_name_analog; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; @@ -101,96 +113,14 @@ struct alc_spec { struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ struct semaphore bind_mutex; /* for bound controls */ -}; - -/* DAC/ADC assignment */ - -static hda_nid_t alc880_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x05, 0x04, 0x03 -}; - -static hda_nid_t alc880_6st_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -static hda_nid_t alc880_w810_dac_nids[3] = { - /* front, rear/surround, clfe */ - 0x02, 0x03, 0x04 -}; - -static hda_nid_t alc880_z71v_dac_nids[1] = { - /* front only? */ - 0x02 -}; - -#if 0 -/* The datasheet says the node 0x07 is connected from inputs, - * but it shows zero connection in the real implementation on some devices. - */ -static hda_nid_t alc880_adc_nids[3] = { - /* ADC0-2 */ - 0x07, 0x08, 0x09, -}; -#else -static hda_nid_t alc880_adc_nids[2] = { - /* ADC1-2 */ - 0x08, 0x09, -}; -#endif - -#define ALC880_DIGOUT_NID 0x06 -#define ALC880_DIGIN_NID 0x0a - -static hda_nid_t alc260_dac_nids[1] = { - /* front */ - 0x02, -}; - -static hda_nid_t alc260_adc_nids[1] = { - /* ADC0 */ - 0x04, -}; -static hda_nid_t alc260_hp_adc_nids[1] = { - /* ADC1 */ - 0x05, -}; - -#define ALC260_DIGOUT_NID 0x03 -#define ALC260_DIGIN_NID 0x06 - -static struct hda_input_mux alc880_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x3 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + unsigned int num_kctl_alloc, num_kctl_used; + snd_kcontrol_new_t *kctl_alloc; + struct hda_input_mux private_imux; }; -//pshou 05/24/05 -static struct hda_input_mux alc880_6stack_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc260_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; /* * input MUX handling @@ -221,6 +151,7 @@ static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); } + /* * channel mode setting */ @@ -229,133 +160,6 @@ struct alc_channel_mode { const struct hda_verb *sequence; }; - -/* - * channel source setting (2/6 channel selection for 3-stack) - */ - -/* - * set the path ways for 2 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static struct hda_verb alc880_threestack_ch2_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* set pin widget 18h (mic1) for input, for mic also enable the vref */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* mute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - /* mute for Mic1 PW */ - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - -/* - * 6ch mode - * need to set the codec line out and mic 1 pin widgets to outputs - */ -static struct hda_verb alc880_threestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for output */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* set pin widget 18h (mic1) for output */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* unmute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* unmute for Mic1 PW */ - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* for rear channel output using Line In 1 - * set select widget connection (nid = 0x12) - to summer node - * for rear NID = 0x0f...offset 3 in connection list - */ - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x3 }, - /* for Mic1 - retask for center/lfe */ - /* set select widget connection (nid = 0x10) - to summer node for - * front CLFE NID = 0x0e...offset 2 in connection list - */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x2 }, - { } /* end */ -}; - -static struct alc_channel_mode alc880_threestack_modes[2] = { - { 2, alc880_threestack_ch2_init }, - { 6, alc880_threestack_ch6_init }, -}; - - -/* - * channel source setting (6/8 channel selection for 5-stack) - */ - -/* set the path ways for 6 channel output - * need to set the codec line out and mic 1 pin widgets to inputs - */ -static struct hda_verb alc880_fivestack_ch6_init[] = { - /* set pin widget 1Ah (line in) for input */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* mute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - -/* need to set the codec line out and mic 1 pin widgets to outputs */ -static struct hda_verb alc880_fivestack_ch8_init[] = { - /* set pin widget 1Ah (line in) for output */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* unmute the output for Line In PW */ - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, - /* output for surround channel output using Line In 1 */ - /* set select widget connection (nid = 0x12) - to summer node - * for surr_rear NID = 0x0d...offset 1 in connection list - */ - { 0x12, AC_VERB_SET_CONNECT_SEL, 0x1 }, - { } /* end */ -}; - -static struct alc_channel_mode alc880_fivestack_modes[2] = { - { 6, alc880_fivestack_ch6_init }, - { 8, alc880_fivestack_ch8_init }, -}; - -/* - * channel source setting for W810 system - * - * W810 has rear IO for: - * Front (DAC 02) - * Surround (DAC 03) - * Center/LFE (DAC 04) - * Digital out (06) - * - * The system also has a pair of internal speakers, and a headphone jack. - * These are both connected to Line2 on the codec, hence to DAC 02. - * - * There is a variable resistor to control the speaker or headphone - * volume. This is a hardware-only device without a software API. - * - * Plugging headphones in will disable the internal speakers. This is - * implemented in hardware, not via the driver using jack sense. In - * a similar fashion, plugging into the rear socket marked "front" will - * disable both the speakers and headphones. - * - * For input, there's a microphone jack, and an "audio in" jack. - * These may not do anything useful with this driver yet, because I - * haven't setup any initialization verbs for these yet... - */ - -static struct alc_channel_mode alc880_w810_modes[1] = { - { 6, NULL } -}; - -static struct alc_channel_mode alc880_z71v_modes[1] = { - { 2, NULL } -}; - -//pshou 05/19/05 -static struct alc_channel_mode alc880_sixstack_modes[1] = { - { 8, NULL }, -}; - -/* - */ static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -478,18 +282,79 @@ static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u #define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) + /* + * ALC880 3-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) + * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b + * HP = 0x19 */ -/* 3-stack mode - * Pin assignment: Front=0x14, Line-In/Rear=0x1a, Mic/CLFE=0x18, F-Mic=0x1b - * HP=0x19 +static hda_nid_t alc880_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x05, 0x04, 0x03 +}; + +static hda_nid_t alc880_adc_nids[3] = { + /* ADC0-2 */ + 0x07, 0x08, 0x09, +}; + +/* The datasheet says the node 0x07 is connected from inputs, + * but it shows zero connection in the real implementation on some devices. */ -static snd_kcontrol_new_t alc880_base_mixer[] = { +static hda_nid_t alc880_adc_nids_alt[2] = { + /* ADC1-2 */ + 0x08, 0x09, +}; + +#define ALC880_DIGOUT_NID 0x06 +#define ALC880_DIGIN_NID 0x0a + +static struct hda_input_mux alc880_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x3 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* channel source setting (2/6 channel selection for 3-stack) */ +/* 2ch mode */ +static struct hda_verb alc880_threestack_ch2_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + /* set mic-in to input vref 80%, mute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* 6ch mode */ +static struct hda_verb alc880_threestack_ch6_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + /* set mic-in to output, unmute it */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; + +static struct alc_channel_mode alc880_threestack_modes[2] = { + { 2, alc880_threestack_ch2_init }, + { 6, alc880_threestack_ch6_init }, +}; + +static snd_kcontrol_new_t alc880_three_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x1a, 2, HDA_INPUT), + ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), @@ -504,13 +369,25 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - /* We don't use NID 0x07 - see above */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc880_ch_mode_info, + .get = alc880_ch_mode_get, + .put = alc880_ch_mode_put, + }, + { } /* end */ +}; + +/* capture mixer elements */ +static snd_kcontrol_new_t alc880_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -519,49 +396,16 @@ static snd_kcontrol_new_t alc880_base_mixer[] = { */ /* .name = "Capture Source", */ .name = "Input Source", - .count = 2, + .count = 3, .info = alc_mux_enum_info, .get = alc_mux_enum_get, .put = alc_mux_enum_put, }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc880_ch_mode_info, - .get = alc880_ch_mode_get, - .put = alc880_ch_mode_put, - }, { } /* end */ }; -/* 5-stack mode - * Pin assignment: Front=0x14, Rear=0x17, CLFE=0x16 - * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19 - */ -static snd_kcontrol_new_t alc880_five_stack_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), - /* We don't use NID 0x07 - see above */ +/* capture mixer elements (in case NID 0x07 not available) */ +static snd_kcontrol_new_t alc880_capture_alt_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), @@ -579,80 +423,77 @@ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { .get = alc_mux_enum_get, .put = alc_mux_enum_put, }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc880_ch_mode_info, - .get = alc880_ch_mode_get, - .put = alc880_ch_mode_put, - }, { } /* end */ }; -static snd_kcontrol_new_t alc880_w810_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, + + +/* + * ALC880 5-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd) + * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16 + * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19 + */ + +/* additional mixers to alc880_three_stack_mixer */ +static snd_kcontrol_new_t alc880_five_stack_mixer[] = { + HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), { } /* end */ }; -static snd_kcontrol_new_t alc880_z71v_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, +/* channel source setting (6/8 channel selection for 5-stack) */ +/* 6ch mode */ +static struct hda_verb alc880_fivestack_ch6_init[] = { + /* set line-in to input, mute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { } /* end */ }; -//pshou 05/24/05 +/* 8ch mode */ +static struct hda_verb alc880_fivestack_ch8_init[] = { + /* set line-in to output, unmute it */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { } /* end */ +}; + +static struct alc_channel_mode alc880_fivestack_modes[2] = { + { 6, alc880_fivestack_ch6_init }, + { 8, alc880_fivestack_ch8_init }, +}; + + +/* + * ALC880 6-stack model + * + * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f) + * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17, + * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b + */ + +static hda_nid_t alc880_6st_dac_nids[4] = { + /* front, rear, clfe, rear_surr */ + 0x02, 0x03, 0x04, 0x05 +}; + +static struct hda_input_mux alc880_6stack_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +/* fixed 8-channels */ +static struct alc_channel_mode alc880_sixstack_modes[1] = { + { 8, NULL }, +}; + static snd_kcontrol_new_t alc880_six_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -674,25 +515,6 @@ static snd_kcontrol_new_t alc880_six_stack_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -703,36 +525,44 @@ static snd_kcontrol_new_t alc880_six_stack_mixer[] = { { } /* end */ }; -// 03/08/05 Fujitsu -static snd_kcontrol_new_t alc880_2_jack_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ + +/* + * ALC880 W810 model + * + * W810 has rear IO for: + * Front (DAC 02) + * Surround (DAC 03) + * Center/LFE (DAC 04) + * Digital out (06) + * + * The system also has a pair of internal speakers, and a headphone jack. + * These are both connected to Line2 on the codec, hence to DAC 02. + * + * There is a variable resistor to control the speaker or headphone + * volume. This is a hardware-only device without a software API. + * + * Plugging headphones in will disable the internal speakers. This is + * implemented in hardware, not via the driver using jack sense. In + * a similar fashion, plugging into the rear socket marked "front" will + * disable both the speakers and headphones. + * + * For input, there's a microphone jack, and an "audio in" jack. + * These may not do anything useful with this driver yet, because I + * haven't setup any initialization verbs for these yet... + */ + +static hda_nid_t alc880_w810_dac_nids[3] = { + /* front, rear/surround, clfe */ + 0x02, 0x03, 0x04 }; -//pshou 04/24/05 -static snd_kcontrol_new_t alc880_asus_mixer[] = { +/* fixed 6 channels */ +static struct alc_channel_mode alc880_w810_modes[1] = { + { 6, NULL } +}; + +/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ +static snd_kcontrol_new_t alc880_w810_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -741,41 +571,80 @@ static snd_kcontrol_new_t alc880_asus_mixer[] = { HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ +}; + + +/* + * Z710V model + * + * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d) + * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a + */ + +static hda_nid_t alc880_z71v_dac_nids[1] = { + 0x02 +}; +#define ALC880_Z71V_HP_DAC 0x03 + +/* fixed 2 channels */ +static struct alc_channel_mode alc880_2_jack_modes[1] = { + { 2, NULL } +}; + +static snd_kcontrol_new_t alc880_z71v_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc880_ch_mode_info, - .get = alc880_ch_mode_get, - .put = alc880_ch_mode_put, - }, { } /* end */ }; -// pshou 05/03/05 -static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { + +/* FIXME! */ +/* + * ALC880 F1734 model + * + * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d) + * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18 + */ + +static hda_nid_t alc880_f1734_dac_nids[1] = { + 0x03 +}; +#define ALC880_F1734_HP_DAC 0x02 + +static snd_kcontrol_new_t alc880_f1734_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + + +/* FIXME! */ +/* + * ALC880 ASUS model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a + */ + +#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */ +#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */ + +static snd_kcontrol_new_t alc880_asus_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -788,27 +657,8 @@ static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - * FIXME: the controls appear in the "playback" view! - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -818,7 +668,26 @@ static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { }, { } /* end */ }; + +/* FIXME! */ +/* + * ALC880 ASUS W1V model + * + * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e) + * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16, + * Mic = 0x18, Line = 0x1a, Line2 = 0x1b + */ + +/* additional mixers to alc880_asus_mixer */ +static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = { + HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT), + { } /* end */ +}; + + /* + * build control elements */ static int alc_build_controls(struct hda_codec *codec) { @@ -845,453 +714,297 @@ static int alc_build_controls(struct hda_codec *codec) return 0; } + /* * initialize the codec volumes, etc */ -#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) -#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) -#define AMP_OUT_MUTE 0xb080 -#define AMP_OUT_UNMUTE 0xb000 -#define AMP_OUT_ZERO 0xb000 -#define PIN_IN 0x20 -#define PIN_VREF80 0x24 -#define PIN_VREF50 0x21 -#define PIN_OUT 0x40 -#define PIN_HP 0xc0 - -static struct hda_verb alc880_init_verbs_three_stack[] = { - /* Set pin widgets for output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* unmute capture amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ +/* + * generic initialization of ADC, input mixers and output mixers + */ +static struct hda_verb alc880_volume_init_verbs[] = { + /* + * Unmute ADC0-2 and set the default input to mic-in + */ {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute capture1 amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute capture2 amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* set vol=0 front mixer amp */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute front-out pin widget amp (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 rear mixer amp */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* mute line-in pin widget amp left and right (no gain on this amp) */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* set vol=0 clfe mixer amp */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* mute mic pin widget amp left and right (no gain on this amp) */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* using rear surround as the path for headphone output */ - /* set vol=0 rear surround mixer amp */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* PASD 3 stack boards use the Mic 2 as the headphone output */ - /* need to program the selector associated with the Mic 2 pin widget to - * surround path (index 0x01) for headphone output */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* unmute pin widget amp left and right (no gain on this amp) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* need to retask the Mic 2 pin widget to output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B) - * to support the input path of analog loopback + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for front panel * mic (mic 2) */ - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ - /* mute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* mute Mic 1 */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* mute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* Unmute input amps for the line out paths to support the output path of - * analog loopback - * the mixers on the output path has 2 inputs, one from the DAC and one - * from the mixer + /* + * Set up output mixers (0x0c - 0x0f) */ - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute Surround (used as HP) out path */ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute C/LFE out path */ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute rear Surround out path */ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, { } }; -static struct hda_verb alc880_init_verbs_five_stack[] = { - /* Set pin widgets for output */ +/* + * 3-stack pin configuration: + * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b + */ +static struct hda_verb alc880_pin_3stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround + */ + {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */ + + /* + * Set pin mode and muting + */ + /* set front pin widgets 0x14 for output */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line In pin widget for input */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* mute capture amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* mute amp1 left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* set vol=0 front mixer amp */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute front-out pin widget amp (no gain on this amp) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 rear mixer amp */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute rear-out pin widget (no gain on this amp) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* set vol=0 clfe mixer amp */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* unmute clfe-pin widget amp (no gain on this amp) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* using rear surround as the path for headphone output */ - /* set vol=0 rear surround mixer amp */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* PASD 3 stack boards use the Mic 2 as the headphone output */ - /* need to program the selector associated with the Mic 2 pin widget to - * surround path (index 0x01) for headphone output - */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* mute pin widget amp left and right (no gain on this amp) */ - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* need to retask the Mic 2 pin widget to output */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + { } +}; - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer - * widget(nid=0x0B) to support the input path of analog loopback +/* + * 5-stack pin configuration: + * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19, + * line-in/side = 0x1a, f-mic = 0x1b + */ +static struct hda_verb alc880_pin_5stack_init_verbs[] = { + /* + * preset connection lists of input pins + * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround */ - /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ - /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */ - /* Unmute input amps for the line out paths to support the output path of - * analog loopback - * the mixers on the output path has 2 inputs, one from the DAC and - * one from the mixer + /* + * Set pin mode and muting */ - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute rear Surround out path */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* set pin widgets 0x14-0x17 for output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* unmute pins for output (no gain on this amp) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + /* Mic1 (rear panel) pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Mic2 (as headphone out) for HP output */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Line In pin widget for input */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line2 (as front mic) pin widget for input and vref at 80% */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* CD pin widget for input */ + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, { } }; -static struct hda_verb alc880_w810_init_verbs[] = { - /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* front channel selector/amp: output 0: unmuted, max volume */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - - /* front out pin: muted, (no volume selection) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +/* + * W810 pin configuration: + * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b + */ +static struct hda_verb alc880_pin_w810_init_verbs[] = { + /* hphone/speaker input selector: front DAC */ + {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* front out pin: NOT headphone enable, out enable, vref disabled */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - - /* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* surround channel selector/amp: output 0: unmuted, max volume */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* surround out pin: muted, (no volume selection) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* surround out pin: NOT headphone enable, out enable, vref disabled */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - - /* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* c/lfe channel selector/amp: output 0: unmuted, max volume */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* c/lfe out pin: muted, (no volume selection) */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - /* c/lfe out pin: NOT headphone enable, out enable, vref disabled */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* hphone/speaker input selector: front DAC */ - {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, - - /* hphone/speaker out pin: muted, (no volume selection) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - - { } }; -static struct hda_verb alc880_z71v_init_verbs[] = { - /* front channel selector/amp: muted, DAC and mix (no vol) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* front channel selector/amp: output 0: vol=0 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* front out pin: unmuted, (no volume selection) */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* front out pin: NOT headphone enable, out enable, vref disabled */ +/* + * Z71V pin configuration: + * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?) + */ +static struct hda_verb alc880_pin_z71v_init_verbs[] = { {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* headphone channel selector/amp: muted, DAC and mix (no vol) */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* headphone channel selector/amp: output 0: vol=0 */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* headphone out pin: muted, (no volume selection) */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* headpohne out pin: headphone enable, out enable, vref disabled */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Line In pin widget for input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Mic1 (rear panel) pin widget for input and vref at 80% */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Mic2 (front panel) pin widget for input and vref at 80% */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* set connection select to mic in */ - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer - * widget(nid=0x0B) to support the input path of analog loopback - */ - /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ - /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, { } }; -//pshou 05/24/05 -static struct hda_verb alc880_six_stack_init_verbs[] = { +/* + * 6-stack pin configuration: + * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19, + * line = 0x1a, HP = 0x1b + */ +static struct hda_verb alc880_pin_6stack_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + +/* FIXME! */ +/* + * F1734 pin configuration: + * HP = 0x14, speaker-out = 0x15, mic = 0x18 + */ +static struct hda_verb alc880_pin_f1734_init_verbs[] = { {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* unmute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer - * widget(nid=0x0B) to support the input path of analog loopback - */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* unmute Mic 2 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mute */ - /* Unmute rear Surround out path */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - { } -}; -static struct hda_verb alc880_2_jack_init_verbs[] = { - /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x0C, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1B, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, { } }; -static struct hda_verb alc880_asus_init_verbs[] = { +/* FIXME! */ +/* + * ASUS pin configuration: + * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a + */ +static struct hda_verb alc880_pin_asus_init_verbs[] = { {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ - /* unmute CD */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* unmute Line In */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* unmute Mic 1 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* unmute Line In 2 (for PASD boards Mic 2) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } +}; - /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ - /* Unmute Front out path */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute Surround (used as HP) out path */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute C/LFE out path */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +/* Enable GPIO mask and set output */ +static struct hda_verb alc880_gpio1_init_verbs[] = { + {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, +}; - { } +/* Enable GPIO mask and set output */ +static struct hda_verb alc880_gpio2_init_verbs[] = { + {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, }; +/* + */ + static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - snd_hda_sequence_write(codec, spec->init_verbs); + unsigned int i; + + for (i = 0; i < spec->num_init_verbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); return 0; } @@ -1305,9 +1018,8 @@ static int alc_resume(struct hda_codec *codec) int i; alc_init(codec); - for (i = 0; i < spec->num_mixers; i++) { + for (i = 0; i < spec->num_mixers; i++) snd_hda_resume_ctls(codec, spec->mixers[i]); - } if (spec->multiout.dig_out_nid) snd_hda_resume_spdif_out(codec); if (spec->dig_in_nid) @@ -1399,7 +1111,7 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, - .nid = 0x02, /* NID to query formats and rates */ + /* NID is set in alc_build_pcms */ .ops = { .open = alc880_playback_pcm_open, .prepare = alc880_playback_pcm_prepare, @@ -1411,9 +1123,7 @@ static struct hda_pcm_stream alc880_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, - .nid = 0x08, /* NID to query formats and rates - * (0x07 might be broken on some devices) - */ + /* NID is set in alc_build_pcms */ .ops = { .prepare = alc880_capture_pcm_prepare, .cleanup = alc880_capture_pcm_cleanup @@ -1449,7 +1159,9 @@ static int alc_build_pcms(struct hda_codec *codec) info->name = spec->stream_name_analog; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; for (i = 0; i < spec->num_channel_mode; i++) { @@ -1477,7 +1189,18 @@ static int alc_build_pcms(struct hda_codec *codec) static void alc_free(struct hda_codec *codec) { - kfree(codec->spec); + struct alc_spec *spec = codec->spec; + unsigned int i; + + if (! spec) + return; + + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } + kfree(spec); } /* @@ -1840,7 +1563,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, - { .modelname = "asua", .config = ALC880_ASUS }, + { .modelname = "asus", .config = ALC880_ASUS }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, @@ -1869,10 +1592,8 @@ static struct hda_board_config alc880_cfg_tbl[] = { * configuration template - to be copied to the spec instance */ struct alc_config_preset { - snd_kcontrol_new_t *mixers; - unsigned int front_panel: 1; /* optional */ - unsigned int gpio_payload; /* optional */ - struct hda_verb *init_verbs; + snd_kcontrol_new_t *mixers[4]; + const struct hda_verb *init_verbs[4]; unsigned int num_dacs; hda_nid_t *dac_nids; hda_nid_t dig_out_nid; /* optional */ @@ -1886,174 +1607,134 @@ struct alc_config_preset { static struct alc_config_preset alc880_presets[] = { [ALC880_3ST] = { - .mixers = alc880_base_mixer, - .init_verbs = alc880_init_verbs_three_stack, + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .front_panel = 1, .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, }, [ALC880_3ST_DIG] = { - .mixers = alc880_base_mixer, - .init_verbs = alc880_init_verbs_three_stack, + .mixers = { alc880_three_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .front_panel = 1, .dac_nids = alc880_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, }, [ALC880_5ST] = { - .mixers = alc880_five_stack_mixer, - .init_verbs = alc880_init_verbs_five_stack, - .front_panel = 1, + .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer}, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), .channel_mode = alc880_fivestack_modes, .input_mux = &alc880_capture_source, }, [ALC880_5ST_DIG] = { - .mixers = alc880_five_stack_mixer, - .init_verbs = alc880_init_verbs_five_stack, - .front_panel = 1, + .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes), .channel_mode = alc880_fivestack_modes, .input_mux = &alc880_capture_source, }, [ALC880_6ST_DIG] = { - .mixers = alc880_six_stack_mixer, - .init_verbs = alc880_six_stack_init_verbs, - .front_panel = 1, + .mixers = { alc880_six_stack_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids), .dac_nids = alc880_6st_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes), .channel_mode = alc880_sixstack_modes, .input_mux = &alc880_6stack_capture_source, }, [ALC880_W810] = { - .mixers = alc880_w810_base_mixer, - .init_verbs = alc880_w810_init_verbs, - .gpio_payload = 0x2, + .mixers = { alc880_w810_base_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), .dac_nids = alc880_w810_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - // No dedicated headphone socket - it's shared with built-in speakers. - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_w810_modes), .channel_mode = alc880_w810_modes, .input_mux = &alc880_capture_source, }, [ALC880_Z71V] = { - .mixers = alc880_z71v_mixer, - .init_verbs = alc880_z71v_init_verbs, + .mixers = { alc880_z71v_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs, + alc880_gpio2_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids), .dac_nids = alc880_z71v_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_z71v_modes), - .channel_mode = alc880_z71v_modes, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, }, [ALC880_F1734] = { - .mixers = alc880_2_jack_mixer, - .init_verbs = alc880_2_jack_init_verbs, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_z71v_modes), - .channel_mode = alc880_z71v_modes, + .mixers = { alc880_f1734_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids), + .dac_nids = alc880_f1734_dac_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), + .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, }, [ALC880_ASUS] = { - .mixers = alc880_asus_mixer, - .init_verbs = alc880_asus_init_verbs, - .gpio_payload = 0x1, - .front_panel = 1, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, .input_mux = &alc880_capture_source, }, [ALC880_ASUS_DIG] = { - .mixers = alc880_asus_mixer, - .init_verbs = alc880_asus_init_verbs, - .gpio_payload = 0x1, - .front_panel = 1, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, .input_mux = &alc880_capture_source, }, [ALC880_ASUS_W1V] = { - .mixers = alc880_asus_w1v_mixer, - .init_verbs = alc880_asus_init_verbs, - .gpio_payload = 0x1, - .front_panel = 1, - .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids), - .dac_nids = alc880_w810_dac_nids, + .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, .input_mux = &alc880_capture_source, }, [ALC880_UNIWILL_DIG] = { - .mixers = alc880_asus_mixer, - .init_verbs = alc880_asus_init_verbs, - .num_dacs = ARRAY_SIZE(alc880_dac_nids), - .dac_nids = alc880_dac_nids, + .mixers = { alc880_asus_mixer }, + .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs }, + .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), + .dac_nids = alc880_asus_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .hp_nid = 0x03, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, + .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), + .channel_mode = alc880_asus_modes, .input_mux = &alc880_capture_source, }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { - .mixers = alc880_test_mixer, - .init_verbs = alc880_test_init_verbs, + .mixers = { alc880_test_mixer }, + .init_verbs = { alc880_test_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_test_dac_nids), .dac_nids = alc880_test_dac_nids, .dig_out_nid = ALC880_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc880_adc_nids), - .adc_nids = alc880_adc_nids, .num_channel_mode = ARRAY_SIZE(alc880_test_modes), .channel_mode = alc880_test_modes, .input_mux = &alc880_test_capture_source, @@ -2061,11 +1742,333 @@ static struct alc_config_preset alc880_presets[] = { #endif }; +/* + * Automatic parse of I/O pins from the BIOS configuration + */ + +#define NUM_CONTROL_ALLOC 32 +#define NUM_VERB_ALLOC 32 + +enum { + ALC_CTL_WIDGET_VOL, + ALC_CTL_WIDGET_MUTE, + ALC_CTL_BIND_MUTE, +}; +static snd_kcontrol_new_t alc880_control_templates[] = { + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + HDA_CODEC_MUTE(NULL, 0, 0, 0), + ALC_BIND_MUTE(NULL, 0, 0, 0), +}; + +/* add dynamic controls */ +static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val) +{ + snd_kcontrol_new_t *knew; + + if (spec->num_kctl_used >= spec->num_kctl_alloc) { + int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; + + knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ + if (! knew) + return -ENOMEM; + if (spec->kctl_alloc) { + memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); + kfree(spec->kctl_alloc); + } + spec->kctl_alloc = knew; + spec->num_kctl_alloc = num; + } + + knew = &spec->kctl_alloc[spec->num_kctl_used]; + *knew = alc880_control_templates[type]; + knew->name = snd_kmalloc_strdup(name, GFP_KERNEL); + if (! knew->name) + return -ENOMEM; + knew->private_value = val; + spec->num_kctl_used++; + return 0; +} + +#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) +#define alc880_fixed_pin_idx(nid) ((nid) - 0x14) +#define alc880_is_multi_pin(nid) ((nid) >= 0x18) +#define alc880_multi_pin_idx(nid) ((nid) - 0x18) +#define alc880_is_input_pin(nid) ((nid) >= 0x18) +#define alc880_input_pin_idx(nid) ((nid) - 0x18) +#define alc880_idx_to_dac(nid) ((nid) + 0x02) +#define alc880_dac_to_idx(nid) ((nid) - 0x02) +#define alc880_idx_to_mixer(nid) ((nid) + 0x0c) +#define alc880_idx_to_selector(nid) ((nid) + 0x10) +#define ALC880_PIN_CD_NID 0x1c + +/* fill in the dac_nids table from the parsed pin configuration */ +static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) +{ + hda_nid_t nid; + int assigned[4]; + int i, j; + + memset(assigned, 0, sizeof(assigned)); + + /* check the pins hardwired to audio widget */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (alc880_is_fixed_pin(nid)) { + int idx = alc880_fixed_pin_idx(nid); + spec->multiout.dac_nids[i] = alc880_dac_to_idx(idx); + assigned[idx] = 1; + } + } + /* left pins can be connect to any audio widget */ + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + if (alc880_is_fixed_pin(nid)) + continue; + /* search for an empty channel */ + for (j = 0; j < cfg->line_outs; j++) { + if (! assigned[j]) { + spec->multiout.dac_nids[i] = alc880_idx_to_dac(j); + assigned[j] = 1; + break; + } + } + } + spec->multiout.num_dacs = cfg->line_outs; + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; + hda_nid_t nid; + int i, err; + + for (i = 0; i < cfg->line_outs; i++) { + if (! spec->multiout.dac_nids[i]) + continue; + nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); + if (i == 2) { + /* Center/LFE */ + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) + return err; + } + } + + return 0; +} + +/* add playback controls for HP output */ +static int alc880_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) +{ + hda_nid_t nid; + int err; + + if (! pin) + return 0; + + if (alc880_is_fixed_pin(pin)) { + nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); + if (! spec->multiout.dac_nids[0]) { + /* use this as the primary output */ + spec->multiout.dac_nids[0] = nid; + if (! spec->multiout.num_dacs) + spec->multiout.num_dacs = 1; + } else + /* specify the DAC as the extra HP output */ + spec->multiout.hp_nid = nid; + /* control HP volume/switch on the output mixer amp */ + nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) + return err; + if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) + return err; + } else if (alc880_is_multi_pin(pin)) { + /* set manual connection */ + if (! spec->multiout.dac_nids[0]) { + /* use this as the primary output */ + spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin)); + if (! spec->multiout.num_dacs) + spec->multiout.num_dacs = 1; + } + /* we have only a switch on HP-out PIN */ + if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0) + return err; + } + return 0; +} + +/* create input playback/capture controls for the given pin */ +static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname) +{ + char name[32]; + int err, idx; + + sprintf(name, "%s Playback Volume", ctlname); + idx = alc880_input_pin_idx(pin); + if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) + return err; + sprintf(name, "%s Playback Switch", ctlname); + if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) + return err; + return 0; +} + +/* create playback/capture controls for input pins */ +static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) +{ + static char *labels[AUTO_PIN_LAST] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" + }; + struct hda_input_mux *imux = &spec->private_imux; + int i, err; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (alc880_is_input_pin(cfg->input_pins[i])) { + err = new_analog_input(spec, cfg->input_pins[i], labels[i]); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]); + imux->num_items++; + } + } + return 0; +} + +static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, + int dac_idx) +{ + /* set as output */ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + /* need the manual connection? */ + if (alc880_is_multi_pin(nid)) { + struct alc_spec *spec = codec->spec; + int idx = alc880_multi_pin_idx(nid); + snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, + AC_VERB_SET_CONNECT_SEL, + alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); + } +} + +static void alc880_auto_init_multi_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; + alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); + } +} + +static void alc880_auto_init_hp_out(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t pin; + + pin = spec->autocfg.hp_pin; + if (pin) /* connect to front */ + alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); +} + +static void alc880_auto_init_analog_input(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int i; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = spec->autocfg.input_pins[i]; + if (alc880_is_input_pin(nid)) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); + if (nid != ALC880_PIN_CD_NID) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } + } +} + +/* parse the BIOS configuration and set up the alc_spec */ +/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ +static int alc880_parse_auto_config(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + + if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) + return err; + if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0) + return err; + if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin) + return 0; /* can't find valid BIOS pin config */ + if ((err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || + (err = alc880_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || + (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = ALC880_DIGIN_NID; + + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; + + spec->input_mux = &spec->private_imux; + + return 1; +} + +/* init callback for auto-configuration model -- overriding the default init */ +static int alc880_auto_init(struct hda_codec *codec) +{ + alc_init(codec); + alc880_auto_init_multi_out(codec); + alc880_auto_init_hp_out(codec); + alc880_auto_init_analog_input(codec); + return 0; +} + +/* + * OK, here we have finally the patch for ALC880 + */ + static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; int board_config; - const struct alc_config_preset *preset; + int i, err; spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -2076,30 +2079,52 @@ static int patch_alc880(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); if (board_config < 0 || board_config >= ALC880_MODEL_LAST) { - snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n"); - board_config = ALC880_3ST; + printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n"); + board_config = ALC880_AUTO; } - preset = &alc880_presets[board_config]; - - spec->mixers[spec->num_mixers] = preset->mixers; - snd_assert(spec->mixers[0], kfree(spec);return -EINVAL); - spec->num_mixers++; - /* some MBs need GPIO setup */ - if (preset->gpio_payload) { - /* Enable mask and set output */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, preset->gpio_payload); - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, preset->gpio_payload); - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, preset->gpio_payload); + if (board_config == ALC880_AUTO) { + /* automatic parse from the BIOS config */ + err = alc880_parse_auto_config(codec); + if (err < 0) { + alc_free(codec); + return err; + } else if (! err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n"); + board_config = ALC880_3ST; + } } - spec->front_panel = preset->front_panel; - spec->init_verbs = preset->init_verbs; - spec->channel_mode = preset->channel_mode; - spec->num_channel_mode = preset->num_channel_mode; + if (board_config != ALC880_AUTO) { + /* set up from the preset table */ + const struct alc_config_preset *preset; + + preset = &alc880_presets[board_config]; + + for (i = 0; preset->mixers[i]; i++) { + snd_assert(spec->num_mixers < ARRAY_SIZE(spec->mixers), break); + spec->mixers[spec->num_mixers++] = preset->mixers[i]; + } + for (i = 0; preset->init_verbs[i]; i++) { + snd_assert(spec->num_init_verbs < ARRAY_SIZE(spec->init_verbs), break); + spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i]; + } + + spec->channel_mode = preset->channel_mode; + spec->num_channel_mode = preset->num_channel_mode; + + spec->multiout.max_channels = spec->channel_mode[0].channels; + + spec->multiout.num_dacs = preset->num_dacs; + spec->multiout.dac_nids = preset->dac_nids; + spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.hp_nid = preset->hp_nid; + + spec->input_mux = preset->input_mux; + + spec->num_adc_nids = preset->num_adc_nids; + spec->adc_nids = preset->adc_nids; + } spec->stream_name_analog = "ALC880 Analog"; spec->stream_analog_playback = &alc880_pcm_analog_playback; @@ -2109,26 +2134,64 @@ static int patch_alc880(struct hda_codec *codec) spec->stream_digital_playback = &alc880_pcm_digital_playback; spec->stream_digital_capture = &alc880_pcm_digital_capture; - spec->multiout.max_channels = spec->channel_mode[0].channels; - - spec->multiout.num_dacs = preset->num_dacs; - spec->multiout.dac_nids = preset->adc_nids; - spec->multiout.dig_out_nid = preset->dig_out_nid; - spec->multiout.hp_nid = preset->hp_nid; - - spec->input_mux = preset->input_mux; - spec->num_adc_nids = preset->num_adc_nids; - spec->adc_nids = preset->adc_nids; + if (! spec->adc_nids && spec->input_mux) { + /* check whether NID 0x07 is valid */ + unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0], + AC_PAR_AUDIO_WIDGET_CAP); + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ + if (wcap != AC_WID_AUD_IN) { + spec->adc_nids = alc880_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); + spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer; + spec->num_mixers++; + } else { + spec->adc_nids = alc880_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); + spec->mixers[spec->num_mixers] = alc880_capture_mixer; + spec->num_mixers++; + } + } codec->patch_ops = alc_patch_ops; + if (board_config == ALC880_AUTO) + codec->patch_ops.init = alc880_auto_init; return 0; } + /* * ALC260 support */ +static hda_nid_t alc260_dac_nids[1] = { + /* front */ + 0x02, +}; + +static hda_nid_t alc260_adc_nids[1] = { + /* ADC0 */ + 0x04, +}; + +static hda_nid_t alc260_hp_adc_nids[1] = { + /* ADC1 */ + 0x05, +}; + +#define ALC260_DIGOUT_NID 0x03 +#define ALC260_DIGIN_NID 0x06 + +static struct hda_input_mux alc260_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + /* * This is just place-holder, so there's something for alc_build_pcms to look * at when it calculates the maximum number of channels. ALC260 has no mixer @@ -2139,7 +2202,7 @@ static struct alc_channel_mode alc260_modes[1] = { { 2, NULL }, }; -snd_kcontrol_new_t alc260_base_mixer[] = { +static snd_kcontrol_new_t alc260_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), @@ -2168,7 +2231,7 @@ snd_kcontrol_new_t alc260_base_mixer[] = { { } /* end */ }; -snd_kcontrol_new_t alc260_hp_mixer[] = { +static snd_kcontrol_new_t alc260_hp_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), @@ -2260,14 +2323,12 @@ static struct hda_pcm_stream alc260_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .nid = 0x2, }; static struct hda_pcm_stream alc260_pcm_analog_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .nid = 0x4, }; static struct hda_board_config alc260_cfg_tbl[] = { @@ -2296,7 +2357,7 @@ static int patch_alc260(struct hda_codec *codec) switch (board_config) { case ALC260_HP: - spec->mixers[spec->num_mixers] = alc260_base_mixer; + spec->mixers[spec->num_mixers] = alc260_hp_mixer; spec->num_mixers++; break; default: @@ -2305,7 +2366,9 @@ static int patch_alc260(struct hda_codec *codec) break; } - spec->init_verbs = alc260_init_verbs; + spec->init_verbs[0] = alc260_init_verbs; + spec->num_init_verbs = 1; + spec->channel_mode = alc260_modes; spec->num_channel_mode = ARRAY_SIZE(alc260_modes); @@ -2320,7 +2383,6 @@ static int patch_alc260(struct hda_codec *codec) spec->input_mux = &alc260_capture_source; switch (board_config) { case ALC260_HP: - spec->stream_analog_capture->nid = 5; spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); spec->adc_nids = alc260_hp_adc_nids; break; @@ -2335,6 +2397,7 @@ static int patch_alc260(struct hda_codec *codec) return 0; } + /* * ALC882 support * @@ -2463,42 +2526,35 @@ static struct hda_verb alc882_init_verbs[] = { {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin: to output mode */ + /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Front Pin: mute amp left and right (no volume) */ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select Front mixer (0x0c, index 0) */ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin */ + /* Rear Pin: output 1 (0x0d) */ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Rear Pin: mute amp left and right (no volume) */ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select Rear mixer (0x0d, index 1) */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin */ + /* CLFE Pin: output 2 (0x0e) */ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* CLFE Pin: mute amp left and right (no volume) */ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select CLFE mixer (0x0e, index 2) */ {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin */ + /* Side Pin: output 3 (0x0f) */ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Side Pin: mute amp left and right (no volume) */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select Side mixer (0x0f, index 3) */ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Headphone Pin */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Headphone Pin: mute amp left and right (no volume) */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* select Front mixer (0x0c, index 0) */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Mic (rear) pin widget for input and vref at 80% */ + /* Mic (rear) pin: input vref at 80% */ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Front Mic pin widget for input and vref at 80% */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Line In pin widget for input */ + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: input */ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line-2 In: Headphone output (output 0 - 0x0c) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* CD pin widget for input */ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -2548,8 +2604,9 @@ static int patch_alc882(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; spec->dig_in_nid = ALC880_DIGIN_NID; - spec->front_panel = 1; - spec->init_verbs = alc882_init_verbs; + spec->init_verbs[0] = alc882_init_verbs; + spec->num_init_verbs = 1; + spec->channel_mode = alc882_ch_modes; spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes); -- cgit v1.2.3-70-g09d2 From ee3b4c60f452f8e24fe30ae73cb97da1beda0ca2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 14 Jun 2005 10:18:20 +0200 Subject: [ALSA] via82xx - Fix info text about dxs_support option VIA82xx driver Fixed the info text about dxs_support option (suggest dxs_support=5). Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e861a011002..7e570a4a4c3 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2211,8 +2211,9 @@ static int __devinit check_dxs_list(struct pci_dev *pci) * not detected, try 48k rate only to be sure. */ printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n"); - printk(KERN_INFO " Please try dxs_support=1 or dxs_support=4 option\n"); + printk(KERN_INFO " Please try dxs_support=5 option\n"); printk(KERN_INFO " and report if it works on your machine.\n"); + printk(KERN_INFO " For more details, read ALSA-Configuration.txt.\n"); return VIA_DXS_48K; }; -- cgit v1.2.3-70-g09d2 From dabbed6f729d806092851150ca3dd9efe2b64b58 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 14 Jun 2005 10:19:34 +0200 Subject: [ALSA] SigmaTel HDA SPDIF and input mux updates HDA Codec driver Adds SPDIF in/out support to the SigmaTel HDA codecs. Now builds the input mux control element names from the defcfg regs. Signed-off-by: Matt Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 184 ++++++++++++++++++++++++++++++++--------- 1 file changed, 145 insertions(+), 39 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1534e20af63..013be2ea513 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -42,9 +42,11 @@ struct sigmatel_spec { /* capture */ hda_nid_t *adc_nids; - hda_nid_t *mux_nids; unsigned int num_adcs; + hda_nid_t *mux_nids; + unsigned int num_muxes; hda_nid_t capture_nid; + hda_nid_t dig_in_nid; /* power management*/ hda_nid_t *pstate_nids; @@ -62,7 +64,8 @@ struct sigmatel_spec { snd_kcontrol_new_t *mixer; /* capture source */ - const struct hda_input_mux *input_mux; + struct hda_input_mux input_mux; + char input_labels[HDA_MAX_NUM_INPUTS][16]; unsigned int cur_mux[2]; /* channel mode */ @@ -105,8 +108,8 @@ static hda_nid_t stac922x_dac_nids[4] = { 0x02, 0x03, 0x04, 0x05, }; -static hda_nid_t stac922x_pstate_nids[7] = { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +static hda_nid_t stac922x_pstate_nids[8] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, }; static hda_nid_t stac922x_pin_nids[10] = { @@ -118,7 +121,7 @@ static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); + return snd_hda_input_mux_info(&spec->input_mux, uinfo); } static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) @@ -137,7 +140,7 @@ static int stac92xx_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t struct sigmatel_spec *spec = codec->spec; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); } @@ -192,30 +195,6 @@ static snd_kcontrol_new_t stac922x_mixer[] = { { } /* end */ }; -static struct hda_input_mux stac9200_input_mux = { - .num_items = 5, - .items = { - { "Port B", 0x0 }, - { "Port C", 0x1 }, - { "Port D", 0x2 }, - { "Port A", 0x3 }, - { "CD", 0x4 }, - } -}; - -static struct hda_input_mux stac922x_input_mux = { - .num_items = 7, - .items = { - { "Port E", 0x0 }, - { "CD", 0x1 }, - { "Port F", 0x2 }, - { "Port B", 0x3 }, - { "Port C", 0x4 }, - { "Port D", 0x5 }, - { "Port A", 0x6 }, - } -}; - static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -224,19 +203,28 @@ static int stac92xx_build_controls(struct hda_codec *codec) err = snd_hda_add_new_ctls(codec, spec->mixer); if (err < 0) return err; - - return 0; + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + if (err < 0) + return err; + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; + } + return 0; } #ifdef STAC_TEST static unsigned int stac9200_pin_configs[8] = { - 0x40000100, 0x40000100, 0x0221401f, 0x01114010, + 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; static unsigned int stac922x_pin_configs[14] = { 0x40000100, 0x40000100, 0x40000100, 0x01114010, - 0x01813122, 0x40000100, 0x40000100, 0x40000100, + 0x01813122, 0x40000100, 0x01447010, 0x01c47010, 0x40000100, 0x40000100, }; @@ -299,29 +287,89 @@ static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid) return 0; } +/* + * retrieve the default device type from the default config value + */ +#define get_defcfg_type(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) +#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) + static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg) { - switch((pin_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) { + struct sigmatel_spec *spec = codec->spec; + u32 location = get_defcfg_location(pin_cfg); + char *label; + const char *type = NULL; + int ainput = 0; + + switch(get_defcfg_type(pin_cfg)) { case AC_JACK_HP_OUT: /* Enable HP amp */ stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN); /* Fall through */ + case AC_JACK_SPDIF_OUT: case AC_JACK_LINE_OUT: case AC_JACK_SPEAKER: /* Enable output */ stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); break; + case AC_JACK_SPDIF_IN: + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; case AC_JACK_MIC_IN: + if ((location & 0x0f) == AC_JACK_LOC_FRONT) + type = "Front Mic"; + else + type = "Mic"; + ainput = 1; /* Set vref */ stac92xx_set_vref(codec, nid); + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; case AC_JACK_CD: + type = "CD"; + ainput = 1; + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; case AC_JACK_LINE_IN: + if ((location & 0x0f) == AC_JACK_LOC_FRONT) + type = "Front Line"; + else + type = "Line"; + ainput = 1; + stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); + break; case AC_JACK_AUX: - /* Enable input */ + if ((location & 0x0f) == AC_JACK_LOC_FRONT) + type = "Front Aux"; + else + type = "Aux"; + ainput = 1; stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); break; } + if (ainput) { + hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; + int i, j, num_cons, index = -1; + if (!type) + type = "Input"; + label = spec->input_labels[spec->input_mux.num_items]; + strcpy(label, type); + spec->input_mux.items[spec->input_mux.num_items].label = label; + for (i=0; inum_muxes; i++) { + num_cons = snd_hda_get_connections(codec, spec->mux_nids[i], con_lst, HDA_MAX_NUM_INPUTS); + for (j=0; j= 0) + break; + } + spec->input_mux.items[spec->input_mux.num_items].index = index; + spec->input_mux.num_items++; + } + return 0; } @@ -401,6 +449,26 @@ static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } +/* + * Digital playback callbacks + */ +static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct sigmatel_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + + /* * Analog capture callbacks */ @@ -427,6 +495,24 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, return 0; } +static struct hda_pcm_stream stac92xx_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in stac92xx_build_pcms */ + .ops = { + .open = stac92xx_dig_playback_pcm_open, + .close = stac92xx_dig_playback_pcm_close + }, +}; + +static struct hda_pcm_stream stac92xx_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in stac92xx_build_pcms */ +}; + static struct hda_pcm_stream stac92xx_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -464,6 +550,20 @@ static int stac92xx_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid; + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + codec->num_pcms++; + info++; + info->name = "STAC92xx Digital"; + if (spec->multiout.dig_out_nid) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + if (spec->dig_in_nid) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } + } + return 0; } @@ -492,9 +592,12 @@ static int patch_stac9200(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.num_dacs = 1; spec->multiout.dac_nids = stac9200_dac_nids; + spec->multiout.dig_out_nid = 0x05; + spec->dig_in_nid = 0x04; spec->adc_nids = stac9200_adc_nids; spec->mux_nids = stac9200_mux_nids; - spec->input_mux = &stac9200_input_mux; + spec->num_muxes = 1; + spec->input_mux.num_items = 0; spec->pstate_nids = stac9200_pstate_nids; spec->num_pstates = 3; spec->pin_nids = stac9200_pin_nids; @@ -525,11 +628,14 @@ static int patch_stac922x(struct hda_codec *codec) spec->multiout.max_channels = 2; spec->multiout.num_dacs = 4; spec->multiout.dac_nids = stac922x_dac_nids; + spec->multiout.dig_out_nid = 0x08; + spec->dig_in_nid = 0x09; spec->adc_nids = stac922x_adc_nids; spec->mux_nids = stac922x_mux_nids; - spec->input_mux = &stac922x_input_mux; + spec->num_muxes = 2; + spec->input_mux.num_items = 0; spec->pstate_nids = stac922x_pstate_nids; - spec->num_pstates = 7; + spec->num_pstates = 8; spec->pin_nids = stac922x_pin_nids; #ifdef STAC_TEST spec->pin_configs = stac922x_pin_configs; -- cgit v1.2.3-70-g09d2 From b3e28ce98a22a4ecc8101128fe18665ab29d3236 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Jun 2005 11:54:50 +0200 Subject: [ALSA] Add dxs_support for Soltek SL-K8Tpro-939 VIA82xx driver Added dxs_support entry for Soltek SL-K8Tpro-939. Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 7e570a4a4c3..42c48f0ce8e 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2186,6 +2186,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .subvendor = 0x1631, .subdevice = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ { .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ + { .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */ { } /* terminator */ }; struct dxs_whitelist *w; -- cgit v1.2.3-70-g09d2 From 2b6b22f3815b2937f272d3666bd18665d3f7f5a8 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sat, 18 Jun 2005 13:50:22 +0200 Subject: [ALSA] emu10k1: Add more card identification entries. EMU10K1/EMU10K2 driver Signed-off-by: James Courtier-Dutton --- sound/pci/emu10k1/emu10k1_main.c | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 77be07283bb..a341e758acd 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -734,12 +734,90 @@ static emu_chip_details_t emu_chip_details[] = { .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102, + .driver = "EMU10K1", .name = "SBLive! [CT4620]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102, + .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102, + .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, + .driver = "EMU10K1", .name = "SBLive! Value [SB0060]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102, + .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102, + .driver = "EMU10K1", .name = "SBLive! Value [SB0103]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102, + .driver = "EMU10K1", .name = "SBLive! [SB0105]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .driver = "EMU10K1", .name = "SB Live [Unknown]", .id = "Live", -- cgit v1.2.3-70-g09d2