From 668d1e6093110f7534e661e2ff43d54c74659b6d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 28 May 2005 02:11:12 -0500 Subject: Input: This patch adds dummy gameport_register_port, gameport_unregister_port and gameport_set_phys functions to gameport.h for the case when a driver can't use gameport. This fixes the compilation of some OSS drivers with GAMEPORT=n without the need to #if inside every single driver. This patch also removes the non-working and now obsolete SOUND_GAMEPORT. This patch is also an alternative solution for ALSA drivers with similar problems (but #if's inside the drivers might have the advantage of saving some more bytes of gameport is not available). The only user-visible change is that for GAMEPORT=m the affected OSS drivers are now allowed to be built statically (but they won't have gameport support). Signed-off-by: Adrian Bunk Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- sound/oss/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index a9602f89d6b1..e537bd66a707 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -112,7 +112,7 @@ config SOUND_BCM_CS4297A config SOUND_ES1370 tristate "Ensoniq AudioPCI (ES1370)" - depends on SOUND_PRIME!=n && SOUND && PCI && SOUND_GAMEPORT + depends on SOUND_PRIME!=n && SOUND && PCI help Say Y or M if you have a PCI sound card utilizing the Ensoniq ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find @@ -125,7 +125,7 @@ config SOUND_ES1370 config SOUND_ES1371 tristate "Creative Ensoniq AudioPCI 97 (ES1371)" - depends on SOUND_PRIME!=n && SOUND && PCI && SOUND_GAMEPORT + depends on SOUND_PRIME!=n && SOUND && PCI help Say Y or M if you have a PCI sound card utilizing the Ensoniq ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if @@ -138,7 +138,7 @@ config SOUND_ES1371 config SOUND_ESSSOLO1 tristate "ESS Technology Solo1" - depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT && PCI + depends on SOUND_PRIME!=n && SOUND && PCI help Say Y or M if you have a PCI sound card utilizing the ESS Technology Solo1 chip. To find out if your sound card uses a @@ -179,7 +179,7 @@ config SOUND_HARMONY config SOUND_SONICVIBES tristate "S3 SonicVibes" - depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT + depends on SOUND_PRIME!=n && SOUND help Say Y or M if you have a PCI sound card utilizing the S3 SonicVibes chipset. To find out if your sound card uses a @@ -226,7 +226,7 @@ config SOUND_AU1550_AC97 config SOUND_TRIDENT tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" - depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT + depends on SOUND_PRIME!=n && SOUND ---help--- Say Y or M if you have a PCI sound card utilizing the Trident 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 @@ -739,7 +739,7 @@ config SOUND_NM256 config SOUND_MAD16 tristate "OPTi MAD16 and/or Mozart based cards" - depends on SOUND_OSS && SOUND_GAMEPORT + depends on SOUND_OSS ---help--- Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi 82C928 or 82C929 or 82C931) audio interface chip. These chips are -- cgit v1.2.1 From 9ae250d175e1cbff82223ce2c07897c790c5b948 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 27 May 2005 12:52:57 -0700 Subject: [PATCH] ppc32: Fix Alsa PowerMac driver on old machines The g5 support code broke some earlier models unfortunately as those bail out early from the detect function, before the point where I added the code to locate the PCI device for use with DMA allocations. This patch fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/ppc/pmac.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 32d94754acf8..080ef3928465 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -876,7 +876,7 @@ static void __init detect_byte_swap(pmac_t *chip) */ static int __init snd_pmac_detect(pmac_t *chip) { - struct device_node *sound; + struct device_node *sound = NULL; unsigned int *prop, l; struct macio_chip* macio; @@ -906,20 +906,22 @@ static int __init snd_pmac_detect(pmac_t *chip) chip->is_pbook_G3 = 1; chip->node = find_devices("awacs"); if (chip->node) - return 0; /* ok */ + sound = chip->node; /* * powermac G3 models have a node called "davbus" * with a child called "sound". */ - chip->node = find_devices("davbus"); + if (!chip->node) + chip->node = find_devices("davbus"); /* * if we didn't find a davbus device, try 'i2s-a' since * this seems to be what iBooks have */ if (! chip->node) { chip->node = find_devices("i2s-a"); - if (chip->node && chip->node->parent && chip->node->parent->parent) { + if (chip->node && chip->node->parent && + chip->node->parent->parent) { if (device_is_compatible(chip->node->parent->parent, "K2-Keylargo")) chip->is_k2 = 1; @@ -928,9 +930,11 @@ static int __init snd_pmac_detect(pmac_t *chip) if (! chip->node) return -ENODEV; - sound = find_devices("sound"); - while (sound && sound->parent != chip->node) - sound = sound->next; + if (!sound) { + sound = find_devices("sound"); + while (sound && sound->parent != chip->node) + sound = sound->next; + } if (! sound) return -ENODEV; prop = (unsigned int *) get_property(sound, "sub-frame", NULL); @@ -1019,7 +1023,8 @@ static int __init snd_pmac_detect(pmac_t *chip) } } if (chip->pdev == NULL) - printk(KERN_WARNING "snd-powermac: can't locate macio PCI device !\n"); + printk(KERN_WARNING "snd-powermac: can't locate macio PCI" + " device !\n"); detect_byte_swap(chip); @@ -1027,7 +1032,8 @@ static int __init snd_pmac_detect(pmac_t *chip) are available */ prop = (unsigned int *) get_property(sound, "sample-rates", &l); if (! prop) - prop = (unsigned int *) get_property(sound, "output-frame-rates", &l); + prop = (unsigned int *) get_property(sound, + "output-frame-rates", &l); if (prop) { int i; chip->freqs_ok = 0; @@ -1054,7 +1060,8 @@ static int __init snd_pmac_detect(pmac_t *chip) /* * exported - boolean info callbacks for ease of programming */ -int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 2; @@ -1063,7 +1070,8 @@ int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * return 0; } -int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; -- cgit v1.2.1 From 94f19c9a6da1fd3a5958f1a0b44aa340f2596a5b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 24 Mar 2005 12:01:15 +0100 Subject: [ALSA] kill dead code ALSA<-OSS emulation The Coverity checker found this obviously dead code. I'm not sure which of the if (plugin == NULL) is correct - this patch removes the one that couldn't be true. Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_plugin.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 6bb31009f0b4..6430410c6c04 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -663,10 +663,7 @@ static int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug, bitset_t *dstmask = bs; int err; bitset_one(dstmask, schannels); - if (plugin == NULL) { - bitset_and(client_vmask, dstmask, schannels); - return 0; - } + while (1) { err = plugin->src_channels_mask(plugin, dstmask, &srcmask); if (err < 0) -- cgit v1.2.1 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') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 4d5db7faad8d..8c703ff056f4 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.1 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') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 82533b45bc8c..901e42bdc8bd 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 97bed1b0899d..231ecac80861 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.1 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') diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index b7cc8e4bffb7..a44d64e828d5 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.1 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 --- sound/pci/emu10k1/irq.c | 46 +++++---- sound/pci/emu10k1/p16v.c | 257 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 271 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index b81a7cafff39..cd8460d56752 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 d03cb2fefc9e..dd6ce9927e10 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.1 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') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c3c96f9f2c7f..e0068872cd9d 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.1 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') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index e0068872cd9d..ff220fc31421 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.1 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') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 0b024ec1f709..7d2854de0c10 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.1 From 51f633dada113ef724a145bb5b33ec77d1b092f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Mar 2005 13:49:06 +0200 Subject: [ALSA] Fix memory leak ALSA sequencer Fixed memory leak by the last change of stack reduction. Signed-off-by: Takashi Iwai --- sound/core/seq/seq_midi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 18247db45db6..57be9155eb62 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -414,6 +414,8 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev) if (newclient) synths[card->number] = client; up(®ister_mutex); + kfree(info); + kfree(port); return 0; /* success */ __nomem: -- cgit v1.2.1 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 --- 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 +- 4 files changed, 48 insertions(+), 49 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index ff220fc31421..38be0f1b0e72 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 b9fa2e887fee..0529fb281125 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 044663d31aa7..d0b296587cc0 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 d990d5eb45a8..732d17d1307f 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.1 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 --- sound/pci/emu10k1/emu10k1_main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 38be0f1b0e72..a2fa5012c843 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.1 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') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index a2fa5012c843..c51a8ae464e2 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.1 From c1ab5d59a0ff0981828a169886b10045dfdf64c6 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 30 Mar 2005 16:22:01 +0200 Subject: [ALSA] usb-audio - allow USB MIDI quirks to specify endpoints explicitly USB generic driver This patch reintroduces the check for endpoint numbers that are specified explicitly in the quirk structure. This check was accidentally dropped in the last rewrite of snd_usbmidi_detect_endpoints(). Signed-off-by: Clemens Ladisch --- sound/usb/usbmidi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 5d32857ff955..600d990ddc90 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1229,6 +1229,9 @@ static int snd_usbmidi_detect_endpoints(snd_usb_midi_t* umidi, if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); + if (endpoint[0].out_ep || endpoint[0].in_ep) + return 0; + intf = umidi->iface; if (!intf || intf->num_altsetting < 1) return -ENOENT; -- cgit v1.2.1 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') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c51a8ae464e2..a3a1a10fb0c9 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.1 From 54ab87e6f53099b9a480b56149fa621c3132c076 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 1 Apr 2005 13:14:14 +0200 Subject: [ALSA] Add mixer map for Sound Blaster MP3+ USB generic driver Added the mixer mapping for Sound Blaster MP3+ by Pavel Mihaylov Signed-off-by: Takashi Iwai --- sound/usb/usbmixer_maps.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index c69b4b0875f8..1e994c9d86d9 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -91,6 +91,33 @@ static struct usbmix_name_map extigy_map[] = { { 0 } /* terminator */ }; +/* Sound Blaster MP3+ controls mapping + * The default mixer channels have totally misleading names, + * e.g. no Master and fake PCM volume + * Pavel Mihaylov + */ +static struct usbmix_name_map mp3plus_map[] = { + /* 1: IT pcm */ + /* 2: IT mic */ + /* 3: IT line */ + /* 4: IT digital in */ + /* 5: OT digital out */ + /* 6: OT speaker */ + /* 7: OT pcm capture */ + { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ + /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ + { 9, "Master Playback" }, /* FU, default Speaker 1 */ + /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ + /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ + { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ + { 11, "Line Capture" }, /* FU, default PCM Capture */ + { 12, "Digital In Playback" }, /* FU, default PCM 1 */ + /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ + { 14, "Line Playback" }, /* FU, default Speaker */ + /* 15: MU */ + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -128,6 +155,7 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { 0x41e, 0x3000, extigy_map, 1 }, + { 0x41e, 0x3010, mp3plus_map, 0 }, { 0x8bb, 0x2702, linex_map, 1 }, { 0xc45, 0x1158, justlink_map, 0 }, { 0 } /* terminator */ -- cgit v1.2.1 From c1935b4d6edf1c4d78bf660992d00b2d8fcb9b59 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 4 Apr 2005 16:44:58 +0200 Subject: [ALSA] timer - added tread semaphore Timer Midlevel Signed-off-by: Jaroslav Kysela --- sound/core/timer.c | 57 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index fa762ca439be..be6d37af76d8 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -69,6 +69,7 @@ typedef struct { struct timespec tstamp; /* trigger tstamp */ wait_queue_head_t qchange_sleep; struct fasync_struct *fasync; + struct semaphore tread_sem; } snd_timer_user_t; /* list of timers */ @@ -1208,6 +1209,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) return -ENOMEM; spin_lock_init(&tu->qlock); init_waitqueue_head(&tu->qchange_sleep); + init_MUTEX(&tu->tread_sem); tu->ticks = 1; tu->queue_size = 128; tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); @@ -1454,18 +1456,23 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * snd_timer_user_t *tu; snd_timer_select_t tselect; char str[32]; - int err; + int err = 0; tu = file->private_data; - if (tu->timeri) + down(&tu->tread_sem); + if (tu->timeri) { snd_timer_close(tu->timeri); - if (copy_from_user(&tselect, _tselect, sizeof(tselect))) - return -EFAULT; + tu->timeri = NULL; + } + if (copy_from_user(&tselect, _tselect, sizeof(tselect))) { + err = -EFAULT; + goto __err; + } sprintf(str, "application %i", current->pid); if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) - return err; + goto __err; if (tu->queue) { kfree(tu->queue); @@ -1477,23 +1484,27 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * } if (tu->tread) { tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); - if (tu->tqueue == NULL) { - snd_timer_close(tu->timeri); - return -ENOMEM; - } + if (tu->tqueue == NULL) + err = -ENOMEM; } else { tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); - if (tu->queue == NULL) { - snd_timer_close(tu->timeri); - return -ENOMEM; - } + if (tu->queue == NULL) + err = -ENOMEM; } - tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; - tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; - tu->timeri->ccallback = snd_timer_user_ccallback; - tu->timeri->callback_data = (void *)tu; - return 0; + if (err < 0) { + snd_timer_close(tu->timeri); + tu->timeri = NULL; + } else { + tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; + tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; + tu->timeri->ccallback = snd_timer_user_ccallback; + tu->timeri->callback_data = (void *)tu; + } + + __err: + up(&tu->tread_sem); + return err; } static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) @@ -1685,11 +1696,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l { int xarg; - if (tu->timeri) /* too late */ + down(&tu->tread_sem); + if (tu->timeri) { /* too late */ + up(&tu->tread_sem); return -EBUSY; - if (get_user(xarg, p)) + } + if (get_user(xarg, p)) { + up(&tu->tread_sem); return -EFAULT; + } tu->tread = xarg ? 1 : 0; + up(&tu->tread_sem); return 0; } case SNDRV_TIMER_IOCTL_GINFO: -- cgit v1.2.1 From 0aa0d387877e8e6408d316aaee1ea84f8e1fb447 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 6 Apr 2005 09:43:59 +0200 Subject: [ALSA] virmidi - fix ioctl parameter passing when creating seq port ALSA sequencer The last change to reduce stack usage did not adjust the parameter to SNDRV_SEQ_IOCTL_CREATE_PORT which resulted in passing the address of the pointer instead of the structure. Signed-off-by: Clemens Ladisch --- sound/core/seq/seq_virmidi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 6b4e630ace54..1274ab4546bc 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -405,7 +405,7 @@ static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev) pcallbacks.unuse = snd_virmidi_unuse; pcallbacks.event_input = snd_virmidi_event_input; pinfo->kernel = &pcallbacks; - err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo); + err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, pinfo); if (err < 0) { snd_seq_delete_kernel_client(client); rdev->client = -1; -- cgit v1.2.1 From 5af4c83375cba113fb7e1ed57024a5442ca5060e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 6 Apr 2005 09:47:02 +0200 Subject: [ALSA] usb-audio - BOSS GS-10 PCM support USB generic driver This patch adds quirks to support 24-bit PCM I/O in the 'Advanced Driver' mode of the BOSS GS-10. Signed-off-by: Clemens Ladisch --- sound/usb/usbquirks.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 88bbd944d4be..00781fea2115 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -609,15 +609,33 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* + * This quirk is for the "Advanced Driver" mode. If off, the GS-10 + * has ID 0x003c and is standard compliant, but has only 16-bit PCM + * and no MIDI. + */ USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "BOSS", .product_name = "GS-10", - .ifnum = 3, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0003, - .in_cables = 0x0003 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } } } }, -- cgit v1.2.1 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 --- sound/pci/emu10k1/emu10k1_main.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index a3a1a10fb0c9..c6d53b459254 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.1 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') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 7d2854de0c10..4ece2053bb13 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.1 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') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 4ece2053bb13..61549b1eb59a 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 13c34a5d8206..473840d431b3 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 6db51c96f5d0..7b7377d0f2ae 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.1 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') diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 67da096d659b..f9972b20050d 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.1 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') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 61549b1eb59a..ab7114c51dcb 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.1 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') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index ab7114c51dcb..1ad7f83a65e1 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.1 From 22e0732e59b3482bb2f068bfe911c532767e5974 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 8 Apr 2005 08:25:23 +0200 Subject: [ALSA] virmidi - fix ioctl parameter passing when setting client name ALSA sequencer The last change to reduce stack usage did not adjust the parameter to SNDRV_SEQ_IOCTL_SET_CLIENT_IOCTL which resulted in passing the address of the pointer instead of the structure. Signed-off-by: Clemens Ladisch --- sound/core/seq/seq_virmidi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 1274ab4546bc..58c56a198d2a 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -384,7 +384,7 @@ static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev) info->client = client; info->type = KERNEL_CLIENT; sprintf(info->name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device); - snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &info); + snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info); /* create a port */ memset(pinfo, 0, sizeof(*pinfo)); -- cgit v1.2.1 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') diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index a44d64e828d5..e64e29dac824 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.1 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') diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 732d17d1307f..187a4e60a5fe 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.1 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 --- sound/pci/emu10k1/emumixer.c | 2 ++ sound/pci/emu10k1/emuproc.c | 21 +++++++++++++++++++++ sound/pci/emu10k1/p16v.c | 16 +++++++--------- 3 files changed, 30 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index d0b296587cc0..b544c2582663 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 187a4e60a5fe..356fb7104253 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 dd6ce9927e10..8dd87838fb22 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.1 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') diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 8dd87838fb22..776761fe5577 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.1 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') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c6d53b459254..bf17db1fd243 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.1 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') diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 8bb1c58c26a0..5ad4728daa7b 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 d1f90832443c..5bf734b04fa0 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 6230cf16989f..13e841b55488 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.1 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') diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 05f1629760bc..997cf37cdddd 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.1 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') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 08e7c5a296d5..3291434f3e0c 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.1 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 --- sound/pci/via82xx.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 9b4d74d49f98..2f1e6ebd56a7 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.1 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') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 2f1e6ebd56a7..e6e746fa4bb5 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.1 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/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 +- 36 files changed, 174 insertions(+), 55 deletions(-) (limited to 'sound') diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 984d5d4ba4e1..038f56ad42f1 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -2270,7 +2270,7 @@ static struct pci_driver driver = { static int __init alsa_card_ali_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_ali_exit(void) diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index f1a5f5723ee6..cdc1134cdedd 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -777,7 +777,7 @@ static struct pci_driver driver = { static int __init alsa_card_als4000_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_als4000_exit(void) diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 6b04c0acc6f7..06551a69fb40 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1645,7 +1645,7 @@ static struct pci_driver driver = { static int __init alsa_card_atiixp_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_atiixp_exit(void) diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index fb7cecea846d..9220aae632b0 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1332,7 +1332,7 @@ static struct pci_driver driver = { static int __init alsa_card_atiixp_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_atiixp_exit(void) diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 889b4a1a51a1..f6236c63aaaa 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -375,7 +375,7 @@ static struct pci_driver driver = { // initialization of the module static int __init alsa_card_vortex_init(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } // clean up the module diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index b8ae534125c1..72bba7b2d983 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1520,7 +1520,7 @@ static int __init alsa_card_azf3328_init(void) { int err; snd_azf3328_dbgcallenter(); - err = pci_module_init(&driver); + err = pci_register_driver(&driver); snd_azf3328_dbgcallleave(); return err; } diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 89a7ffe5e7d7..defdc5a459f0 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -918,7 +918,7 @@ static int __init alsa_card_bt87x_init(void) { if (load_all) driver.id_table = snd_bt87x_default_ids; - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit alsa_card_bt87x_exit(void) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 901e42bdc8bd..d4cb8edf7080 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1268,7 +1268,7 @@ static int __init alsa_card_ca0106_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/cmipci.c b/sound/pci/cmipci.c index 113208fbde1b..b4503385ea69 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 d7e06b3caf97..8b42e8631f2a 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 25d6466a867c..db212ecd792a 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 6446afe19d80..2085a998eaeb 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 27dfd8ddddf4..04ba63762d3b 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 f910399db5c3..4e63498a58b2 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 b4ca8adf393c..b492777bc30f 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 faf63ff19c42..da10d40b2d91 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 3291434f3e0c..ff10e637a95e 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 959953ca320a..cbc9ca73c2ab 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 79fba6be3503..a2545a5b26c4 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 95500f06f0c6..79b5f12e06fc 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 8b33b12fa5dc..9c5710daed50 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 f9972b20050d..f655cf914060 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 bb1de2008176..79d8eda54f0d 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 2cf33083d7cc..9f184ea8a9d3 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 65bb0f47af2c..082c0d0f73d2 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 356fbeac6f9e..8a52091f8552 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 b96acd5a57db..b7b554df6705 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 8e2666841d21..10c4f45a913c 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 12efbf0fab54..44ca7ddb68f6 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 69cd81eaa111..5861f234af21 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 cfd2c5fd6ddf..60ecb2bdb65e 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 ad58e08d66e2..5d21cb811c8a 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 e6e746fa4bb5..64cc40f97b53 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 ea5c6f640159..098870aea264 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 4ffbb25658a5..dca6bd2c7580 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 9f3ef22df08d..5b5b624b47d0 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.1 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') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index b544c2582663..6be82c5fe138 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.1 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') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8d94325529a8..a2757fcec1f0 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 f1d5f7a6ee0c..9a174fb96565 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 afb711421e47..0bc1d783a840 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 04ba63762d3b..f8d92335a353 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 356fb7104253..cc22707c91fa 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.1 From 004e65389714721ce0f52a8f0fc22999d3908a2a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Apr 2005 17:33:59 +0200 Subject: [ALSA] Fix capture on OSS emulation ALSA<-OSS emulation Fix the noisy capture on some hardwares over OSS emulation. Change back to avail_min = period_size for capture direction. Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 1a805020f57a..6c8fdcaf9f4f 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -464,7 +464,8 @@ static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream) sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; sw_params->period_step = 1; sw_params->sleep_min = 0; - sw_params->avail_min = 1; + sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + 1 : runtime->period_size; sw_params->xfer_align = 1; if (atomic_read(&runtime->mmap_count) || (substream->oss.setup && substream->oss.setup->nosilence)) { -- cgit v1.2.1 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 --- sound/pci/ac97/ac97_patch.c | 426 ++++++++++++++++++++++++-------------------- 1 file changed, 236 insertions(+), 190 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 473840d431b3..7f16c306165b 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.1 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') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c9e9dc9c7c98..042bcfc6dbbd 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 69f7b6c4cf83..c233e7f1a74a 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.1 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') diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 570a59d33b41..bd8cb33c4fb4 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 9ed117ac0c09..be6cba349394 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 cf6abce42bc9..a5de684b6944 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 000000000000..1534e20af63d --- /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.1 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') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 75d23849f71a..caa486993446 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.1 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') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index be6cba349394..890b7566154a 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.1 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') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 042bcfc6dbbd..263f5b698bac 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.1 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') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 64cc40f97b53..881af1d11aad 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.1 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') diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index d1c2a02c486b..fd7cc389f82a 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.1 From 230cd5e24853ed4dd960461989b8ed0986d37a99 Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Wed, 20 Apr 2005 10:12:35 +0200 Subject: [ALSA] prevent oops & dead keyboard on usb unplugging while the device is being used USB generic driver,USB USX2Y Without this patch, some usb kobjects, which are parents to the usx2y's kobjects can be freed before the usx2y's. This led to an oops in get_kobj_path_length() and a dead keyboard, when the usx2y's kobjects were freed. The patch ensures the correct sequence. Tested ok on kernel 2.6.12-rc2. Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 2 +- sound/usb/usx2y/usbusx2y.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 84b0bbddbd22..aae66144d411 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3289,7 +3289,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) } usb_chip[chip->index] = NULL; up(®ister_mutex); - snd_card_free_in_thread(card); + snd_card_free(card); } else { up(®ister_mutex); } diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index b06a267e5dac..89ee8b732013 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -1,6 +1,11 @@ /* * usbusy2y.c - ALSA USB US-428 Driver * +2005-04-14 Karsten Wiese + Version 0.8.7.2: + Call snd_card_free() instead of snd_card_free_in_thread() to prevent oops with dead keyboard symptom. + Tested ok with kernel 2.6.12-rc2. + 2004-12-14 Karsten Wiese Version 0.8.7.1: snd_pcm_open for rawusb pcm-devices now returns -EBUSY if called without rawusb's hwdep device being open. @@ -143,7 +148,7 @@ MODULE_AUTHOR("Karsten Wiese "); -MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.1"); +MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}"); @@ -430,8 +435,6 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) if (ptr) { usX2Ydev_t* usX2Y = usX2Y((snd_card_t*)ptr); struct list_head* p; - if (usX2Y->chip_status == USX2Y_STAT_CHIP_HUP) // on 2.6.1 kernel snd_usbmidi_disconnect() - return; // calls us back. better leave :-) . usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); @@ -443,7 +446,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) } if (usX2Y->us428ctls_sharedmem) wake_up(&usX2Y->us428ctls_wait_queue_head); - snd_card_free_in_thread((snd_card_t*)ptr); + snd_card_free((snd_card_t*)ptr); } } -- cgit v1.2.1 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') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index c233e7f1a74a..bfbeff2e0d0c 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.1 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') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 8c703ff056f4..15df7162f17e 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.1 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') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 890b7566154a..44fac2182fcc 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 263f5b698bac..43fc245d9a62 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 e64e29dac824..087230ca20a5 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.1 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') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 881af1d11aad..4c41df053523 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.1 From 863ad944b9a32dc43baa76143275411824d5928e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 08:52:03 +0200 Subject: [ALSA] usb-audio: add Audigy 2 NX control names USB generic driver Add a mixer control map for the SB Audigy 2 NX so that we get meaningful mixer control names. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer_maps.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 1e994c9d86d9..4918a1854223 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -118,6 +118,50 @@ static struct usbmix_name_map mp3plus_map[] = { { 0 } /* terminator */ }; +/* Topology of SB Audigy 2 NX + + +----------------------------->EU[27]--+ + | v + | +----------------------------------->SU[29]---->FU[22]-->Dig_OUT[24] + | | ^ +USB_IN[1]-+------------+ +->EU[17]->+->FU[11]-+ + | v | v | +Dig_IN[4]---+->FU[6]-->MU[16]->FU[18]-+->EU[21]->SU[31]----->FU[30]->Hph_OUT[20] + | ^ | | +Lin_IN[7]-+--->FU[8]---+ +->EU[23]->FU[28]------------->Spk_OUT[19] + | | v + +--->FU[12]------------------------------------->SU[14]--->USB_OUT[15] + | ^ + +->FU[13]--------------------------------------+ +*/ +static struct usbmix_name_map audigy2nx_map[] = { + /* 1: IT pcm playback */ + /* 4: IT digital in */ + { 6, "Digital In Playback" }, /* FU */ + /* 7: IT line in */ + { 8, "Line Playback" }, /* FU */ + { 11, "What-U-Hear Capture" }, /* FU */ + { 12, "Line Capture" }, /* FU */ + { 13, "Digital In Capture" }, /* FU */ + { 14, "Capture Source" }, /* SU */ + /* 15: OT pcm capture */ + /* 16: MU w/o controls */ + { 17, NULL }, /* DISABLED: EU (for what?) */ + { 18, "Master Playback" }, /* FU */ + /* 19: OT speaker */ + /* 20: OT headphone */ + { 21, NULL }, /* DISABLED: EU (for what?) */ + { 22, "Digital Out Playback" }, /* FU */ + { 23, NULL }, /* DISABLED: EU (for what?) */ + /* 24: OT digital out */ + { 27, NULL }, /* DISABLED: EU (for what?) */ + { 28, "Speaker Playback" }, /* FU */ + { 29, "Digital Out Source" }, /* SU */ + { 30, "Headphone Playback" }, /* FU */ + { 31, "Headphone Source" }, /* SU */ + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -156,6 +200,7 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { 0x41e, 0x3000, extigy_map, 1 }, { 0x41e, 0x3010, mp3plus_map, 0 }, + { 0x41e, 0x3020, audigy2nx_map, 0 }, { 0x8bb, 0x2702, linex_map, 1 }, { 0xc45, 0x1158, justlink_map, 0 }, { 0 } /* terminator */ -- cgit v1.2.1 From 08fe15899df9696a6d34abf96230ae0691f5de66 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 15:33:01 +0200 Subject: [ALSA] usb-audio - show exact synchronous frequency in proc file USB generic driver In the streamX proc file, show the exact number of samples per USB frame as 16.16 hexadecimal floating point value. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index aae66144d411..a7183c5876b3 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1990,10 +1990,11 @@ static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffe snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); snd_iprintf(buffer, "]\n"); snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); - snd_iprintf(buffer, " Momentary freq = %u Hz\n", + snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", snd_usb_get_speed(subs->dev) == USB_SPEED_FULL ? get_full_speed_hz(subs->freqm) - : get_high_speed_hz(subs->freqm)); + : get_high_speed_hz(subs->freqm), + subs->freqm >> 16, subs->freqm & 0xffff); } else { snd_iprintf(buffer, " Status: Stop\n"); } -- cgit v1.2.1 From 8e062ec7108f8a91149e6bccddc3b7341e406274 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 22 Apr 2005 15:49:52 +0200 Subject: [ALSA] usb-audio - add selector unit names override for Audigy 2 NX USB generic driver Add a mechanism to specify source names of selector units, and add such names for the SB Audigy 2 NX. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 21 +++++++++++++++++- sound/usb/usbmixer_maps.c | 54 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5f1906915aa6..6ad154aaba1b 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -70,6 +70,7 @@ struct usb_mixer_build { DECLARE_BITMAP(unitbitmap, 32*32); usb_audio_term_t oterm; const struct usbmix_name_map *map; + const struct usbmix_selector_map *selector_map; }; struct usb_mixer_elem_info { @@ -187,6 +188,21 @@ static int check_ignored_ctl(mixer_build_t *state, int unitid, int control) return 0; } +/* get the mapped selector source name */ +static int check_mapped_selector_name(mixer_build_t *state, int unitid, + int index, char *buf, int buflen) +{ + const struct usbmix_selector_map *p; + + if (! state->selector_map) + return 0; + for (p = state->selector_map; p->id; p++) { + if (p->id == unitid && index < p->count) + return strlcpy(buf, p->names[index], buflen); + } + return 0; +} + /* * find an audio control unit with the given unit id */ @@ -1415,7 +1431,9 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned kfree(cval); return -ENOMEM; } - if (check_input_term(state, desc[5 + i], &iterm) >= 0) + len = check_mapped_selector_name(state, unitid, i, namelist[i], + MAX_ITEM_NAME_LEN); + if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0) len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); if (! len) sprintf(namelist[i], "Input %d", i); @@ -1521,6 +1539,7 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) for (map = usbmix_ctl_maps; map->vendor; map++) { if (map->vendor == state.vendor && map->product == state.product) { state.map = map->map; + state.selector_map = map->selector_map; chip->ignore_ctl_error = map->ignore_ctl_error; break; } diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 4918a1854223..adb0abb3ee85 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -26,10 +26,17 @@ struct usbmix_name_map { int control; }; +struct usbmix_selector_map { + int id; + int count; + const char **names; +}; + struct usbmix_ctl_map { int vendor; int product; const struct usbmix_name_map *map; + const struct usbmix_selector_map *selector_map; int ignore_ctl_error; }; @@ -162,6 +169,25 @@ static struct usbmix_name_map audigy2nx_map[] = { { 0 } /* terminator */ }; +static struct usbmix_selector_map audigy2nx_selectors[] = { + { + .id = 14, /* Capture Source */ + .count = 3, + .names = (const char*[]) {"Line", "Digital In", "What-U-Hear"} + }, + { + .id = 29, /* Digital Out Source */ + .count = 3, + .names = (const char*[]) {"Front", "PCM", "Digital In"} + }, + { + .id = 31, /* Headphone Source */ + .count = 2, + .names = (const char*[]) {"Front", "Side"} + }, + { 0 } /* terminator */ +}; + /* LineX FM Transmitter entry - needed to bypass controls bug */ static struct usbmix_name_map linex_map[] = { /* 1: IT pcm */ @@ -198,11 +224,29 @@ static struct usbmix_name_map justlink_map[] = { */ static struct usbmix_ctl_map usbmix_ctl_maps[] = { - { 0x41e, 0x3000, extigy_map, 1 }, - { 0x41e, 0x3010, mp3plus_map, 0 }, - { 0x41e, 0x3020, audigy2nx_map, 0 }, - { 0x8bb, 0x2702, linex_map, 1 }, - { 0xc45, 0x1158, justlink_map, 0 }, + { + .vendor = 0x41e, .product = 0x3000, + .map = extigy_map, + .ignore_ctl_error = 1, + }, + { + .vendor = 0x41e, .product = 0x3010, + .map = mp3plus_map, + }, + { + .vendor = 0x41e, .product = 0x3020, + .map = audigy2nx_map, + .selector_map = audigy2nx_selectors, + }, + { + .vendor = 0x8bb, .product = 0x2702, + .map = linex_map, + .ignore_ctl_error = 1, + }, + { + .vendor = 0xc45, .product = 0x1158, + .map = justlink_map, + }, { 0 } /* terminator */ }; -- cgit v1.2.1 From ee7333970bee3e7565feeb3edfef4db81cbe72e5 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 25 Apr 2005 10:34:13 +0200 Subject: [ALSA] usb-audio - remove superfluous parameter USB generic driver,USB USX2Y This patch removes the superfluous driver parameter from the disconnect functions. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 6 +++--- sound/usb/usbaudio.h | 2 +- sound/usb/usbmidi.c | 2 +- sound/usb/usx2y/usbusx2y.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a7183c5876b3..08c5efcf5be2 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2588,7 +2588,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) * disconnect streams * called from snd_usb_audio_disconnect() */ -static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver *driver) +static void snd_usb_stream_disconnect(struct list_head *head) { int idx; snd_usb_stream_t *as; @@ -3282,11 +3282,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) snd_card_disconnect(card); /* release the pcm resources */ list_for_each(p, &chip->pcm_list) { - snd_usb_stream_disconnect(p, &usb_audio_driver); + snd_usb_stream_disconnect(p); } /* release the midi resources */ list_for_each(p, &chip->midi_list) { - snd_usbmidi_disconnect(p, &usb_audio_driver); + snd_usbmidi_disconnect(p); } usb_chip[chip->index] = NULL; up(®ister_mutex); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index eecbf19fcb6f..14f7cf7e363c 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -223,7 +223,7 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); -void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver); +void snd_usbmidi_disconnect(struct list_head *p); /* * retrieve usb_interface descriptor from the host interface diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 600d990ddc90..304a13451ec9 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -912,7 +912,7 @@ static void snd_usbmidi_free(snd_usb_midi_t* umidi) /* * Unlinks all URBs (must be done before the usb_device is deleted). */ -void snd_usbmidi_disconnect(struct list_head* p, struct usb_driver *driver) +void snd_usbmidi_disconnect(struct list_head* p) { snd_usb_midi_t* umidi; int i; diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 89ee8b732013..e6e6da159671 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -442,7 +442,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) snd_card_disconnect((snd_card_t*)ptr); /* release the midi resources */ list_for_each(p, &usX2Y->chip.midi_list) { - snd_usbmidi_disconnect(p, &snd_usX2Y_usb_driver); + snd_usbmidi_disconnect(p); } if (usX2Y->us428ctls_sharedmem) wake_up(&usX2Y->us428ctls_wait_queue_head); -- cgit v1.2.1 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') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 1ad7f83a65e1..36a33ae9ae03 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.1 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') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 7f16c306165b..737c4bb94d2a 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.1 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') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 44ca7ddb68f6..b35ed5f0c042 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.1 From 8c1872dcf29e2a194197e1d5a9c366a265986b84 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 28 Apr 2005 09:31:53 +0200 Subject: [ALSA] usb-audio - restrict Audigy 2 NX frequencies to 48/96 kHz USB generic driver On the SB Audigy 2 NX, frequency feedback doesn't quite work when playing at 44.1 kHz, so temporarily disable this frequency. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 08c5efcf5be2..e4b91045ca16 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2422,15 +2422,17 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, if (err < 0) return err; #if 1 - /* FIXME: temporary hack for extigy */ + /* FIXME: temporary hack for extigy/audigy 2 nx */ /* extigy apparently supports sample rates other than 48k * but not in ordinary way. so we enable only 48k atm. */ if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { + (le16_to_cpu(dev->descriptor.idProduct) == 0x3000 || + le16_to_cpu(dev->descriptor.idProduct) == 0x3020)) { if (fmt[3] == USB_FORMAT_TYPE_I && stream == SNDRV_PCM_STREAM_PLAYBACK && - fp->rates != SNDRV_PCM_RATE_48000) + fp->rates != SNDRV_PCM_RATE_48000 && + fp->rates != SNDRV_PCM_RATE_96000) return -1; /* use 48k only */ } #endif -- cgit v1.2.1 From 707e60732fc25fe3760f916d083b262a86a666c0 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 09:56:17 +0200 Subject: [ALSA] usb-audio - reduce size of unitbitmap array USB generic driver Unit/terminal IDs are 8-bit integers, so the unitbitmap variable does not need to be bigger than 256 bits. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 6ad154aaba1b..e601f4ba5f2c 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -67,7 +67,7 @@ struct usb_mixer_build { unsigned int ctrlif; unsigned short vendor; unsigned short product; - DECLARE_BITMAP(unitbitmap, 32*32); + DECLARE_BITMAP(unitbitmap, 256); usb_audio_term_t oterm; const struct usbmix_name_map *map; const struct usbmix_selector_map *selector_map; -- cgit v1.2.1 From 84957a8ab086377a025e0448fa716ed5983f3c3a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:23:13 +0200 Subject: [ALSA] usb-audio - move mixer data into separate struct USB generic driver Move all data related to audio control interfaces into a separate struct local to usbmixer.c. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 5 ++ sound/usb/usbaudio.h | 3 +- sound/usb/usbmixer.c | 142 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 105 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e4b91045ca16..eeb09bb8cbf3 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3091,6 +3091,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->card = card; INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->midi_list); + INIT_LIST_HEAD(&chip->mixer_list); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_usb_audio_free(chip); @@ -3290,6 +3291,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) list_for_each(p, &chip->midi_list) { snd_usbmidi_disconnect(p); } + /* release mixer resources */ + list_for_each(p, &chip->mixer_list) { + snd_usb_mixer_disconnect(p); + } usb_chip[chip->index] = NULL; up(®ister_mutex); snd_card_free(card); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 14f7cf7e363c..41d842dab3e8 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -136,7 +136,7 @@ struct snd_usb_audio { struct list_head midi_list; /* list of midi interfaces */ int next_midi_device; - unsigned int ignore_ctl_error; /* for mixer */ + struct list_head mixer_list; /* list of mixer interfaces */ }; /* @@ -219,6 +219,7 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout); int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); +void snd_usb_mixer_disconnect(struct list_head *p); int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); void snd_usbmidi_input_stop(struct list_head* p); diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index e601f4ba5f2c..7bbccebd76c6 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -50,6 +50,14 @@ typedef struct usb_audio_term usb_audio_term_t; typedef struct usb_mixer_elem_info usb_mixer_elem_info_t; +struct usb_mixer_interface { + snd_usb_audio_t *chip; + unsigned int ctrlif; + struct list_head list; + unsigned int ignore_ctl_error; +}; + + struct usb_audio_term { int id; int type; @@ -62,9 +70,9 @@ struct usbmix_name_map; struct usb_mixer_build { snd_usb_audio_t *chip; + struct usb_mixer_interface *mixer; unsigned char *buffer; unsigned int buflen; - unsigned int ctrlif; unsigned short vendor; unsigned short product; DECLARE_BITMAP(unitbitmap, 256); @@ -74,8 +82,7 @@ struct usb_mixer_build { }; struct usb_mixer_elem_info { - snd_usb_audio_t *chip; - unsigned int ctrlif; + struct usb_mixer_interface *mixer; unsigned int id; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ @@ -317,16 +324,18 @@ static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i int timeout = 10; while (timeout-- > 0) { - if (snd_usb_ctl_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0), + if (snd_usb_ctl_msg(cval->mixer->chip->dev, + usb_rcvctrlpipe(cval->mixer->chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, cval->ctrlif | (cval->id << 8), + validx, cval->mixer->ctrlif | (cval->id << 8), buf, val_len, 100) >= 0) { *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); return 0; } } - snd_printdd(KERN_ERR "cannot get ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type); + snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", + request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); return -EINVAL; } @@ -355,13 +364,15 @@ static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, i buf[0] = value_set & 0xff; buf[1] = (value_set >> 8) & 0xff; while (timeout -- > 0) - if (snd_usb_ctl_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0), + if (snd_usb_ctl_msg(cval->mixer->chip->dev, + usb_sndctrlpipe(cval->mixer->chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - validx, cval->ctrlif | (cval->id << 8), + validx, cval->mixer->ctrlif | (cval->id << 8), buf, val_len, 100) >= 0) return 0; - snd_printdd(KERN_ERR "cannot set ctl value: req = 0x%x, wValue = 0x%x, wIndex = 0x%x, type = %d, data = 0x%x/0x%x\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]); + snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", + request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]); return -EINVAL; } @@ -401,12 +412,13 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou * if failed, give up and free the control instance. */ -static int add_control_to_empty(snd_card_t *card, snd_kcontrol_t *kctl) +static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) { int err; - while (snd_ctl_find_id(card, &kctl->id)) + + while (snd_ctl_find_id(state->chip->card, &kctl->id)) kctl->id.index++; - if ((err = snd_ctl_add(card, kctl)) < 0) { + if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); snd_ctl_free_one(kctl); } @@ -624,7 +636,8 @@ static int get_min_max(usb_mixer_elem_info_t *cval, int default_min) } if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { - snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, cval->control, cval->id); + snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", + cval->id, cval->mixer->ctrlif, cval->control, cval->id); return -EINVAL; } if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { @@ -684,7 +697,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -700,7 +713,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t /* master channel */ err = get_cur_mix_value(cval, 0, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -726,7 +739,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -743,7 +756,7 @@ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t } else { /* master channel */ err = get_cur_mix_value(cval, 0, &oval); - if (err < 0 && cval->chip->ignore_ctl_error) + if (err < 0 && cval->mixer->ignore_ctl_error) return 0; if (err < 0) return err; @@ -795,8 +808,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = control; cval->cmask = ctl_mask; @@ -880,7 +892,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); - add_control_to_empty(state->chip->card, kctl); + add_control_to_empty(state, kctl); } @@ -963,8 +975,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, if (! cval) return; - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = in_ch + 1; /* based on 1 */ cval->val_type = USB_MIXER_S16; @@ -995,7 +1006,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - add_control_to_empty(state->chip->card, kctl); + add_control_to_empty(state, kctl); } @@ -1058,7 +1069,7 @@ static int mixer_ctl_procunit_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t int err, val; err = get_cur_ctl_value(cval, cval->control << 8, &val); - if (err < 0 && cval->chip->ignore_ctl_error) { + if (err < 0 && cval->mixer->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } @@ -1077,7 +1088,7 @@ static int mixer_ctl_procunit_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, cval->control << 8, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -1215,8 +1226,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->control = valinfo->control; cval->val_type = valinfo->val_type; @@ -1257,7 +1267,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) + if ((err = add_control_to_empty(state, kctl)) < 0) return err; } return 0; @@ -1305,7 +1315,7 @@ static int mixer_ctl_selector_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, 0, &val); if (err < 0) { - if (cval->chip->ignore_ctl_error) { + if (cval->mixer->ignore_ctl_error) { ucontrol->value.enumerated.item[0] = 0; return 0; } @@ -1324,7 +1334,7 @@ static int mixer_ctl_selector_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t err = get_cur_ctl_value(cval, 0, &oval); if (err < 0) { - if (cval->chip->ignore_ctl_error) + if (cval->mixer->ignore_ctl_error) return 0; return err; } @@ -1402,8 +1412,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; } - cval->chip = state->chip; - cval->ctrlif = state->ctrlif; + cval->mixer = state->mixer; cval->id = unitid; cval->val_type = USB_MIXER_U8; cval->channels = 1; @@ -1468,7 +1477,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", cval->id, kctl->id.name, num_ins); - if ((err = add_control_to_empty(state->chip->card, kctl)) < 0) + if ((err = add_control_to_empty(state, kctl)) < 0) return err; return 0; @@ -1511,27 +1520,38 @@ static int parse_audio_unit(mixer_build_t *state, int unitid) } } +static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) +{ + kfree(mixer); +} + +static int snd_usb_mixer_dev_free(snd_device_t *device) +{ + struct usb_mixer_interface *mixer = device->device_data; + snd_usb_mixer_free(mixer); + return 0; +} + /* * create mixer controls * * walk through all OUTPUT_TERMINAL descriptors to search for mixers */ -int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) +static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) { unsigned char *desc; mixer_build_t state; int err; const struct usbmix_ctl_map *map; - struct usb_device_descriptor *dev = &chip->dev->descriptor; - struct usb_host_interface *hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; - - strcpy(chip->card->mixername, "USB Mixer"); + struct usb_device_descriptor *dev = &mixer->chip->dev->descriptor; + struct usb_host_interface *hostif; + hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; memset(&state, 0, sizeof(state)); - state.chip = chip; + state.chip = mixer->chip; + state.mixer = mixer; state.buffer = hostif->extra; state.buflen = hostif->extralen; - state.ctrlif = ctrlif; state.vendor = le16_to_cpu(dev->idVendor); state.product = le16_to_cpu(dev->idProduct); @@ -1540,13 +1560,10 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) if (map->vendor == state.vendor && map->product == state.product) { state.map = map->map; state.selector_map = map->selector_map; - chip->ignore_ctl_error = map->ignore_ctl_error; + mixer->ignore_ctl_error = map->ignore_ctl_error; break; } } -#ifdef IGNORE_CTL_ERROR - chip->ignore_ctl_error = 1; -#endif desc = NULL; while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { @@ -1562,3 +1579,40 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) } return 0; } + +int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) +{ + static snd_device_ops_t dev_ops = { + .dev_free = snd_usb_mixer_dev_free + }; + struct usb_mixer_interface *mixer; + int err; + + strcpy(chip->card->mixername, "USB Mixer"); + + mixer = kcalloc(1, sizeof(*mixer), GFP_KERNEL); + if (!mixer) + return -ENOMEM; + mixer->chip = chip; + mixer->ctrlif = ctrlif; +#ifdef IGNORE_CTL_ERROR + mixer->ignore_ctl_error = 1; +#endif + + if ((err = snd_usb_mixer_controls(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; + } + + err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); + if (err < 0) { + snd_usb_mixer_free(mixer); + return err; + } + list_add(&mixer->list, &chip->mixer_list); + return 0; +} + +void snd_usb_mixer_disconnect(struct list_head *p) +{ +} -- cgit v1.2.1 From 6639b6c2367f884ca172b78d69f7da17bfab2e5e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:26:14 +0200 Subject: [ALSA] usb-audio - add mixer control notifications USB generic driver Add support for the optional status interrupt endpoint in audio control interfaces, and translate USB status notifications into ALSA mixer control notifications. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 7bbccebd76c6..dd045ea6fb01 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -55,6 +55,8 @@ struct usb_mixer_interface { unsigned int ctrlif; struct list_head list; unsigned int ignore_ctl_error; + struct urb *urb; + usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */ }; @@ -83,13 +85,15 @@ struct usb_mixer_build { struct usb_mixer_elem_info { struct usb_mixer_interface *mixer; + usb_mixer_elem_info_t *next_id_elem; /* list of controls with same id */ + snd_ctl_elem_id_t *elem_id; unsigned int id; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ int channels; int val_type; int min, max, res; - unsigned int initialized: 1; + u8 initialized; }; @@ -414,6 +418,7 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) { + usb_mixer_elem_info_t *cval = kctl->private_data; int err; while (snd_ctl_find_id(state->chip->card, &kctl->id)) @@ -421,8 +426,12 @@ static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); snd_ctl_free_one(kctl); + return err; } - return err; + cval->elem_id = &kctl->id; + cval->next_id_elem = state->mixer->id_elems[cval->id]; + state->mixer->id_elems[cval->id] = cval; + return 0; } @@ -1522,6 +1531,11 @@ static int parse_audio_unit(mixer_build_t *state, int unitid) static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) { + kfree(mixer->id_elems); + if (mixer->urb) { + kfree(mixer->urb->transfer_buffer); + usb_free_urb(mixer->urb); + } kfree(mixer); } @@ -1580,6 +1594,76 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) return 0; } +static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, + int unitid) +{ + usb_mixer_elem_info_t *info; + + for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + info->elem_id); +} + +static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) +{ + struct usb_mixer_interface *mixer = urb->context; + + if (urb->status == 0) { + u8 *buf = urb->transfer_buffer; + int i; + + for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) { + snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n", + buf[0], buf[1]); + /* ignore any notifications not from the control interface */ + if ((buf[0] & 0x0f) != 0) + continue; + if (!(buf[0] & 0x40)) + snd_usb_mixer_notify_id(mixer, buf[1]); + } + } + if (urb->status != -ENOENT && urb->status != -ECONNRESET) { + urb->dev = mixer->chip->dev; + usb_submit_urb(urb, GFP_ATOMIC); + } +} + +/* create the handler for the optional status interrupt endpoint */ +static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) +{ + struct usb_host_interface *hostif; + struct usb_endpoint_descriptor *ep; + void *transfer_buffer; + int buffer_length; + unsigned int epnum; + + hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; + /* we need one interrupt input endpoint */ + if (get_iface_desc(hostif)->bNumEndpoints < 1) + return 0; + ep = get_endpoint(hostif, 0); + if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN || + (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + return 0; + + epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + buffer_length = le16_to_cpu(ep->wMaxPacketSize); + transfer_buffer = kmalloc(buffer_length, GFP_KERNEL); + if (!transfer_buffer) + return -ENOMEM; + mixer->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mixer->urb) { + kfree(transfer_buffer); + return -ENOMEM; + } + usb_fill_int_urb(mixer->urb, mixer->chip->dev, + usb_rcvintpipe(mixer->chip->dev, epnum), + transfer_buffer, buffer_length, + snd_usb_mixer_status_complete, mixer, ep->bInterval); + usb_submit_urb(mixer->urb, GFP_KERNEL); + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1598,8 +1682,14 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) #ifdef IGNORE_CTL_ERROR mixer->ignore_ctl_error = 1; #endif + mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL); + if (!mixer->id_elems) { + kfree(mixer); + return -ENOMEM; + } - if ((err = snd_usb_mixer_controls(mixer)) < 0) { + if ((err = snd_usb_mixer_controls(mixer)) < 0 || + (err = snd_usb_mixer_status_create(mixer)) < 0) { snd_usb_mixer_free(mixer); return err; } @@ -1615,4 +1705,9 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) void snd_usb_mixer_disconnect(struct list_head *p) { + struct usb_mixer_interface *mixer; + + mixer = list_entry(p, struct usb_mixer_interface, list); + if (mixer->urb) + usb_kill_urb(mixer->urb); } -- cgit v1.2.1 From b259b10c420a59a2fdbcf5a3498253ebcbdffa1e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 29 Apr 2005 16:29:28 +0200 Subject: [ALSA] usb-audio - add Extigy/Audigy 2 NX remote control support ALSA Core,USB generic driver Add an hwdep interface that supports reading remote control data from Sound Blaster Extigy and Audigy 2 NX devices. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index dd045ea6fb01..7ea42d43d7ff 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "usbaudio.h" @@ -57,6 +58,19 @@ struct usb_mixer_interface { unsigned int ignore_ctl_error; struct urb *urb; usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */ + + /* Sound Blaster remote control stuff */ + enum { + RC_NONE, + RC_EXTIGY, + RC_AUDIGY2NX, + } rc_type; + unsigned long rc_hwdep_open; + u32 rc_code; + wait_queue_head_t rc_waitq; + struct urb *rc_urb; + struct usb_ctrlrequest *rc_setup_packet; + u8 rc_buffer[6]; }; @@ -1536,6 +1550,9 @@ static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) kfree(mixer->urb->transfer_buffer); usb_free_urb(mixer->urb); } + if (mixer->rc_urb) + usb_free_urb(mixer->rc_urb); + kfree(mixer->rc_setup_packet); kfree(mixer); } @@ -1604,6 +1621,17 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, info->elem_id); } +static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, + int unitid) +{ + /* SB remote control */ + if (mixer->rc_type != RC_NONE && unitid == 0) { + /* read control code from device memory */ + mixer->rc_urb->dev = mixer->chip->dev; + usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); + } +} + static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) { struct usb_mixer_interface *mixer = urb->context; @@ -1620,6 +1648,8 @@ static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs) continue; if (!(buf[0] & 0x40)) snd_usb_mixer_notify_id(mixer, buf[1]); + else + snd_usb_mixer_memory_change(mixer, buf[1]); } } if (urb->status != -ENOENT && urb->status != -ECONNRESET) { @@ -1664,6 +1694,126 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) return 0; } +static void snd_usb_soundblaster_remote_complete(struct urb *urb, + struct pt_regs *regs) +{ + struct usb_mixer_interface *mixer = urb->context; + /* + * format of remote control data: + * Extigy: xx 00 + * Audigy 2 NX: 06 80 xx 00 00 00 + */ + int offset = mixer->rc_type == RC_EXTIGY ? 0 : 2; + u32 code; + + if (urb->status < 0 || urb->actual_length <= offset) + return; + code = mixer->rc_buffer[offset]; + /* the Mute button actually changes the mixer control */ + if (code == 13) + snd_usb_mixer_notify_id(mixer, 18); + mixer->rc_code = code; + wmb(); + wake_up(&mixer->rc_waitq); +} + +static int snd_usb_sbrc_hwdep_open(snd_hwdep_t *hw, struct file *file) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + if (test_and_set_bit(0, &mixer->rc_hwdep_open)) + return -EBUSY; + return 0; +} + +static int snd_usb_sbrc_hwdep_release(snd_hwdep_t *hw, struct file *file) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + clear_bit(0, &mixer->rc_hwdep_open); + smp_mb__after_clear_bit(); + return 0; +} + +static long snd_usb_sbrc_hwdep_read(snd_hwdep_t *hw, char __user *buf, + long count, loff_t *offset) +{ + struct usb_mixer_interface *mixer = hw->private_data; + int err; + u32 rc_code; + + if (count != 1) + return -EINVAL; + err = wait_event_interruptible(mixer->rc_waitq, + (rc_code = xchg(&mixer->rc_code, 0)) != 0); + if (err == 0) { + err = put_user(rc_code, buf); + } + return err < 0 ? err : count; +} + +static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, + poll_table *wait) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + poll_wait(file, &mixer->rc_waitq, wait); + return mixer->rc_code ? POLLIN | POLLRDNORM : 0; +} + +static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) +{ + snd_hwdep_t *hwdep; + int err, len; + + switch (le16_to_cpu(mixer->chip->dev->descriptor.idProduct)) { + case 0x3000: + mixer->rc_type = RC_EXTIGY; + len = 2; + break; + case 0x3020: + mixer->rc_type = RC_AUDIGY2NX; + len = 6; + break; + default: + return 0; + } + + init_waitqueue_head(&mixer->rc_waitq); + err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); + if (err < 0) + return err; + snprintf(hwdep->name, sizeof(hwdep->name), + "%s remote control", mixer->chip->card->shortname); + hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; + hwdep->private_data = mixer; + hwdep->ops.read = snd_usb_sbrc_hwdep_read; + hwdep->ops.open = snd_usb_sbrc_hwdep_open; + hwdep->ops.release = snd_usb_sbrc_hwdep_release; + hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; + + mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!mixer->rc_urb) + return -ENOMEM; + mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); + if (!mixer->rc_setup_packet) { + usb_free_urb(mixer->rc_urb); + mixer->rc_urb = NULL; + return -ENOMEM; + } + mixer->rc_setup_packet->bRequestType = + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + mixer->rc_setup_packet->bRequest = GET_MEM; + mixer->rc_setup_packet->wValue = cpu_to_le16(0); + mixer->rc_setup_packet->wIndex = cpu_to_le16(0); + mixer->rc_setup_packet->wLength = cpu_to_le16(len); + usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, + usb_rcvctrlpipe(mixer->chip->dev, 0), + (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, + snd_usb_soundblaster_remote_complete, mixer); + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1694,6 +1844,13 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) return err; } + if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x041e) { + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; + } + } + err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); if (err < 0) { snd_usb_mixer_free(mixer); @@ -1710,4 +1867,6 @@ void snd_usb_mixer_disconnect(struct list_head *p) mixer = list_entry(p, struct usb_mixer_interface, list); if (mixer->urb) usb_kill_urb(mixer->urb); + if (mixer->rc_urb) + usb_kill_urb(mixer->rc_urb); } -- cgit v1.2.1 From 27d10f5664c7650af3b2ffadfefaf19b36dc7bd8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:51:26 +0200 Subject: [ALSA] usb-audio - cache vendor/product IDs USB generic driver Cache the decoded values of idVendor/idProduct to get rid of most of those ugly le16_to_cpu() calls. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 104 +++++++++++++++++++-------------------- sound/usb/usbaudio.h | 6 +++ sound/usb/usbmidi.c | 123 ++++++++++++++++++++++------------------------ sound/usb/usbmixer.c | 38 +++++++------- sound/usb/usbmixer_maps.c | 13 +++-- 5 files changed, 139 insertions(+), 145 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index eeb09bb8cbf3..e759b73942c2 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2184,17 +2184,15 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor /* * check if the device uses big-endian samples */ -static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) +static int is_big_endian_format(snd_usb_audio_t *chip, struct audioformat *fp) { - /* M-Audio */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763) { - /* Quattro: captured data only */ - if (le16_to_cpu(dev->descriptor.idProduct) == 0x2001 && - fp->endpoint & USB_DIR_IN) - return 1; - /* Audiophile USB */ - if (le16_to_cpu(dev->descriptor.idProduct) == 0x2003) + switch (chip->usb_id) { + case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ + if (fp->endpoint & USB_DIR_IN) return 1; + break; + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ + return 1; } return 0; } @@ -2208,7 +2206,7 @@ static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) * @format: the format tag (wFormatTag) * @fmt: the format type descriptor */ -static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_i_type(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int pcm_format; @@ -2221,12 +2219,12 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat switch (format) { case 0: /* some devices don't define this correctly... */ snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", - dev->devnum, fp->iface, fp->altsetting); + chip->dev->devnum, fp->iface, fp->altsetting); /* fall-through */ case USB_AUDIO_FORMAT_PCM: if (sample_width > sample_bytes * 8) { snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", - dev->devnum, fp->iface, fp->altsetting, + chip->dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); } /* check the format byte size */ @@ -2235,13 +2233,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat pcm_format = SNDRV_PCM_FORMAT_S8; break; case 2: - if (is_big_endian_format(dev, fp)) + if (is_big_endian_format(chip, fp)) pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; case 3: - if (is_big_endian_format(dev, fp)) + if (is_big_endian_format(chip, fp)) pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S24_3LE; @@ -2251,14 +2249,14 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", - dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); + chip->dev->devnum, fp->iface, + fp->altsetting, sample_width, sample_bytes); break; } break; case USB_AUDIO_FORMAT_PCM8: /* Dallas DS4201 workaround */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && - le16_to_cpu(dev->descriptor.idProduct) == 0x4201) + if (chip->usb_id == USB_ID(0x04fa, 0x4201)) pcm_format = SNDRV_PCM_FORMAT_S8; else pcm_format = SNDRV_PCM_FORMAT_U8; @@ -2274,7 +2272,7 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", - dev->devnum, fp->iface, fp->altsetting, format); + chip->dev->devnum, fp->iface, fp->altsetting, format); break; } return pcm_format; @@ -2291,13 +2289,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat * @offset: the start offset of descriptor pointing the rate type * (7 for type I and II, 8 for type II) */ -static int parse_audio_format_rates(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *fp, unsigned char *fmt, int offset) { int nr_rates = fmt[offset]; if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", - dev->devnum, fp->iface, fp->altsetting); + chip->dev->devnum, fp->iface, fp->altsetting); return -1; } @@ -2344,7 +2342,7 @@ static int parse_audio_format_rates(struct usb_device *dev, struct audioformat * /* * parse the format type I and III descriptors */ -static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_i(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int pcm_format; @@ -2356,7 +2354,7 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, */ pcm_format = SNDRV_PCM_FORMAT_S16_LE; } else { - pcm_format = parse_audio_format_i_type(dev, fp, format, fmt); + pcm_format = parse_audio_format_i_type(chip, fp, format, fmt); if (pcm_format < 0) return -1; } @@ -2364,16 +2362,16 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, fp->channels = fmt[4]; if (fp->channels < 1) { snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", - dev->devnum, fp->iface, fp->altsetting, fp->channels); + chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); return -1; } - return parse_audio_format_rates(dev, fp, fmt, 7); + return parse_audio_format_rates(chip, fp, fmt, 7); } /* * prase the format type II descriptor */ -static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_ii(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt) { int brate, framesize; @@ -2388,7 +2386,7 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, break; default: snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n", - dev->devnum, fp->iface, fp->altsetting, format); + chip->dev->devnum, fp->iface, fp->altsetting, format); fp->format = SNDRV_PCM_FORMAT_MPEG; break; } @@ -2397,10 +2395,10 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); fp->frame_size = framesize; - return parse_audio_format_rates(dev, fp, fmt, 8); /* fmt[8..] sample rates */ + return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */ } -static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp, int format, unsigned char *fmt, int stream) { int err; @@ -2408,14 +2406,14 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, switch (fmt[3]) { case USB_FORMAT_TYPE_I: case USB_FORMAT_TYPE_III: - err = parse_audio_format_i(dev, fp, format, fmt); + err = parse_audio_format_i(chip, fp, format, fmt); break; case USB_FORMAT_TYPE_II: - err = parse_audio_format_ii(dev, fp, format, fmt); + err = parse_audio_format_ii(chip, fp, format, fmt); break; default: snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", - dev->devnum, fp->iface, fp->altsetting, fmt[3]); + chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]); return -1; } fp->fmt_type = fmt[3]; @@ -2426,9 +2424,8 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, /* extigy apparently supports sample rates other than 48k * but not in ordinary way. so we enable only 48k atm. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - (le16_to_cpu(dev->descriptor.idProduct) == 0x3000 || - le16_to_cpu(dev->descriptor.idProduct) == 0x3020)) { + if (chip->usb_id == USB_ID(0x041e, 0x3000) || + chip->usb_id == USB_ID(0x041e, 0x3020)) { if (fmt[3] == USB_FORMAT_TYPE_I && stream == SNDRV_PCM_STREAM_PLAYBACK && fp->rates != SNDRV_PCM_RATE_48000 && @@ -2532,8 +2529,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) /* some quirks for attributes here */ /* workaround for AudioTrak Optoplay */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0a92 && - le16_to_cpu(dev->descriptor.idProduct) == 0x0053) { + if (chip->usb_id == USB_ID(0x0a92, 0x0053)) { /* Optoplay sets the sample rate attribute although * it seems not supporting it in fact. */ @@ -2541,8 +2537,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) } /* workaround for M-Audio Audiophile USB */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763 && - le16_to_cpu(dev->descriptor.idProduct) == 0x2003) { + if (chip->usb_id == USB_ID(0x0763, 0x2003)) { /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; } @@ -2551,11 +2546,9 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) * plantronics headset and Griffin iMic have set adaptive-in * although it's really not... */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x047f && - le16_to_cpu(dev->descriptor.idProduct) == 0x0ca1) || + if (chip->usb_id == USB_ID(0x047f, 0x0ca1) || /* Griffin iMic (note that there is an older model 77d:223) */ - (le16_to_cpu(dev->descriptor.idVendor) == 0x077d && - le16_to_cpu(dev->descriptor.idProduct) == 0x07af)) { + chip->usb_id == USB_ID(0x077d, 0x07af)) { fp->ep_attr &= ~EP_ATTR_MASK; if (stream == SNDRV_PCM_STREAM_PLAYBACK) fp->ep_attr |= EP_ATTR_ADAPTIVE; @@ -2564,7 +2557,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) } /* ok, let's parse further... */ - if (parse_audio_format(dev, fp, format, fmt, stream) < 0) { + if (parse_audio_format(chip, fp, format, fmt, stream) < 0) { kfree(fp->rate_table); kfree(fp); continue; @@ -2799,7 +2792,7 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &ua25_ep }; - if (le16_to_cpu(chip->dev->descriptor.idProduct) == 0x002b) + if (chip->usb_id == USB_ID(0x0582, 0x002b)) return snd_usb_create_midi_interface(chip, iface, &ua700_quirk); else @@ -3018,8 +3011,8 @@ static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *bu snd_usb_audio_t *chip = entry->private_data; if (! chip->shutdown) snd_iprintf(buffer, "%04x:%04x\n", - le16_to_cpu(chip->dev->descriptor.idVendor), - le16_to_cpu(chip->dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) @@ -3089,6 +3082,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->index = idx; chip->dev = dev; chip->card = card; + chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->midi_list); INIT_LIST_HEAD(&chip->mixer_list); @@ -3101,8 +3096,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, strcpy(card->driver, "USB-Audio"); sprintf(component, "USB%04x:%04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); snd_component_add(card, component); /* retrieve the device string as shortname */ @@ -3114,8 +3108,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, card->shortname, sizeof(card->shortname)) <= 0) { /* no name available from anywhere, so use ID */ sprintf(card->shortname, "USB Device %#04x:%#04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } } @@ -3173,17 +3167,19 @@ static void *snd_usb_audio_probe(struct usb_device *dev, snd_usb_audio_t *chip; struct usb_host_interface *alts; int ifnum; + u32 id; alts = &intf->altsetting[0]; ifnum = get_iface_desc(alts)->bInterfaceNumber; + id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) goto __err_val; /* SB Extigy needs special boot-up sequence */ /* if more models come, this will go to the quirk list. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { + if (id == USB_ID(0x041e, 0x3000)) { if (snd_usb_extigy_boot_quirk(dev, intf) < 0) goto __err_val; config = dev->actconfig; @@ -3217,8 +3213,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } for (i = 0; i < SNDRV_CARDS; i++) if (enable[i] && ! usb_chip[i] && - (vid[i] == -1 || vid[i] == le16_to_cpu(dev->descriptor.idVendor)) && - (pid[i] == -1 || pid[i] == le16_to_cpu(dev->descriptor.idProduct))) { + (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && + (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { goto __error; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 41d842dab3e8..aedb42aaa749 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -118,6 +118,11 @@ /* maximum number of endpoints per interface */ #define MIDI_MAX_ENDPOINTS 2 +/* handling of USB vendor/product ID pairs as 32-bit numbers */ +#define USB_ID(vendor, product) (((vendor) << 16) | (product)) +#define USB_ID_VENDOR(id) ((id) >> 16) +#define USB_ID_PRODUCT(id) ((u16)(id)) + /* */ @@ -127,6 +132,7 @@ struct snd_usb_audio { int index; struct usb_device *dev; snd_card_t *card; + u32 usb_id; int shutdown; int num_interfaces; diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 304a13451ec9..bee70068dce0 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -955,88 +955,87 @@ static snd_rawmidi_substream_t* snd_usbmidi_find_substream(snd_usb_midi_t* umidi * such as internal control or synthesizer ports. */ static struct { - __u16 vendor; - __u16 product; + u32 id; int port; const char *name_format; } snd_usbmidi_port_names[] = { /* Roland UA-100 */ - {0x0582, 0x0000, 2, "%s Control"}, + { USB_ID(0x0582, 0x0000), 2, "%s Control" }, /* Roland SC-8850 */ - {0x0582, 0x0003, 0, "%s Part A"}, - {0x0582, 0x0003, 1, "%s Part B"}, - {0x0582, 0x0003, 2, "%s Part C"}, - {0x0582, 0x0003, 3, "%s Part D"}, - {0x0582, 0x0003, 4, "%s MIDI 1"}, - {0x0582, 0x0003, 5, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0003), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0003), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0003), 2, "%s Part C" }, + { USB_ID(0x0582, 0x0003), 3, "%s Part D" }, + { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" }, /* Roland U-8 */ - {0x0582, 0x0004, 0, "%s MIDI"}, - {0x0582, 0x0004, 1, "%s Control"}, + { USB_ID(0x0582, 0x0004), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0004), 1, "%s Control" }, /* Roland SC-8820 */ - {0x0582, 0x0007, 0, "%s Part A"}, - {0x0582, 0x0007, 1, "%s Part B"}, - {0x0582, 0x0007, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x0007), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0007), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0007), 2, "%s MIDI" }, /* Roland SK-500 */ - {0x0582, 0x000b, 0, "%s Part A"}, - {0x0582, 0x000b, 1, "%s Part B"}, - {0x0582, 0x000b, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x000b), 0, "%s Part A" }, + { USB_ID(0x0582, 0x000b), 1, "%s Part B" }, + { USB_ID(0x0582, 0x000b), 2, "%s MIDI" }, /* Roland SC-D70 */ - {0x0582, 0x000c, 0, "%s Part A"}, - {0x0582, 0x000c, 1, "%s Part B"}, - {0x0582, 0x000c, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x000c), 0, "%s Part A" }, + { USB_ID(0x0582, 0x000c), 1, "%s Part B" }, + { USB_ID(0x0582, 0x000c), 2, "%s MIDI" }, /* Edirol UM-880 */ - {0x0582, 0x0014, 8, "%s Control"}, + { USB_ID(0x0582, 0x0014), 8, "%s Control" }, /* Edirol SD-90 */ - {0x0582, 0x0016, 0, "%s Part A"}, - {0x0582, 0x0016, 1, "%s Part B"}, - {0x0582, 0x0016, 2, "%s MIDI 1"}, - {0x0582, 0x0016, 3, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0016), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0016), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" }, /* Edirol UM-550 */ - {0x0582, 0x0023, 5, "%s Control"}, + { USB_ID(0x0582, 0x0023), 5, "%s Control" }, /* Edirol SD-20 */ - {0x0582, 0x0027, 0, "%s Part A"}, - {0x0582, 0x0027, 1, "%s Part B"}, - {0x0582, 0x0027, 2, "%s MIDI"}, + { USB_ID(0x0582, 0x0027), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0027), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0027), 2, "%s MIDI" }, /* Edirol SD-80 */ - {0x0582, 0x0029, 0, "%s Part A"}, - {0x0582, 0x0029, 1, "%s Part B"}, - {0x0582, 0x0029, 2, "%s MIDI 1"}, - {0x0582, 0x0029, 3, "%s MIDI 2"}, + { USB_ID(0x0582, 0x0029), 0, "%s Part A" }, + { USB_ID(0x0582, 0x0029), 1, "%s Part B" }, + { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" }, + { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" }, /* Edirol UA-700 */ - {0x0582, 0x002b, 0, "%s MIDI"}, - {0x0582, 0x002b, 1, "%s Control"}, + { USB_ID(0x0582, 0x002b), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x002b), 1, "%s Control" }, /* Roland VariOS */ - {0x0582, 0x002f, 0, "%s MIDI"}, - {0x0582, 0x002f, 1, "%s External MIDI"}, - {0x0582, 0x002f, 2, "%s Sync"}, + { USB_ID(0x0582, 0x002f), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" }, + { USB_ID(0x0582, 0x002f), 2, "%s Sync" }, /* Edirol PCR */ - {0x0582, 0x0033, 0, "%s MIDI"}, - {0x0582, 0x0033, 1, "%s 1"}, - {0x0582, 0x0033, 2, "%s 2"}, + { USB_ID(0x0582, 0x0033), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0033), 1, "%s 1" }, + { USB_ID(0x0582, 0x0033), 2, "%s 2" }, /* BOSS GS-10 */ - {0x0582, 0x003b, 0, "%s MIDI"}, - {0x0582, 0x003b, 1, "%s Control"}, + { USB_ID(0x0582, 0x003b), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x003b), 1, "%s Control" }, /* Edirol UA-1000 */ - {0x0582, 0x0044, 0, "%s MIDI"}, - {0x0582, 0x0044, 1, "%s Control"}, + { USB_ID(0x0582, 0x0044), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0044), 1, "%s Control" }, /* Edirol UR-80 */ - {0x0582, 0x0048, 0, "%s MIDI"}, - {0x0582, 0x0048, 1, "%s 1"}, - {0x0582, 0x0048, 2, "%s 2"}, + { USB_ID(0x0582, 0x0048), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x0048), 1, "%s 1" }, + { USB_ID(0x0582, 0x0048), 2, "%s 2" }, /* Edirol PCR-A */ - {0x0582, 0x004d, 0, "%s MIDI"}, - {0x0582, 0x004d, 1, "%s 1"}, - {0x0582, 0x004d, 2, "%s 2"}, + { USB_ID(0x0582, 0x004d), 0, "%s MIDI" }, + { USB_ID(0x0582, 0x004d), 1, "%s 1" }, + { USB_ID(0x0582, 0x004d), 2, "%s 2" }, /* M-Audio MidiSport 8x8 */ - {0x0763, 0x1031, 8, "%s Control"}, - {0x0763, 0x1033, 8, "%s Control"}, + { USB_ID(0x0763, 0x1031), 8, "%s Control" }, + { USB_ID(0x0763, 0x1033), 8, "%s Control" }, /* MOTU Fastlane */ - {0x07fd, 0x0001, 0, "%s MIDI A"}, - {0x07fd, 0x0001, 1, "%s MIDI B"}, + { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" }, + { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" }, /* Emagic Unitor8/AMT8/MT4 */ - {0x086a, 0x0001, 8, "%s Broadcast"}, - {0x086a, 0x0002, 8, "%s Broadcast"}, - {0x086a, 0x0003, 4, "%s Broadcast"}, + { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" }, + { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" }, + { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" }, }; static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, @@ -1044,7 +1043,6 @@ static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, snd_rawmidi_substream_t** rsubstream) { int i; - __u16 vendor, product; const char *name_format; snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, number); @@ -1055,11 +1053,8 @@ static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, /* TODO: read port name from jack descriptor */ name_format = "%s MIDI %d"; - vendor = le16_to_cpu(umidi->chip->dev->descriptor.idVendor); - product = le16_to_cpu(umidi->chip->dev->descriptor.idProduct); for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { - if (snd_usbmidi_port_names[i].vendor == vendor && - snd_usbmidi_port_names[i].product == product && + if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id && snd_usbmidi_port_names[i].port == number) { name_format = snd_usbmidi_port_names[i].name_format; break; @@ -1226,7 +1221,7 @@ static int snd_usbmidi_detect_endpoints(snd_usb_midi_t* umidi, struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (le16_to_cpu(umidi->chip->dev->descriptor.idVendor) == 0x0582) + if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 7ea42d43d7ff..bfaec4fc1851 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -89,8 +89,6 @@ struct usb_mixer_build { struct usb_mixer_interface *mixer; unsigned char *buffer; unsigned int buflen; - unsigned short vendor; - unsigned short product; DECLARE_BITMAP(unitbitmap, 256); usb_audio_term_t oterm; const struct usbmix_name_map *map; @@ -906,11 +904,16 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */ /* is not very clear from datasheets */ /* I hope that the min value is -15360 for newer firmware --jk */ - if (((state->vendor == 0x471 && (state->product == 0x104 || state->product == 0x105 || state->product == 0x101)) || - (state->vendor == 0x672 && state->product == 0x1041)) && !strcmp(kctl->id.name, "PCM Playback Volume") && - cval->min == -15616) { - snd_printk("USB Audio: using volume control quirk for the UDA1321/N101 chip\n"); - cval->max = -256; + switch (state->chip->usb_id) { + case USB_ID(0x0471, 0x0101): + case USB_ID(0x0471, 0x0104): + case USB_ID(0x0471, 0x0105): + case USB_ID(0x0672, 0x1041): + if (!strcmp(kctl->id.name, "PCM Playback Volume") && + cval->min == -15616) { + snd_printk("using volume control quirk for the UDA1321/N101 chip\n"); + cval->max = -256; + } } snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", @@ -1574,7 +1577,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) mixer_build_t state; int err; const struct usbmix_ctl_map *map; - struct usb_device_descriptor *dev = &mixer->chip->dev->descriptor; struct usb_host_interface *hostif; hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; @@ -1583,12 +1585,10 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) state.mixer = mixer; state.buffer = hostif->extra; state.buflen = hostif->extralen; - state.vendor = le16_to_cpu(dev->idVendor); - state.product = le16_to_cpu(dev->idProduct); /* check the mapping table */ - for (map = usbmix_ctl_maps; map->vendor; map++) { - if (map->vendor == state.vendor && map->product == state.product) { + for (map = usbmix_ctl_maps; map->id; map++) { + if (map->id == state.chip->usb_id) { state.map = map->map; state.selector_map = map->selector_map; mixer->ignore_ctl_error = map->ignore_ctl_error; @@ -1766,12 +1766,12 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) snd_hwdep_t *hwdep; int err, len; - switch (le16_to_cpu(mixer->chip->dev->descriptor.idProduct)) { - case 0x3000: + switch (mixer->chip->usb_id) { + case USB_ID(0x041e, 0x3000): mixer->rc_type = RC_EXTIGY; len = 2; break; - case 0x3020: + case USB_ID(0x041e, 0x3020): mixer->rc_type = RC_AUDIGY2NX; len = 6; break; @@ -1844,11 +1844,9 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) return err; } - if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x041e) { - if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; - } + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { + snd_usb_mixer_free(mixer); + return err; } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index adb0abb3ee85..f05500b05ec0 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -33,8 +33,7 @@ struct usbmix_selector_map { }; struct usbmix_ctl_map { - int vendor; - int product; + u32 id; const struct usbmix_name_map *map; const struct usbmix_selector_map *selector_map; int ignore_ctl_error; @@ -225,26 +224,26 @@ static struct usbmix_name_map justlink_map[] = { static struct usbmix_ctl_map usbmix_ctl_maps[] = { { - .vendor = 0x41e, .product = 0x3000, + .id = USB_ID(0x041e, 0x3000), .map = extigy_map, .ignore_ctl_error = 1, }, { - .vendor = 0x41e, .product = 0x3010, + .id = USB_ID(0x041e, 0x3010), .map = mp3plus_map, }, { - .vendor = 0x41e, .product = 0x3020, + .id = USB_ID(0x041e, 0x3020), .map = audigy2nx_map, .selector_map = audigy2nx_selectors, }, { - .vendor = 0x8bb, .product = 0x2702, + .id = USB_ID(0x08bb, 0x2702), .map = linex_map, .ignore_ctl_error = 1, }, { - .vendor = 0xc45, .product = 0x1158, + .id = USB_ID(0x0c45, 0x1158), .map = justlink_map, }, { 0 } /* terminator */ -- cgit v1.2.1 From 4dc40a3cc4778ebcb6212bdb71b48690a153be07 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:52:32 +0200 Subject: [ALSA] usb-audio - allow type 0 extension units USB generic driver Extension units can have type 0, so do not ignore them when constructing mixer controls. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index bfaec4fc1851..5683ae0b5ba1 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1232,9 +1232,6 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char } type = combine_word(&dsc[4]); - if (! type) - return 0; /* undefined? */ - for (info = list; info && info->type; info++) if (info->type == type) break; -- cgit v1.2.1 From 1149a64fe4916fe6fdc8938043a0dc9a6551ab63 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:53:46 +0200 Subject: [ALSA] usb-audio - use proper interval between synchronization packets USB generic driver Add sanity checks when reading the bRefresh value, and actually use it for the synchronization packets instead of polling at 1000 Hz. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e759b73942c2..e1a648d7ffff 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1051,10 +1051,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by u->urb->pipe = subs->syncpipe; u->urb->transfer_flags = URB_ISO_ASAP; u->urb->number_of_packets = u->packets; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) - u->urb->interval = 8; - else - u->urb->interval = 1; + u->urb->interval = 1 << subs->syncinterval; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); } @@ -1272,7 +1269,12 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) subs->syncpipe = usb_rcvisocpipe(dev, ep); else subs->syncpipe = usb_sndisocpipe(dev, ep); - subs->syncinterval = get_endpoint(alts, 1)->bRefresh; + if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + get_endpoint(alts, 1)->bRefresh >= 1 && + get_endpoint(alts, 1)->bRefresh <= 9) + subs->syncinterval = get_endpoint(alts, 1)->bRefresh; + else + subs->syncinterval = 1; } /* always fill max packet size */ -- cgit v1.2.1 From ca81090a00e3e7152fe1f3d7398f11d57919428e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:55:54 +0200 Subject: [ALSA] usb-audio - use only one packet in synchronization feedback URBs USB generic driver Do not use more than one packet in synchronization feedback URBs because it would be pointless to send or receive more than one value at the same time. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 93 ++++++++++++++++++---------------------------------- 1 file changed, 31 insertions(+), 62 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index e1a648d7ffff..a5e97d081c3b 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -177,7 +177,7 @@ struct snd_usb_substream { unsigned int nurbs; /* # urbs */ snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ - char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */ + char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */ char *tmpbuf; /* temporary buffer for playback */ u64 formats; /* format bitmasks (all or'ed) */ @@ -251,17 +251,13 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs, { unsigned char *cp = urb->transfer_buffer; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - int i, offs; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - cp[0] = subs->freqn >> 2; - cp[1] = subs->freqn >> 10; - cp[2] = subs->freqn >> 18; - } + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn >> 2; + cp[1] = subs->freqn >> 10; + cp[2] = subs->freqn >> 18; return 0; } @@ -277,18 +273,14 @@ static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs, { unsigned char *cp = urb->transfer_buffer; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - int i, offs; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { - urb->iso_frame_desc[i].length = 4; - urb->iso_frame_desc[i].offset = offs; - cp[0] = subs->freqn; - cp[1] = subs->freqn >> 8; - cp[2] = subs->freqn >> 16; - cp[3] = subs->freqn >> 24; - } + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn; + cp[1] = subs->freqn >> 8; + cp[2] = subs->freqn >> 16; + cp[3] = subs->freqn >> 24; return 0; } @@ -418,15 +410,11 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i, offs; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - } + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; return 0; } @@ -440,15 +428,11 @@ static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i, offs; snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { - urb->iso_frame_desc[i].length = 4; - urb->iso_frame_desc[i].offset = offs; - } + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; return 0; } @@ -462,17 +446,12 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i; - unsigned int f, found; - unsigned char *cp = urb->transfer_buffer; + unsigned int f; unsigned long flags; - found = 0; - for (i = 0; i < urb->number_of_packets; i++, cp += 4) { - if (urb->iso_frame_desc[i].status || - urb->iso_frame_desc[i].actual_length < 3) - continue; - f = combine_triple(cp) << 2; + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 3) { + f = combine_triple((u8*)urb->transfer_buffer) << 2; #if 0 if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", @@ -481,11 +460,8 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, continue; } #endif - found = f; - } - if (found) { spin_lock_irqsave(&subs->lock, flags); - subs->freqm = found; + subs->freqm = f; spin_unlock_irqrestore(&subs->lock, flags); } @@ -502,21 +478,14 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *urb) { - int i; - unsigned int found; - unsigned char *cp = urb->transfer_buffer; + unsigned int f; unsigned long flags; - found = 0; - for (i = 0; i < urb->number_of_packets; i++, cp += 4) { - if (urb->iso_frame_desc[i].status || - urb->iso_frame_desc[i].actual_length < 4) - continue; - found = combine_quad(cp) & 0x0fffffff; - } - if (found) { + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 4) { + f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; spin_lock_irqsave(&subs->lock, flags); - subs->freqm = found; + subs->freqm = f; spin_unlock_irqrestore(&subs->lock, flags); } @@ -1039,18 +1008,18 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by snd_urb_ctx_t *u = &subs->syncurb[i]; u->index = i; u->subs = subs; - u->packets = nrpacks; - u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); + u->packets = 1; + u->urb = usb_alloc_urb(1, GFP_KERNEL); if (! u->urb) { release_substream_urbs(subs, 0); return -ENOMEM; } - u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4; - u->urb->transfer_buffer_length = nrpacks * 4; + u->urb->transfer_buffer = subs->syncbuf + i * 4; + u->urb->transfer_buffer_length = 4; u->urb->dev = subs->dev; u->urb->pipe = subs->syncpipe; u->urb->transfer_flags = URB_ISO_ASAP; - u->urb->number_of_packets = u->packets; + u->urb->number_of_packets = 1; u->urb->interval = 1 << subs->syncinterval; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); -- cgit v1.2.1 From 434b7f56872fc5783c77f362e895da8e22168325 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2005 08:58:31 +0200 Subject: [ALSA] usb-audio - make SB remote control device LIRC compatible USB generic driver Add ioctls to the Sound Blaster remote control hwdep device so that it can be used with LIRC. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5683ae0b5ba1..d90d6fa7431a 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -39,6 +39,18 @@ #include "usbaudio.h" +#if 0 +#include +#else +/* only those symbols from lirc.h we actually need: */ +#include +#define LIRC_MODE2REC(x) ((x) << 16) +#define LIRC_MODE_CODE 0x00000008 +#define LIRC_CAN_REC_CODE LIRC_MODE2REC(LIRC_MODE_CODE) +#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) +#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) +#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) +#endif /* */ @@ -1739,12 +1751,15 @@ static long snd_usb_sbrc_hwdep_read(snd_hwdep_t *hw, char __user *buf, int err; u32 rc_code; - if (count != 1) + if (count != 1 && count != 4) return -EINVAL; err = wait_event_interruptible(mixer->rc_waitq, (rc_code = xchg(&mixer->rc_code, 0)) != 0); if (err == 0) { - err = put_user(rc_code, buf); + if (count == 1) + err = put_user(rc_code, buf); + else + err = put_user(rc_code, (u32 __user *)buf); } return err < 0 ? err : count; } @@ -1758,6 +1773,25 @@ static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, return mixer->rc_code ? POLLIN | POLLRDNORM : 0; } +static int snd_usb_sbrc_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + u32 __user *argp = (u32 __user *)arg; + u32 mode; + + switch (cmd) { + case LIRC_GET_FEATURES: + return put_user(LIRC_CAN_REC_CODE, argp); + case LIRC_GET_REC_MODE: + return put_user(LIRC_MODE_CODE, argp); + case LIRC_SET_REC_MODE: + if (get_user(mode, argp)) + return -EFAULT; + return mode == LIRC_MODE_CODE ? 0 : -ENOSYS; + } + return -ENOTTY; +} + static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) { snd_hwdep_t *hwdep; @@ -1788,6 +1822,7 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) hwdep->ops.open = snd_usb_sbrc_hwdep_open; hwdep->ops.release = snd_usb_sbrc_hwdep_release; hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; + hwdep->ops.ioctl = snd_usb_sbrc_hwdep_ioctl; mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); if (!mixer->rc_urb) -- cgit v1.2.1 From 93446edcd05589201f20cf8843e8c4f990c18ae4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 3 May 2005 08:02:40 +0200 Subject: [ALSA] usb-audio - Audigy 2 NX blinkenlights USB generic driver Adds mixer controls for the CMSS/Dolby Digital/Power LEDs on the SB Audigy 2 NX. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 106 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index d90d6fa7431a..ec880ff52625 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -83,6 +83,8 @@ struct usb_mixer_interface { struct urb *rc_urb; struct usb_ctrlrequest *rc_setup_packet; u8 rc_buffer[6]; + + u8 audigy2nx_leds[3]; }; @@ -1846,6 +1848,85 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) return 0; } +static int snd_audigy2nx_led_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_audigy2nx_led_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + int index = kcontrol->private_value; + + ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; + return 0; +} + +static int snd_audigy2nx_led_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + int index = kcontrol->private_value; + int value = ucontrol->value.integer.value[0]; + int err, changed; + + if (value > 1) + return -EINVAL; + changed = value != mixer->audigy2nx_leds[index]; + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + value, index + 2, NULL, 0, 100); + if (err < 0) + return err; + mixer->audigy2nx_leds[index] = value; + return changed; +} + +static snd_kcontrol_new_t snd_audigy2nx_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "CMSS LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 0, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Power LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 1, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Dolby Digital LED Switch", + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, + .private_value = 2, + }, +}; + +static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) +{ + int i, err; + + for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { + err = snd_ctl_add(mixer->chip->card, + snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); + if (err < 0) + return err; + } + mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ + return 0; +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1871,23 +1952,26 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) } if ((err = snd_usb_mixer_controls(mixer)) < 0 || - (err = snd_usb_mixer_status_create(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; - } + (err = snd_usb_mixer_status_create(mixer)) < 0) + goto _error; - if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) { - snd_usb_mixer_free(mixer); - return err; + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) + goto _error; + + if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { + if ((err = snd_audigy2nx_controls_create(mixer)) < 0) + goto _error; } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); - if (err < 0) { - snd_usb_mixer_free(mixer); - return err; - } + if (err < 0) + goto _error; list_add(&mixer->list, &chip->mixer_list); return 0; + +_error: + snd_usb_mixer_free(mixer); + return err; } void snd_usb_mixer_disconnect(struct list_head *p) -- cgit v1.2.1 From c3f9329716df9965cbaf74ce313a12fe889c1a62 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 4 May 2005 14:56:04 +0200 Subject: [ALSA] usb-audio - set sample rate attribute on Audigy 2 NX endpoints USB generic driver The SB Audigy 2 NX does not advertise the sample rate attribute in its endpoint descriptors although it supports it. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a5e97d081c3b..da1fe0f0bca0 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2499,32 +2499,31 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) /* some quirks for attributes here */ - /* workaround for AudioTrak Optoplay */ - if (chip->usb_id == USB_ID(0x0a92, 0x0053)) { + switch (chip->usb_id) { + case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ /* Optoplay sets the sample rate attribute although * it seems not supporting it in fact. */ fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; - } - - /* workaround for M-Audio Audiophile USB */ - if (chip->usb_id == USB_ID(0x0763, 0x2003)) { + break; + case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; - } - + break; + case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ + case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is + an older model 77d:223) */ /* * plantronics headset and Griffin iMic have set adaptive-in * although it's really not... */ - if (chip->usb_id == USB_ID(0x047f, 0x0ca1) || - /* Griffin iMic (note that there is an older model 77d:223) */ - chip->usb_id == USB_ID(0x077d, 0x07af)) { fp->ep_attr &= ~EP_ATTR_MASK; if (stream == SNDRV_PCM_STREAM_PLAYBACK) fp->ep_attr |= EP_ATTR_ADAPTIVE; else fp->ep_attr |= EP_ATTR_SYNC; + break; } /* ok, let's parse further... */ -- cgit v1.2.1 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') diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 776761fe5577..13f7e62ee56b 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.1 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 --- sound/pci/emu10k1/p16v.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 13f7e62ee56b..93dff4c6b233 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.1 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') diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 93dff4c6b233..98f980189892 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.1 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') diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8b42e8631f2a..b6e1854e9389 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.1 From 3714b5344e2da58d18f0b885663226826c22a1b3 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 8 May 2005 22:22:27 +0200 Subject: [ALSA] Fix snd-usb-audio dependency on snd-hwdep. USB Signed-off-by: James Courtier-Dutton --- sound/usb/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 9329e992c841..f05d02f5b69f 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -6,6 +6,7 @@ menu "USB devices" config SND_USB_AUDIO tristate "USB Audio/MIDI driver" depends on SND && USB + select SND_HWDEP select SND_RAWMIDI select SND_PCM help -- cgit v1.2.1 From 3a2f08560d61e267aacddc63c26bf997d0d85e91 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 May 2005 09:20:31 +0200 Subject: [ALSA] usb-audio - enable high speed (not) on Audigy 2 NX USB generic driver The SB Audigy 2 NX needs a special boot-up command before it works in high speed mode. However, we don't actually enable it yet because high speed synchronization doesn't seem to work with this device. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index da1fe0f0bca0..34d5f58985b6 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2925,6 +2925,25 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac return 0; } +static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) +{ +#if 0 + /* TODO: enable this when high speed synchronization actually works */ + u8 buf = 1; + + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 0, 0, &buf, 1, 1000); + if (buf == 0) { + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 1, 2000, NULL, 0, 1000); + return -ENODEV; + } +#endif + return 0; +} + /* * audio-interface quirks @@ -3154,6 +3173,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __err_val; config = dev->actconfig; } + /* SB Audigy 2 NX needs its own boot-up magic, too */ + if (id == USB_ID(0x041e, 0x3020)) { + if (snd_usb_audigy2nx_boot_quirk(dev) < 0) + goto __err_val; + } /* * found a config. now register to ALSA -- cgit v1.2.1 From f55a655bf9eeb1431633bd313f47c8e4dadcf47c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 9 May 2005 09:21:28 +0200 Subject: [ALSA] usb-audio - remove superfluous LIRC ioctls USB generic driver The ioctls for LIRC compatibility can be removed because the infrastructure and detection stuff is better done in user space. Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index ec880ff52625..4a49e1930a1a 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -39,19 +39,6 @@ #include "usbaudio.h" -#if 0 -#include -#else -/* only those symbols from lirc.h we actually need: */ -#include -#define LIRC_MODE2REC(x) ((x) << 16) -#define LIRC_MODE_CODE 0x00000008 -#define LIRC_CAN_REC_CODE LIRC_MODE2REC(LIRC_MODE_CODE) -#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) -#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) -#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) -#endif - /* */ @@ -1775,25 +1762,6 @@ static unsigned int snd_usb_sbrc_hwdep_poll(snd_hwdep_t *hw, struct file *file, return mixer->rc_code ? POLLIN | POLLRDNORM : 0; } -static int snd_usb_sbrc_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, - unsigned int cmd, unsigned long arg) -{ - u32 __user *argp = (u32 __user *)arg; - u32 mode; - - switch (cmd) { - case LIRC_GET_FEATURES: - return put_user(LIRC_CAN_REC_CODE, argp); - case LIRC_GET_REC_MODE: - return put_user(LIRC_MODE_CODE, argp); - case LIRC_SET_REC_MODE: - if (get_user(mode, argp)) - return -EFAULT; - return mode == LIRC_MODE_CODE ? 0 : -ENOSYS; - } - return -ENOTTY; -} - static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) { snd_hwdep_t *hwdep; @@ -1824,7 +1792,6 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) hwdep->ops.open = snd_usb_sbrc_hwdep_open; hwdep->ops.release = snd_usb_sbrc_hwdep_release; hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; - hwdep->ops.ioctl = snd_usb_sbrc_hwdep_ioctl; mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); if (!mixer->rc_urb) -- cgit v1.2.1 From aafad5629a949d0ad41180f8a746b6cd7654e317 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:47:38 +0200 Subject: [ALSA] usb-audio - add a proc file for Audigy 2 NX jack status USB generic driver This patch adds a proc file for the SB Audigy 2 NX which shows the connection status of the various jacks. Unfortunately, no SPDIF input frequency (yet). Signed-off-by: Clemens Ladisch --- sound/usb/usbmixer.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 4a49e1930a1a..83ba665e5c6e 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "usbaudio.h" @@ -1622,11 +1623,22 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, int unitid) { - /* SB remote control */ - if (mixer->rc_type != RC_NONE && unitid == 0) { - /* read control code from device memory */ + if (mixer->rc_type == RC_NONE) + return; + /* unit ids specific to Extigy/Audigy 2 NX: */ + switch (unitid) { + case 0: /* remote control */ mixer->rc_urb->dev = mixer->chip->dev; usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); + break; + case 4: /* digital in jack */ + case 7: /* line in jacks */ + case 19: /* speaker out jacks */ + case 20: /* headphones out jack */ + break; + default: + snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); + break; } } @@ -1894,6 +1906,37 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) return 0; } +static void snd_audigy2nx_proc_read(snd_info_entry_t *entry, + snd_info_buffer_t *buffer) +{ + static const struct { + int unitid; + const char *name; + } jacks[] = { + {4, "dig in "}, + {7, "line in"}, + {19, "spk out"}, + {20, "hph out"}, + }; + struct usb_mixer_interface *mixer = entry->private_data; + int i, err; + u8 buf[3]; + + snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); + for (i = 0; i < ARRAY_SIZE(jacks); ++i) { + snd_iprintf(buffer, "%s: ", jacks[i].name); + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_rcvctrlpipe(mixer->chip->dev, 0), + GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, 0, + jacks[i].unitid << 8, buf, 3, 100); + if (err == 3 && buf[0] == 3) + snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); + else + snd_iprintf(buffer, "?\n"); + } +} + int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) { static snd_device_ops_t dev_ops = { @@ -1926,8 +1969,13 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) goto _error; if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { + snd_info_entry_t *entry; + if ((err = snd_audigy2nx_controls_create(mixer)) < 0) goto _error; + if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) + snd_info_set_text_ops(entry, mixer, 1024, + snd_audigy2nx_proc_read); } err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); -- cgit v1.2.1 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') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 737c4bb94d2a..05efff08ddcc 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.1 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') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 05efff08ddcc..ce02e7091fcb 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.1 From 1dcd3ec4728f9568ee204ceb46b0851be324a7f9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 May 2005 14:51:40 +0200 Subject: [ALSA] usb-audio - bind to control interface instead of usb_device USB generic driver Bind the device files to the (first) audio control interface instead of the entire USB device. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 34d5f58985b6..c360ab9783d5 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3129,8 +3129,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, snd_usb_audio_create_proc(chip); - snd_card_set_dev(card, &dev->dev); - *rchip = chip; return 0; } @@ -3212,6 +3210,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { goto __error; } + snd_card_set_dev(chip->card, &intf->dev); break; } if (! chip) { -- cgit v1.2.1 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') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index bf17db1fd243..070be6af97b5 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.1 From 9b9a5afffd8636a82c6b32970342aef9d1f3d17d Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 May 2005 10:25:58 +0200 Subject: [ALSA] ARM DMA subsystem ARM DMA routines The patch below adds a convenient re-usable shim around the extended ARM DMA API, and is used by several ARM ALSA drivers. Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/devdma.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sound/arm/devdma.h | 3 ++ 2 files changed, 84 insertions(+) create mode 100644 sound/arm/devdma.c create mode 100644 sound/arm/devdma.h (limited to 'sound') diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c new file mode 100644 index 000000000000..60826a5324b4 --- /dev/null +++ b/sound/arm/devdma.c @@ -0,0 +1,81 @@ +/* + * linux/sound/arm/devdma.c + * + * Copyright (C) 2003-2004 Russell King, All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ARM DMA shim for ALSA. + */ +#include +#include + +#include +#include +#include + +#include "devdma.h" + +void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct snd_dma_buffer *buf = runtime->dma_buffer_p; + + if (runtime->dma_area == NULL) + return; + + if (buf != &substream->dma_buffer) { + dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr); + kfree(runtime->dma_buffer_p); + } + + snd_pcm_set_runtime_buffer(substream, NULL); +} + +int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct snd_dma_buffer *buf = runtime->dma_buffer_p; + int ret = 0; + + if (buf) { + if (buf->bytes >= size) + goto out; + devdma_hw_free(dev, substream); + } + + if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { + buf = &substream->dma_buffer; + } else { + buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); + if (!buf) + goto nomem; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = dev; + buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL); + buf->bytes = size; + buf->private_data = NULL; + + if (!buf->area) + goto free; + } + snd_pcm_set_runtime_buffer(substream, buf); + ret = 1; + out: + runtime->dma_bytes = size; + return ret; + + free: + kfree(buf); + nomem: + return -ENOMEM; +} + +int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); +} diff --git a/sound/arm/devdma.h b/sound/arm/devdma.h new file mode 100644 index 000000000000..5a33b6bacc34 --- /dev/null +++ b/sound/arm/devdma.h @@ -0,0 +1,3 @@ +void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream); +int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size); +int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma); -- cgit v1.2.1 From cb5a6ffc5c09bc354af69407dae710dcddcced37 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 May 2005 14:04:59 +0200 Subject: [ALSA] ARM AACI primecell driver ARM,/arm/Makefile,ARM AACI PL041 driver Add support for the ARM AACI Primecell, which provides an AC'97 based interface. This driver only provides playback support. This has been extensively tested with an LM4549 AC'97 codec. Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/Kconfig | 6 + sound/arm/Makefile | 3 + sound/arm/aaci.c | 968 +++++++++++++++++++++++++++++++++++++++++++++++++++++ sound/arm/aaci.h | 246 ++++++++++++++ 4 files changed, 1223 insertions(+) create mode 100644 sound/arm/aaci.c create mode 100644 sound/arm/aaci.h (limited to 'sound') diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index cdacf4d3a387..34c1740aa6e9 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -14,5 +14,11 @@ config SND_SA11XX_UDA1341 To compile this driver as a module, choose M here: the module will be called snd-sa11xx-uda1341. +config SND_ARMAACI + tristate "ARM PrimeCell PL041 AC Link support" + depends on SND && ARM_AMBA + select SND_PCM + select SND_AC97_CODEC + endmenu diff --git a/sound/arm/Makefile b/sound/arm/Makefile index d7e7dc0c3cdf..f74ec28e1068 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -6,3 +6,6 @@ snd-sa11xx-uda1341-objs := sa11xx-uda1341.o # Toplevel Module Dependency obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o + +obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o +snd-aaci-objs := aaci.o devdma.o diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c new file mode 100644 index 000000000000..08cc3ddca96f --- /dev/null +++ b/sound/arm/aaci.c @@ -0,0 +1,968 @@ +/* + * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Documentation: ARM DDI 0173B + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "aaci.h" +#include "devdma.h" + +#define DRIVER_NAME "aaci-pl041" + +/* + * PM support is not complete. Turn it off. + */ +#undef CONFIG_PM + +static void aaci_ac97_select_codec(struct aaci *aaci, ac97_t *ac97) +{ + u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num); + + /* + * Ensure that the slot 1/2 RX registers are empty. + */ + v = readl(aaci->base + AACI_SLFR); + if (v & SLFR_2RXV) + readl(aaci->base + AACI_SL2RX); + if (v & SLFR_1RXV) + readl(aaci->base + AACI_SL1RX); + + writel(maincr, aaci->base + AACI_MAINCR); +} + +/* + * P29: + * The recommended use of programming the external codec through slot 1 + * and slot 2 data is to use the channels during setup routines and the + * slot register at any other time. The data written into slot 1, slot 2 + * and slot 12 registers is transmitted only when their corresponding + * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR + * register. + */ +static void aaci_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) +{ + struct aaci *aaci = ac97->private_data; + u32 v; + + if (ac97->num >= 4) + return; + + down(&aaci->ac97_sem); + + aaci_ac97_select_codec(aaci, ac97); + + /* + * P54: You must ensure that AACI_SL2TX is always written + * to, if required, before data is written to AACI_SL1TX. + */ + writel(val << 4, aaci->base + AACI_SL2TX); + writel(reg << 12, aaci->base + AACI_SL1TX); + + /* + * Wait for the transmission of both slots to complete. + */ + do { + v = readl(aaci->base + AACI_SLFR); + } while (v & (SLFR_1TXB|SLFR_2TXB)); + + up(&aaci->ac97_sem); +} + +/* + * Read an AC'97 register. + */ +static unsigned short aaci_ac97_read(ac97_t *ac97, unsigned short reg) +{ + struct aaci *aaci = ac97->private_data; + u32 v; + + if (ac97->num >= 4) + return ~0; + + down(&aaci->ac97_sem); + + aaci_ac97_select_codec(aaci, ac97); + + /* + * Write the register address to slot 1. + */ + writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX); + + /* + * Wait for the transmission to complete. + */ + do { + v = readl(aaci->base + AACI_SLFR); + } while (v & SLFR_1TXB); + + /* + * Give the AC'97 codec more than enough time + * to respond. (42us = ~2 frames at 48kHz.) + */ + udelay(42); + + /* + * Wait for slot 2 to indicate data. + */ + do { + cond_resched(); + v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); + } while (v != (SLFR_1RXV|SLFR_2RXV)); + + v = readl(aaci->base + AACI_SL1RX) >> 12; + if (v == reg) { + v = readl(aaci->base + AACI_SL2RX) >> 4; + } else { + dev_err(&aaci->dev->dev, + "wrong ac97 register read back (%x != %x)\n", + v, reg); + v = ~0; + } + + up(&aaci->ac97_sem); + return v; +} + +static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) +{ + u32 val; + int timeout = 5000; + + do { + val = readl(aacirun->base + AACI_SR); + } while (val & (SR_TXB|SR_RXB) && timeout--); +} + + + +/* + * Interrupt support. + */ +static void aaci_fifo_irq(struct aaci *aaci, u32 mask) +{ + if (mask & ISR_URINTR) { + writel(ICLR_TXUEC1, aaci->base + AACI_INTCLR); + } + + if (mask & ISR_TXINTR) { + struct aaci_runtime *aacirun = &aaci->playback; + void *ptr; + + if (!aacirun->substream || !aacirun->start) { + dev_warn(&aaci->dev->dev, "TX interrupt???"); + writel(0, aacirun->base + AACI_IE); + return; + } + + ptr = aacirun->ptr; + do { + unsigned int len = aacirun->fifosz; + u32 val; + + if (aacirun->bytes <= 0) { + aacirun->bytes += aacirun->period; + aacirun->ptr = ptr; + spin_unlock(&aaci->lock); + snd_pcm_period_elapsed(aacirun->substream); + spin_lock(&aaci->lock); + } + if (!(aacirun->cr & TXCR_TXEN)) + break; + + val = readl(aacirun->base + AACI_SR); + if (!(val & SR_TXHE)) + break; + if (!(val & SR_TXFE)) + len >>= 1; + + aacirun->bytes -= len; + + /* writing 16 bytes at a time */ + for ( ; len > 0; len -= 16) { + asm( + "ldmia %0!, {r0, r1, r2, r3}\n\t" + "stmia %1, {r0, r1, r2, r3}" + : "+r" (ptr) + : "r" (aacirun->fifo) + : "r0", "r1", "r2", "r3", "cc"); + + if (ptr >= aacirun->end) + ptr = aacirun->start; + } + } while (1); + + aacirun->ptr = ptr; + } +} + +static irqreturn_t aaci_irq(int irq, void *devid, struct pt_regs *regs) +{ + struct aaci *aaci = devid; + u32 mask; + int i; + + spin_lock(&aaci->lock); + mask = readl(aaci->base + AACI_ALLINTS); + if (mask) { + u32 m = mask; + for (i = 0; i < 4; i++, m >>= 7) { + if (m & 0x7f) { + aaci_fifo_irq(aaci, m); + } + } + } + spin_unlock(&aaci->lock); + + return mask ? IRQ_HANDLED : IRQ_NONE; +} + + + +/* + * ALSA support. + */ + +struct aaci_stream { + unsigned char codec_idx; + unsigned char rate_idx; +}; + +static struct aaci_stream aaci_streams[] = { + [ACSTREAM_FRONT] = { + .codec_idx = 0, + .rate_idx = AC97_RATES_FRONT_DAC, + }, + [ACSTREAM_SURROUND] = { + .codec_idx = 0, + .rate_idx = AC97_RATES_SURR_DAC, + }, + [ACSTREAM_LFE] = { + .codec_idx = 0, + .rate_idx = AC97_RATES_LFE_DAC, + }, +}; + +static inline unsigned int aaci_rate_mask(struct aaci *aaci, int streamid) +{ + struct aaci_stream *s = aaci_streams + streamid; + return aaci->ac97_bus->codec[s->codec_idx]->rates[s->rate_idx]; +} + +static unsigned int rate_list[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, + 48000, 64000, 88200, 96000, 176400, 192000 +}; + +/* + * Double-rate rule: we can support double rate iff channels == 2 + * (unimplemented) + */ +static int +aaci_rule_rate_by_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule) +{ + struct aaci *aaci = rule->private; + unsigned int rate_mask = SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_5512; + snd_interval_t *c = hw_param_interval(p, SNDRV_PCM_HW_PARAM_CHANNELS); + + switch (c->max) { + case 6: + rate_mask &= aaci_rate_mask(aaci, ACSTREAM_LFE); + case 4: + rate_mask &= aaci_rate_mask(aaci, ACSTREAM_SURROUND); + case 2: + rate_mask &= aaci_rate_mask(aaci, ACSTREAM_FRONT); + } + + return snd_interval_list(hw_param_interval(p, rule->var), + ARRAY_SIZE(rate_list), rate_list, + rate_mask); +} + +static snd_pcm_hardware_t aaci_hw_info = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME, + + /* + * ALSA doesn't support 18-bit or 20-bit packed into 32-bit + * words. It also doesn't support 12-bit at all. + */ + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + /* should this be continuous or knot? */ + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_max = 48000, + .rate_min = 4000, + .channels_min = 2, + .channels_max = 6, + .buffer_bytes_max = 64 * 1024, + .period_bytes_min = 256, + .period_bytes_max = PAGE_SIZE, + .periods_min = 4, + .periods_max = PAGE_SIZE / 16, +}; + +static int aaci_pcm_open(struct aaci *aaci, snd_pcm_substream_t *substream, + struct aaci_runtime *aacirun) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + int ret; + + aacirun->substream = substream; + runtime->private_data = aacirun; + runtime->hw = aaci_hw_info; + + /* + * FIXME: ALSA specifies fifo_size in bytes. If we're in normal + * mode, each 32-bit word contains one sample. If we're in + * compact mode, each 32-bit word contains two samples, effectively + * halving the FIFO size. However, we don't know for sure which + * we'll be using at this point. We set this to the lower limit. + */ + runtime->hw.fifo_size = aaci->fifosize * 2; + + /* + * Add rule describing hardware rate dependency + * on the number of channels. + */ + ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + aaci_rule_rate_by_channels, aaci, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (ret) + goto out; + + ret = request_irq(aaci->dev->irq[0], aaci_irq, SA_SHIRQ|SA_INTERRUPT, + DRIVER_NAME, aaci); + if (ret) + goto out; + + return 0; + + out: + return ret; +} + + +/* + * Common ALSA stuff + */ +static int aaci_pcm_close(snd_pcm_substream_t *substream) +{ + struct aaci *aaci = substream->private_data; + struct aaci_runtime *aacirun = substream->runtime->private_data; + + WARN_ON(aacirun->cr & TXCR_TXEN); + + aacirun->substream = NULL; + free_irq(aaci->dev->irq[0], aaci); + + return 0; +} + +static int aaci_pcm_hw_free(snd_pcm_substream_t *substream) +{ + struct aaci_runtime *aacirun = substream->runtime->private_data; + + /* + * This must not be called with the device enabled. + */ + WARN_ON(aacirun->cr & TXCR_TXEN); + + if (aacirun->pcm_open) + snd_ac97_pcm_close(aacirun->pcm); + aacirun->pcm_open = 0; + + /* + * Clear out the DMA and any allocated buffers. + */ + devdma_hw_free(NULL, substream); + + return 0; +} + +static int aaci_pcm_hw_params(snd_pcm_substream_t *substream, + struct aaci_runtime *aacirun, + snd_pcm_hw_params_t *params) +{ + int err; + + aaci_pcm_hw_free(substream); + + err = devdma_hw_alloc(NULL, substream, + params_buffer_bytes(params)); + if (err < 0) + goto out; + + err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + params_channels(params), + aacirun->pcm->r[0].slots); + if (err) + goto out; + + aacirun->pcm_open = 1; + + out: + return err; +} + +static int aaci_pcm_prepare(snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct aaci_runtime *aacirun = runtime->private_data; + + aacirun->start = (void *)runtime->dma_area; + aacirun->end = aacirun->start + runtime->dma_bytes; + aacirun->ptr = aacirun->start; + aacirun->period = + aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); + + return 0; +} + +static snd_pcm_uframes_t aaci_pcm_pointer(snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct aaci_runtime *aacirun = runtime->private_data; + ssize_t bytes = aacirun->ptr - aacirun->start; + + return bytes_to_frames(runtime, bytes); +} + +static int aaci_pcm_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *vma) +{ + return devdma_mmap(NULL, substream, vma); +} + + +/* + * Playback specific ALSA stuff + */ +static const u32 channels_to_txmask[] = { + [2] = TXCR_TX3 | TXCR_TX4, + [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8, + [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9, +}; + +/* + * We can support two and four channel audio. Unfortunately + * six channel audio requires a non-standard channel ordering: + * 2 -> FL(3), FR(4) + * 4 -> FL(3), FR(4), SL(7), SR(8) + * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required) + * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual) + * This requires an ALSA configuration file to correct. + */ +static unsigned int channel_list[] = { 2, 4, 6 }; + +static int +aaci_rule_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule) +{ + struct aaci *aaci = rule->private; + unsigned int chan_mask = 1 << 0, slots; + + /* + * pcms[0] is the our 5.1 PCM instance. + */ + slots = aaci->ac97_bus->pcms[0].r[0].slots; + if (slots & (1 << AC97_SLOT_PCM_SLEFT)) { + chan_mask |= 1 << 1; + if (slots & (1 << AC97_SLOT_LFE)) + chan_mask |= 1 << 2; + } + + return snd_interval_list(hw_param_interval(p, rule->var), + ARRAY_SIZE(channel_list), channel_list, + chan_mask); +} + +static int aaci_pcm_playback_open(snd_pcm_substream_t *substream) +{ + struct aaci *aaci = substream->private_data; + int ret; + + /* + * Add rule describing channel dependency. + */ + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + aaci_rule_channels, aaci, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret) + return ret; + + return aaci_pcm_open(aaci, substream, &aaci->playback); +} + +static int aaci_pcm_playback_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *params) +{ + struct aaci *aaci = substream->private_data; + struct aaci_runtime *aacirun = substream->runtime->private_data; + unsigned int channels = params_channels(params); + int ret; + + WARN_ON(channels >= ARRAY_SIZE(channels_to_txmask) || + !channels_to_txmask[channels]); + + ret = aaci_pcm_hw_params(substream, aacirun, params); + + /* + * Enable FIFO, compact mode, 16 bits per sample. + * FIXME: double rate slots? + */ + if (ret >= 0) { + aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16; + aacirun->cr |= channels_to_txmask[channels]; + + aacirun->fifosz = aaci->fifosize * 4; + if (aacirun->cr & TXCR_COMPACT) + aacirun->fifosz >>= 1; + } + return ret; +} + +static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) +{ + u32 ie; + + ie = readl(aacirun->base + AACI_IE); + ie &= ~(IE_URIE|IE_TXIE); + writel(ie, aacirun->base + AACI_IE); + aacirun->cr &= ~TXCR_TXEN; + aaci_chan_wait_ready(aacirun); + writel(aacirun->cr, aacirun->base + AACI_TXCR); +} + +static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) +{ + u32 ie; + + aaci_chan_wait_ready(aacirun); + aacirun->cr |= TXCR_TXEN; + + ie = readl(aacirun->base + AACI_IE); + ie |= IE_URIE | IE_TXIE; + writel(ie, aacirun->base + AACI_IE); + writel(aacirun->cr, aacirun->base + AACI_TXCR); +} + +static int aaci_pcm_playback_trigger(snd_pcm_substream_t *substream, int cmd) +{ + struct aaci *aaci = substream->private_data; + struct aaci_runtime *aacirun = substream->runtime->private_data; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&aaci->lock, flags); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + aaci_pcm_playback_start(aacirun); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + aaci_pcm_playback_start(aacirun); + break; + + case SNDRV_PCM_TRIGGER_STOP: + aaci_pcm_playback_stop(aacirun); + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + aaci_pcm_playback_stop(aacirun); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(&aaci->lock, flags); + + return ret; +} + +static snd_pcm_ops_t aaci_playback_ops = { + .open = aaci_pcm_playback_open, + .close = aaci_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = aaci_pcm_playback_hw_params, + .hw_free = aaci_pcm_hw_free, + .prepare = aaci_pcm_prepare, + .trigger = aaci_pcm_playback_trigger, + .pointer = aaci_pcm_pointer, + .mmap = aaci_pcm_mmap, +}; + + + +/* + * Power Management. + */ +#ifdef CONFIG_PM +static int aaci_do_suspend(snd_card_t *card, unsigned int state) +{ + struct aaci *aaci = card->private_data; + if (aaci->card->power_state != SNDRV_CTL_POWER_D3cold) { + snd_pcm_suspend_all(aaci->pcm); + snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D3cold); + } + return 0; +} + +static int aaci_do_resume(snd_card_t *card, unsigned int state) +{ + struct aaci *aaci = card->private_data; + if (aaci->card->power_state != SNDRV_CTL_POWER_D0) { + snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D0); + } + return 0; +} + +static int aaci_suspend(struct amba_device *dev, u32 state) +{ + snd_card_t *card = amba_get_drvdata(dev); + return card ? aaci_do_suspend(card) : 0; +} + +static int aaci_resume(struct amba_device *dev) +{ + snd_card_t *card = amba_get_drvdata(dev); + return card ? aaci_do_resume(card) : 0; +} +#else +#define aaci_do_suspend NULL +#define aaci_do_resume NULL +#define aaci_suspend NULL +#define aaci_resume NULL +#endif + + +static struct ac97_pcm ac97_defs[] __devinitdata = { + [0] = { /* Front PCM */ + .exclusive = 1, + .r = { + [0] = { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) | + (1 << AC97_SLOT_PCM_CENTER) | + (1 << AC97_SLOT_PCM_SLEFT) | + (1 << AC97_SLOT_PCM_SRIGHT) | + (1 << AC97_SLOT_LFE), + }, + }, + }, + [1] = { /* PCM in */ + .stream = 1, + .exclusive = 1, + .r = { + [0] = { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT), + }, + }, + }, + [2] = { /* Mic in */ + .stream = 1, + .exclusive = 1, + .r = { + [0] = { + .slots = (1 << AC97_SLOT_MIC), + }, + }, + } +}; + +static ac97_bus_ops_t aaci_bus_ops = { + .write = aaci_ac97_write, + .read = aaci_ac97_read, +}; + +static int __devinit aaci_probe_ac97(struct aaci *aaci) +{ + ac97_template_t ac97_template; + ac97_bus_t *ac97_bus; + ac97_t *ac97; + int ret; + + /* + * Assert AACIRESET for 2us + */ + writel(0, aaci->base + AACI_RESET); + udelay(2); + writel(RESET_NRST, aaci->base + AACI_RESET); + + /* + * Give the AC'97 codec more than enough time + * to wake up. (42us = ~2 frames at 48kHz.) + */ + udelay(42); + + ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus); + if (ret) + goto out; + + ac97_bus->clock = 48000; + aaci->ac97_bus = ac97_bus; + + memset(&ac97_template, 0, sizeof(ac97_template_t)); + ac97_template.private_data = aaci; + ac97_template.num = 0; + ac97_template.scaps = AC97_SCAP_SKIP_MODEM; + + ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); + if (ret) + goto out; + + /* + * Disable AC97 PC Beep input on audio codecs. + */ + if (ac97_is_audio(ac97)) + snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e); + + ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs); + if (ret) + goto out; + + aaci->playback.pcm = &ac97_bus->pcms[0]; + + out: + return ret; +} + +static void aaci_free_card(snd_card_t *card) +{ + struct aaci *aaci = card->private_data; + if (aaci->base) + iounmap(aaci->base); +} + +static struct aaci * __devinit aaci_init_card(struct amba_device *dev) +{ + struct aaci *aaci; + snd_card_t *card; + + card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, sizeof(struct aaci)); + if (card == NULL) + return ERR_PTR(-ENOMEM); + + card->private_free = aaci_free_card; + snd_card_set_pm_callback(card, aaci_do_suspend, aaci_do_resume, NULL); + + strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); + strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%08lx, irq %d", + card->shortname, dev->res.start, dev->irq[0]); + + aaci = card->private_data; + init_MUTEX(&aaci->ac97_sem); + spin_lock_init(&aaci->lock); + aaci->card = card; + aaci->dev = dev; + + /* Set MAINCR to allow slot 1 and 2 data IO */ + aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN | + MAINCR_SL2RXEN | MAINCR_SL2TXEN; + + return aaci; +} + +static int __devinit aaci_init_pcm(struct aaci *aaci) +{ + snd_pcm_t *pcm; + int ret; + + ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm); + if (ret == 0) { + aaci->pcm = pcm; + pcm->private_data = aaci; + pcm->info_flags = 0; + + strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); + } + + return ret; +} + +static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) +{ + void *base = aaci->base + AACI_CSCH1; + int i; + + writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR); + + for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++) + writel(0, aaci->base + AACI_DR1); + + writel(0, base + AACI_TXCR); + + /* + * Re-initialise the AACI after the FIFO depth test, to + * ensure that the FIFOs are empty. Unfortunately, merely + * disabling the channel doesn't clear the FIFO. + */ + writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR); + writel(aaci->maincr, aaci->base + AACI_MAINCR); + + /* + * If we hit 4096, we failed. Go back to the specified + * fifo depth. + */ + if (i == 4096) + i = 8; + + return i; +} + +static int __devinit aaci_probe(struct amba_device *dev, void *id) +{ + struct aaci *aaci; + int ret, i; + + ret = amba_request_regions(dev, NULL); + if (ret) + return ret; + + aaci = aaci_init_card(dev); + if (IS_ERR(aaci)) { + ret = PTR_ERR(aaci); + goto out; + } + + aaci->base = ioremap(dev->res.start, SZ_4K); + if (!aaci->base) { + ret = -ENOMEM; + goto out; + } + + /* + * Playback uses AACI channel 0 + */ + aaci->playback.base = aaci->base + AACI_CSCH1; + aaci->playback.fifo = aaci->base + AACI_DR1; + + for (i = 0; i < 4; i++) { + void *base = aaci->base + i * 0x14; + + writel(0, base + AACI_IE); + writel(0, base + AACI_TXCR); + writel(0, base + AACI_RXCR); + } + + writel(0x1fff, aaci->base + AACI_INTCLR); + writel(aaci->maincr, aaci->base + AACI_MAINCR); + + /* + * Size the FIFOs. + */ + aaci->fifosize = aaci_size_fifo(aaci); + + ret = aaci_probe_ac97(aaci); + if (ret) + goto out; + + ret = aaci_init_pcm(aaci); + if (ret) + goto out; + + ret = snd_card_register(aaci->card); + if (ret == 0) { + dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, + aaci->fifosize); + amba_set_drvdata(dev, aaci->card); + return ret; + } + + out: + if (aaci) + snd_card_free(aaci->card); + amba_release_regions(dev); + return ret; +} + +static int __devexit aaci_remove(struct amba_device *dev) +{ + snd_card_t *card = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + if (card) { + struct aaci *aaci = card->private_data; + writel(0, aaci->base + AACI_MAINCR); + + snd_card_free(card); + amba_release_regions(dev); + } + + return 0; +} + +static struct amba_id aaci_ids[] = { + { + .id = 0x00041041, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver aaci_driver = { + .drv = { + .name = DRIVER_NAME, + }, + .probe = aaci_probe, + .remove = __devexit_p(aaci_remove), + .suspend = aaci_suspend, + .resume = aaci_resume, + .id_table = aaci_ids, +}; + +static int __init aaci_init(void) +{ + return amba_driver_register(&aaci_driver); +} + +static void __exit aaci_exit(void) +{ + amba_driver_unregister(&aaci_driver); +} + +module_init(aaci_init); +module_exit(aaci_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver"); diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h new file mode 100644 index 000000000000..d752e6426894 --- /dev/null +++ b/sound/arm/aaci.h @@ -0,0 +1,246 @@ +/* + * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef AACI_H +#define AACI_H + +/* + * Control and status register offsets + * P39. + */ +#define AACI_CSCH1 0x000 +#define AACI_CSCH2 0x014 +#define AACI_CSCH3 0x028 +#define AACI_CSCH4 0x03c + +#define AACI_RXCR 0x000 /* 29 bits Control Rx FIFO */ +#define AACI_TXCR 0x004 /* 17 bits Control Tx FIFO */ +#define AACI_SR 0x008 /* 12 bits Status */ +#define AACI_ISR 0x00c /* 7 bits Int Status */ +#define AACI_IE 0x010 /* 7 bits Int Enable */ + +/* + * Other registers + */ +#define AACI_SL1RX 0x050 +#define AACI_SL1TX 0x054 +#define AACI_SL2RX 0x058 +#define AACI_SL2TX 0x05c +#define AACI_SL12RX 0x060 +#define AACI_SL12TX 0x064 +#define AACI_SLFR 0x068 /* slot flags */ +#define AACI_SLISTAT 0x06c /* slot interrupt status */ +#define AACI_SLIEN 0x070 /* slot interrupt enable */ +#define AACI_INTCLR 0x074 /* interrupt clear */ +#define AACI_MAINCR 0x078 /* main control */ +#define AACI_RESET 0x07c /* reset control */ +#define AACI_SYNC 0x080 /* sync control */ +#define AACI_ALLINTS 0x084 /* all fifo interrupt status */ +#define AACI_MAINFR 0x088 /* main flag register */ +#define AACI_DR1 0x090 /* data read/written fifo 1 */ +#define AACI_DR2 0x0b0 /* data read/written fifo 2 */ +#define AACI_DR3 0x0d0 /* data read/written fifo 3 */ +#define AACI_DR4 0x0f0 /* data read/written fifo 4 */ + +/* + * transmit fifo control register. P48 + */ +#define TXCR_FEN (1 << 16) /* fifo enable */ +#define TXCR_COMPACT (1 << 15) /* compact mode */ +#define TXCR_TSZ16 (0 << 13) /* 16 bits */ +#define TXCR_TSZ18 (1 << 13) /* 18 bits */ +#define TXCR_TSZ20 (2 << 13) /* 20 bits */ +#define TXCR_TSZ12 (3 << 13) /* 12 bits */ +#define TXCR_TX12 (1 << 12) /* transmits slot 12 */ +#define TXCR_TX11 (1 << 11) /* transmits slot 12 */ +#define TXCR_TX10 (1 << 10) /* transmits slot 12 */ +#define TXCR_TX9 (1 << 9) /* transmits slot 12 */ +#define TXCR_TX8 (1 << 8) /* transmits slot 12 */ +#define TXCR_TX7 (1 << 7) /* transmits slot 12 */ +#define TXCR_TX6 (1 << 6) /* transmits slot 12 */ +#define TXCR_TX5 (1 << 5) /* transmits slot 12 */ +#define TXCR_TX4 (1 << 4) /* transmits slot 12 */ +#define TXCR_TX3 (1 << 3) /* transmits slot 12 */ +#define TXCR_TX2 (1 << 2) /* transmits slot 12 */ +#define TXCR_TX1 (1 << 1) /* transmits slot 12 */ +#define TXCR_TXEN (1 << 0) /* transmit enable */ + +/* + * status register bits. P49 + */ +#define SR_RXTOFE (1 << 11) /* rx timeout fifo empty */ +#define SR_TXTO (1 << 10) /* rx timeout fifo nonempty */ +#define SR_TXU (1 << 9) /* tx underrun */ +#define SR_RXO (1 << 8) /* rx overrun */ +#define SR_TXB (1 << 7) /* tx busy */ +#define SR_RXB (1 << 6) /* rx busy */ +#define SR_TXFF (1 << 5) /* tx fifo full */ +#define SR_RXFF (1 << 4) /* rx fifo full */ +#define SR_TXHE (1 << 3) /* tx fifo half empty */ +#define SR_RXHF (1 << 2) /* rx fifo half full */ +#define SR_TXFE (1 << 1) /* tx fifo empty */ +#define SR_RXFE (1 << 0) /* rx fifo empty */ + +/* + * interrupt status register bits. + */ +#define ISR_RXTOFEINTR (1 << 6) /* rx fifo empty */ +#define ISR_URINTR (1 << 5) /* tx underflow */ +#define ISR_ORINTR (1 << 4) /* rx overflow */ +#define ISR_RXINTR (1 << 3) /* rx fifo */ +#define ISR_TXINTR (1 << 2) /* tx fifo intr */ +#define ISR_RXTOINTR (1 << 1) /* tx timeout */ +#define ISR_TXCINTR (1 << 0) /* tx complete */ + +/* + * interrupt enable register bits. + */ +#define IE_RXTOIE (1 << 6) +#define IE_URIE (1 << 5) +#define IE_ORIE (1 << 4) +#define IE_RXIE (1 << 3) +#define IE_TXIE (1 << 2) +#define IE_RXTIE (1 << 1) +#define IE_TXCIE (1 << 0) + +/* + * interrupt status. P51 + */ +#define ISR_RXTOFE (1 << 6) /* rx timeout fifo empty */ +#define ISR_UR (1 << 5) /* tx fifo underrun */ +#define ISR_OR (1 << 4) /* rx fifo overrun */ +#define ISR_RX (1 << 3) /* rx interrupt status */ +#define ISR_TX (1 << 2) /* tx interrupt status */ +#define ISR_RXTO (1 << 1) /* rx timeout */ +#define ISR_TXC (1 << 0) /* tx complete */ + +/* + * interrupt enable. P52 + */ +#define IE_RXTOFE (1 << 6) /* rx timeout fifo empty */ +#define IE_UR (1 << 5) /* tx fifo underrun */ +#define IE_OR (1 << 4) /* rx fifo overrun */ +#define IE_RX (1 << 3) /* rx interrupt status */ +#define IE_TX (1 << 2) /* tx interrupt status */ +#define IE_RXTO (1 << 1) /* rx timeout */ +#define IE_TXC (1 << 0) /* tx complete */ + +/* + * slot flag register bits. P56 + */ +#define SLFR_RWIS (1 << 13) /* raw wake-up interrupt status */ +#define SLFR_RGPIOINTR (1 << 12) /* raw gpio interrupt */ +#define SLFR_12TXE (1 << 11) /* slot 12 tx empty */ +#define SLFR_12RXV (1 << 10) /* slot 12 rx valid */ +#define SLFR_2TXE (1 << 9) /* slot 2 tx empty */ +#define SLFR_2RXV (1 << 8) /* slot 2 rx valid */ +#define SLFR_1TXE (1 << 7) /* slot 1 tx empty */ +#define SLFR_1RXV (1 << 6) /* slot 1 rx valid */ +#define SLFR_12TXB (1 << 5) /* slot 12 tx busy */ +#define SLFR_12RXB (1 << 4) /* slot 12 rx busy */ +#define SLFR_2TXB (1 << 3) /* slot 2 tx busy */ +#define SLFR_2RXB (1 << 2) /* slot 2 rx busy */ +#define SLFR_1TXB (1 << 1) /* slot 1 tx busy */ +#define SLFR_1RXB (1 << 0) /* slot 1 rx busy */ + +/* + * Interrupt clear register. + */ +#define ICLR_RXTOFEC4 (1 << 12) +#define ICLR_RXTOFEC3 (1 << 11) +#define ICLR_RXTOFEC2 (1 << 10) +#define ICLR_RXTOFEC1 (1 << 9) +#define ICLR_TXUEC4 (1 << 8) +#define ICLR_TXUEC3 (1 << 7) +#define ICLR_TXUEC2 (1 << 6) +#define ICLR_TXUEC1 (1 << 5) +#define ICLR_RXOEC4 (1 << 4) +#define ICLR_RXOEC3 (1 << 3) +#define ICLR_RXOEC2 (1 << 2) +#define ICLR_RXOEC1 (1 << 1) +#define ICLR_WISC (1 << 0) + +/* + * Main control register bits. P62 + */ +#define MAINCR_SCRA(x) ((x) << 10) /* secondary codec reg access */ +#define MAINCR_DMAEN (1 << 9) /* dma enable */ +#define MAINCR_SL12TXEN (1 << 8) /* slot 12 transmit enable */ +#define MAINCR_SL12RXEN (1 << 7) /* slot 12 receive enable */ +#define MAINCR_SL2TXEN (1 << 6) /* slot 2 transmit enable */ +#define MAINCR_SL2RXEN (1 << 5) /* slot 2 receive enable */ +#define MAINCR_SL1TXEN (1 << 4) /* slot 1 transmit enable */ +#define MAINCR_SL1RXEN (1 << 3) /* slot 1 receive enable */ +#define MAINCR_LPM (1 << 2) /* low power mode */ +#define MAINCR_LOOPBK (1 << 1) /* loopback */ +#define MAINCR_IE (1 << 0) /* aaci interface enable */ + +/* + * Reset register bits. P65 + */ +#define RESET_NRST (1 << 0) + +/* + * Sync register bits. P65 + */ +#define SYNC_FORCE (1 << 0) + +/* + * Main flag register bits. P66 + */ +#define MAINFR_TXB (1 << 1) /* transmit busy */ +#define MAINFR_RXB (1 << 0) /* receive busy */ + + + +struct aaci_runtime { + void *base; + void *fifo; + + struct ac97_pcm *pcm; + int pcm_open; + + u32 cr; + snd_pcm_substream_t *substream; + + /* + * PIO support + */ + void *start; + void *end; + void *ptr; + int bytes; + unsigned int period; + unsigned int fifosz; +}; + +struct aaci { + struct amba_device *dev; + snd_card_t *card; + void *base; + unsigned int fifosize; + + /* AC'97 */ + struct semaphore ac97_sem; + ac97_bus_t *ac97_bus; + + u32 maincr; + spinlock_t lock; + + struct aaci_runtime playback; + struct aaci_runtime capture; + + snd_pcm_t *pcm; +}; + +#define ACSTREAM_FRONT 0 +#define ACSTREAM_SURROUND 1 +#define ACSTREAM_LFE 2 + +#endif -- cgit v1.2.1 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') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 9f184ea8a9d3..293cc10e3cbb 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.1 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') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 293cc10e3cbb..c1c7eeeb199b 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.1 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') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index c1c7eeeb199b..3690ea05b042 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.1 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 --- sound/pci/hda/hda_intel.c | 85 ++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 37 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cbc9ca73c2ab..104593fa08eb 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.1 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 --- sound/pci/hda/patch_realtek.c | 109 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 17c5062423ae..c106e1fe01cf 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.1 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') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c106e1fe01cf..75ec1970cc0a 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.1 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 --- sound/pci/hda/hda_intel.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 104593fa08eb..d8329a79bcd2 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.1 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 --- sound/pci/hda/hda_intel.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d8329a79bcd2..87988da47bff 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.1 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') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 44fac2182fcc..87018dfd02f7 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 7c7b849875a0..b8fbbc4901d9 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 75ec1970cc0a..8a104827a95c 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.1 From 50cdbf1519a891bec4ce306c7bae397a0d8e7246 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 13 May 2005 07:44:13 +0200 Subject: [ALSA] usb-audio - sanity-check sync feedback frequency values USB generic driver Check that the synchronization feedback frequency values returned by the device are more or less near the nominal frequency. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index c360ab9783d5..a6ed0d08337e 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -452,17 +452,11 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, if (urb->iso_frame_desc[0].status == 0 && urb->iso_frame_desc[0].actual_length == 3) { f = combine_triple((u8*)urb->transfer_buffer) << 2; -#if 0 - if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { - snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", - f, f >> 14, (f & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1), - subs->freqn, subs->freqn >> 14, (subs->freqn & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1)); - continue; + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); } -#endif - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = f; - spin_unlock_irqrestore(&subs->lock, flags); } return 0; @@ -484,9 +478,11 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, if (urb->iso_frame_desc[0].status == 0 && urb->iso_frame_desc[0].actual_length == 4) { f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = f; - spin_unlock_irqrestore(&subs->lock, flags); + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); + } } return 0; -- cgit v1.2.1 From 29b16931f936fdbcd78995e66d0f5626f3afbda8 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 13 May 2005 07:50:28 +0200 Subject: [ALSA] usb-audio - avoid unnecessary double buffering USB generic driver When a USB packet boundary falls exactly on a buffer boundary, hwptr remains at the end of the buffer which causes an overflow in the next iteration and triggers double buffering although the next packet would actually be contiguous. This patch ensures that hwptr is always smaller than buffer_size. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a6ed0d08337e..076da19a9e28 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -565,6 +565,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, /* set the buffer pointer */ urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride; subs->hwptr += offs; + if (subs->hwptr == runtime->buffer_size) + subs->hwptr = 0; } spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = offs * stride; -- cgit v1.2.1 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') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index ce02e7091fcb..bcb1a20d75dc 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.1 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') diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 0bc1d783a840..3e5161a32363 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 87018dfd02f7..70e3cb6dd252 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.1 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') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 70e3cb6dd252..56941031ab0d 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.1 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') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 87988da47bff..f05a6384b9c0 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.1 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') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8a104827a95c..9f12d1fd02dc 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.1 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') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 56941031ab0d..e6efaed4b464 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.1 From 6d85be612d8b6a6730d19e742329e5ffa60eafdd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 14:32:50 +0200 Subject: [ALSA] Suppress debug message Control Midlevel Suppress 'unknown ioctl' debug message (replaced with snd_printdd). Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index f4ea6bff1dd3..4e39a2103d0a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1102,7 +1102,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg } } up_read(&snd_ioctl_rwsem); - snd_printd("unknown ioctl = 0x%x\n", cmd); + snd_printdd("unknown ioctl = 0x%x\n", cmd); return -ENOTTY; } -- cgit v1.2.1 From 92bb010cd874e53e4c2e2a73510966e45cfa4525 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 14:41:20 +0200 Subject: [ALSA] Add PnP ID ADS7180 AD1816A driver Added PnP ID 'ADS7180' (AD1816?). Signed-off-by: Takashi Iwai --- sound/isa/ad1816a/ad1816a.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 9fa7a78da6c3..563296d02894 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -83,6 +83,8 @@ struct snd_card_ad1816a { static struct pnp_card_device_id snd_ad1816a_pnpids[] = { /* Analog Devices AD1815 */ { .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } }, + /* Analog Device AD1816? */ + { .id = "ADS7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, /* Analog Devices AD1816A - added by Kenneth Platz */ { .id = "ADS7181", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, /* Analog Devices AD1816A - Aztech/Newcom SC-16 3D */ -- cgit v1.2.1 From 15790a6be14852850ee7cbd791225fa51750d8af Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 15:04:14 +0200 Subject: [ALSA] Add missing PAUSE ioctl Timer Midlevel Added the missing implemenation of TIMER PAUSE ioctl. Signed-off-by: Takashi Iwai --- sound/core/timer.c | 12 ++++++++++++ sound/core/timer_compat.c | 1 + 2 files changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index be6d37af76d8..48aebdf6550b 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1680,6 +1680,16 @@ static int snd_timer_user_continue(struct file *file) return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; } +static int snd_timer_user_pause(struct file *file) +{ + int err; + snd_timer_user_t *tu; + + tu = file->private_data; + snd_assert(tu->timeri != NULL, return -ENXIO); + return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; +} + static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { snd_timer_user_t *tu; @@ -1729,6 +1739,8 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l return snd_timer_user_stop(file); case SNDRV_TIMER_IOCTL_CONTINUE: return snd_timer_user_continue(file); + case SNDRV_TIMER_IOCTL_PAUSE: + return snd_timer_user_pause(file); } return -ENOTTY; } diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 9fbc3957a22d..420817d10b7c 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -108,6 +108,7 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns case SNDRV_TIMER_IOCTL_START: case SNDRV_TIMER_IOCTL_STOP: case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_PAUSE: case SNDRV_TIMER_IOCTL_NEXT_DEVICE: return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); case SNDRV_TIMER_IOCTL_INFO32: -- cgit v1.2.1 From 8c50b37c04a026ab6641ecb7eaf0fd479798e8b8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 15 May 2005 15:43:54 +0200 Subject: [ALSA] Change some timer ioctls due to confliction Timer Midlevel,ALSA Core Change values of some timer ioctls to avoid confliction with FIO* ioctls. The protocol version is increased to indicate this change. Signed-off-by: Takashi Iwai --- sound/core/timer.c | 11 +++++++++++ sound/core/timer_compat.c | 4 ++++ 2 files changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 48aebdf6550b..305e39d74092 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1690,6 +1690,13 @@ static int snd_timer_user_pause(struct file *file) return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; } +enum { + SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20), + SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21), + SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22), + SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), +}; + static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { snd_timer_user_t *tu; @@ -1734,12 +1741,16 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l case SNDRV_TIMER_IOCTL_STATUS: return snd_timer_user_status(file, argp); case SNDRV_TIMER_IOCTL_START: + case SNDRV_TIMER_IOCTL_START_OLD: return snd_timer_user_start(file); case SNDRV_TIMER_IOCTL_STOP: + case SNDRV_TIMER_IOCTL_STOP_OLD: return snd_timer_user_stop(file); case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_CONTINUE_OLD: return snd_timer_user_continue(file); case SNDRV_TIMER_IOCTL_PAUSE: + case SNDRV_TIMER_IOCTL_PAUSE_OLD: return snd_timer_user_pause(file); } return -ENOTTY; diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 420817d10b7c..3de552dfe80f 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -106,9 +106,13 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns case SNDRV_TIMER_IOCTL_SELECT: case SNDRV_TIMER_IOCTL_PARAMS: case SNDRV_TIMER_IOCTL_START: + case SNDRV_TIMER_IOCTL_START_OLD: case SNDRV_TIMER_IOCTL_STOP: + case SNDRV_TIMER_IOCTL_STOP_OLD: case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_CONTINUE_OLD: case SNDRV_TIMER_IOCTL_PAUSE: + case SNDRV_TIMER_IOCTL_PAUSE_OLD: case SNDRV_TIMER_IOCTL_NEXT_DEVICE: return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); case SNDRV_TIMER_IOCTL_INFO32: -- cgit v1.2.1 From d138b44589cc180418f5a20cb0ecfe338123d86c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 16 May 2005 13:51:39 +0200 Subject: [ALSA] fixed PAUSE ioctl for user space interface Timer Midlevel - fixed traditional cut-n-paste error Signed-off-by: Jaroslav Kysela --- sound/core/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index 305e39d74092..cb011a1d4c3e 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1687,7 +1687,7 @@ static int snd_timer_user_pause(struct file *file) tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); - return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; + return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; } enum { -- cgit v1.2.1 From d3ff42fd2b4fddb5d779e9e03a2ea44147aa8048 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 17 May 2005 09:14:27 +0200 Subject: [ALSA] usb-audio - claim all interfaces for Roland USB MIDI devices USB generic driver Many Roland USB MIDI devices have two interfaces that are currently not used by the driver; claim them anyway. Signed-off-by: Clemens Ladisch --- sound/usb/usbquirks.h | 270 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 220 insertions(+), 50 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 00781fea2115..f5135641b3e2 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -203,11 +203,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-4", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x000f, - .in_cables = 0x000f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, + { + .ifnum = -1 + } } } }, @@ -216,11 +233,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SC-8850", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x003f, - .in_cables = 0x003f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x003f, + .in_cables = 0x003f + } + }, + { + .ifnum = -1 + } } } }, @@ -229,11 +263,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "U-8", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0005, - .in_cables = 0x0005 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0005, + .in_cables = 0x0005 + } + }, + { + .ifnum = -1 + } } } }, @@ -242,11 +293,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-2", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0003, - .in_cables = 0x0003 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } + }, + { + .ifnum = -1 + } } } }, @@ -255,11 +323,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SC-8820", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0013, - .in_cables = 0x0013 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0013, + .in_cables = 0x0013 + } + }, + { + .ifnum = -1 + } } } }, @@ -268,11 +353,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "PC-300", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, @@ -281,11 +383,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "UM-1", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, @@ -294,11 +413,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "SK-500", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0013, - .in_cables = 0x0013 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0013, + .in_cables = 0x0013 + } + }, + { + .ifnum = -1 + } } } }, @@ -421,11 +557,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", .product_name = "SD-90", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x000f, - .in_cables = 0x000f + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, + { + .ifnum = -1 + } } } }, @@ -434,11 +587,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", .product_name = "MMP-2", - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } }, -- cgit v1.2.1 From 604cf499256af85703bd4858da56e777ec71714d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 17 May 2005 09:15:27 +0200 Subject: [ALSA] usb-audio - fix synchronization packet interval with Audigy 2 NX USB generic driver When a device does not provide the bRefresh field in its audio endpoint descriptors, use the bInterval field instead. Furthermore, increase the number of sync URBs for better queueing. Signed-off-by: Clemens Ladisch --- sound/usb/usbaudio.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 076da19a9e28..a82412b8790d 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -98,7 +98,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); #define MAX_PACKS 10 #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ #define MAX_URBS 5 /* max. 20ms long packets */ -#define SYNC_URBS 2 /* always two urbs for sync */ +#define SYNC_URBS 4 /* always four urbs for sync */ #define MIN_PACKS_URB 1 /* minimum 1 packet per urb */ typedef struct snd_usb_substream snd_usb_substream_t; @@ -1240,8 +1240,13 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) get_endpoint(alts, 1)->bRefresh >= 1 && get_endpoint(alts, 1)->bRefresh <= 9) subs->syncinterval = get_endpoint(alts, 1)->bRefresh; - else + else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) subs->syncinterval = 1; + else if (get_endpoint(alts, 1)->bInterval >= 1 && + get_endpoint(alts, 1)->bInterval <= 16) + subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; + else + subs->syncinterval = 3; } /* always fill max packet size */ -- cgit v1.2.1 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') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index bcb1a20d75dc..5520f5d97490 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.1 From 9502dcad6c1138a3ce2bae23ccd4be44c718d2a9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 May 2005 16:25:46 +0200 Subject: [ALSA] Export missing snd_pcm_format_*() PCM Midlevel Export snd_pcm_format_size(). This function is used by some out-of-kernel drivers. Make snd_pcm_format_cpu_endian() macro for optimization. Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 1 + sound/core/pcm_misc.c | 16 ---------------- 2 files changed, 1 insertion(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index a2757fcec1f0..d57f4ec3b08b 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1069,6 +1069,7 @@ EXPORT_SYMBOL(snd_pcm_format_little_endian); EXPORT_SYMBOL(snd_pcm_format_big_endian); EXPORT_SYMBOL(snd_pcm_format_width); EXPORT_SYMBOL(snd_pcm_format_physical_width); +EXPORT_SYMBOL(snd_pcm_format_size); EXPORT_SYMBOL(snd_pcm_format_silence_64); EXPORT_SYMBOL(snd_pcm_format_set_silence); EXPORT_SYMBOL(snd_pcm_build_linear_format); diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 422b8db14154..1453743e4da0 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -269,22 +269,6 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format) return !val; } -/** - * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian - * @format: the format to check - * - * Returns 1 if the given PCM format is CPU-endian, 0 if - * opposite, or a negative error code if endian not specified. - */ -int snd_pcm_format_cpu_endian(snd_pcm_format_t format) -{ -#ifdef SNDRV_LITTLE_ENDIAN - return snd_pcm_format_little_endian(format); -#else - return snd_pcm_format_big_endian(format); -#endif -} - /** * snd_pcm_format_width - return the bit-width of the format * @format: the format to check -- cgit v1.2.1 From 5218064c885af5c49e380d09d54f3cc86891a580 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 18 May 2005 16:31:51 +0200 Subject: [ALSA] ppc32: Fix Alsa PowerMac driver on old machines PPC PMAC driver The g5 support code broke some earlier models unfortunately as those bail out early from the detect function, before the point where I added the code to locate the PCI device for use with DMA allocations. This patch fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Takashi Iwai --- sound/ppc/pmac.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 32d94754acf8..080ef3928465 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -876,7 +876,7 @@ static void __init detect_byte_swap(pmac_t *chip) */ static int __init snd_pmac_detect(pmac_t *chip) { - struct device_node *sound; + struct device_node *sound = NULL; unsigned int *prop, l; struct macio_chip* macio; @@ -906,20 +906,22 @@ static int __init snd_pmac_detect(pmac_t *chip) chip->is_pbook_G3 = 1; chip->node = find_devices("awacs"); if (chip->node) - return 0; /* ok */ + sound = chip->node; /* * powermac G3 models have a node called "davbus" * with a child called "sound". */ - chip->node = find_devices("davbus"); + if (!chip->node) + chip->node = find_devices("davbus"); /* * if we didn't find a davbus device, try 'i2s-a' since * this seems to be what iBooks have */ if (! chip->node) { chip->node = find_devices("i2s-a"); - if (chip->node && chip->node->parent && chip->node->parent->parent) { + if (chip->node && chip->node->parent && + chip->node->parent->parent) { if (device_is_compatible(chip->node->parent->parent, "K2-Keylargo")) chip->is_k2 = 1; @@ -928,9 +930,11 @@ static int __init snd_pmac_detect(pmac_t *chip) if (! chip->node) return -ENODEV; - sound = find_devices("sound"); - while (sound && sound->parent != chip->node) - sound = sound->next; + if (!sound) { + sound = find_devices("sound"); + while (sound && sound->parent != chip->node) + sound = sound->next; + } if (! sound) return -ENODEV; prop = (unsigned int *) get_property(sound, "sub-frame", NULL); @@ -1019,7 +1023,8 @@ static int __init snd_pmac_detect(pmac_t *chip) } } if (chip->pdev == NULL) - printk(KERN_WARNING "snd-powermac: can't locate macio PCI device !\n"); + printk(KERN_WARNING "snd-powermac: can't locate macio PCI" + " device !\n"); detect_byte_swap(chip); @@ -1027,7 +1032,8 @@ static int __init snd_pmac_detect(pmac_t *chip) are available */ prop = (unsigned int *) get_property(sound, "sample-rates", &l); if (! prop) - prop = (unsigned int *) get_property(sound, "output-frame-rates", &l); + prop = (unsigned int *) get_property(sound, + "output-frame-rates", &l); if (prop) { int i; chip->freqs_ok = 0; @@ -1054,7 +1060,8 @@ static int __init snd_pmac_detect(pmac_t *chip) /* * exported - boolean info callbacks for ease of programming */ -int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 2; @@ -1063,7 +1070,8 @@ int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * return 0; } -int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; -- cgit v1.2.1 From 123992f728785e05f385d23893bd5ec69871aeb4 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 18 May 2005 18:02:04 +0200 Subject: [ALSA] sound/core/: possible cleanups PCM Midlevel,ALSA Core,Timer Midlevel,ALSA sequencer,Virtual Midi This patch contains the following possible cleanups: - make needlessly global code static - #if 0 the following unused global functions - remove the following unneeded EXPORT_SYMBOL's Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 1 - sound/core/pcm_lib.c | 52 +++++++++++++++++++++++------------------ sound/core/pcm_native.c | 4 ++-- sound/core/seq/seq_midi_event.c | 6 +++-- sound/core/seq/seq_queue.c | 3 ++- sound/core/seq/seq_queue.h | 1 - sound/core/seq/seq_timer.c | 3 ++- sound/core/seq/seq_timer.h | 2 -- sound/core/seq/seq_virmidi.c | 4 ++-- sound/core/sound.c | 1 - sound/core/timer.c | 8 +------ 11 files changed, 42 insertions(+), 43 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index d57f4ec3b08b..9f4c9209b271 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1049,7 +1049,6 @@ EXPORT_SYMBOL(snd_pcm_release_substream); EXPORT_SYMBOL(snd_pcm_format_name); /* pcm_native.c */ EXPORT_SYMBOL(snd_pcm_link_rwlock); -EXPORT_SYMBOL(snd_pcm_start); #ifdef CONFIG_PM EXPORT_SYMBOL(snd_pcm_suspend); EXPORT_SYMBOL(snd_pcm_suspend_all); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 151fd99ca2c9..7ce8b2164f6c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1143,7 +1143,8 @@ int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime, #define INT_MIN ((int)((unsigned int)INT_MAX+1)) #endif -void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) +static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) { if (hw_is_mask(var)) { snd_mask_any(hw_param_mask(params, var)); @@ -1163,12 +1164,14 @@ void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) /** * snd_pcm_hw_param_any */ +#if 0 int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) { _snd_pcm_hw_param_any(params, var); return snd_pcm_hw_refine(pcm, params); } +#endif /* 0 */ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) { @@ -1186,11 +1189,13 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) * * Fill PARAMS with full configuration space boundaries */ +#if 0 int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { _snd_pcm_hw_params_any(params); return snd_pcm_hw_refine(pcm, params); } +#endif /* 0 */ /** * snd_pcm_hw_param_value @@ -1198,8 +1203,8 @@ int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) * Return the value for field PAR if it's fixed in configuration space * defined by PARAMS. Return -EINVAL otherwise */ -int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, int *dir) +static int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, int *dir) { if (hw_is_mask(var)) { const snd_mask_t *mask = hw_param_mask_c(params, var); @@ -1303,6 +1308,7 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, * non integer values. Reduce configuration space accordingly. * Return -EINVAL if the configuration space is empty */ +#if 0 int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) @@ -1317,9 +1323,10 @@ int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm, } return 0; } +#endif /* 0 */ -int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) +static int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) { int changed; if (hw_is_mask(var)) @@ -1345,9 +1352,9 @@ int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, * values > minimum. Reduce configuration space accordingly. * Return the minimum. */ -int snd_pcm_hw_param_first(snd_pcm_t *pcm, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, int *dir) +static int snd_pcm_hw_param_first(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, int *dir) { int changed = _snd_pcm_hw_param_first(params, var); if (changed < 0) @@ -1359,8 +1366,8 @@ int snd_pcm_hw_param_first(snd_pcm_t *pcm, return snd_pcm_hw_param_value(params, var, dir); } -int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) +static int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) { int changed; if (hw_is_mask(var)) @@ -1386,9 +1393,9 @@ int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, * values < maximum. Reduce configuration space accordingly. * Return the maximum. */ -int snd_pcm_hw_param_last(snd_pcm_t *pcm, - snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, int *dir) +static int snd_pcm_hw_param_last(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, int *dir) { int changed = _snd_pcm_hw_param_last(params, var); if (changed < 0) @@ -1437,8 +1444,9 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params, * values < VAL. Reduce configuration space accordingly. * Return new minimum or -EINVAL if the configuration space is empty */ -int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, unsigned int val, int *dir) +static int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, + int *dir) { int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); if (changed < 0) @@ -1451,8 +1459,9 @@ int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, return snd_pcm_hw_param_value_min(params, var, dir); } -int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, unsigned int val, int dir) +static int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, + int dir) { int changed; int open = 0; @@ -1490,8 +1499,9 @@ int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, * values >= VAL + 1. Reduce configuration space accordingly. * Return new maximum or -EINVAL if the configuration space is empty */ -int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var, unsigned int val, int *dir) +static int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val, + int *dir) { int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); if (changed < 0) @@ -2564,9 +2574,6 @@ snd_pcm_sframes_t snd_pcm_lib_readv(snd_pcm_substream_t *substream, EXPORT_SYMBOL(snd_interval_refine); EXPORT_SYMBOL(snd_interval_list); EXPORT_SYMBOL(snd_interval_ratnum); -EXPORT_SYMBOL(snd_interval_muldivk); -EXPORT_SYMBOL(snd_interval_mulkdiv); -EXPORT_SYMBOL(snd_interval_div); EXPORT_SYMBOL(_snd_pcm_hw_params_any); EXPORT_SYMBOL(_snd_pcm_hw_param_min); EXPORT_SYMBOL(_snd_pcm_hw_param_set); @@ -2580,7 +2587,6 @@ EXPORT_SYMBOL(snd_pcm_hw_param_last); EXPORT_SYMBOL(snd_pcm_hw_param_near); EXPORT_SYMBOL(snd_pcm_hw_param_set); EXPORT_SYMBOL(snd_pcm_hw_refine); -EXPORT_SYMBOL(snd_pcm_hw_params); EXPORT_SYMBOL(snd_pcm_hw_constraints_init); EXPORT_SYMBOL(snd_pcm_hw_constraints_complete); EXPORT_SYMBOL(snd_pcm_hw_constraint_list); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index cad9bbde9986..4e582415a086 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -337,8 +337,8 @@ out: return err; } -int snd_pcm_hw_params(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *params) +static int snd_pcm_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *params) { snd_pcm_runtime_t *runtime; int err; diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 21e569062bc3..df1e2bb39745 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -171,11 +171,13 @@ void snd_midi_event_reset_decode(snd_midi_event_t *dev) spin_unlock_irqrestore(&dev->lock, flags); } +#if 0 void snd_midi_event_init(snd_midi_event_t *dev) { snd_midi_event_reset_encode(dev); snd_midi_event_reset_decode(dev); } +#endif /* 0 */ void snd_midi_event_no_status(snd_midi_event_t *dev, int on) { @@ -185,6 +187,7 @@ void snd_midi_event_no_status(snd_midi_event_t *dev, int on) /* * resize buffer */ +#if 0 int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize) { unsigned char *new_buf, *old_buf; @@ -204,6 +207,7 @@ int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize) kfree(old_buf); return 0; } +#endif /* 0 */ /* * read bytes and encode to sequencer event if finished @@ -517,8 +521,6 @@ static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int coun EXPORT_SYMBOL(snd_midi_event_new); EXPORT_SYMBOL(snd_midi_event_free); -EXPORT_SYMBOL(snd_midi_event_resize_buffer); -EXPORT_SYMBOL(snd_midi_event_init); EXPORT_SYMBOL(snd_midi_event_reset_encode); EXPORT_SYMBOL(snd_midi_event_reset_decode); EXPORT_SYMBOL(snd_midi_event_no_status); diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 3afc7cc0c9a7..98de2e711fde 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -672,7 +672,8 @@ static void queue_broadcast_event(queue_t *q, snd_seq_event_t *ev, int atomic, i * process a received queue-control event. * this function is exported for seq_sync.c. */ -void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop) +static void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, + int atomic, int hop) { switch (ev->type) { case SNDRV_SEQ_EVENT_START: diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h index b1bf5519fb3b..ea3c54216ea8 100644 --- a/sound/core/seq/seq_queue.h +++ b/sound/core/seq/seq_queue.h @@ -111,7 +111,6 @@ int snd_seq_queue_use(int queueid, int client, int use); int snd_seq_queue_is_used(int queueid, int client); int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop); -void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop); /* * 64bit division - for sync stuff.. diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 753f1c0863cc..a7f76fc95280 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -36,7 +36,8 @@ extern int seq_default_timer_resolution; #define SKEW_BASE 0x10000 /* 16bit shift */ -void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks) +static void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, + int tempo, int ppq, int nticks) { if (tempo < 1000000) tick->resolution = (tempo * 1000) / ppq; diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 4c0872df8931..287ed68591de 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h @@ -64,8 +64,6 @@ extern seq_timer_t *snd_seq_timer_new(void); /* delete timer (destructor) */ extern void snd_seq_timer_delete(seq_timer_t **tmr); -void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks); - /* */ static inline void snd_seq_timer_update_tick(seq_timer_tick_t *tick, unsigned long resolution) { diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 58c56a198d2a..a66484b5cf0e 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -110,7 +110,7 @@ static int snd_virmidi_dev_receive_event(snd_virmidi_dev_t *rdev, snd_seq_event_ * handler of a remote port which is attached to the virmidi via * SNDRV_VIRMIDI_SEQ_ATTACH. */ -/* exported */ +#if 0 int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev) { snd_virmidi_dev_t *rdev; @@ -118,6 +118,7 @@ int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev) rdev = rmidi->private_data; return snd_virmidi_dev_receive_event(rdev, ev); } +#endif /* 0 */ /* * event handler of virmidi port @@ -548,4 +549,3 @@ module_init(alsa_virmidi_init) module_exit(alsa_virmidi_exit) EXPORT_SYMBOL(snd_virmidi_new); -EXPORT_SYMBOL(snd_virmidi_receive); diff --git a/sound/core/sound.c b/sound/core/sound.c index 88e052079f85..fa92e660ec2c 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -431,7 +431,6 @@ EXPORT_SYMBOL(snd_card_pci_resume); EXPORT_SYMBOL(snd_device_new); EXPORT_SYMBOL(snd_device_register); EXPORT_SYMBOL(snd_device_free); -EXPORT_SYMBOL(snd_device_free_all); /* isadma.c */ #ifdef CONFIG_ISA EXPORT_SYMBOL(snd_dma_program); diff --git a/sound/core/timer.c b/sound/core/timer.c index cb011a1d4c3e..d67a5e91a108 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -845,7 +845,7 @@ int snd_timer_dev_register(snd_device_t *dev) return 0; } -int snd_timer_unregister(snd_timer_t *timer) +static int snd_timer_unregister(snd_timer_t *timer) { struct list_head *p, *n; snd_timer_instance_t *ti; @@ -946,11 +946,6 @@ struct snd_timer_system_private { unsigned long correction; }; -unsigned int snd_timer_system_resolution(void) -{ - return 1000000000L / HZ; -} - static void snd_timer_s_function(unsigned long data) { snd_timer_t *timer = (snd_timer_t *)data; @@ -1938,4 +1933,3 @@ EXPORT_SYMBOL(snd_timer_global_free); EXPORT_SYMBOL(snd_timer_global_register); EXPORT_SYMBOL(snd_timer_global_unregister); EXPORT_SYMBOL(snd_timer_interrupt); -EXPORT_SYMBOL(snd_timer_system_resolution); -- cgit v1.2.1 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') diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 098870aea264..276ce5299684 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.1 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') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 3690ea05b042..096f15132853 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.1 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') diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 231ecac80861..48e248608244 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.1 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') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index d4cb8edf7080..90d493ca7c99 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.1 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') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index deb028851056..c623858428cd 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 90d493ca7c99..a56e68ea87bc 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.1 From 209ac85d76e4edf05779b4bd5c2a92b059e9ab4d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 23 May 2005 10:29:53 +0200 Subject: [ALSA] sound/isa/: cleanups GUS Library This patch contains the following possible cleanups: - make needlesly global code static - #if 0 the following unused global functions: - gus/gus_volume.c: snd_gf1_gvol_to_lvol_raw - gus/gus_volume.c: snd_gf1_calc_ramp_rate - gus/gus_volume.c: snd_gf1_compute_vibrato - gus/gus_volume.c: snd_gf1_compute_pitchbend - gus/gus_volume.c: snd_gf1_compute_freq - gus/gus_io.c: snd_gf1_i_adlib_write - gus/gus_io.c: snd_gf1_i_write_addr - gus/gus_io.c: snd_gf1_pokew - gus/gus_io.c: snd_gf1_peekw - gus/gus_io.c: snd_gf1_dram_setmem - gus/gus_io.c: snd_gf1_print_global_registers - gus/gus_io.c: snd_gf1_print_setup_registers - gus/gus_io.c: snd_gf1_peek_print_block - gus/gus_io.c: snd_gf1_print_setup_registers - gus/gus_io.c: snd_gf1_peek_print_block - #if 0 the following unused global variable: - gus/gus_tables.h: snd_gf1_scale_table - remove the following unneeded EXPORT_SYMBOL's: - gus/gus_main.c: snd_gf1_i_write16 - gus/gus_main.c: snd_gf1_start - gus/gus_main.c: snd_gf1_stop Signed-off-by: Adrian Bunk Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_io.c | 14 +++++++++++--- sound/isa/gus/gus_main.c | 3 --- sound/isa/gus/gus_mem.c | 12 ++++++------ sound/isa/gus/gus_reset.c | 3 ++- sound/isa/gus/gus_synth.c | 3 ++- sound/isa/gus/gus_tables.h | 4 ++++ sound/isa/gus/gus_volume.c | 8 ++++++++ 7 files changed, 33 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c index f0570f2bf75f..337b0e2a8a36 100644 --- a/sound/isa/gus/gus_io.c +++ b/sound/isa/gus/gus_io.c @@ -244,6 +244,8 @@ unsigned short snd_gf1_i_look16(snd_gus_card_t * gus, unsigned char reg) return res; } +#if 0 + void snd_gf1_i_adlib_write(snd_gus_card_t * gus, unsigned char reg, unsigned char data) @@ -265,6 +267,8 @@ void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg, spin_unlock_irqrestore(&gus->reg_lock, flags); } +#endif /* 0 */ + unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus, unsigned char reg, short w_16bit) { @@ -329,6 +333,8 @@ unsigned char snd_gf1_peek(snd_gus_card_t * gus, unsigned int addr) return res; } +#if 0 + void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data) { unsigned long flags; @@ -405,9 +411,7 @@ void snd_gf1_dram_setmem(snd_gus_card_t * gus, unsigned int addr, spin_unlock_irqrestore(&gus->reg_lock, flags); } -/* - - */ +#endif /* 0 */ void snd_gf1_select_active_voices(snd_gus_card_t * gus) { @@ -469,6 +473,8 @@ void snd_gf1_print_voice_registers(snd_gus_card_t * gus) printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c)); } +#if 0 + void snd_gf1_print_global_registers(snd_gus_card_t * gus) { unsigned char global_mode = 0x00; @@ -528,4 +534,6 @@ void snd_gf1_peek_print_block(snd_gus_card_t * gus, unsigned int addr, int count } } +#endif /* 0 */ + #endif diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 73f81c14f768..94bbd344be5e 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -459,7 +459,6 @@ EXPORT_SYMBOL(snd_gf1_write16); EXPORT_SYMBOL(snd_gf1_look16); EXPORT_SYMBOL(snd_gf1_i_write8); EXPORT_SYMBOL(snd_gf1_i_look8); -EXPORT_SYMBOL(snd_gf1_i_write16); EXPORT_SYMBOL(snd_gf1_i_look16); EXPORT_SYMBOL(snd_gf1_dram_addr); EXPORT_SYMBOL(snd_gf1_write_addr); @@ -470,8 +469,6 @@ EXPORT_SYMBOL(snd_gf1_alloc_voice); EXPORT_SYMBOL(snd_gf1_free_voice); EXPORT_SYMBOL(snd_gf1_ctrl_stop); EXPORT_SYMBOL(snd_gf1_stop_voice); -EXPORT_SYMBOL(snd_gf1_start); -EXPORT_SYMBOL(snd_gf1_stop); /* gus_mixer.c */ EXPORT_SYMBOL(snd_gf1_new_mixer); /* gus_pcm.c */ diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index bfc2b91001d5..609838e8ef67 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -39,8 +39,8 @@ void snd_gf1_mem_lock(snd_gf1_mem_t * alloc, int xup) } } -snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc, - snd_gf1_mem_block_t * block) +static snd_gf1_mem_block_t *snd_gf1_mem_xalloc(snd_gf1_mem_t * alloc, + snd_gf1_mem_block_t * block) { snd_gf1_mem_block_t *pblock, *nblock; @@ -105,8 +105,8 @@ int snd_gf1_mem_xfree(snd_gf1_mem_t * alloc, snd_gf1_mem_block_t * block) return 0; } -snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, - unsigned int address) +static snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, + unsigned int address) { snd_gf1_mem_block_t *block; @@ -118,8 +118,8 @@ snd_gf1_mem_block_t *snd_gf1_mem_look(snd_gf1_mem_t * alloc, return NULL; } -snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc, - unsigned int *share_id) +static snd_gf1_mem_block_t *snd_gf1_mem_share(snd_gf1_mem_t * alloc, + unsigned int *share_id) { snd_gf1_mem_block_t *block; diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c index b4e66f6a10ae..ef687abc7070 100644 --- a/sound/isa/gus/gus_reset.c +++ b/sound/isa/gus/gus_reset.c @@ -161,7 +161,8 @@ void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice) #endif } -void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, unsigned short v_max) +static void snd_gf1_clear_voices(snd_gus_card_t * gus, unsigned short v_min, + unsigned short v_max) { unsigned long flags; unsigned int daddr; diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c index 66552e6013a4..f51c386ee192 100644 --- a/sound/isa/gus/gus_synth.c +++ b/sound/isa/gus/gus_synth.c @@ -99,7 +99,8 @@ static void snd_gus_synth_free_private_instruments(snd_gus_port_t *p, int client snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0); } -int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop) +static int snd_gus_synth_event_input(snd_seq_event_t *ev, int direct, + void *private_data, int atomic, int hop) { snd_gus_port_t * p = (snd_gus_port_t *) private_data; diff --git a/sound/isa/gus/gus_tables.h b/sound/isa/gus/gus_tables.h index ed8e9d85ad31..4adf098d3269 100644 --- a/sound/isa/gus/gus_tables.h +++ b/sound/isa/gus/gus_tables.h @@ -23,6 +23,8 @@ #ifdef __GUS_TABLES_ALLOC__ +#if 0 + unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] = { 8372, 8870, 9397, 9956, 10548, 11175, @@ -49,6 +51,8 @@ unsigned int snd_gf1_scale_table[SNDRV_GF1_SCALE_TABLE_SIZE] = 12123977, 12844906 }; +#endif /* 0 */ + unsigned short snd_gf1_atten_table[SNDRV_GF1_ATTEN_TABLE_SIZE] = { 4095 /* 0 */,1789 /* 1 */,1533 /* 2 */,1383 /* 3 */,1277 /* 4 */, 1195 /* 5 */,1127 /* 6 */,1070 /* 7 */,1021 /* 8 */,978 /* 9 */, diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c index b72bcfb28617..3d36f6c8ee6a 100644 --- a/sound/isa/gus/gus_volume.c +++ b/sound/isa/gus/gus_volume.c @@ -55,6 +55,8 @@ unsigned short snd_gf1_lvol_to_gvol_raw(unsigned int vol) return (e << 8) | m; } +#if 0 + unsigned int snd_gf1_gvol_to_lvol_raw(unsigned short gf1_vol) { unsigned int rvol; @@ -108,6 +110,8 @@ unsigned int snd_gf1_calc_ramp_rate(snd_gus_card_t * gus, return (range << 6) | (increment & 0x3f); } +#endif /* 0 */ + unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16) { freq16 >>= 3; @@ -120,6 +124,8 @@ unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16) return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq; } +#if 0 + short snd_gf1_compute_vibrato(short cents, unsigned short fc_register) { static short vibrato_table[] = @@ -208,3 +214,5 @@ unsigned short snd_gf1_compute_freq(unsigned int freq, } return (unsigned short) fc; } + +#endif /* 0 */ -- cgit v1.2.1 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') diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index da10d40b2d91..ea889b311390 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.1 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') diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 3bd92627231c..ab61e383024f 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 f949eb804cae..e0b613c0f6a0 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.1 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 --- sound/pci/ice1712/vt1720_mobo.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h index e0b613c0f6a0..0b1b0ee1bea7 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.1 From 23854c30021fb6da1a76a0e6901b35be03419d5f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 15:22:40 +0200 Subject: [ALSA] Add comments for Sound Core Added (minimal) comments for in Kconfig, so that configurators can choose this entry explicitly. A more descriptive comment by someone else is appreciated... Signed-off-by: Takashi Iwai --- sound/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index 047d59ea0573..fe175151f089 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -42,6 +42,11 @@ menu "Advanced Linux Sound Architecture" config SND tristate "Advanced Linux Sound Architecture" depends on SOUND + help + Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), + the new base sound system. + + For more information, see http://www.alsa-project.org/ source "sound/core/Kconfig" -- cgit v1.2.1 From 62144100471e940468d7a0f2d989df193afe870c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 17:24:59 +0200 Subject: [ALSA] Make docproc happy PCM Midlevel Make docproc happy by moving '#if 0' before comments. Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7ce8b2164f6c..c5bfd0918cff 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1161,10 +1161,10 @@ static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_BUG(); } +#if 0 /** * snd_pcm_hw_param_any */ -#if 0 int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) { @@ -1184,12 +1184,12 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) params->info = ~0U; } +#if 0 /** * snd_pcm_hw_params_any * * Fill PARAMS with full configuration space boundaries */ -#if 0 int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { _snd_pcm_hw_params_any(params); @@ -1301,6 +1301,7 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, return changed; } +#if 0 /** * snd_pcm_hw_param_setinteger * @@ -1308,7 +1309,6 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, * non integer values. Reduce configuration space accordingly. * Return -EINVAL if the configuration space is empty */ -#if 0 int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var) -- cgit v1.2.1 From 9baf6507ff4d0dcab22460e8785582d4eaadebeb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 17:27:00 +0200 Subject: [ALSA] Use standard form for URL Sound Core Use the standard form with <> for URL in Kconfig help texts. Signed-off-by: Takashi Iwai --- sound/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index fe175151f089..ee794ae06040 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -46,7 +46,7 @@ config SND Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), the new base sound system. - For more information, see http://www.alsa-project.org/ + For more information, see source "sound/core/Kconfig" -- cgit v1.2.1 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') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 43fc245d9a62..1b1203539ea6 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.1 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') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9f12d1fd02dc..ee1c4cd7f00a 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.1 From c3a9cfac750d78241b5dde7d004522f687703b90 Mon Sep 17 00:00:00 2001 From: Roger Mach Date: Thu, 26 May 2005 17:58:01 +0200 Subject: [ALSA] pcm_oss - fix SNDCTL_DSP_GETOPTR not working correctly ALSA<-OSS emulation This patch changes snd_pcm_oss_bytes() by adding a local variable for the frames -> bytes conversion, which means that the frame count is no longer corrupted by this conversion. Signed-off-by: Roger Mach Signed-off-by: Clemens Ladisch --- sound/core/oss/pcm_oss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 6c8fdcaf9f4f..6f90dbb76804 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -124,11 +124,12 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin) static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { + long bytes = 0; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); - frames = frames_to_bytes(runtime, frames); + bytes = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) - return frames; + return bytes; return (runtime->oss.buffer_bytes * frames) / buffer_size; } -- cgit v1.2.1 From 8e72ab349e54da49cf3e11480581a3e6704d9553 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 27 May 2005 10:07:06 +0200 Subject: [ALSA] Reverted last patch for SNDCTL_DSP_GETOPTR fix & possible overflow fix ALSA<-OSS emulation This reverts the last patch which wrongly mixes bytes and frames. The real culprit might be the 32-bit overflow, so the return expression uses 64-bit values now in snd_pcm_oss_bytes(). Signed-off-by: Jaroslav Kysela --- sound/core/oss/pcm_oss.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 6f90dbb76804..a293982bdd21 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -124,13 +124,12 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin) static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { - long bytes = 0; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); - bytes = frames_to_bytes(runtime, frames); + frames = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) - return bytes; - return (runtime->oss.buffer_bytes * frames) / buffer_size; + return frames; + return (long)(((int64_t)runtime->oss.buffer_bytes * (int64_t)frames) / (int64_t)buffer_size); } static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) -- cgit v1.2.1 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') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 5520f5d97490..b81064133c61 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.1 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') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 4c41df053523..bb322de4777f 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.1 From bfc5bddb8efb7e3d10e2f2e07dc2d68e808a9c68 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 27 May 2005 11:12:35 +0200 Subject: [ALSA] alsa-oss - improve readability of snd_pcm_oss_bytes() function ALSA<-OSS emulation Added bytes variable and do not use the frames argument as a temporaly storage for the byte counter. Signed-off-by: Jaroslav Kysela --- sound/core/oss/pcm_oss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index a293982bdd21..b9deef9179a0 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -126,10 +126,10 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); - frames = frames_to_bytes(runtime, frames); + long bytes = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) - return frames; - return (long)(((int64_t)runtime->oss.buffer_bytes * (int64_t)frames) / (int64_t)buffer_size); + return bytes; + return (long)(((int64_t)runtime->oss.buffer_bytes * (int64_t)bytes) / (int64_t)buffer_size); } static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) -- cgit v1.2.1 From af0816139fcf926b6b5c3f866c509507b411d547 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 27 May 2005 11:15:20 +0200 Subject: [ALSA] alsa-oss - 2nd - improved readability ALSA<-OSS emulation Use 'long' for byte counters in snd_pcm_oss_bytes() snd_pcm_alsa_bytes(). Signed-off-by: Jaroslav Kysela --- sound/core/oss/pcm_oss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index b9deef9179a0..131522ea4b93 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -125,7 +125,7 @@ int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin) static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); + long buffer_size = snd_pcm_lib_buffer_bytes(substream); long bytes = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) return bytes; @@ -135,7 +135,7 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); + long buffer_size = snd_pcm_lib_buffer_bytes(substream); if (buffer_size == runtime->oss.buffer_bytes) return bytes_to_frames(runtime, bytes); return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); -- cgit v1.2.1 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') diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index cdc1134cdedd..ca28b229c704 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.1 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 --- sound/pci/ice1712/amp.c | 30 ++++++++++++++++++++++++++++++ sound/pci/ice1712/amp.h | 16 +++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 779951725e1e..289b0b5711e4 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 d58d43383e83..a0fc89b48122 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.1 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') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 070be6af97b5..77be07283bb0 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.1 From cdc5c53fde266055debf7f5c9c043d5acf47c5ff Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 May 2005 12:40:52 +0200 Subject: [ALSA] Fix compilation on 32bit arch ALSA<-OSS emulation Fix the division with int64 for 32bit architectures. Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 131522ea4b93..468fca8894d9 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -129,7 +129,16 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) long bytes = frames_to_bytes(runtime, frames); if (buffer_size == runtime->oss.buffer_bytes) return bytes; - return (long)(((int64_t)runtime->oss.buffer_bytes * (int64_t)bytes) / (int64_t)buffer_size); +#if BITS_PER_LONG >= 64 + return runtime->oss.buffer_bytes * bytes / buffer_size; +#else + { + u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes; + u32 rem; + div64_32(&bsize, buffer_size, &rem); + return (long)bsize; + } +#endif } static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) -- cgit v1.2.1 From 7028b09eecf01549ccaee9c884f48e5e00ec3d65 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 27 May 2005 12:42:26 +0200 Subject: [ALSA] select ISAPNP for SND_INTERWAVE_STB target ISA Signed-off-by: Jaroslav Kysela --- sound/isa/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 3a3228b18726..148a856a43ad 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -179,6 +179,7 @@ config SND_INTERWAVE_STB select SND_RAWMIDI select SND_CS4231_LIB select SND_GUS_SYNTH + select ISAPNP help Say Y here to include support for AMD InterWave based soundcards with a TEA6330T bass and treble regulator -- cgit v1.2.1 From efa93dbedd0e2eacf49ea6fff1fe4397d520cf61 Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Tue, 14 Jun 2005 09:54:55 -0700 Subject: [PATCH] usbaudio: prevent oops & dead keyboard on usb unplugging while the device is being used Without this patch, some usb kobjects, which are parents to the usx2y's kobjects can be freed before the usx2y's. This led to an oops in get_kobj_path_length() and a dead keyboard, when the usx2y's kobjects were freed. The patch ensures the correct sequence. Tested ok on kernel 2.6.12-rc2. Present in ALSA cvs Signed-off-by: Karsten Wiese Signed-off-by: Greg Kroah-Hartman Signed-off-by: Chris Wright Signed-off-by: Linus Torvalds --- sound/usb/usbaudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 84b0bbddbd22..aae66144d411 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3289,7 +3289,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) } usb_chip[chip->index] = NULL; up(®ister_mutex); - snd_card_free_in_thread(card); + snd_card_free(card); } else { up(®ister_mutex); } -- cgit v1.2.1 From dcf78d80a6c2de829ec08c8e663a3370e982d616 Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Tue, 14 Jun 2005 09:56:20 -0700 Subject: [PATCH] usbusx2y: prevent oops & dead keyboard on usb unplugging while the device is being used Without this patch, some usb kobjects, which are parents to the usx2y's kobjects can be freed before the usx2y's. This led to an oops in get_kobj_path_length() and a dead keyboard, when the usx2y's kobjects were freed. The patch ensures the correct sequence. Tested ok on kernel 2.6.12-rc2. Present in ALSA cvs Signed-off-by: Karsten Wiese Signed-off-by: Greg Kroah-Hartman Signed-off-by: Chris Wright Signed-off-by: Linus Torvalds --- sound/usb/usx2y/usbusx2y.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index b06a267e5dac..89ee8b732013 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -1,6 +1,11 @@ /* * usbusy2y.c - ALSA USB US-428 Driver * +2005-04-14 Karsten Wiese + Version 0.8.7.2: + Call snd_card_free() instead of snd_card_free_in_thread() to prevent oops with dead keyboard symptom. + Tested ok with kernel 2.6.12-rc2. + 2004-12-14 Karsten Wiese Version 0.8.7.1: snd_pcm_open for rawusb pcm-devices now returns -EBUSY if called without rawusb's hwdep device being open. @@ -143,7 +148,7 @@ MODULE_AUTHOR("Karsten Wiese "); -MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.1"); +MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}"); @@ -430,8 +435,6 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) if (ptr) { usX2Ydev_t* usX2Y = usX2Y((snd_card_t*)ptr); struct list_head* p; - if (usX2Y->chip_status == USX2Y_STAT_CHIP_HUP) // on 2.6.1 kernel snd_usbmidi_disconnect() - return; // calls us back. better leave :-) . usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); @@ -443,7 +446,7 @@ static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr) } if (usX2Y->us428ctls_sharedmem) wake_up(&usX2Y->us428ctls_wait_queue_head); - snd_card_free_in_thread((snd_card_t*)ptr); + snd_card_free((snd_card_t*)ptr); } } -- cgit v1.2.1 From 619e666b7e9d2b0545ab60a9c824ae5f77c20c3b Mon Sep 17 00:00:00 2001 From: "gregkh@suse.de" Date: Wed, 23 Mar 2005 09:51:41 -0800 Subject: [PATCH] class: convert sound/* to use the new class api instead of class_simple Signed-off-by: Greg Kroah-Hartman --- sound/core/sound.c | 6 +++--- sound/oss/soundcard.c | 19 +++++++++---------- sound/sound_core.c | 10 +++++----- 3 files changed, 17 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/core/sound.c b/sound/core/sound.c index 88e052079f85..33eaa5e5d284 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -64,7 +64,7 @@ static struct list_head snd_minors_hash[SNDRV_CARDS]; static DECLARE_MUTEX(sound_mutex); -extern struct class_simple *sound_class; +extern struct class *sound_class; #ifdef CONFIG_KMOD @@ -231,7 +231,7 @@ int snd_register_device(int type, snd_card_t * card, int dev, snd_minor_t * reg, devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); if (card) device = card->dev; - class_simple_device_add(sound_class, MKDEV(major, minor), device, name); + class_device_create(sound_class, MKDEV(major, minor), device, "%s", name); up(&sound_mutex); return 0; @@ -263,7 +263,7 @@ int snd_unregister_device(int type, snd_card_t * card, int dev) if (strncmp(mptr->name, "controlC", 8) || card->number >= cards_limit) /* created in sound.c */ devfs_remove("snd/%s", mptr->name); - class_simple_device_remove(MKDEV(major, minor)); + class_device_destroy(sound_class, MKDEV(major, minor)); list_del(&mptr->list); up(&sound_mutex); diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index de91c90a0112..a686be936aff 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -73,7 +73,7 @@ static char dma_alloc_map[MAX_DMA_CHANNELS]; unsigned long seq_time = 0; /* Time for /dev/sequencer */ -extern struct class_simple *sound_class; +extern struct class *sound_class; /* * Table for configurable mixer volume handling @@ -567,9 +567,9 @@ static int __init oss_init(void) devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor), S_IFCHR | dev_list[i].mode, "sound/%s", dev_list[i].name); - class_simple_device_add(sound_class, - MKDEV(SOUND_MAJOR, dev_list[i].minor), - NULL, "%s", dev_list[i].name); + class_device_create(sound_class, + MKDEV(SOUND_MAJOR, dev_list[i].minor), + NULL, "%s", dev_list[i].name); if (!dev_list[i].num) continue; @@ -579,10 +579,9 @@ static int __init oss_init(void) dev_list[i].minor + (j*0x10)), S_IFCHR | dev_list[i].mode, "sound/%s%d", dev_list[i].name, j); - class_simple_device_add(sound_class, - MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)), - NULL, - "%s%d", dev_list[i].name, j); + class_device_create(sound_class, + MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)), + NULL, "%s%d", dev_list[i].name, j); } } @@ -598,12 +597,12 @@ static void __exit oss_cleanup(void) for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) { devfs_remove("sound/%s", dev_list[i].name); - class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor)); + class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor)); if (!dev_list[i].num) continue; for (j = 1; j < *dev_list[i].num; j++) { devfs_remove("sound/%s%d", dev_list[i].name, j); - class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10))); + class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10))); } } diff --git a/sound/sound_core.c b/sound/sound_core.c index 30f75c9288cb..21a69e096225 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -65,7 +65,7 @@ extern int msnd_classic_init(void); extern int msnd_pinnacle_init(void); #endif -struct class_simple *sound_class; +struct class *sound_class; EXPORT_SYMBOL(sound_class); /* @@ -174,7 +174,7 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor), S_IFCHR | mode, s->name); - class_simple_device_add(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor), + class_device_create(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor), NULL, s->name+6); return r; @@ -198,7 +198,7 @@ static void sound_remove_unit(struct sound_unit **list, int unit) spin_unlock(&sound_loader_lock); if (p) { devfs_remove(p->name); - class_simple_device_remove(MKDEV(SOUND_MAJOR, p->unit_minor)); + class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor)); kfree(p); } } @@ -562,7 +562,7 @@ static void __exit cleanup_soundcore(void) empty */ unregister_chrdev(SOUND_MAJOR, "sound"); devfs_remove("sound"); - class_simple_destroy(sound_class); + class_destroy(sound_class); } static int __init init_soundcore(void) @@ -572,7 +572,7 @@ static int __init init_soundcore(void) return -EBUSY; } devfs_mk_dir ("sound"); - sound_class = class_simple_create(THIS_MODULE, "sound"); + sound_class = class_create(THIS_MODULE, "sound"); if (IS_ERR(sound_class)) return PTR_ERR(sound_class); -- cgit v1.2.1 From 7c2f3fda5666c280bcd00ac3b86963270b23e796 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 21 Jun 2005 17:15:09 -0700 Subject: [PATCH] rme96xx: fix PageReserved range rme96xx busmaster_malloc miscalculates and fails to set PageReserved on any page of char *buf; but busmaster_free does it right, so do the same (I don't have the card, just noticed this while sifting for rmap BUGs). Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/rme96xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c index 76774bbc1436..b4278eecc917 100644 --- a/sound/oss/rme96xx.c +++ b/sound/oss/rme96xx.c @@ -807,7 +807,7 @@ static void* busmaster_malloc(int size) { struct page* page, *last_page; page = virt_to_page(buf); - last_page = virt_to_page(buf + (1 << pg)); + last_page = page + (1 << pg); DBG(printk("setting reserved bit\n")); while (page < last_page) { SetPageReserved(page); -- cgit v1.2.1 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') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index c623858428cd..67e56a530b22 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 a56e68ea87bc..58d9026c8ca6 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 3e5161a32363..1c9cc821d1b9 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.1 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') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 67e56a530b22..beac9dad2ed9 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 48e248608244..0e5e9ce0ff28 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.1 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') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 58d9026c8ca6..1c26206b4fb9 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.1 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') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 1c26206b4fb9..bfd558c9f3d5 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.1 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') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 36a33ae9ae03..996fcfb09532 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 b81064133c61..a15eb8522b7c 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.1 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') diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 9220aae632b0..a6b4b8d589fd 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 f655cf914060..bb758c77d211 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 276ce5299684..e10fceb3ede9 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.1 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') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index bfd558c9f3d5..85caf1bbcc11 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.1 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') diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 038f56ad42f1..eb5c36d31a52 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.1 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') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index bb322de4777f..4c47fc83797f 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.1 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 --- sound/pci/ac97/ac97_codec.c | 8 +-- sound/pci/atiixp.c | 4 +- sound/pci/via82xx.c | 118 ++++++++++++++++++++++---------------------- 3 files changed, 65 insertions(+), 65 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 996fcfb09532..a4b72cd2eea0 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 06551a69fb40..cafab4af5c57 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 4c47fc83797f..52d1074f8696 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.1 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') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 9c5710daed50..53fa5d8d0c4b 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.1 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') diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 638cc148706d..1a7736cbf3a4 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 e88967c5b93d..ea945a5d2a0b 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 d67a5e91a108..b498e5482d77 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 98587176b327..af381b15fe5c 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 bb503e70b664..2da8d7f157f4 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 8995ad9c516d..b75066ab46fc 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 85caf1bbcc11..0ec0c3ec220b 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 5f2ffb7efa06..fd4c50c88bc9 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 f8d92335a353..e90c5ddd1d17 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 fd7cc389f82a..520b99af5f55 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 52d1074f8696..e329e19b674f 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 e10fceb3ede9..5896d289f9ac 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 997cf37cdddd..2ae79610ecb5 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 53d8172c52ae..332bbca3dfc4 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 ec3fc1ba7fca..4764940f11a0 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 a82412b8790d..a75695045f29 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 83ba665e5c6e..e73c1c9d3e73 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 4c292e090069..62dfd28b3b07 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.1 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 --- sound/core/memalloc.c | 201 ++++++++++++++++++++++++-------------------- sound/pci/rme9652/hdsp.c | 14 +-- sound/pci/rme9652/rme9652.c | 14 +-- 3 files changed, 127 insertions(+), 102 deletions(-) (limited to 'sound') diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 344a83fd7c2e..dbc23e35fa06 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 b35ed5f0c042..a673cc438b91 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 5861f234af21..f3037402d58f 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.1 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') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f05a6384b9c0..0d546addc091 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.1 From 21cb2a2ec5818cbba01bcb7f24388670322c77f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 May 2005 14:35:31 +0200 Subject: [ALSA] Fix races between PCM drain and other ops PCM Midlevel Fix semaphore races between PCM drain and other ops. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 70 +++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 4e582415a086..10c2c9832649 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1368,43 +1368,32 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - down_read(&snd_pcm_link_rwsem); snd_power_lock(card); if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); - if (result < 0) - goto _unlock; + if (result < 0) { + snd_power_unlock(card); + return result; + } } /* allocate temporary record for drain sync */ + down_read(&snd_pcm_link_rwsem); if (snd_pcm_stream_linked(substream)) { drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL); if (! drec) { - result = -ENOMEM; - goto _unlock; + up_read(&snd_pcm_link_rwsem); + snd_power_unlock(card); + return -ENOMEM; } } else drec = &drec_tmp; - snd_pcm_stream_lock_irq(substream); - /* resume pause */ - if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) - snd_pcm_pause(substream, 0); - - /* pre-start/stop - all running streams are changed to DRAINING state */ - result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); - if (result < 0) - goto _end; - - /* check streams with PLAYBACK & DRAINING */ + /* count only playback streams */ num_drecs = 0; snd_pcm_group_for_each(pos, substream) { snd_pcm_substream_t *s = snd_pcm_group_substream_entry(pos); runtime = s->runtime; - if (runtime->status->state != SNDRV_PCM_STATE_DRAINING) { - runtime->status->state = SNDRV_PCM_STATE_SETUP; - continue; - } if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { d = &drec[num_drecs++]; d->substream = s; @@ -1418,9 +1407,21 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) runtime->stop_threshold = runtime->buffer_size; } } - + up_read(&snd_pcm_link_rwsem); if (! num_drecs) - goto _end; + goto _error; + + snd_pcm_stream_lock_irq(substream); + /* resume pause */ + if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) + snd_pcm_pause(substream, 0); + + /* pre-start/stop - all running streams are changed to DRAINING state */ + result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); + if (result < 0) { + snd_pcm_stream_unlock_irq(substream); + goto _error; + } for (;;) { long tout; @@ -1428,6 +1429,15 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) result = -ERESTARTSYS; break; } + /* all finished? */ + for (i = 0; i < num_drecs; i++) { + runtime = drec[i].substream->runtime; + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) + break; + } + if (i == num_drecs) + break; /* yes, all drained */ + set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); snd_power_unlock(card); @@ -1444,15 +1454,11 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) } break; } - /* all finished? */ - for (i = 0; i < num_drecs; i++) { - runtime = drec[i].substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) - break; - } - if (i == num_drecs) - break; } + + snd_pcm_stream_unlock_irq(substream); + + _error: for (i = 0; i < num_drecs; i++) { d = &drec[i]; runtime = d->substream->runtime; @@ -1460,13 +1466,9 @@ static int snd_pcm_drain(snd_pcm_substream_t *substream) runtime->stop_threshold = d->stop_threshold; } - _end: - snd_pcm_stream_unlock_irq(substream); if (drec != &drec_tmp) kfree(drec); - _unlock: snd_power_unlock(card); - up_read(&snd_pcm_link_rwsem); return result; } -- cgit v1.2.1 From fb4bd0adc4b5b6538933b098a67851d8f99b5ca3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 31 May 2005 15:44:23 +0200 Subject: [ALSA] OSS PCM emulation - The final fix for SNDCTL_DSP_GETOPTR problem ALSA<-OSS emulation The problem was negative result (info.bytes) in a specific condition at playback startup. Signed-off-by: Jaroslav Kysela --- sound/core/oss/pcm_oss.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 468fca8894d9..203470df5857 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1539,10 +1539,13 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str } else { delay = snd_pcm_oss_bytes(substream, delay) + fixup; info.blocks = delay / runtime->oss.period_bytes; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (runtime->oss.bytes == 0) + delay = 0; info.bytes = (runtime->oss.bytes - delay) & INT_MAX; - else + } else { info.bytes = (runtime->oss.bytes + delay) & INT_MAX; + } } if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; -- cgit v1.2.1 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') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 53fa5d8d0c4b..cc16f95f9cef 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.1 From 5ac0fab95c09497bed24640eb3f09893127d6d65 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 31 May 2005 16:59:39 +0200 Subject: [ALSA] OSS PCM emulation - The 2nd final fix for SNDCTL_DSP_GETOPTR problem ALSA<-OSS emulation The problem was negative/wrong result (info.bytes) in a specific condition at playback startup. Signed-off-by: Jaroslav Kysela --- sound/core/oss/pcm_oss.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 203470df5857..cab30977e7c0 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1537,13 +1537,13 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str snd_pcm_oss_simulate_fill(substream, delay); info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; } else { - delay = snd_pcm_oss_bytes(substream, delay) + fixup; - info.blocks = delay / runtime->oss.period_bytes; + delay = snd_pcm_oss_bytes(substream, delay); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (runtime->oss.bytes == 0) - delay = 0; + info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes; info.bytes = (runtime->oss.bytes - delay) & INT_MAX; } else { + delay += fixup; + info.blocks = delay / runtime->oss.period_bytes; info.bytes = (runtime->oss.bytes + delay) & INT_MAX; } } -- cgit v1.2.1 From 375389288ae55754bd7d009a30f2bb0453a5b369 Mon Sep 17 00:00:00 2001 From: Christoph Schulz Date: Fri, 3 Jun 2005 08:28:31 +0200 Subject: [ALSA] cs4236-irq-handling-fix.patch CS4236+ driver Background: The card/chipset supports an external MIDI interrupt. By default, this interrupt isn't used (because the isapnp mechanism chooses a configuration without an assigned interrupt). If the user wishes to explicitly select an interrupt via the mpu_irq parameter for such a configured device, it doesn't work: The driver always shows: isapnp MPU: port=0x330, irq=-1 (note the 'irq=-1') Problem: The driver only allows to set the irq if pnp_irq_valid returns true for this particular pnp device. This, however, is only true if an interrupt has already been assigned (pnp_valid_irq returns true if the flag IORESOURCE_IRQ is set and IORESOURCE_UNSET is not set). If no interrupt has been assigned so far, IORESOURCE_UNSET is set and pnp_irq_valid returns false, thereby inhibiting the selection of a valid irq. Solution: Don't check for a valid (= already assigned) irq at the point of calling pnp_resource_change. Tested successfully on Linux 2.6.11. Signed-off-by: Andrew Morton Signed-off-by: Jaroslav Kysela --- sound/isa/cs423x/cs4236.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index e745a54e00a1..39f4eff44f5c 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -349,8 +349,7 @@ static int __devinit snd_card_cs4236_pnp(int dev, struct snd_card_cs4236 *acard, pnp_init_resource_table(cfg); if (mpu_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); - if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0 && - pnp_irq_valid(pdev, 0)) + if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0) pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); err = pnp_manual_config_dev(pdev, cfg, 0); if (err < 0) -- cgit v1.2.1 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 --- sound/pci/Kconfig | 13 + sound/pci/rme9652/Makefile | 2 + sound/pci/rme9652/hdspm.c | 3671 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 3686 insertions(+) create mode 100644 sound/pci/rme9652/hdspm.c (limited to 'sound') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 428efdbd70a1..6d7a00f34d82 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 917374c9cd40..d2c294e136f9 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 000000000000..9e86d0eb41ce --- /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.1 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') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index beac9dad2ed9..da09cab405a9 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 0ec0c3ec220b..95c289284267 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.1 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') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e329e19b674f..e861a0110027 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.1 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') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e6efaed4b464..cb3a76139341 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.1 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') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index caa486993446..2fd05bb84136 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.1 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') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ee1c4cd7f00a..0ca5151908d7 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.1 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') diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 5d21cb811c8a..940d531575c0 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.1 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') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 15df7162f17e..de1217bd8e68 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.1 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') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index cb3a76139341..8805928167f5 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.1 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') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0ca5151908d7..84ae90cc1114 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.1 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') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8805928167f5..f62d1d5eb7fa 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.1 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') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1b1203539ea6..59991560d492 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 0d546addc091..d89849197422 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 84ae90cc1114..ce280c006be1 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.1 From b636a71d9b9525ee51ca872d461817a5bd5c39fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 13 Jun 2005 14:13:09 +0200 Subject: [ALSA] Add const prefix Control Midlevel Add const prefix to snd_kcontrol_new_t pointer for better protection. Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 4e39a2103d0a..227f3cf02771 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -215,7 +215,7 @@ snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access) * * Returns the pointer of the newly generated instance, or NULL on failure. */ -snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data) +snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * ncontrol, void *private_data) { snd_kcontrol_t kctl; unsigned int access; -- cgit v1.2.1 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 --- 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 +++++++++++++++++++++-------------------- 6 files changed, 1214 insertions(+), 1105 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f62d1d5eb7fa..e2cf02387289 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 bfbeff2e0d0c..2d046abb5911 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 d89849197422..5e0cca36ed57 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 b8fbbc4901d9..810cfd2d9bba 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 087230ca20a5..2d6e3e3d0a38 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 ce280c006be1..9edd558d6bd3 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.1 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') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index e861a0110027..7e570a4a4c3a 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.1 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') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1534e20af63d..013be2ea513a 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.1 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') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 7e570a4a4c3a..42c48f0ce8e8 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.1 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') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 77be07283bb0..a341e758acde 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.1 From 543537bd922692bc978e2e356fcd8bfc9c2ee7d5 Mon Sep 17 00:00:00 2001 From: Paulo Marques Date: Thu, 23 Jun 2005 00:09:02 -0700 Subject: [PATCH] create a kstrdup library function This patch creates a new kstrdup library function and changes the "local" implementations in several places to use this function. Most of the changes come from the sound and net subsystems. The sound part had already been acknowledged by Takashi Iwai and the net part by David S. Miller. I left UML alone for now because I would need more time to read the code carefully before making changes there. Signed-off-by: Paulo Marques Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/core/info.c | 3 ++- sound/core/info_oss.c | 3 ++- sound/core/memory.c | 41 ++++++++++++++--------------------------- sound/core/oss/mixer_oss.c | 3 ++- sound/core/oss/pcm_oss.c | 3 ++- sound/core/sound.c | 2 +- sound/core/timer.c | 3 ++- sound/isa/gus/gus_mem.c | 7 ++++--- sound/pci/hda/patch_realtek.c | 2 +- sound/synth/emux/emux.c | 3 ++- 10 files changed, 32 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/core/info.c b/sound/core/info.c index 31faffe01cb0..5e122bbe7c92 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -754,7 +755,7 @@ static snd_info_entry_t *snd_info_create_entry(const char *name) entry = kcalloc(1, sizeof(*entry), GFP_KERNEL); if (entry == NULL) return NULL; - entry->name = snd_kmalloc_strdup(name, GFP_KERNEL); + entry->name = kstrdup(name, GFP_KERNEL); if (entry->name == NULL) { kfree(entry); return NULL; diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index f9e4ce443454..12107968d402 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,7 @@ int snd_oss_info_register(int dev, int num, char *string) x = NULL; } } else { - x = snd_kmalloc_strdup(string, GFP_KERNEL); + x = kstrdup(string, GFP_KERNEL); if (x == NULL) { up(&strings); return -ENOMEM; diff --git a/sound/core/memory.c b/sound/core/memory.c index 20860fec9364..c1fb28e84330 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -184,6 +184,20 @@ void snd_hidden_vfree(void *obj) snd_wrapper_vfree(obj); } +char *snd_hidden_kstrdup(const char *s, int flags) +{ + int len; + char *buf; + + if (!s) return NULL; + + len = strlen(s) + 1; + buf = _snd_kmalloc(len, flags); + if (buf) + memcpy(buf, s, len); + return buf; +} + static void snd_memory_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { snd_iprintf(buffer, "kmalloc: %li bytes\n", snd_alloc_kmalloc); @@ -214,35 +228,8 @@ int __exit snd_memory_info_done(void) return 0; } -#else - -#define _snd_kmalloc kmalloc - #endif /* CONFIG_SND_DEBUG_MEMORY */ -/** - * snd_kmalloc_strdup - copy the string - * @string: the original string - * @flags: allocation conditions, GFP_XXX - * - * Allocates a memory chunk via kmalloc() and copies the string to it. - * - * Returns the pointer, or NULL if no enoguh memory. - */ -char *snd_kmalloc_strdup(const char *string, int flags) -{ - size_t len; - char *ptr; - - if (!string) - return NULL; - len = strlen(string) + 1; - ptr = _snd_kmalloc(len, flags); - if (ptr) - memcpy(ptr, string, len); - return ptr; -} - /** * copy_to_user_fromio - copy data from mmio-space to user-space * @dst: the destination pointer on user-space diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 98ed9a9f0da6..98fc0766f885 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1137,7 +1138,7 @@ static void snd_mixer_oss_proc_write(snd_info_entry_t *entry, goto __unlock; } tbl->oss_id = ch; - tbl->name = snd_kmalloc_strdup(str, GFP_KERNEL); + tbl->name = kstrdup(str, GFP_KERNEL); if (! tbl->name) { kfree(tbl); goto __unlock; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index cab30977e7c0..de7444c586f9 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2360,7 +2361,7 @@ static void snd_pcm_oss_proc_write(snd_info_entry_t *entry, for (setup1 = pstr->oss.setup_list; setup1->next; setup1 = setup1->next); setup1->next = setup; } - template.task_name = snd_kmalloc_strdup(task_name, GFP_KERNEL); + template.task_name = kstrdup(task_name, GFP_KERNEL); } else { buffer->error = -ENOMEM; } diff --git a/sound/core/sound.c b/sound/core/sound.c index 0815fadeb3ec..7612884f530b 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -399,8 +399,8 @@ EXPORT_SYMBOL(snd_hidden_kcalloc); EXPORT_SYMBOL(snd_hidden_kfree); EXPORT_SYMBOL(snd_hidden_vmalloc); EXPORT_SYMBOL(snd_hidden_vfree); +EXPORT_SYMBOL(snd_hidden_kstrdup); #endif -EXPORT_SYMBOL(snd_kmalloc_strdup); EXPORT_SYMBOL(copy_to_user_fromio); EXPORT_SYMBOL(copy_from_user_toio); /* init.c */ diff --git a/sound/core/timer.c b/sound/core/timer.c index b498e5482d77..cfaccd415b3b 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -100,7 +101,7 @@ static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *ti timeri = kcalloc(1, sizeof(*timeri), GFP_KERNEL); if (timeri == NULL) return NULL; - timeri->owner = snd_kmalloc_strdup(owner, GFP_KERNEL); + timeri->owner = kstrdup(owner, GFP_KERNEL); if (! timeri->owner) { kfree(timeri); return NULL; diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index 609838e8ef67..5eb766dd564b 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -213,7 +214,7 @@ snd_gf1_mem_block_t *snd_gf1_mem_alloc(snd_gf1_mem_t * alloc, int owner, if (share_id != NULL) memcpy(&block.share_id, share_id, sizeof(block.share_id)); block.owner = owner; - block.name = snd_kmalloc_strdup(name, GFP_KERNEL); + block.name = kstrdup(name, GFP_KERNEL); nblock = snd_gf1_mem_xalloc(alloc, &block); snd_gf1_mem_lock(alloc, 1); return nblock; @@ -253,13 +254,13 @@ int snd_gf1_mem_init(snd_gus_card_t * gus) if (gus->gf1.enh_mode) { block.ptr = 0; block.size = 1024; - block.name = snd_kmalloc_strdup("InterWave LFOs", GFP_KERNEL); + block.name = kstrdup("InterWave LFOs", GFP_KERNEL); if (snd_gf1_mem_xalloc(alloc, &block) == NULL) return -ENOMEM; } block.ptr = gus->gf1.default_voice_address; block.size = 4; - block.name = snd_kmalloc_strdup("Voice default (NULL's)", GFP_KERNEL); + block.name = kstrdup("Voice default (NULL's)", GFP_KERNEL); if (snd_gf1_mem_xalloc(alloc, &block) == NULL) return -ENOMEM; #ifdef CONFIG_SND_DEBUG diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9edd558d6bd3..bab89843d850 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1781,7 +1781,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name, unsign knew = &spec->kctl_alloc[spec->num_kctl_used]; *knew = alc880_control_templates[type]; - knew->name = snd_kmalloc_strdup(name, GFP_KERNEL); + knew->name = kstrdup(name, GFP_KERNEL); if (! knew->name) return -ENOMEM; knew->private_value = val; diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index 16f3b461627a..60d0b2c66698 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -76,7 +77,7 @@ int snd_emux_register(snd_emux_t *emu, snd_card_t *card, int index, char *name) snd_assert(name != NULL, return -EINVAL); emu->card = card; - emu->name = snd_kmalloc_strdup(name, GFP_KERNEL); + emu->name = kstrdup(name, GFP_KERNEL); emu->voices = kcalloc(emu->max_voices, sizeof(snd_emux_voice_t), GFP_KERNEL); if (emu->voices == NULL) return -ENOMEM; -- cgit v1.2.1 From 09417379be9b126e10ae7dcd7afc20b666146266 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 25 Jun 2005 14:58:49 -0700 Subject: [PATCH] remove redundant NULL checks before kfree() in sound/ and avoid casting pointers about to be kfree()'ed 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: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/ad1848.c | 3 +-- sound/oss/ad1889.c | 3 +-- sound/oss/dmasound/dmasound_awacs.c | 20 +++++++------------- sound/oss/emu10k1/midi.c | 6 ++---- sound/oss/emu10k1/passthrough.c | 3 +-- sound/oss/maestro.c | 2 +- sound/oss/mpu401.c | 3 +-- sound/oss/sb_common.c | 4 ++-- 8 files changed, 16 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index 4384dac3f794..7c835abd99bc 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c @@ -2178,8 +2178,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int if (devc != NULL) { - if(audio_devs[dev]->portc!=NULL) - kfree(audio_devs[dev]->portc); + kfree(audio_devs[dev]->portc); release_region(devc->base, 4); if (!share_dma) diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c index b767c621fd09..2cfd214e4c2a 100644 --- a/sound/oss/ad1889.c +++ b/sound/oss/ad1889.c @@ -277,8 +277,7 @@ static void ad1889_free_dev(ad1889_dev_t *dev) for (j = 0; j < AD_MAX_STATES; j++) { dmabuf = &dev->state[j].dmabuf; - if (dmabuf->rawbuf != NULL) - kfree(dmabuf->rawbuf); + kfree(dmabuf->rawbuf); } kfree(dev); diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 5281b88987f3..33108661e671 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -671,14 +671,10 @@ static void PMacIrqCleanup(void) release_OF_resource(awacs_node, 1); release_OF_resource(awacs_node, 2); - if (awacs_tx_cmd_space) - kfree(awacs_tx_cmd_space); - if (awacs_rx_cmd_space) - kfree(awacs_rx_cmd_space); - if (beep_dbdma_cmd_space) - kfree(beep_dbdma_cmd_space); - if (beep_buf) - kfree(beep_buf); + kfree(awacs_tx_cmd_space); + kfree(awacs_rx_cmd_space); + kfree(beep_dbdma_cmd_space); + kfree(beep_buf); #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&awacs_sleep_notifier); #endif @@ -2301,8 +2297,7 @@ if (count <= 0) #endif if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) { - if (awacs_tx_cmd_space) - kfree(awacs_tx_cmd_space); + kfree(awacs_tx_cmd_space); number_of_tx_cmd_buffers = 0; /* we need nbufs + 1 (for the loop) and we should request + 1 @@ -2360,8 +2355,7 @@ if (count <= 0) #endif if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) { - if (awacs_rx_cmd_space) - kfree(awacs_rx_cmd_space); + kfree(awacs_rx_cmd_space); number_of_rx_cmd_buffers = 0; /* we need nbufs + 1 (for the loop) and we should request + 1 again @@ -2805,7 +2799,7 @@ __init setup_beep(void) beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); if (beep_buf == NULL) { printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n"); - if( beep_dbdma_cmd_space ) kfree(beep_dbdma_cmd_space) ; + kfree(beep_dbdma_cmd_space) ; return -ENOMEM ; } return 0 ; diff --git a/sound/oss/emu10k1/midi.c b/sound/oss/emu10k1/midi.c index 33dea3d56c1e..b40b5f97aace 100644 --- a/sound/oss/emu10k1/midi.c +++ b/sound/oss/emu10k1/midi.c @@ -523,10 +523,8 @@ void emu10k1_seq_midi_close(int dev) card = midi_devs[dev]->devc; emu10k1_mpuout_close(card); - if (card->seq_mididev) { - kfree(card->seq_mididev); - card->seq_mididev = NULL; - } + kfree(card->seq_mididev); + card->seq_mididev = NULL; } int emu10k1_seq_midi_out(int dev, unsigned char midi_byte) diff --git a/sound/oss/emu10k1/passthrough.c b/sound/oss/emu10k1/passthrough.c index 4094be55f3be..4e3baca7d41f 100644 --- a/sound/oss/emu10k1/passthrough.c +++ b/sound/oss/emu10k1/passthrough.c @@ -213,8 +213,7 @@ void emu10k1_pt_stop(struct emu10k1_card *card) sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]); } pt->state = PT_STATE_INACTIVE; - if(pt->buf) - kfree(pt->buf); + kfree(pt->buf); } } diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c index 52d2db4bc312..3dce504e6d6d 100644 --- a/sound/oss/maestro.c +++ b/sound/oss/maestro.c @@ -2356,7 +2356,7 @@ ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) } rec_return_free: - if(combbuf) kfree(combbuf); + kfree(combbuf); return ret; } diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index b66f53fa8db0..0aac54c68f01 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -1240,8 +1240,7 @@ void unload_mpu401(struct address_info *hw_config) p=mpu401_synth_operations[n]; sound_unload_mididev(n); sound_unload_timerdev(hw_config->slots[2]); - if(p) - kfree(p); + kfree(p); } } diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c index ce359e6c933a..5f955e3d2e26 100644 --- a/sound/oss/sb_common.c +++ b/sound/oss/sb_common.c @@ -915,8 +915,8 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu) } else release_region(hw_config->io_base, 16); - if(detected_devc) - kfree(detected_devc); + + kfree(detected_devc); } /* -- cgit v1.2.1 From 155542c271ba76fec37146b26aea1001019eb60d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 25 Jun 2005 14:58:53 -0700 Subject: [PATCH] sound/oss/: cleanups This patch contains cleanups including the following: - make needlessly global code static Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/ad1816.c | 2 +- sound/oss/nm256.h | 2 +- sound/oss/nm256_audio.c | 4 ++-- sound/oss/nm256_coeff.h | 2 +- sound/oss/v_midi.c | 2 -- sound/oss/wavfront.c | 12 ++++++------ 6 files changed, 11 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/oss/ad1816.c b/sound/oss/ad1816.c index 22dae5d0fda3..95586de02028 100644 --- a/sound/oss/ad1816.c +++ b/sound/oss/ad1816.c @@ -592,7 +592,7 @@ typedef struct mixer_def mixer_ent; {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}} -mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = { +static mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = { MIX_ENT(SOUND_MIXER_VOLUME, 14, 1, 8, 5, 14, 1, 0, 5), MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), diff --git a/sound/oss/nm256.h b/sound/oss/nm256.h index eae7d99d6826..762331765328 100644 --- a/sound/oss/nm256.h +++ b/sound/oss/nm256.h @@ -284,7 +284,7 @@ nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset, } /* Returns a non-zero value if we should use the coefficient cache. */ -extern int nm256_cachedCoefficients (struct nm256_info *card); +static int nm256_cachedCoefficients (struct nm256_info *card); #endif diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c index f9166e135192..f1a7ba6ae340 100644 --- a/sound/oss/nm256_audio.c +++ b/sound/oss/nm256_audio.c @@ -31,7 +31,7 @@ #include "nm256.h" #include "nm256_coeff.h" -int nm256_debug; +static int nm256_debug; static int force_load; /* @@ -138,7 +138,7 @@ static int usecache; static int buffertop; /* Check to see if we're using the bank of cached coefficients. */ -int +static int nm256_cachedCoefficients (struct nm256_info *card) { return usecache; diff --git a/sound/oss/nm256_coeff.h b/sound/oss/nm256_coeff.h index 0ceecc20077b..6fc07f3cb33b 100644 --- a/sound/oss/nm256_coeff.h +++ b/sound/oss/nm256_coeff.h @@ -4650,7 +4650,7 @@ nm256_loadAllCoefficients (struct nm256_info *card) card->coeffsCurrent = 1; } -void +static void nm256_loadCoefficient (struct nm256_info *card, int which, int number) { static u16 addrs[3] = { 0x1c, 0x21c, 0x408 }; diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c index 077b76797665..a7ef04fab075 100644 --- a/sound/oss/v_midi.c +++ b/sound/oss/v_midi.c @@ -39,8 +39,6 @@ static void *midi_mem = NULL; */ -void (*midi_input_intr) (int dev, unsigned char data); - static int v_midi_open (int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev) diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c index cce1278dc487..b92ba8921638 100644 --- a/sound/oss/wavfront.c +++ b/sound/oss/wavfront.c @@ -151,11 +151,11 @@ static int (*midi_load_patch) (int devno, int format, const char __user *addr, /*** Module-accessible parameters ***************************************/ -int wf_raw; /* we normally check for "raw state" to firmware - loading. if set, then during driver loading, the - state of the board is ignored, and we reset the - board and load the firmware anyway. - */ +static int wf_raw; /* we normally check for "raw state" to firmware + loading. if set, then during driver loading, the + state of the board is ignored, and we reset the + board and load the firmware anyway. + */ static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in whatever state it is when the driver is loaded. @@ -2911,7 +2911,7 @@ int __init detect_wffx (void) return 0; } -void +static void wffx_mute (int onoff) { -- cgit v1.2.1 From 4f00945a8e35e46b98f3ec4adae747397393e3ee Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 25 Jun 2005 14:58:53 -0700 Subject: [PATCH] nm256 oss build failure static declaration follows non static Signed-off-by: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/nm256.h | 3 --- sound/oss/nm256_audio.c | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/oss/nm256.h b/sound/oss/nm256.h index 762331765328..21e07b5081f2 100644 --- a/sound/oss/nm256.h +++ b/sound/oss/nm256.h @@ -128,9 +128,6 @@ struct nm256_info struct nm256_info *next_card; }; -/* Debug flag--bigger numbers mean more output. */ -extern int nm256_debug; - /* The BIOS signature. */ #define NM_SIGNATURE 0x4e4d0000 /* Signature mask. */ diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c index f1a7ba6ae340..66970062eb36 100644 --- a/sound/oss/nm256_audio.c +++ b/sound/oss/nm256_audio.c @@ -28,12 +28,13 @@ #include #include #include "sound_config.h" -#include "nm256.h" -#include "nm256_coeff.h" static int nm256_debug; static int force_load; +#include "nm256.h" +#include "nm256_coeff.h" + /* * The size of the playback reserve. When the playback buffer has less * than NM256_PLAY_WMARK_SIZE bytes to output, we request a new -- cgit v1.2.1 From f040ffab7488c02c0806ec8808fa619d463560f9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 25 Jun 2005 14:58:54 -0700 Subject: [PATCH] sound/oss/rme96xx.c: remove kernel 2.2 #if's This patch removes #if's for kernel 2.2 . Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/rme96xx.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c index b4278eecc917..7609c68a89f4 100644 --- a/sound/oss/rme96xx.c +++ b/sound/oss/rme96xx.c @@ -1750,9 +1750,7 @@ static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wa static struct file_operations rme96xx_audio_fops = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) .owner = THIS_MODULE, -#endif .read = rme96xx_read, .write = rme96xx_write, .poll = rme96xx_poll, @@ -1852,9 +1850,7 @@ static int rme96xx_mixer_release(struct inode *inode, struct file *file) } static /*const*/ struct file_operations rme96xx_mixer_fops = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) .owner = THIS_MODULE, -#endif .ioctl = rme96xx_mixer_ioctl, .open = rme96xx_mixer_open, .release = rme96xx_mixer_release, -- cgit v1.2.1 From f25ad2d3b886e61d7ec03a3bdefc22871c14e9da Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 25 Jun 2005 14:59:02 -0700 Subject: [PATCH] sound/oss/sscape.c: remove dead code The Coverity checker found that sscape_sb_enable never get's assigned any value different from 0, and therefore some code paths are impossible. This patch removes this variable and the dead code paths. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/sscape.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c index 50ca64629450..9ed5211c3168 100644 --- a/sound/oss/sscape.c +++ b/sound/oss/sscape.c @@ -991,7 +991,6 @@ static void __init sscape_pnp_init_hw(sscape_info* devc) unsigned i; static char code_file_name[23] = "/sndscape/sndscape.cox"; - int sscape_sb_enable = 0; int sscape_joystic_enable = 0x7f; int sscape_mic_enable = 0; int sscape_ext_midi = 0; @@ -1015,14 +1014,9 @@ static void __init sscape_pnp_init_hw(sscape_info* devc) sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); sscape_write( devc, 3, ( devc -> dma << 4) | 0x80); - if ( sscape_sb_enable ) - sscape_write (devc, 4, 0xF0 | (sb_irq << 2) | midi_irq); - else - sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq); + sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq); i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0); - if ( sscape_sb_enable ) - i |= devc->ic_type == IC_ODIE ? 0x05 : 0x07; if (sscape_joystic_enable) i |= 8; sscape_write (devc, 9, i); -- cgit v1.2.1 From b6260cd354ec2b3ec026d6c899dc01e442b5e6cc Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 25 Jun 2005 14:59:11 -0700 Subject: [PATCH] change the SOUND_PRIME handling SOUND_PRIME (for OSS) is a tristate. This doesn't make much sense if most users are checking for SOUND_PRIME!=0. This patch changes the semantics of SOUND_PRIME to being a limit for all OSS modules, IOW: SOUND_PRIME=m does now say that all OSS drivers can only be modular. As a side effect, since SOUND_PRIME already depends on SOUND, there's no longer a reason for drivers depending on SOUND_PRIME to additionally depend on SOUND. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/Kconfig | 62 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index e537bd66a707..3b1fafc8f4f5 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -6,7 +6,7 @@ # Prompt user for primary drivers. config SOUND_BT878 tristate "BT878 audio dma" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME ---help--- Audio DMA support for bt878 based grabber boards. As you might have already noticed, bt878 is listed with two functions in /proc/pci. @@ -22,7 +22,7 @@ config SOUND_BT878 config SOUND_CMPCI tristate "C-Media PCI (CMI8338/8738)" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card using the CMI8338 or the CMI8738 chipset. Data on these chips are available at @@ -61,7 +61,7 @@ config SOUND_CMPCI_JOYSTICK config SOUND_EMU10K1 tristate "Creative SBLive! (EMU10K1)" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI ---help--- Say Y or M if you have a PCI sound card using the EMU10K1 chipset, such as the Creative SBLive!, SB PCI512 or Emu-APS. @@ -87,7 +87,7 @@ config MIDI_EMU10K1 config SOUND_FUSION tristate "Crystal SoundFusion (CS4280/461x)" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME help This module drives the Crystal SoundFusion devices (CS4280/46xx series) when wired as native sound drivers with AC97 codecs. If @@ -95,14 +95,14 @@ config SOUND_FUSION config SOUND_CS4281 tristate "Crystal Sound CS4281" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME help Picture and feature list at . config SOUND_BCM_CS4297A tristate "Crystal Sound CS4297a (for Swarm)" - depends on SOUND_PRIME!=n && SIBYTE_SWARM && SOUND + depends on SOUND_PRIME && SIBYTE_SWARM help The BCM91250A has a Crystal CS4297a on synchronous serial port B (in addition to the DB-9 serial port). Say Y or M @@ -112,7 +112,7 @@ config SOUND_BCM_CS4297A config SOUND_ES1370 tristate "Ensoniq AudioPCI (ES1370)" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card utilizing the Ensoniq ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find @@ -125,7 +125,7 @@ config SOUND_ES1370 config SOUND_ES1371 tristate "Creative Ensoniq AudioPCI 97 (ES1371)" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card utilizing the Ensoniq ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if @@ -138,7 +138,7 @@ config SOUND_ES1371 config SOUND_ESSSOLO1 tristate "ESS Technology Solo1" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card utilizing the ESS Technology Solo1 chip. To find out if your sound card uses a @@ -149,7 +149,7 @@ config SOUND_ESSSOLO1 config SOUND_MAESTRO tristate "ESS Maestro, Maestro2, Maestro2E driver" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a sound system driven by ESS's Maestro line of PCI sound chips. These include the Maestro 1, Maestro 2, and @@ -158,28 +158,28 @@ config SOUND_MAESTRO config SOUND_MAESTRO3 tristate "ESS Maestro3/Allegro driver (EXPERIMENTAL)" - depends on SOUND_PRIME!=n && SOUND && PCI && EXPERIMENTAL + depends on SOUND_PRIME && PCI && EXPERIMENTAL help Say Y or M if you have a sound system driven by ESS's Maestro 3 PCI sound chip. config SOUND_ICH tristate "Intel ICH (i8xx) audio support" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI help Support for integral audio in Intel's I/O Controller Hub (ICH) chipset, as used on the 810/820/840 motherboards. config SOUND_HARMONY tristate "PA Harmony audio driver" - depends on GSC_LASI && SOUND_PRIME!=n + depends on GSC_LASI && SOUND_PRIME help Say 'Y' or 'M' to include support for Harmony soundchip on HP 712, 715/new and many other GSC based machines. config SOUND_SONICVIBES tristate "S3 SonicVibes" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME help Say Y or M if you have a PCI sound card utilizing the S3 SonicVibes chipset. To find out if your sound card uses a @@ -190,7 +190,7 @@ config SOUND_SONICVIBES config SOUND_VWSND tristate "SGI Visual Workstation Sound" - depends on SOUND_PRIME!=n && X86_VISWS && SOUND + depends on SOUND_PRIME && X86_VISWS help Say Y or M if you have an SGI Visual Workstation and you want to be able to use its on-board audio. Read @@ -199,18 +199,18 @@ config SOUND_VWSND config SOUND_HAL2 tristate "SGI HAL2 sound (EXPERIMENTAL)" - depends on SOUND_PRIME!=n && SOUND && SGI_IP22 && EXPERIMENTAL + depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL help Say Y or M if you have an SGI Indy system and want to be able to use it's on-board A2 audio system. config SOUND_IT8172 tristate "IT8172G Sound" - depends on SOUND_PRIME!=n && (MIPS_ITE8172 || MIPS_IVR) && SOUND + depends on SOUND_PRIME && (MIPS_ITE8172 || MIPS_IVR) config SOUND_VRC5477 tristate "NEC Vrc5477 AC97 sound" - depends on SOUND_PRIME!=n && DDB5477 && SOUND + depends on SOUND_PRIME && DDB5477 help Say Y here to enable sound support for the NEC Vrc5477 chip, an integrated, multi-function controller chip for MIPS CPUs. Works @@ -218,15 +218,15 @@ config SOUND_VRC5477 config SOUND_AU1000 tristate "Au1000 Sound" - depends on SOUND_PRIME!=n && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SOUND + depends on SOUND_PRIME && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) config SOUND_AU1550_AC97 tristate "Au1550 AC97 Sound" - depends on SOUND_PRIME!=n && SOC_AU1550 && SOUND + depends on SOUND_PRIME && SOC_AU1550 config SOUND_TRIDENT tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME ---help--- Say Y or M if you have a PCI sound card utilizing the Trident 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 @@ -267,7 +267,7 @@ config SOUND_TRIDENT config SOUND_MSNDCLAS tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" - depends on SOUND_PRIME!=n && SOUND && (m || !STANDALONE) + depends on SOUND_PRIME && (m || !STANDALONE) help Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or Monterey (not for the Pinnacle or Fiji). @@ -331,7 +331,7 @@ config MSNDCLAS_IO config SOUND_MSNDPIN tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" - depends on SOUND_PRIME!=n && SOUND && (m || !STANDALONE) + depends on SOUND_PRIME && (m || !STANDALONE) help Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. See for important information @@ -492,7 +492,7 @@ config MSND_FIFOSIZE config SOUND_VIA82CXXX tristate "VIA 82C686 Audio Codec" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI help Say Y here to include support for the audio codec found on VIA 82Cxxx-based chips. Typically these are built into a motherboard. @@ -512,7 +512,7 @@ config MIDI_VIA82CXXX config SOUND_OSS tristate "OSS sound modules" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME help OSS is the Open Sound System suite of sound card drivers. They make sound programming easier since they provide a common API. Say Y or @@ -1077,7 +1077,7 @@ config SOUND_WAVEARTIST config SOUND_TVMIXER tristate "TV card (bt848) mixer support" - depends on SOUND_PRIME!=n && SOUND && I2C + depends on SOUND_PRIME && I2C help Support for audio mixer facilities on the BT848 TV frame-grabber card. @@ -1088,11 +1088,11 @@ config SOUND_KAHLUA config SOUND_ALI5455 tristate "ALi5455 audio support" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI config SOUND_FORTE tristate "ForteMedia FM801 driver" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you want driver support for the ForteMedia FM801 PCI audio controller (Abit AU10, Genius Sound Maker, HP Workstation @@ -1100,7 +1100,7 @@ config SOUND_FORTE config SOUND_RME96XX tristate "RME Hammerfall (RME96XX) support" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a Hammerfall or Hammerfall light multichannel card from RME. If you want to access advanced @@ -1108,11 +1108,11 @@ config SOUND_RME96XX config SOUND_AD1980 tristate "AD1980 front/back switch plugin" - depends on SOUND_PRIME!=n + depends on SOUND_PRIME config SOUND_SH_DAC_AUDIO tristate "SuperH DAC audio support" - depends on SOUND_PRIME!=n && SOUND && CPU_SH3 + depends on SOUND_PRIME && CPU_SH3 config SOUND_SH_DAC_AUDIO_CHANNEL int " DAC channel" -- cgit v1.2.1 From caac3a444ce3b5a8d76069abfbb699d2a65b3f09 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 25 Jun 2005 14:59:25 -0700 Subject: [PATCH] sound/oss/esssolo1: Use the DMA_32BIT_MASK constant 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: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/esssolo1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c index 6b3b9a99579d..fb09065d07c8 100644 --- a/sound/oss/esssolo1.c +++ b/sound/oss/esssolo1.c @@ -104,6 +104,7 @@ #include #include #include +#include #include #include @@ -2326,7 +2327,7 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device * to 24 bits first, then 32 bits (playback only) if that fails. */ if (pci_set_dma_mask(pcidev, 0x00ffffff) && - pci_set_dma_mask(pcidev, 0xffffffff)) { + pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) { printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n"); return -ENODEV; } -- cgit v1.2.1 From 3ee538a2e867c7fbdb2a5940b610682d5d08e8be Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 25 Jun 2005 14:59:26 -0700 Subject: [PATCH] sound/oss/es1371: Use the DMA_32BIT_MASK constant 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: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/es1371.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c index a50fddaeea21..9266b777387b 100644 --- a/sound/oss/es1371.c +++ b/sound/oss/es1371.c @@ -128,6 +128,7 @@ #include #include #include +#include #include #include @@ -2804,7 +2805,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic return -ENODEV; if (pcidev->irq == 0) return -ENODEV; - i = pci_set_dma_mask(pcidev, 0xffffffff); + i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); if (i) { printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); return i; -- cgit v1.2.1 From 738c7b4f7f36ce2c547d0a2c2aa397aae904510f Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 25 Jun 2005 14:59:27 -0700 Subject: [PATCH] sound/oss/es1370: Use the DMA_32BIT_MASK constant 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: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/es1370.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c index 056091cff266..886f61c1c34a 100644 --- a/sound/oss/es1370.c +++ b/sound/oss/es1370.c @@ -156,6 +156,7 @@ #include #include #include +#include #include #include @@ -2569,7 +2570,7 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic return -ENODEV; if (pcidev->irq == 0) return -ENODEV; - i = pci_set_dma_mask(pcidev, 0xffffffff); + i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); if (i) { printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n"); return i; -- cgit v1.2.1 From 4f11842ebbb3b98a88c38ef6c18345ccc792a54b Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sat, 25 Jun 2005 14:59:27 -0700 Subject: [PATCH] sound/oss/cmpci: Use the DMA_32BIT_MASK constant 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: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/cmpci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c index 34720e66dae1..74dcca78c6c0 100644 --- a/sound/oss/cmpci.c +++ b/sound/oss/cmpci.c @@ -123,6 +123,7 @@ #include #include #include +#include #include #include @@ -3058,7 +3059,7 @@ static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id return -ENODEV; if (pcidev->irq == 0) return -ENODEV; - i = pci_set_dma_mask(pcidev, 0xffffffff); + i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); if (i) { printk(KERN_WARNING "cmpci: architecture does not support 32bit PCI busmaster DMA\n"); return i; -- cgit v1.2.1