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

Reply via email to