Update of /cvsroot/alsa/alsa-kernel/pci/ac97 In directory sc8-pr-cvs1:/tmp/cvs-serv24118
Modified Files: Makefile ac97_codec.c ac97_patch.c ac97_patch.h Added Files: ac97_local.h ac97_proc.c Log Message: Moved codec-specific code to ac97_patch.c --- NEW FILE: ac97_local.h --- /* * Copyright (c) by Jaroslav Kysela <[EMAIL PROTECTED]> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 * by Intel Corporation (http://developer.intel.com). * * * 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 * */ #define AC97_SINGLE(xname, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \ .get = snd_ac97_get_single, .put = snd_ac97_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } /* ac97_codec.c */ extern const char *snd_ac97_stereo_enhancements[]; extern const snd_kcontrol_new_t snd_ac97_controls_3d[]; extern const snd_kcontrol_new_t snd_ac97_controls_spdif[]; snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97); void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem); int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo); int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit); /* ac97_proc.c */ void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix); --- NEW FILE: ac97_proc.c --- /* * Copyright (c) by Jaroslav Kysela <[EMAIL PROTECTED]> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 * by Intel Corporation (http://developer.intel.com). * * * 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 <sound/driver.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/ac97_codec.h> #include <sound/asoundef.h> #include "ac97_local.h" #include "ac97_id.h" /* * proc interface */ static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx) { char name[64]; unsigned int id; unsigned short val, tmp, ext, mext; static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" }; static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" }; static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" }; id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); snd_ac97_get_name(NULL, id, name, 0); snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name); if ((ac97->scaps & AC97_SCAP_AUDIO) == 0) goto __modem; // val = snd_ac97_read(ac97, AC97_RESET); val = ac97->caps; snd_iprintf(buffer, "Capabilities :%s%s%s%s%s%s\n", val & AC97_BC_DEDICATED_MIC ? " -dedicated MIC PCM IN channel-" : "", val & AC97_BC_RESERVED1 ? " -reserved1-" : "", val & AC97_BC_BASS_TREBLE ? " -bass & treble-" : "", val & AC97_BC_SIM_STEREO ? " -simulated stereo-" : "", val & AC97_BC_HEADPHONE ? " -headphone out-" : "", val & AC97_BC_LOUDNESS ? " -loudness-" : ""); tmp = ac97->caps & AC97_BC_DAC_MASK; snd_iprintf(buffer, "DAC resolution : %s%s%s%s\n", tmp == AC97_BC_16BIT_DAC ? "16-bit" : "", tmp == AC97_BC_18BIT_DAC ? "18-bit" : "", tmp == AC97_BC_20BIT_DAC ? "20-bit" : "", tmp == AC97_BC_DAC_MASK ? "???" : ""); tmp = ac97->caps & AC97_BC_ADC_MASK; snd_iprintf(buffer, "ADC resolution : %s%s%s%s\n", tmp == AC97_BC_16BIT_ADC ? "16-bit" : "", tmp == AC97_BC_18BIT_ADC ? "18-bit" : "", tmp == AC97_BC_20BIT_ADC ? "20-bit" : "", tmp == AC97_BC_ADC_MASK ? "???" : ""); snd_iprintf(buffer, "3D enhancement : %s\n", snd_ac97_stereo_enhancements[(val >> 10) & 0x1f]); snd_iprintf(buffer, "\nCurrent setup\n"); val = snd_ac97_read(ac97, AC97_MIC); snd_iprintf(buffer, "Mic gain : %s [%s]\n", val & 0x0040 ? "+20dB" : "+0dB", ac97->regs[AC97_MIC] & 0x0040 ? "+20dB" : "+0dB"); val = snd_ac97_read(ac97, AC97_GENERAL_PURPOSE); snd_iprintf(buffer, "POP path : %s 3D\n" "Sim. stereo : %s\n" "3D enhancement : %s\n" "Loudness : %s\n" "Mono output : %s\n" "Mic select : %s\n" "ADC/DAC loopback : %s\n", val & 0x8000 ? "post" : "pre", val & 0x4000 ? "on" : "off", val & 0x2000 ? "on" : "off", val & 0x1000 ? "on" : "off", val & 0x0200 ? "Mic" : "MIX", val & 0x0100 ? "Mic2" : "Mic1", val & 0x0080 ? "on" : "off"); ext = snd_ac97_read(ac97, AC97_EXTENDED_ID); if (ext == 0) goto __modem; snd_iprintf(buffer, "Extended ID : codec=%i rev=%i%s%s%s%s DSA=%i%s%s%s%s\n", (ext & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT, (ext & AC97_EI_REV_MASK) >> AC97_EI_REV_SHIFT, ext & AC97_EI_AMAP ? " AMAP" : "", ext & AC97_EI_LDAC ? " LDAC" : "", ext & AC97_EI_SDAC ? " SDAC" : "", ext & AC97_EI_CDAC ? " CDAC" : "", (ext & AC97_EI_DACS_SLOT_MASK) >> AC97_EI_DACS_SLOT_SHIFT, ext & AC97_EI_VRM ? " VRM" : "", ext & AC97_EI_SPDIF ? " SPDIF" : "", ext & AC97_EI_DRA ? " DRA" : "", ext & AC97_EI_VRA ? " VRA" : ""); val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); snd_iprintf(buffer, "Extended status :%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", val & AC97_EA_PRL ? " PRL" : "", val & AC97_EA_PRK ? " PRK" : "", val & AC97_EA_PRJ ? " PRJ" : "", val & AC97_EA_PRI ? " PRI" : "", val & AC97_EA_SPCV ? " SPCV" : "", val & AC97_EA_MDAC ? " MADC" : "", val & AC97_EA_LDAC ? " LDAC" : "", val & AC97_EA_SDAC ? " SDAC" : "", val & AC97_EA_CDAC ? " CDAC" : "", ext & AC97_EI_SPDIF ? spdif_slots[(val & AC97_EA_SPSA_SLOT_MASK) >> AC97_EA_SPSA_SLOT_SHIFT] : "", val & AC97_EA_VRM ? " VRM" : "", val & AC97_EA_SPDIF ? " SPDIF" : "", val & AC97_EA_DRA ? " DRA" : "", val & AC97_EA_VRA ? " VRA" : ""); if (ext & AC97_EI_VRA) { /* VRA */ val = snd_ac97_read(ac97, AC97_PCM_FRONT_DAC_RATE); snd_iprintf(buffer, "PCM front DAC : %iHz\n", val); if (ext & AC97_EI_SDAC) { val = snd_ac97_read(ac97, AC97_PCM_SURR_DAC_RATE); snd_iprintf(buffer, "PCM Surr DAC : %iHz\n", val); } if (ext & AC97_EI_LDAC) { val = snd_ac97_read(ac97, AC97_PCM_LFE_DAC_RATE); snd_iprintf(buffer, "PCM LFE DAC : %iHz\n", val); } val = snd_ac97_read(ac97, AC97_PCM_LR_ADC_RATE); snd_iprintf(buffer, "PCM ADC : %iHz\n", val); } if (ext & AC97_EI_VRM) { val = snd_ac97_read(ac97, AC97_PCM_MIC_ADC_RATE); snd_iprintf(buffer, "PCM MIC ADC : %iHz\n", val); } if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF)) { if (ac97->flags & AC97_CS_SPDIF) val = snd_ac97_read(ac97, AC97_CSR_SPDIF); else val = snd_ac97_read(ac97, AC97_SPDIF); snd_iprintf(buffer, "SPDIF Control :%s%s%s%s Category=0x%x Generation=%i%s%s%s\n", val & AC97_SC_PRO ? " PRO" : " Consumer", val & AC97_SC_NAUDIO ? " Non-audio" : " PCM", val & AC97_SC_COPY ? " Copyright" : "", val & AC97_SC_PRE ? " Preemph50/15" : "", (val & AC97_SC_CC_MASK) >> AC97_SC_CC_SHIFT, (val & AC97_SC_L) >> 11, (ac97->flags & AC97_CS_SPDIF) ? spdif_rates_cs4205[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT] : spdif_rates[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT], (ac97->flags & AC97_CS_SPDIF) ? (val & AC97_SC_DRS ? " Validity" : "") : (val & AC97_SC_DRS ? " DRS" : ""), (ac97->flags & AC97_CS_SPDIF) ? (val & AC97_SC_V ? " Enabled" : "") : (val & AC97_SC_V ? " Validity" : "")); } __modem: mext = snd_ac97_read(ac97, AC97_EXTENDED_MID); if (mext == 0) return; snd_iprintf(buffer, "Extended modem ID: codec=%i%s%s%s%s%s\n", (mext & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT, mext & AC97_MEI_CID2 ? " CID2" : "", mext & AC97_MEI_CID1 ? " CID1" : "", mext & AC97_MEI_HANDSET ? " HSET" : "", mext & AC97_MEI_LINE2 ? " LIN2" : "", mext & AC97_MEI_LINE1 ? " LIN1" : ""); val = snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS); snd_iprintf(buffer, "Modem status :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", val & AC97_MEA_GPIO ? " GPIO" : "", val & AC97_MEA_MREF ? " MREF" : "", val & AC97_MEA_ADC1 ? " ADC1" : "", val & AC97_MEA_DAC1 ? " DAC1" : "", val & AC97_MEA_ADC2 ? " ADC2" : "", val & AC97_MEA_DAC2 ? " DAC2" : "", val & AC97_MEA_HADC ? " HADC" : "", val & AC97_MEA_HDAC ? " HDAC" : "", val & AC97_MEA_PRA ? " PRA(GPIO)" : "", val & AC97_MEA_PRB ? " PRB(res)" : "", val & AC97_MEA_PRC ? " PRC(ADC1)" : "", val & AC97_MEA_PRD ? " PRD(DAC1)" : "", val & AC97_MEA_PRE ? " PRE(ADC2)" : "", val & AC97_MEA_PRF ? " PRF(DAC2)" : "", val & AC97_MEA_PRG ? " PRG(HADC)" : "", val & AC97_MEA_PRH ? " PRH(HDAC)" : ""); if (mext & AC97_MEI_LINE1) { val = snd_ac97_read(ac97, AC97_LINE1_RATE); snd_iprintf(buffer, "Line1 rate : %iHz\n", val); } if (mext & AC97_MEI_LINE2) { val = snd_ac97_read(ac97, AC97_LINE2_RATE); snd_iprintf(buffer, "Line2 rate : %iHz\n", val); } if (mext & AC97_MEI_HANDSET) { val = snd_ac97_read(ac97, AC97_HANDSET_RATE); snd_iprintf(buffer, "Headset rate : %iHz\n", val); } } static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 int idx; down(&ac97->spec.ad18xx.mutex); for (idx = 0; idx < 3; idx++) if (ac97->spec.ad18xx.id[idx]) { /* select single codec */ snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]); snd_ac97_proc_read_main(ac97, buffer, idx); snd_iprintf(buffer, "\n\n"); } /* select all codecs */ snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); up(&ac97->spec.ad18xx.mutex); snd_iprintf(buffer, "\nAD18XX configuration\n"); snd_iprintf(buffer, "Unchained : 0x%04x,0x%04x,0x%04x\n", ac97->spec.ad18xx.unchained[0], ac97->spec.ad18xx.unchained[1], ac97->spec.ad18xx.unchained[2]); snd_iprintf(buffer, "Chained : 0x%04x,0x%04x,0x%04x\n", ac97->spec.ad18xx.chained[0], ac97->spec.ad18xx.chained[1], ac97->spec.ad18xx.chained[2]); } else { snd_ac97_proc_read_main(ac97, buffer, 0); } } static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx) { int reg, val; for (reg = 0; reg < 0x80; reg += 2) { val = snd_ac97_read(ac97, reg); snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val); } } static void snd_ac97_proc_regs_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 int idx; down(&ac97->spec.ad18xx.mutex); for (idx = 0; idx < 3; idx++) if (ac97->spec.ad18xx.id[idx]) { /* select single codec */ snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]); snd_ac97_proc_regs_read_main(ac97, buffer, idx); } /* select all codecs */ snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); up(&ac97->spec.ad18xx.mutex); } else { snd_ac97_proc_regs_read_main(ac97, buffer, 0); } } void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix) { snd_info_entry_t *entry; char name[32]; if (ac97->num) sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); else sprintf(name, "%s#%d", prefix, ac97->addr); if (! snd_card_proc_new(card, name, &entry)) snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read); if (ac97->num) sprintf(name, "%s#%d-%dregs", prefix, ac97->addr, ac97->num); else sprintf(name, "%s#%dregs", prefix, ac97->addr); if (! snd_card_proc_new(card, name, &entry)) snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); } Index: Makefile =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/pci/ac97/Makefile,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- Makefile 17 Apr 2003 12:02:27 -0000 1.11 +++ Makefile 17 Jun 2003 18:43:31 -0000 1.12 @@ -3,7 +3,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <[EMAIL PROTECTED]> # -snd-ac97-codec-objs := ac97_codec.o ac97_patch.o +snd-ac97-codec-objs := ac97_codec.o ac97_proc.o ac97_patch.o snd-ak4531-codec-objs := ak4531_codec.o # Toplevel Module Dependency Index: ac97_codec.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/pci/ac97/ac97_codec.c,v retrieving revision 1.97 retrieving revision 1.98 diff -u -r1.97 -r1.98 --- ac97_codec.c 17 Jun 2003 15:11:00 -0000 1.97 +++ ac97_codec.c 17 Jun 2003 18:43:32 -0000 1.98 @@ -32,6 +32,7 @@ #include <sound/ac97_codec.h> #include <sound/asoundef.h> #include <sound/initval.h> +#include "ac97_local.h" #include "ac97_id.h" #include "ac97_patch.h" @@ -51,8 +52,6 @@ */ -static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix); - typedef struct { unsigned int id; unsigned int mask; @@ -114,7 +113,7 @@ { 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL }, { 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL }, { 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, -{ 0x434d4941, 0xffffffff, "CMI9738", NULL, NULL }, +{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, { 0x43525900, 0xfffffff8, "CS4297", NULL, NULL }, { 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif, NULL }, @@ -134,8 +133,8 @@ { 0x49434501, 0xffffffff, "ICE1230", NULL, NULL }, { 0x49434511, 0xffffffff, "ICE1232", NULL, NULL }, // alias VIA VT1611A? { 0x49434514, 0xffffffff, "ICE1232A", NULL, NULL }, -{ 0x49434551, 0xffffffff, "VT1616", NULL, NULL }, -{ 0x49434552, 0xffffffff, "VT1616i", NULL, NULL }, // VT1616 compatible (chipset integrated) +{ 0x49434551, 0xffffffff, "VT1616", patch_vt1616, NULL }, +{ 0x49434552, 0xffffffff, "VT1616i", patch_vt1616, NULL }, // VT1616 compatible (chipset integrated) { 0x49544520, 0xffffffff, "IT2226E", NULL, NULL }, { 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, @@ -158,7 +157,7 @@ { 0x594d4800, 0xffffffff, "YMF743", NULL, NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, { 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL }, -{ 0x83847600, 0xffffffff, "STAC9700/83/84", NULL, NULL }, +{ 0x83847600, 0xffffffff, "STAC9700/83/84", patch_sigmatel_stac9700, NULL }, { 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL, NULL }, { 0x83847605, 0xffffffff, "STAC9704", NULL, NULL }, { 0x83847608, 0xffffffff, "STAC9708/11", patch_sigmatel_stac9708, NULL }, @@ -171,7 +170,7 @@ { 0, 0, NULL, NULL, NULL } }; -static const char *snd_ac97_stereo_enhancements[] = +const char *snd_ac97_stereo_enhancements[] = { /* 0 */ "No 3D Stereo Enhancement", /* 1 */ "Analog Devices Phat Stereo", @@ -310,21 +309,6 @@ set_bit(reg, ac97->reg_accessed); } -static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned short value) -{ -#if 0 - if (!snd_ac97_valid_reg(ac97, reg)) - return; - //spin_lock(&ac97->reg_lock); - ac97->write(ac97, reg, value); - ac97->regs[reg] = ac97->read(ac97, reg); - if (value != ac97->regs[reg]) - snd_printk("AC97 reg=%02x val=%04x real=%04x\n", reg, value, ac97->regs[reg]); - //spin_unlock(&ac97->reg_lock); -#endif - snd_ac97_write_cache(ac97, reg, value); -} - /** * snd_ac97_update - update the value on the given register * @ac97: the ac97 instance @@ -518,12 +502,7 @@ return snd_ac97_update_bits(ac97, reg, 1 << shift, val << shift); } -#define AC97_SINGLE(xname, reg, shift, mask, invert) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \ - .get = snd_ac97_get_single, .put = snd_ac97_put_single, \ - .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } - -static int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { int mask = (kcontrol->private_value >> 16) & 0xff; @@ -534,7 +513,7 @@ return 0; } -static int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; @@ -548,7 +527,7 @@ return 0; } -static int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; @@ -718,7 +697,7 @@ AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0) }; -static const snd_kcontrol_new_t snd_ac97_controls_3d[2] = { +const snd_kcontrol_new_t snd_ac97_controls_3d[2] = { AC97_SINGLE("3D Control - Center", AC97_3D_CONTROL, 8, 15, 0), AC97_SINGLE("3D Control - Depth", AC97_3D_CONTROL, 0, 15, 0) }; @@ -743,27 +722,9 @@ AC97_DOUBLE("Sigmatel Surround Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1) }; -static const snd_kcontrol_new_t snd_ac97_sigmatel_4speaker = -AC97_SINGLE("Sigmatel 4-Speaker Stereo Playback Switch", AC97_SIGMATEL_DAC2INVERT, 2, 1, 0); - -static const snd_kcontrol_new_t snd_ac97_sigmatel_phaseinvert = -AC97_SINGLE("Sigmatel Surround Phase Inversion Playback Switch", AC97_SIGMATEL_DAC2INVERT, 3, 1, 0); - -static const snd_kcontrol_new_t snd_ac97_sigmatel_controls[] = { -AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0), -AC97_SINGLE("Sigmatel ADC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 0, 1, 0) -}; - static const snd_kcontrol_new_t snd_ac97_control_eapd = AC97_SINGLE("External Amplifier Power Down", AC97_POWERDOWN, 15, 1, 0); -static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = { -AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0), -AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0), -AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0), -AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), -}; - static int snd_ac97_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; @@ -898,7 +859,7 @@ return 0; } -static const snd_kcontrol_new_t snd_ac97_controls_spdif[5] = { +const snd_kcontrol_new_t snd_ac97_controls_spdif[5] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -933,15 +894,6 @@ }, }; -static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = { - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0), - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0) -}; - -static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[2] = { - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0), -}; - #define AD18XX_PCM_BITS(xname, codec, shift, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_ad18xx_pcm_info_bits, \ .get = snd_ac97_ad18xx_pcm_get_bits, .put = snd_ac97_ad18xx_pcm_put_bits, \ @@ -1037,325 +989,6 @@ AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31) }; -static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - static char *texts[2] = { "AC-Link", "A/D Converter" }; - - 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_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - val = ac97->regs[AC97_AD_SERIAL_CFG]; - ucontrol->value.enumerated.item[0] = (val >> 2) & 1; - return 0; -} - -static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - if (ucontrol->value.enumerated.item[0] > 1) - return -EINVAL; - val = ucontrol->value.enumerated.item[0] << 2; - return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val); -} - -static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = snd_ac97_ad1980_spdif_source_info, - .get = snd_ac97_ad1980_spdif_source_get, - .put = snd_ac97_ad1980_spdif_source_put, -}; - -/* - * ALC650 - */ -static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { - AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), - AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0), - AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0), - AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0), - /* 4: Analog Input To Surround */ - /* 5: Analog Input To Center/LFE */ - /* 6: Independent Master Volume Right */ - /* 7: Independent Master Volume Left */ - /* 8: reserved */ - AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), - AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), -#if 0 /* always set in patch_alc650 */ - AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), - AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0), - AC97_SINGLE("Surround DAC Switch", AC97_ALC650_SURR_DAC_VOL, 15, 1, 1), - AC97_DOUBLE("Surround DAC Volume", AC97_ALC650_SURR_DAC_VOL, 8, 0, 31, 1), - 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 -}; - -static const snd_kcontrol_new_t snd_ac97_control_alc650_mic = -AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0); - - -static int snd_ac97_alc650_mic_gpio_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_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - int change; - change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, - ucontrol->value.integer.value[0] ? (1 << 10) : 0); - if (change) { - /* GPIO0 write for mic */ - snd_ac97_update_bits(ac97, 0x76, 0x01, - ucontrol->value.integer.value[0] ? 0 : 0x01); - /* GPIO0 high for mic */ - snd_ac97_update_bits(ac97, 0x78, 0x100, - ucontrol->value.integer.value[0] ? 0 : 0x100); - } - return change; -} - -static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_single, - .get = snd_ac97_alc650_mic_gpio_get, - .put = snd_ac97_alc650_mic_gpio_put, - .private_value = (1 << 16), /* for info */ -}; - -static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { - AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), - AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0), - AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), -}; - -/* The following snd_ac97_ymf753_... items added by David Shust ([EMAIL PROTECTED]) */ - -/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ -static int snd_ac97_ymf753_info_speaker(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - static char *texts[3] = { - "Standard", "Small", "Smaller" - }; - - 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 snd_ac97_ymf753_get_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - val = ac97->regs[AC97_YMF753_3D_MODE_SEL]; - val = (val >> 10) & 3; - if (val > 0) /* 0 = invalid */ - val--; - ucontrol->value.enumerated.item[0] = val; - return 0; -} - -static int snd_ac97_ymf753_put_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - if (ucontrol->value.enumerated.item[0] > 2) - return -EINVAL; - val = (ucontrol->value.enumerated.item[0] + 1) << 10; - return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val); -} - -static const snd_kcontrol_new_t snd_ac97_ymf753_controls_speaker = -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "3D Control - Speaker", - .info = snd_ac97_ymf753_info_speaker, - .get = snd_ac97_ymf753_get_speaker, - .put = snd_ac97_ymf753_put_speaker, -}; - -/* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */ -static int snd_ac97_ymf753_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - static char *texts[2] = { "AC-Link", "A/D Converter" }; - - 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_ac97_ymf753_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - val = ac97->regs[AC97_YMF753_DIT_CTRL2]; - ucontrol->value.enumerated.item[0] = (val >> 1) & 1; - return 0; -} - -static int snd_ac97_ymf753_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - if (ucontrol->value.enumerated.item[0] > 1) - return -EINVAL; - val = ucontrol->value.enumerated.item[0] << 1; - return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val); -} - -/* The AC'97 spec states that the S/PDIF signal is to be output at pin 48. - The YMF753 will output the S/PDIF signal to pin 43, 47 (EAPD), or 48. - By default, no output pin is selected, and the S/PDIF signal is not output. - There is also a bit to mute S/PDIF output in a vendor-specific register. */ -static int snd_ac97_ymf753_spdif_output_pin_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" }; - - 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 snd_ac97_ymf753_spdif_output_pin_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - val = ac97->regs[AC97_YMF753_DIT_CTRL2]; - ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0; - return 0; -} - -static int snd_ac97_ymf753_spdif_output_pin_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - if (ucontrol->value.enumerated.item[0] > 2) - return -EINVAL; - val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 : - (ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0; - return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val); - /* The following can be used to direct S/PDIF output to pin 47 (EAPD). - snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */ -} - -static const snd_kcontrol_new_t snd_ac97_ymf753_controls_spdif[3] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = snd_ac97_ymf753_spdif_source_info, - .get = snd_ac97_ymf753_spdif_source_get, - .put = snd_ac97_ymf753_spdif_source_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Output Pin", - .info = snd_ac97_ymf753_spdif_output_pin_info, - .get = snd_ac97_ymf753_spdif_output_pin_get, - .put = snd_ac97_ymf753_spdif_output_pin_put, - }, - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1) -}; - - -/* - * C-Media codecs - */ - -static int snd_ac97_cmedia_spdif_playback_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - static char *texts[] = { "Analog", "Digital" }; - - 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_ac97_cmedia_spdif_playback_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - unsigned short val; - - val = ac97->regs[AC97_CM9739_SPDIF_CTRL]; - ucontrol->value.enumerated.item[0] = (val >> 1) & 0x01; - return 0; -} - -static int snd_ac97_cmedia_spdif_playback_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - - return snd_ac97_update_bits(ac97, AC97_CM9739_SPDIF_CTRL, - 0x01 << 1, - (ucontrol->value.enumerated.item[0] & 0x01) << 1); -} - -static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { - /* BIT 0: SPDI_EN - always true */ - { /* BIT 1: SPDIFS */ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = snd_ac97_cmedia_spdif_playback_source_info, - .get = snd_ac97_cmedia_spdif_playback_source_get, - .put = snd_ac97_cmedia_spdif_playback_source_put, - }, - /* BIT 2: IG_SPIV */ - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9739_SPDIF_CTRL, 2, 1, 0), - /* BIT 3: SPI2F */ - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9739_SPDIF_CTRL, 3, 1, 0), - /* BIT 4: SPI2SDI */ - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9739_SPDIF_CTRL, 4, 1, 0), - /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ -}; - -static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { - AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 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), -}; - /* * */ @@ -1420,7 +1053,7 @@ if (!(val & mask)) { /* nothing seems to be here - mute flag is not set */ /* try another test */ - snd_ac97_write_cache_test(ac97, reg, val | mask); + snd_ac97_write_cache(ac97, reg, val | mask); val = snd_ac97_read(ac97, reg); if (!(val & mask)) return 0; /* nothing here */ @@ -1428,7 +1061,7 @@ return 1; /* success, useable */ } -static int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit) +int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit) { unsigned short mask, val, orig, res; @@ -1497,7 +1130,7 @@ return x; } -static snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97) +snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97) { snd_kcontrol_new_t template; memcpy(&template, _template, sizeof(template)); @@ -1506,8 +1139,9 @@ return snd_ctl_new1(&template, ac97); } -static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97) +static int snd_ac97_mixer_build(ac97_t * ac97) { + snd_card_t *card = ac97->card; snd_kcontrol_t *kctl; const snd_kcontrol_new_t *knew; int err; @@ -1757,39 +1391,9 @@ snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x0000); /* build 3D controls */ - switch (ac97->id) { - case AC97_ID_STAC9708: - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) - return err; - strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); - kctl->private_value = AC97_3D_CONTROL | (3 << 16); - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) - return err; - strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); - kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16); - snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); - break; - case AC97_ID_STAC9700: - case AC97_ID_STAC9721: - case AC97_ID_STAC9744: - case AC97_ID_STAC9756: - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) - return err; - strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); - kctl->private_value = AC97_3D_CONTROL | (3 << 16); - snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); - break; - case AC97_ID_YMF753: - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) - return err; - strcpy(kctl->id.name, "3D Control - Wide"); - kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16); - snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) - return err; - snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); - break; - default: + if (ac97->build_ops && ac97->build_ops->build_3d) { + ac97->build_ops->build_3d(ac97); + } else { if (snd_ac97_try_volume_mix(ac97, AC97_3D_CONTROL)) { unsigned short val; val = 0x0707; @@ -1807,121 +1411,31 @@ snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); } } - + /* build S/PDIF controls */ if (ac97->ext_id & AC97_EI_SPDIF) { - if (ac97->flags & AC97_CS_SPDIF) { - for (idx = 0; idx < 3; idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) - return err; - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cirrus_controls_spdif[0], ac97))) < 0) + if (ac97->build_ops && ac97->build_ops->build_spdif) { + if ((err = ac97->build_ops->build_spdif(ac97)) < 0) return err; - switch (ac97->id & AC97_ID_CS_MASK) { - case AC97_ID_CS4205: - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cirrus_controls_spdif[1], ac97))) < 0) - return err; - break; - } - /* set default PCM S/PDIF params */ - /* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ - snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20); - } else if (ac97->flags & AC97_CX_SPDIF) { - for (idx = 0; idx < 3; idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) - return err; - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_conexant_controls_spdif[0], ac97))) < 0) - return err; - /* set default PCM S/PDIF params */ - /* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ - snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC, - snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK)); - } else { for (idx = 0; idx < 5; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0) return err; - switch (ac97->id) { - case AC97_ID_YMF753: - for (idx = 0; idx < 3; idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_spdif[idx], ac97))) < 0) - return err; - break; - case AC97_ID_AD1980: - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ad1980_spdif_source, ac97))) < 0) + if (ac97->build_ops && ac97->build_ops->build_post_spdif) { + if ((err = ac97->build_ops->build_post_spdif(ac97)) < 0) return err; - break; - case AC97_ID_CM9739: - for (idx = 0; idx < ARRAY_SIZE(snd_ac97_cm9739_controls_spdif); idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9739_controls_spdif[idx], ac97))) < 0) - return err; - break; } /* set default PCM S/PDIF params */ /* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20); } - ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF; } /* build chip specific controls */ - switch (ac97->id) { - case AC97_ID_STAC9700: - case AC97_ID_STAC9708: - case AC97_ID_STAC9721: - case AC97_ID_STAC9744: - case AC97_ID_STAC9756: - snd_ac97_write_cache_test(ac97, AC97_SIGMATEL_ANALOG, snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) & ~0x0003); - if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1)) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[0], ac97))) < 0) - return err; - if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0)) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[1], ac97))) < 0) - return err; - if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 2)) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_4speaker, ac97))) < 0) - return err; - if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 3)) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_phaseinvert, ac97))) < 0) - return err; - break; - case AC97_ID_ALC650: - /* detect ALC650 rev.E of later */ - for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_alc650); idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_alc650[idx], ac97))) < 0) - return err; - if ((err = snd_ctl_add(card, snd_ac97_cnew(ac97->spec.dev_flags ? - &snd_ac97_control_alc650_mic : - &snd_ac97_control_alc650_mic_gpio, ac97))) < 0) - return err; - if (ac97->ext_id & AC97_EI_SPDIF) { - for (idx = 0; idx < ARRAY_SIZE(snd_ac97_spdif_controls_alc650); idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_spdif_controls_alc650[idx], ac97))) < 0) - return err; - } - break; - case AC97_ID_VT1616: - if (snd_ac97_try_bit(ac97, 0x5a, 9)) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_vt1616[0], ac97))) < 0) - return err; - for (idx = 1; idx < ARRAY_SIZE(snd_ac97_controls_vt1616); idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_vt1616[idx], ac97))) < 0) - return err; - break; - case AC97_ID_CM9739: - for (idx = 1; idx < ARRAY_SIZE(snd_ac97_cm9739_controls); idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9739_controls[idx], ac97))) < 0) - return err; - break; - case AC97_ID_CM9738: - for (idx = 1; idx < ARRAY_SIZE(snd_ac97_cm9738_controls); idx++) - if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_cm9738_controls[idx], ac97))) < 0) - return err; - break; - default: - /* nothing */ - break; - } + if (ac97->build_ops && ac97->build_ops->build_specific) + if ((err = ac97->build_ops->build_specific(ac97)) < 0) + return err; if (snd_ac97_try_bit(ac97, AC97_POWERDOWN, 15)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_eapd, ac97))) < 0) @@ -1943,7 +1457,7 @@ unsigned int tmp; tmp = ((unsigned int)rate * ac97->clock) / 48000; - snd_ac97_write_cache_test(ac97, reg, tmp & 0xffff); + snd_ac97_write_cache(ac97, reg, tmp & 0xffff); val = snd_ac97_read(ac97, reg); return val == (tmp & 0xffff); } @@ -1973,7 +1487,7 @@ *r_result = result; } -static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem) +void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem) { const ac97_codec_id_t *pid; @@ -2150,12 +1664,12 @@ /* FIXME: add powerdown control */ if (ac97_is_audio(ac97)) { /* nothing should be in powerdown mode */ - snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0); - snd_ac97_write_cache_test(ac97, AC97_RESET, 0); /* reset to defaults */ + snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0); + snd_ac97_write_cache(ac97, AC97_RESET, 0); /* reset to defaults */ udelay(100); /* nothing should be in powerdown mode */ - snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0); - snd_ac97_write_cache_test(ac97, AC97_GENERAL_PURPOSE, 0); + snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0); + snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0); end_time = jiffies + (HZ / 10); do { if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) @@ -2224,10 +1738,10 @@ snd_ac97_free(ac97); return err; } - } - if (ac97_is_audio(ac97) && snd_ac97_mixer_build(card, ac97) < 0) { - snd_ac97_free(ac97); - return -ENOMEM; + if (snd_ac97_mixer_build(ac97) < 0) { + snd_ac97_free(ac97); + return -ENOMEM; + } } snd_ac97_proc_init(card, ac97, "ac97"); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) { @@ -2369,21 +1883,21 @@ /* 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_test(ac97, AC97_LINE1_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; } if (ac97->ext_mid & AC97_MEI_LINE2) { - snd_ac97_write_cache_test(ac97, AC97_LINE2_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; } if (ac97->ext_mid & AC97_MEI_HANDSET) { - snd_ac97_write_cache_test(ac97, AC97_HANDSET_RATE, 12000); + snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; } - snd_ac97_write_cache_test(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); udelay(100); /* nothing should be in powerdown mode */ - snd_ac97_write_cache_test(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); end_time = jiffies + (HZ / 10); do { if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) @@ -2431,270 +1945,6 @@ } *rac97 = ac97; return 0; -} - -/* - * proc interface - */ - -static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx) -{ - char name[64]; - unsigned int id; - unsigned short val, tmp, ext, mext; - static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" }; - static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" }; - static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" }; - - id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; - id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); - snd_ac97_get_name(NULL, id, name, 0); - snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name); - if ((ac97->scaps & AC97_SCAP_AUDIO) == 0) - goto __modem; - - // val = snd_ac97_read(ac97, AC97_RESET); - val = ac97->caps; - snd_iprintf(buffer, "Capabilities :%s%s%s%s%s%s\n", - val & AC97_BC_DEDICATED_MIC ? " -dedicated MIC PCM IN channel-" : "", - val & AC97_BC_RESERVED1 ? " -reserved1-" : "", - val & AC97_BC_BASS_TREBLE ? " -bass & treble-" : "", - val & AC97_BC_SIM_STEREO ? " -simulated stereo-" : "", - val & AC97_BC_HEADPHONE ? " -headphone out-" : "", - val & AC97_BC_LOUDNESS ? " -loudness-" : ""); - tmp = ac97->caps & AC97_BC_DAC_MASK; - snd_iprintf(buffer, "DAC resolution : %s%s%s%s\n", - tmp == AC97_BC_16BIT_DAC ? "16-bit" : "", - tmp == AC97_BC_18BIT_DAC ? "18-bit" : "", - tmp == AC97_BC_20BIT_DAC ? "20-bit" : "", - tmp == AC97_BC_DAC_MASK ? "???" : ""); - tmp = ac97->caps & AC97_BC_ADC_MASK; - snd_iprintf(buffer, "ADC resolution : %s%s%s%s\n", - tmp == AC97_BC_16BIT_ADC ? "16-bit" : "", - tmp == AC97_BC_18BIT_ADC ? "18-bit" : "", - tmp == AC97_BC_20BIT_ADC ? "20-bit" : "", - tmp == AC97_BC_ADC_MASK ? "???" : ""); - snd_iprintf(buffer, "3D enhancement : %s\n", - snd_ac97_stereo_enhancements[(val >> 10) & 0x1f]); - snd_iprintf(buffer, "\nCurrent setup\n"); - val = snd_ac97_read(ac97, AC97_MIC); - snd_iprintf(buffer, "Mic gain : %s [%s]\n", val & 0x0040 ? "+20dB" : "+0dB", ac97->regs[AC97_MIC] & 0x0040 ? "+20dB" : "+0dB"); - val = snd_ac97_read(ac97, AC97_GENERAL_PURPOSE); - snd_iprintf(buffer, "POP path : %s 3D\n" - "Sim. stereo : %s\n" - "3D enhancement : %s\n" - "Loudness : %s\n" - "Mono output : %s\n" - "Mic select : %s\n" - "ADC/DAC loopback : %s\n", - val & 0x8000 ? "post" : "pre", - val & 0x4000 ? "on" : "off", - val & 0x2000 ? "on" : "off", - val & 0x1000 ? "on" : "off", - val & 0x0200 ? "Mic" : "MIX", - val & 0x0100 ? "Mic2" : "Mic1", - val & 0x0080 ? "on" : "off"); - - ext = snd_ac97_read(ac97, AC97_EXTENDED_ID); - if (ext == 0) - goto __modem; - - snd_iprintf(buffer, "Extended ID : codec=%i rev=%i%s%s%s%s DSA=%i%s%s%s%s\n", - (ext & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT, - (ext & AC97_EI_REV_MASK) >> AC97_EI_REV_SHIFT, - ext & AC97_EI_AMAP ? " AMAP" : "", - ext & AC97_EI_LDAC ? " LDAC" : "", - ext & AC97_EI_SDAC ? " SDAC" : "", - ext & AC97_EI_CDAC ? " CDAC" : "", - (ext & AC97_EI_DACS_SLOT_MASK) >> AC97_EI_DACS_SLOT_SHIFT, - ext & AC97_EI_VRM ? " VRM" : "", - ext & AC97_EI_SPDIF ? " SPDIF" : "", - ext & AC97_EI_DRA ? " DRA" : "", - ext & AC97_EI_VRA ? " VRA" : ""); - val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); - snd_iprintf(buffer, "Extended status :%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - val & AC97_EA_PRL ? " PRL" : "", - val & AC97_EA_PRK ? " PRK" : "", - val & AC97_EA_PRJ ? " PRJ" : "", - val & AC97_EA_PRI ? " PRI" : "", - val & AC97_EA_SPCV ? " SPCV" : "", - val & AC97_EA_MDAC ? " MADC" : "", - val & AC97_EA_LDAC ? " LDAC" : "", - val & AC97_EA_SDAC ? " SDAC" : "", - val & AC97_EA_CDAC ? " CDAC" : "", - ext & AC97_EI_SPDIF ? spdif_slots[(val & AC97_EA_SPSA_SLOT_MASK) >> AC97_EA_SPSA_SLOT_SHIFT] : "", - val & AC97_EA_VRM ? " VRM" : "", - val & AC97_EA_SPDIF ? " SPDIF" : "", - val & AC97_EA_DRA ? " DRA" : "", - val & AC97_EA_VRA ? " VRA" : ""); - if (ext & AC97_EI_VRA) { /* VRA */ - val = snd_ac97_read(ac97, AC97_PCM_FRONT_DAC_RATE); - snd_iprintf(buffer, "PCM front DAC : %iHz\n", val); - if (ext & AC97_EI_SDAC) { - val = snd_ac97_read(ac97, AC97_PCM_SURR_DAC_RATE); - snd_iprintf(buffer, "PCM Surr DAC : %iHz\n", val); - } - if (ext & AC97_EI_LDAC) { - val = snd_ac97_read(ac97, AC97_PCM_LFE_DAC_RATE); - snd_iprintf(buffer, "PCM LFE DAC : %iHz\n", val); - } - val = snd_ac97_read(ac97, AC97_PCM_LR_ADC_RATE); - snd_iprintf(buffer, "PCM ADC : %iHz\n", val); - } - if (ext & AC97_EI_VRM) { - val = snd_ac97_read(ac97, AC97_PCM_MIC_ADC_RATE); - snd_iprintf(buffer, "PCM MIC ADC : %iHz\n", val); - } - if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF)) { - if (ac97->flags & AC97_CS_SPDIF) - val = snd_ac97_read(ac97, AC97_CSR_SPDIF); - else - val = snd_ac97_read(ac97, AC97_SPDIF); - - snd_iprintf(buffer, "SPDIF Control :%s%s%s%s Category=0x%x Generation=%i%s%s%s\n", - val & AC97_SC_PRO ? " PRO" : " Consumer", - val & AC97_SC_NAUDIO ? " Non-audio" : " PCM", - val & AC97_SC_COPY ? " Copyright" : "", - val & AC97_SC_PRE ? " Preemph50/15" : "", - (val & AC97_SC_CC_MASK) >> AC97_SC_CC_SHIFT, - (val & AC97_SC_L) >> 11, - (ac97->flags & AC97_CS_SPDIF) ? - spdif_rates_cs4205[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT] : - spdif_rates[(val & AC97_SC_SPSR_MASK) >> AC97_SC_SPSR_SHIFT], - (ac97->flags & AC97_CS_SPDIF) ? - (val & AC97_SC_DRS ? " Validity" : "") : - (val & AC97_SC_DRS ? " DRS" : ""), - (ac97->flags & AC97_CS_SPDIF) ? - (val & AC97_SC_V ? " Enabled" : "") : - (val & AC97_SC_V ? " Validity" : "")); - } - - __modem: - mext = snd_ac97_read(ac97, AC97_EXTENDED_MID); - if (mext == 0) - return; - - snd_iprintf(buffer, "Extended modem ID: codec=%i%s%s%s%s%s\n", - (mext & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT, - mext & AC97_MEI_CID2 ? " CID2" : "", - mext & AC97_MEI_CID1 ? " CID1" : "", - mext & AC97_MEI_HANDSET ? " HSET" : "", - mext & AC97_MEI_LINE2 ? " LIN2" : "", - mext & AC97_MEI_LINE1 ? " LIN1" : ""); - val = snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS); - snd_iprintf(buffer, "Modem status :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - val & AC97_MEA_GPIO ? " GPIO" : "", - val & AC97_MEA_MREF ? " MREF" : "", - val & AC97_MEA_ADC1 ? " ADC1" : "", - val & AC97_MEA_DAC1 ? " DAC1" : "", - val & AC97_MEA_ADC2 ? " ADC2" : "", - val & AC97_MEA_DAC2 ? " DAC2" : "", - val & AC97_MEA_HADC ? " HADC" : "", - val & AC97_MEA_HDAC ? " HDAC" : "", - val & AC97_MEA_PRA ? " PRA(GPIO)" : "", - val & AC97_MEA_PRB ? " PRB(res)" : "", - val & AC97_MEA_PRC ? " PRC(ADC1)" : "", - val & AC97_MEA_PRD ? " PRD(DAC1)" : "", - val & AC97_MEA_PRE ? " PRE(ADC2)" : "", - val & AC97_MEA_PRF ? " PRF(DAC2)" : "", - val & AC97_MEA_PRG ? " PRG(HADC)" : "", - val & AC97_MEA_PRH ? " PRH(HDAC)" : ""); - if (mext & AC97_MEI_LINE1) { - val = snd_ac97_read(ac97, AC97_LINE1_RATE); - snd_iprintf(buffer, "Line1 rate : %iHz\n", val); - } - if (mext & AC97_MEI_LINE2) { - val = snd_ac97_read(ac97, AC97_LINE2_RATE); - snd_iprintf(buffer, "Line2 rate : %iHz\n", val); - } - if (mext & AC97_MEI_HANDSET) { - val = snd_ac97_read(ac97, AC97_HANDSET_RATE); - snd_iprintf(buffer, "Headset rate : %iHz\n", val); - } -} - -static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) -{ - ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); - - if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 - int idx; - down(&ac97->spec.ad18xx.mutex); - for (idx = 0; idx < 3; idx++) - if (ac97->spec.ad18xx.id[idx]) { - /* select single codec */ - snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]); - snd_ac97_proc_read_main(ac97, buffer, idx); - snd_iprintf(buffer, "\n\n"); - } - /* select all codecs */ - snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); - up(&ac97->spec.ad18xx.mutex); - - snd_iprintf(buffer, "\nAD18XX configuration\n"); - snd_iprintf(buffer, "Unchained : 0x%04x,0x%04x,0x%04x\n", - ac97->spec.ad18xx.unchained[0], - ac97->spec.ad18xx.unchained[1], - ac97->spec.ad18xx.unchained[2]); - snd_iprintf(buffer, "Chained : 0x%04x,0x%04x,0x%04x\n", - ac97->spec.ad18xx.chained[0], - ac97->spec.ad18xx.chained[1], - ac97->spec.ad18xx.chained[2]); - } else { - snd_ac97_proc_read_main(ac97, buffer, 0); - } -} - -static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx) -{ - int reg, val; - - for (reg = 0; reg < 0x80; reg += 2) { - val = snd_ac97_read(ac97, reg); - snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val); - } -} - -static void snd_ac97_proc_regs_read(snd_info_entry_t *entry, - snd_info_buffer_t * buffer) -{ - ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); - - if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 - - int idx; - down(&ac97->spec.ad18xx.mutex); - for (idx = 0; idx < 3; idx++) - if (ac97->spec.ad18xx.id[idx]) { - /* select single codec */ - snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]); - snd_ac97_proc_regs_read_main(ac97, buffer, idx); - } - /* select all codecs */ - snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); - up(&ac97->spec.ad18xx.mutex); - } else { - snd_ac97_proc_regs_read_main(ac97, buffer, 0); - } -} - -static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix) -{ - snd_info_entry_t *entry; - char name[32]; - - if (ac97->num) - sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); - else - sprintf(name, "%s#%d", prefix, ac97->addr); - if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read); - if (ac97->num) - sprintf(name, "%s#%d-%dregs", prefix, ac97->addr, ac97->num); - else - sprintf(name, "%s#%dregs", prefix, ac97->addr); - if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); } /* Index: ac97_patch.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/pci/ac97/ac97_patch.c,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- ac97_patch.c 6 Jun 2003 09:29:17 -0000 1.15 +++ ac97_patch.c 17 Jun 2003 18:43:32 -0000 1.16 @@ -3,7 +3,8 @@ * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 - * by Intel Corporation (http://developer.intel.com). + * by Intel Corporation (http://developer.intel.com) and to datasheets + * for specific codecs. * * * This program is free software; you can redistribute it and/or modify @@ -28,15 +29,203 @@ #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> +#include <sound/control.h> #include <sound/ac97_codec.h> -#include <sound/asoundef.h> -#include <sound/initval.h> #include "ac97_patch.h" +#include "ac97_id.h" +#include "ac97_local.h" + +#define chip_t ac97_t /* * Chip specific initialization */ +static int patch_build_controls(ac97_t * ac97, const snd_kcontrol_new_t *controls, int count) +{ + int idx, err; + + for (idx = 0; idx < count; idx++) + if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&controls[idx], ac97))) < 0) + return err; + return 0; +} + +/* The following snd_ac97_ymf753_... items added by David Shust ([EMAIL PROTECTED]) */ + +/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ +static int snd_ac97_ymf753_info_speaker(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[3] = { + "Standard", "Small", "Smaller" + }; + + 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 snd_ac97_ymf753_get_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_YMF753_3D_MODE_SEL]; + val = (val >> 10) & 3; + if (val > 0) /* 0 = invalid */ + val--; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int snd_ac97_ymf753_put_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + if (ucontrol->value.enumerated.item[0] > 2) + return -EINVAL; + val = (ucontrol->value.enumerated.item[0] + 1) << 10; + return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val); +} + +static const snd_kcontrol_new_t snd_ac97_ymf753_controls_speaker = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "3D Control - Speaker", + .info = snd_ac97_ymf753_info_speaker, + .get = snd_ac97_ymf753_get_speaker, + .put = snd_ac97_ymf753_put_speaker, +}; + +/* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */ +static int snd_ac97_ymf753_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[2] = { "AC-Link", "A/D Converter" }; + + 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_ac97_ymf753_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_YMF753_DIT_CTRL2]; + ucontrol->value.enumerated.item[0] = (val >> 1) & 1; + return 0; +} + +static int snd_ac97_ymf753_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + if (ucontrol->value.enumerated.item[0] > 1) + return -EINVAL; + val = ucontrol->value.enumerated.item[0] << 1; + return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val); +} + +/* The AC'97 spec states that the S/PDIF signal is to be output at pin 48. + The YMF753 will output the S/PDIF signal to pin 43, 47 (EAPD), or 48. + By default, no output pin is selected, and the S/PDIF signal is not output. + There is also a bit to mute S/PDIF output in a vendor-specific register. */ +static int snd_ac97_ymf753_spdif_output_pin_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" }; + + 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 snd_ac97_ymf753_spdif_output_pin_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_YMF753_DIT_CTRL2]; + ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0; + return 0; +} + +static int snd_ac97_ymf753_spdif_output_pin_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + if (ucontrol->value.enumerated.item[0] > 2) + return -EINVAL; + val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 : + (ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0; + return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val); + /* The following can be used to direct S/PDIF output to pin 47 (EAPD). + snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */ +} + +static const snd_kcontrol_new_t snd_ac97_ymf753_controls_spdif[3] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", + .info = snd_ac97_ymf753_spdif_source_info, + .get = snd_ac97_ymf753_spdif_source_get, + .put = snd_ac97_ymf753_spdif_source_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Output Pin", + .info = snd_ac97_ymf753_spdif_output_pin_info, + .get = snd_ac97_ymf753_spdif_output_pin_get, + .put = snd_ac97_ymf753_spdif_output_pin_put, + }, + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1) +}; + +static int patch_yamaha_ymf753_3d(ac97_t * ac97) +{ + snd_kcontrol_t *kctl; + int err; + + if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + return err; + strcpy(kctl->id.name, "3D Control - Wide"); + kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16); + snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); + if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) + return err; + snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); + return 0; +} + +static int patch_yamaha_ymf753_post_spdif(ac97_t * ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, snd_ac97_ymf753_controls_spdif, ARRAY_SIZE(snd_ac97_ymf753_controls_spdif))) < 0) + return err; + return 0; +} + +static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { + .build_3d = patch_yamaha_ymf753_3d, + .build_post_spdif = patch_yamaha_ymf753_post_spdif +}; + int patch_yamaha_ymf753(ac97_t * ac97) { /* Patch for Yamaha YMF753, Copyright (c) by David Shust, [EMAIL PROTECTED] @@ -46,6 +235,7 @@ By default, no output pin is selected, and the S/PDIF signal is not output. There is also a bit to mute S/PDIF output in a vendor-specific register. */ + ac97->build_ops = &patch_yamaha_ymf753_ops; ac97->caps |= AC97_BC_BASS_TREBLE; ac97->caps |= 0x04 << 10; /* Yamaha 3D enhancement */ return 0; @@ -57,12 +247,6 @@ * added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. */ -#define AC97_WM97XX_FMIXER_VOL 0x72 -#define AC97_WM9704_RMIXER_VOL 0x74 -#define AC97_WM9704_TEST 0x5a -#define AC97_WM9704_RPCM_VOL 0x70 -#define AC97_WM9711_OUT3VOL 0x16 - int patch_wolfson03(ac97_t * ac97) { /* This is known to work for the ViewSonic ViewPad 1000 @@ -117,10 +301,89 @@ return 0; } +static int patch_sigmatel_stac9700_3d(ac97_t * ac97) +{ + snd_kcontrol_t *kctl; + int err; + + if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + return err; + strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); + kctl->private_value = AC97_3D_CONTROL | (3 << 16); + snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); + return 0; +} + +static int patch_sigmatel_stac9708_3d(ac97_t * ac97) +{ + snd_kcontrol_t *kctl; + int err; + + if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + return err; + strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); + kctl->private_value = AC97_3D_CONTROL | (3 << 16); + if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + return err; + strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); + kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16); + snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); + return 0; +} + +static const snd_kcontrol_new_t snd_ac97_sigmatel_4speaker = +AC97_SINGLE("Sigmatel 4-Speaker Stereo Playback Switch", AC97_SIGMATEL_DAC2INVERT, 2, 1, 0); + +static const snd_kcontrol_new_t snd_ac97_sigmatel_phaseinvert = +AC97_SINGLE("Sigmatel Surround Phase Inversion Playback Switch", AC97_SIGMATEL_DAC2INVERT, 3, 1, 0); + +static const snd_kcontrol_new_t snd_ac97_sigmatel_controls[] = { +AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0), +AC97_SINGLE("Sigmatel ADC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 0, 1, 0) +}; + +static int patch_sigmatel_stac97xx_specific(ac97_t * ac97) +{ + int err; + + snd_ac97_write_cache(ac97, AC97_SIGMATEL_ANALOG, snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) & ~0x0003); + if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1)) + if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[0], 1)) < 0) + return err; + if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0)) + if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[1], 1)) < 0) + return err; + if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 2)) + if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_4speaker, 1)) < 0) + return err; + if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 3)) + if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_phaseinvert, 1)) < 0) + return err; + return 0; +} + +static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = { + .build_3d = patch_sigmatel_stac9700_3d, + .build_specific = patch_sigmatel_stac97xx_specific +}; + +static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = { + .build_3d = patch_sigmatel_stac9708_3d, + .build_specific = patch_sigmatel_stac97xx_specific +}; + +int patch_sigmatel_stac9700(ac97_t * ac97) +{ + ac97->build_ops = &patch_sigmatel_stac9700_ops; + return 0; +} + int patch_sigmatel_stac9708(ac97_t * ac97) { unsigned int codec72, codec6c; + ac97->build_ops = &patch_sigmatel_stac9708_ops; + codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000; codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG); @@ -142,6 +405,7 @@ int patch_sigmatel_stac9721(ac97_t * ac97) { + ac97->build_ops = &patch_sigmatel_stac9700_ops; if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) { // patch for SigmaTel snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); @@ -156,6 +420,7 @@ int patch_sigmatel_stac9744(ac97_t * ac97) { // patch for SigmaTel + ac97->build_ops = &patch_sigmatel_stac9700_ops; snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */ snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba); @@ -167,6 +432,7 @@ int patch_sigmatel_stac9756(ac97_t * ac97) { // patch for SigmaTel + ac97->build_ops = &patch_sigmatel_stac9700_ops; snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */ snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba); @@ -175,6 +441,35 @@ return 0; } +static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = { + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0), + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0) +}; + +static int patch_cirrus_build_spdif(ac97_t * ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0) + return err; + if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1)) < 0) + return err; + switch (ac97->id & AC97_ID_CS_MASK) { + case AC97_ID_CS4205: + if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[1], 1)) < 0) + return err; + break; + } + /* set default PCM S/PDIF params */ + /* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ + snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20); + return 0; +} + +static struct snd_ac97_build_ops patch_cirrus_ops = { + .build_spdif = patch_cirrus_build_spdif +}; + int patch_cirrus_spdif(ac97_t * ac97) { /* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers. @@ -188,6 +483,7 @@ - sp/dif ssource select is in 0x5e bits 0,1. */ + ac97->build_ops = &patch_cirrus_ops; ac97->flags |= AC97_CS_SPDIF; ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000; ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ @@ -203,8 +499,32 @@ return patch_cirrus_spdif(ac97); } +static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[1] = { + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0), +}; + +static int patch_conexant_build_spdif(ac97_t * ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0) + return err; + if ((err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1)) < 0) + return err; + /* set default PCM S/PDIF params */ + /* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ + snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC, + snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK)); + return 0; +} + +static struct snd_ac97_build_ops patch_conexant_ops = { + .build_spdif = patch_conexant_build_spdif +}; + int patch_conexant(ac97_t * ac97) { + ac97->build_ops = &patch_conexant_ops; ac97->flags |= AC97_CX_SPDIF; ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ return 0; @@ -353,11 +673,63 @@ return 0; } +static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[2] = { "AC-Link", "A/D Converter" }; + + 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_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_SERIAL_CFG]; + ucontrol->value.enumerated.item[0] = (val >> 2) & 1; + return 0; +} + +static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + if (ucontrol->value.enumerated.item[0] > 1) + return -EINVAL; + val = ucontrol->value.enumerated.item[0] << 2; + return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val); +} + +static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", + .info = snd_ac97_ad1980_spdif_source_info, + .get = snd_ac97_ad1980_spdif_source_get, + .put = snd_ac97_ad1980_spdif_source_put, +}; + +static int patch_ad1980_post_spdif(ac97_t * ac97) +{ + return patch_build_controls(ac97, &snd_ac97_ad1980_spdif_source, 1); +} + +static struct snd_ac97_build_ops patch_ad1980_build_ops = { + .build_post_spdif = &patch_ad1980_post_spdif +}; + int patch_ad1980(ac97_t * ac97) { unsigned short misc; patch_ad1881(ac97); + ac97->build_ops = &patch_ad1980_build_ops; /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ /* it seems that most vendors connect line-out connector to headphone out of AC'97 */ misc = snd_ac97_read(ac97, AC97_AD_MISC); @@ -365,6 +737,92 @@ return 0; } +static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { + AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), + AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0), + AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0), + AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0), + /* 4: Analog Input To Surround */ + /* 5: Analog Input To Center/LFE */ + /* 6: Independent Master Volume Right */ + /* 7: Independent Master Volume Left */ + /* 8: reserved */ + AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), + AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), +#if 0 /* always set in patch_alc650 */ + AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), + AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0), + AC97_SINGLE("Surround DAC Switch", AC97_ALC650_SURR_DAC_VOL, 15, 1, 1), + AC97_DOUBLE("Surround DAC Volume", AC97_ALC650_SURR_DAC_VOL, 8, 0, 31, 1), + 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 +}; + +static const snd_kcontrol_new_t snd_ac97_control_alc650_mic = +AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0); + +static int snd_ac97_alc650_mic_gpio_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_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + int change; + change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, + ucontrol->value.integer.value[0] ? (1 << 10) : 0); + if (change) { + /* GPIO0 write for mic */ + snd_ac97_update_bits(ac97, 0x76, 0x01, + ucontrol->value.integer.value[0] ? 0 : 0x01); + /* GPIO0 high for mic */ + snd_ac97_update_bits(ac97, 0x78, 0x100, + ucontrol->value.integer.value[0] ? 0 : 0x100); + } + return change; +} + +static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic As Center/LFE", + .info = snd_ac97_info_single, + .get = snd_ac97_alc650_mic_gpio_get, + .put = snd_ac97_alc650_mic_gpio_put, + .private_value = (1 << 16), /* for info */ +}; + +static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { + AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), + AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0), + AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), +}; + +static int patch_alc650_specific(ac97_t * ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650))) < 0) + return err; + if ((err = patch_build_controls(ac97, + ac97->spec.dev_flags ? + &snd_ac97_control_alc650_mic : + &snd_ac97_control_alc650_mic_gpio, 1)) < 0) + return err; + if (ac97->ext_id & AC97_EI_SPDIF) { + if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) + return err; + } + return 0; +} + +static struct snd_ac97_build_ops patch_alc650_ops = { + .build_specific = patch_alc650_specific +}; + int patch_alc650(ac97_t * ac97) { unsigned short val; @@ -374,6 +832,7 @@ * this is used for switching mic and center/lfe, which needs * resetting GPIO0 level on the older revision. */ + ac97->build_ops = &patch_alc650_ops; ac97->spec.dev_flags = 0; /* check spdif (should be only on rev.E) */ @@ -417,10 +876,101 @@ return 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), +}; + +static int patch_cm9738_specific(ac97_t * ac97) +{ + return patch_build_controls(ac97, snd_ac97_cm9738_controls, ARRAY_SIZE(snd_ac97_cm9738_controls)); +} + +static struct snd_ac97_build_ops patch_cm9738_ops = { + .build_specific = patch_cm9738_specific +}; + +int patch_cm9738(ac97_t * ac97) +{ + ac97->build_ops = &patch_cm9738_ops; + return 0; +} + +static int snd_ac97_cmedia_spdif_playback_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "Analog", "Digital" }; + + 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_ac97_cmedia_spdif_playback_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_CM9739_SPDIF_CTRL]; + ucontrol->value.enumerated.item[0] = (val >> 1) & 0x01; + return 0; +} + +static int snd_ac97_cmedia_spdif_playback_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + return snd_ac97_update_bits(ac97, AC97_CM9739_SPDIF_CTRL, + 0x01 << 1, + (ucontrol->value.enumerated.item[0] & 0x01) << 1); +} + +static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { + /* BIT 0: SPDI_EN - always true */ + { /* BIT 1: SPDIFS */ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", + .info = snd_ac97_cmedia_spdif_playback_source_info, + .get = snd_ac97_cmedia_spdif_playback_source_get, + .put = snd_ac97_cmedia_spdif_playback_source_put, + }, + /* BIT 2: IG_SPIV */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9739_SPDIF_CTRL, 2, 1, 0), + /* BIT 3: SPI2F */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9739_SPDIF_CTRL, 3, 1, 0), + /* BIT 4: SPI2SDI */ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9739_SPDIF_CTRL, 4, 1, 0), + /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ +}; + +static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { + AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), +}; + +static int patch_cm9739_specific(ac97_t * ac97) +{ + return patch_build_controls(ac97, snd_ac97_cm9739_controls, ARRAY_SIZE(snd_ac97_cm9739_controls)); +} + +static int patch_cm9739_post_spdif(ac97_t * ac97) +{ + return patch_build_controls(ac97, snd_ac97_cm9739_controls_spdif, ARRAY_SIZE(snd_ac97_cm9739_controls_spdif)); +} + +static struct snd_ac97_build_ops patch_cm9739_ops = { + .build_specific = patch_cm9739_specific, + .build_post_spdif = patch_cm9739_post_spdif +}; + int patch_cm9739(ac97_t * ac97) { unsigned short val; + ac97->build_ops = &patch_cm9739_ops; + /* check spdif */ val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); if (val & AC97_EA_SPCV) { @@ -444,3 +994,31 @@ return 0; } +static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = { +AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0), +AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0), +AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0), +AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), +}; + +static int patch_vt1616_specific(ac97_t * ac97) +{ + int err; + + if (snd_ac97_try_bit(ac97, 0x5a, 9)) + if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[0], 1)) < 0) + return err; + if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) + return err; + return 0; +} + +static struct snd_ac97_build_ops patch_vt1616_ops = { + .build_specific = patch_vt1616_specific +}; + +int patch_vt1616(ac97_t * ac97) +{ + ac97->build_ops = &patch_vt1616_ops; + return 0; +} Index: ac97_patch.h =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/pci/ac97/ac97_patch.h,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- ac97_patch.h 5 May 2003 14:28:23 -0000 1.7 +++ ac97_patch.h 17 Jun 2003 18:43:32 -0000 1.8 @@ -29,6 +29,7 @@ int patch_wolfson05(ac97_t * ac97); int patch_wolfson11(ac97_t * ac97); int patch_tritech_tr28028(ac97_t * ac97); +int patch_sigmatel_stac9700(ac97_t * ac97); int patch_sigmatel_stac9708(ac97_t * ac97); int patch_sigmatel_stac9721(ac97_t * ac97); int patch_sigmatel_stac9744(ac97_t * ac97); @@ -42,4 +43,6 @@ int patch_ad1886(ac97_t * ac97); int patch_ad1980(ac97_t * ac97); int patch_alc650(ac97_t * ac97); +int patch_cm9738(ac97_t * ac97); int patch_cm9739(ac97_t * ac97); +int patch_vt1616(ac97_t * ac97); ------------------------------------------------------- This SF.Net email is sponsored by: INetU Attention Web Developers & Consultants: Become An INetU Hosting Partner. Refer Dedicated Servers. We Manage Them. You Get 10% Monthly Commission! INetU Dedicated Managed Hosting http://www.inetu.net/partner/index.php _______________________________________________ Alsa-cvslog mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-cvslog