ALSA: hda: add model for Intel DG45ID/DG45FC boards
[safe/jmp/linux-2.6] / sound / pci / hda / patch_sigmatel.c
index 9acf2f0..6990cfc 100644 (file)
@@ -43,6 +43,7 @@ enum {
 };
 
 enum {
+       STAC_AUTO,
        STAC_REF,
        STAC_9200_OQO,
        STAC_9200_DELL_D21,
@@ -55,22 +56,27 @@ enum {
        STAC_9200_DELL_M25,
        STAC_9200_DELL_M26,
        STAC_9200_DELL_M27,
-       STAC_9200_GATEWAY,
+       STAC_9200_M4,
+       STAC_9200_M4_2,
        STAC_9200_PANASONIC,
        STAC_9200_MODELS
 };
 
 enum {
+       STAC_9205_AUTO,
        STAC_9205_REF,
        STAC_9205_DELL_M42,
        STAC_9205_DELL_M43,
        STAC_9205_DELL_M44,
+       STAC_9205_EAPD,
        STAC_9205_MODELS
 };
 
 enum {
+       STAC_92HD73XX_AUTO,
        STAC_92HD73XX_NO_JD, /* no jack-detection */
        STAC_92HD73XX_REF,
+       STAC_92HD73XX_INTEL,
        STAC_DELL_M6_AMIC,
        STAC_DELL_M6_DMIC,
        STAC_DELL_M6_BOTH,
@@ -79,28 +85,41 @@ enum {
 };
 
 enum {
+       STAC_92HD83XXX_AUTO,
        STAC_92HD83XXX_REF,
+       STAC_92HD83XXX_PWR_REF,
+       STAC_DELL_S14,
        STAC_92HD83XXX_MODELS
 };
 
 enum {
+       STAC_92HD71BXX_AUTO,
        STAC_92HD71BXX_REF,
        STAC_DELL_M4_1,
        STAC_DELL_M4_2,
        STAC_DELL_M4_3,
        STAC_HP_M4,
+       STAC_HP_DV5,
+       STAC_HP_HDX,
+       STAC_HP_DV4_1222NR,
        STAC_92HD71BXX_MODELS
 };
 
 enum {
+       STAC_925x_AUTO,
        STAC_925x_REF,
+       STAC_M1,
+       STAC_M1_2,
+       STAC_M2,
        STAC_M2_2,
-       STAC_MA6,
-       STAC_PA6,
+       STAC_M3,
+       STAC_M5,
+       STAC_M6,
        STAC_925x_MODELS
 };
 
 enum {
+       STAC_922X_AUTO,
        STAC_D945_REF,
        STAC_D945GTP3,
        STAC_D945GTP5,
@@ -128,15 +147,23 @@ enum {
 };
 
 enum {
+       STAC_927X_AUTO,
        STAC_D965_REF_NO_JD, /* no jack-detection */
        STAC_D965_REF,
        STAC_D965_3ST,
        STAC_D965_5ST,
+       STAC_D965_5ST_NO_FP,
        STAC_DELL_3ST,
        STAC_DELL_BIOS,
        STAC_927X_MODELS
 };
 
+enum {
+       STAC_9872_AUTO,
+       STAC_9872_VAIO,
+       STAC_9872_MODELS
+};
+
 struct sigmatel_event {
        hda_nid_t nid;
        unsigned char type;
@@ -160,6 +187,7 @@ struct sigmatel_spec {
        unsigned int alt_switch: 1;
        unsigned int hp_detect: 1;
        unsigned int spdif_mute: 1;
+       unsigned int check_volume_offset:1;
 
        /* gpio lines */
        unsigned int eapd_mask;
@@ -167,11 +195,13 @@ struct sigmatel_spec {
        unsigned int gpio_dir;
        unsigned int gpio_data;
        unsigned int gpio_mute;
+       unsigned int gpio_led;
 
        /* stream */
        unsigned int stream_delay;
 
        /* analog loopback */
+       struct snd_kcontrol_new *aloopback_ctl;
        unsigned char aloopback_mask;
        unsigned char aloopback_shift;
 
@@ -196,6 +226,8 @@ struct sigmatel_spec {
        hda_nid_t hp_dacs[5];
        hda_nid_t speaker_dacs[5];
 
+       int volume_offset;
+
        /* capture */
        hda_nid_t *adc_nids;
        unsigned int num_adcs;
@@ -217,7 +249,6 @@ struct sigmatel_spec {
        /* pin widgets */
        hda_nid_t *pin_nids;
        unsigned int num_pins;
-       unsigned int *pin_configs;
 
        /* codec specific stuff */
        struct hda_verb *init;
@@ -328,7 +359,11 @@ static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
 };
 
 static unsigned int stac92hd83xxx_pwr_mapping[4] = {
-       0x03, 0x0c, 0x10, 0x40,
+       0x03, 0x0c, 0x20, 0x40,
+};
+
+static hda_nid_t stac92hd83xxx_amp_nids[1] = {
+       0xc,
 };
 
 static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
@@ -389,6 +424,10 @@ static hda_nid_t stac922x_mux_nids[2] = {
         0x12, 0x13,
 };
 
+static hda_nid_t stac927x_slave_dig_outs[2] = {
+       0x1f, 0,
+};
+
 static hda_nid_t stac927x_adc_nids[3] = {
         0x07, 0x08, 0x09
 };
@@ -461,15 +500,21 @@ static hda_nid_t stac92hd73xx_pin_nids[13] = {
        0x14, 0x22, 0x23
 };
 
-static hda_nid_t stac92hd83xxx_pin_nids[14] = {
+static hda_nid_t stac92hd83xxx_pin_nids[10] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
-       0x0f, 0x10, 0x11, 0x12, 0x13,
-       0x1d, 0x1e, 0x1f, 0x20
+       0x0f, 0x10, 0x11, 0x1f, 0x20,
+};
+
+#define STAC92HD71BXX_NUM_PINS 13
+static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
+       0x0a, 0x0b, 0x0c, 0x0d, 0x00,
+       0x00, 0x14, 0x18, 0x19, 0x1e,
+       0x1f, 0x20, 0x27
 };
-static hda_nid_t stac92hd71bxx_pin_nids[11] = {
+static hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x14, 0x18, 0x19, 0x1e,
-       0x1f,
+       0x1f, 0x20, 0x27
 };
 
 static hda_nid_t stac927x_pin_nids[14] = {
@@ -592,6 +637,40 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static unsigned int stac92xx_vref_set(struct hda_codec *codec,
+                                       hda_nid_t nid, unsigned int new_vref)
+{
+       int error;
+       unsigned int pincfg;
+       pincfg = snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+       pincfg &= 0xff;
+       pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+       pincfg |= new_vref;
+
+       if (new_vref == AC_PINCTL_VREF_HIZ)
+               pincfg |= AC_PINCTL_OUT_EN;
+       else
+               pincfg |= AC_PINCTL_IN_EN;
+
+       error = snd_hda_codec_write_cache(codec, nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg);
+       if (error < 0)
+               return error;
+       else
+               return 1;
+}
+
+static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int vref;
+       vref = snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+       vref &= AC_PINCTL_VREFEN;
+       return vref;
+}
+
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -831,13 +910,9 @@ static struct hda_verb stac92hd73xx_10ch_core_init[] = {
 };
 
 static struct hda_verb stac92hd83xxx_core_init[] = {
-       /* start of config #1 */
-       { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
-
-       /* start of config #2 */
-       { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
-       { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
-       { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
+       { 0xa, AC_VERB_SET_CONNECT_SEL, 0x1},
+       { 0xb, AC_VERB_SET_CONNECT_SEL, 0x1},
+       { 0xd, AC_VERB_SET_CONNECT_SEL, 0x0},
 
        /* power state controls amps */
        { 0x01, AC_VERB_SET_EAPD, 1 << 2},
@@ -847,26 +922,25 @@ static struct hda_verb stac92hd83xxx_core_init[] = {
 static struct hda_verb stac92hd71bxx_core_init[] = {
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
-       { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {}
 };
 
-#define HD_DISABLE_PORTF 2
+#define HD_DISABLE_PORTF 1
 static struct hda_verb stac92hd71bxx_analog_core_init[] = {
        /* start of config #1 */
 
        /* connect port 0f to audio mixer */
        { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
-       /* unmute right and left channels for node 0x0f */
-       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        /* start of config #2 */
 
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* unmute right and left channels for nodes 0x0a, 0xd */
+       {}
+};
+
+static struct hda_verb stac92hd71bxx_unmute_core_init[] = {
+       /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
+       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {}
@@ -875,6 +949,8 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
 static struct hda_verb stac925x_core_init[] = {
        /* set dac0mux for dac converter */
        { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* mute the master volume */
+       { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
        {}
 };
 
@@ -945,16 +1021,6 @@ static struct hda_verb stac9205_core_init[] = {
                .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
        }
 
-#define STAC_INPUT_SOURCE(cnt) \
-       { \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-               .name = "Input Source", \
-               .count = cnt, \
-               .info = stac92xx_mux_enum_info, \
-               .get = stac92xx_mux_enum_get, \
-               .put = stac92xx_mux_enum_put, \
-       }
-
 #define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -966,10 +1032,20 @@ static struct hda_verb stac9205_core_init[] = {
                .private_value = verb_read | (verb_write << 16), \
        }
 
+#define DC_BIAS(xname, idx, nid) \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = xname, \
+               .index = idx, \
+               .info = stac92xx_dc_bias_info, \
+               .get = stac92xx_dc_bias_get, \
+               .put = stac92xx_dc_bias_put, \
+               .private_value = nid, \
+       }
+
 static struct snd_kcontrol_new stac9200_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
-       STAC_INPUT_SOURCE(1),
        HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
        { } /* end */
@@ -994,8 +1070,6 @@ static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
        HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
 
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 
@@ -1005,9 +1079,22 @@ static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
        { } /* end */
 };
 
-static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
+static struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
+       {}
+};
+
+static struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
        STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
+       {}
+};
+
+static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
+       {}
+};
 
+static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 
@@ -1032,8 +1119,6 @@ static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
 
@@ -1085,9 +1170,6 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
-       STAC_INPUT_SOURCE(2),
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 
@@ -1113,10 +1195,11 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
        { } /* end */
 };
 
-static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
-       STAC_INPUT_SOURCE(2),
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
+static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
+};
 
+static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
 
@@ -1126,16 +1209,14 @@ static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac925x_mixer[] = {
-       STAC_INPUT_SOURCE(1),
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
        { } /* end */
 };
 
 static struct snd_kcontrol_new stac9205_mixer[] = {
-       STAC_INPUT_SOURCE(2),
-       STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
 
@@ -1144,9 +1225,13 @@ static struct snd_kcontrol_new stac9205_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new stac9205_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
+       {}
+};
+
 /* This needs to be generated dynamically based on sequence */
 static struct snd_kcontrol_new stac922x_mixer[] = {
-       STAC_INPUT_SOURCE(2),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
 
@@ -1157,9 +1242,6 @@ static struct snd_kcontrol_new stac922x_mixer[] = {
 
 
 static struct snd_kcontrol_new stac927x_mixer[] = {
-       STAC_INPUT_SOURCE(3),
-       STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
-
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
 
@@ -1171,6 +1253,11 @@ static struct snd_kcontrol_new stac927x_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new stac927x_loopback[] = {
+       STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
+       {}
+};
+
 static struct snd_kcontrol_new stac_dmux_mixer = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Digital Input Source",
@@ -1196,10 +1283,7 @@ static const char *slave_vols[] = {
        "LFE Playback Volume",
        "Side Playback Volume",
        "Headphone Playback Volume",
-       "Headphone Playback Volume",
        "Speaker Playback Volume",
-       "External Speaker Playback Volume",
-       "Speaker2 Playback Volume",
        NULL
 };
 
@@ -1210,10 +1294,7 @@ static const char *slave_sws[] = {
        "LFE Playback Switch",
        "Side Playback Switch",
        "Headphone Playback Switch",
-       "Headphone Playback Switch",
        "Speaker Playback Switch",
-       "External Speaker Playback Switch",
-       "Speaker2 Playback Switch",
        "IEC958 Playback Switch",
        NULL
 };
@@ -1283,6 +1364,8 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                unsigned int vmaster_tlv[4];
                snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
                                        HDA_OUTPUT, vmaster_tlv);
+               /* correct volume offset */
+               vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
                err = snd_hda_add_vmaster(codec, "Master Playback Volume",
                                          vmaster_tlv, slave_vols);
                if (err < 0)
@@ -1295,6 +1378,13 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                        return err;
        }
 
+       if (spec->aloopback_ctl &&
+           snd_hda_get_bool_hint(codec, "loopback") == 1) {
+               err = snd_hda_add_new_ctls(codec, spec->aloopback_ctl);
+               if (err < 0)
+                       return err;
+       }
+
        stac92xx_free_kctls(codec); /* no longer needed */
 
        /* create jack input elements */
@@ -1334,7 +1424,16 @@ static unsigned int ref9200_pin_configs[8] = {
        0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 };
 
-/* 
+static unsigned int gateway9200_m4_pin_configs[8] = {
+       0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
+       0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
+};
+static unsigned int gateway9200_m4_2_pin_configs[8] = {
+       0x400000fe, 0x404500f4, 0x400100f0, 0x90110010,
+       0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3,
+};
+
+/*
     STAC 9200 pin configs for
     102801A8
     102801DE
@@ -1464,10 +1563,13 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
        [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
        [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
        [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
+       [STAC_9200_M4] = gateway9200_m4_pin_configs,
+       [STAC_9200_M4_2] = gateway9200_m4_2_pin_configs,
        [STAC_9200_PANASONIC] = ref9200_pin_configs,
 };
 
 static const char *stac9200_models[STAC_9200_MODELS] = {
+       [STAC_AUTO] = "auto",
        [STAC_REF] = "ref",
        [STAC_9200_OQO] = "oqo",
        [STAC_9200_DELL_D21] = "dell-d21",
@@ -1480,7 +1582,8 @@ static const char *stac9200_models[STAC_9200_MODELS] = {
        [STAC_9200_DELL_M25] = "dell-m25",
        [STAC_9200_DELL_M26] = "dell-m26",
        [STAC_9200_DELL_M27] = "dell-m27",
-       [STAC_9200_GATEWAY] = "gateway",
+       [STAC_9200_M4] = "gateway-m4",
+       [STAC_9200_M4_2] = "gateway-m4-2",
        [STAC_9200_PANASONIC] = "panasonic",
 };
 
@@ -1488,6 +1591,8 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_REF),
        /* Dell laptops have BIOS problem */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
                      "unknown Dell", STAC_9200_DELL_D21),
@@ -1550,11 +1655,9 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
        /* Panasonic */
        SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
        /* Gateway machines needs EAPD to be set on resume */
-       SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
-       SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
-                     STAC_9200_GATEWAY),
-       SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
-                     STAC_9200_GATEWAY),
+       SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4),
+       SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2),
+       SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2),
        /* OQO Mobile */
        SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
        {} /* terminator */
@@ -1565,44 +1668,87 @@ static unsigned int ref925x_pin_configs[8] = {
        0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
 };
 
-static unsigned int stac925x_MA6_pin_configs[8] = {
-       0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
-       0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
+static unsigned int stac925xM1_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 
-static unsigned int stac925x_PA6_pin_configs[8] = {
-       0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
-       0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
+static unsigned int stac925xM1_2_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM2_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
 };
 
 static unsigned int stac925xM2_2_pin_configs[8] = {
-       0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
-       0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM3_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3,
+};
+
+static unsigned int stac925xM5_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e,
+};
+
+static unsigned int stac925xM6_pin_configs[8] = {
+       0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020,
+       0x40a000f0, 0x90100210, 0x400003f1, 0x90330320,
 };
 
 static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
        [STAC_REF] = ref925x_pin_configs,
+       [STAC_M1] = stac925xM1_pin_configs,
+       [STAC_M1_2] = stac925xM1_2_pin_configs,
+       [STAC_M2] = stac925xM2_pin_configs,
        [STAC_M2_2] = stac925xM2_2_pin_configs,
-       [STAC_MA6] = stac925x_MA6_pin_configs,
-       [STAC_PA6] = stac925x_PA6_pin_configs,
+       [STAC_M3] = stac925xM3_pin_configs,
+       [STAC_M5] = stac925xM5_pin_configs,
+       [STAC_M6] = stac925xM6_pin_configs,
 };
 
 static const char *stac925x_models[STAC_925x_MODELS] = {
+       [STAC_925x_AUTO] = "auto",
        [STAC_REF] = "ref",
+       [STAC_M1] = "m1",
+       [STAC_M1_2] = "m1-2",
+       [STAC_M2] = "m2",
        [STAC_M2_2] = "m2-2",
-       [STAC_MA6] = "m6",
-       [STAC_PA6] = "pa6",
+       [STAC_M3] = "m3",
+       [STAC_M5] = "m5",
+       [STAC_M6] = "m6",
+};
+
+static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
+       SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
+       SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
+       SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2),
+       SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2),
+       /* Not sure about the brand name for those */
+       SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1),
+       SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3),
+       SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6),
+       SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2),
+       {} /* terminator */
 };
 
 static struct snd_pci_quirk stac925x_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
        SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
-       SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
-       SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
-       SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
-       SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
-       SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
+
+       /* Default table for unknown ID */
+       SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2),
+
        {} /* terminator */
 };
 
@@ -1629,8 +1775,10 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
 };
 
 static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
+       [STAC_92HD73XX_AUTO] = "auto",
        [STAC_92HD73XX_NO_JD] = "no-jd",
        [STAC_92HD73XX_REF] = "ref",
+       [STAC_92HD73XX_INTEL] = "intel",
        [STAC_DELL_M6_AMIC] = "dell-m6-amic",
        [STAC_DELL_M6_DMIC] = "dell-m6-dmic",
        [STAC_DELL_M6_BOTH] = "dell-m6",
@@ -1641,6 +1789,12 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                                "DFI LanParty", STAC_92HD73XX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                               "DFI LanParty", STAC_92HD73XX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5002,
+                               "Intel DG45ID", STAC_92HD73XX_INTEL),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5003,
+                               "Intel DG45FC", STAC_92HD73XX_INTEL),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
                                "Dell Studio 1535", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
@@ -1661,53 +1815,73 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
                                "Dell Studio 1537", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
                                "Dell Studio 17", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be,
+                               "Dell Studio 1555", STAC_DELL_M6_DMIC),
        {} /* terminator */
 };
 
-static unsigned int ref92hd83xxx_pin_configs[14] = {
+static unsigned int ref92hd83xxx_pin_configs[10] = {
        0x02214030, 0x02211010, 0x02a19020, 0x02170130,
        0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
-       0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
        0x01451160, 0x98560170,
 };
 
+static unsigned int dell_s14_pin_configs[10] = {
+       0x02214030, 0x02211010, 0x02a19020, 0x01014050,
+       0x40f000f0, 0x01819040, 0x40f000f0, 0x90a60160,
+       0x40f000f0, 0x40f000f0,
+};
+
 static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
+       [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
+       [STAC_DELL_S14] = dell_s14_pin_configs,
 };
 
 static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
+       [STAC_92HD83XXX_AUTO] = "auto",
        [STAC_92HD83XXX_REF] = "ref",
+       [STAC_92HD83XXX_PWR_REF] = "mic-ref",
+       [STAC_DELL_S14] = "dell-s14",
 };
 
 static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_92HD83XXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_92HD83XXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
+                     "unknown Dell", STAC_DELL_S14),
        {} /* terminator */
 };
 
-static unsigned int ref92hd71bxx_pin_configs[11] = {
+static unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = {
        0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
        0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
-       0x90a000f0, 0x01452050, 0x01452050,
+       0x90a000f0, 0x01452050, 0x01452050, 0x00000000,
+       0x00000000
 };
 
-static unsigned int dell_m4_1_pin_configs[11] = {
+static unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = {
        0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
        0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
-       0x40f000f0, 0x4f0000f0, 0x4f0000f0,
+       0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000,
+       0x00000000
 };
 
-static unsigned int dell_m4_2_pin_configs[11] = {
+static unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = {
        0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
        0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
-       0x40f000f0, 0x044413b0, 0x044413b0,
+       0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
+       0x00000000
 };
 
-static unsigned int dell_m4_3_pin_configs[11] = {
+static unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = {
        0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
        0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
-       0x40f000f0, 0x044413b0, 0x044413b0,
+       0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
+       0x00000000
 };
 
 static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
@@ -1716,30 +1890,43 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
        [STAC_DELL_M4_2]        = dell_m4_2_pin_configs,
        [STAC_DELL_M4_3]        = dell_m4_3_pin_configs,
        [STAC_HP_M4]            = NULL,
+       [STAC_HP_DV5]           = NULL,
+       [STAC_HP_HDX]           = NULL,
+       [STAC_HP_DV4_1222NR]    = NULL,
 };
 
 static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
+       [STAC_92HD71BXX_AUTO] = "auto",
        [STAC_92HD71BXX_REF] = "ref",
        [STAC_DELL_M4_1] = "dell-m4-1",
        [STAC_DELL_M4_2] = "dell-m4-2",
        [STAC_DELL_M4_3] = "dell-m4-3",
        [STAC_HP_M4] = "hp-m4",
+       [STAC_HP_DV5] = "hp-dv5",
+       [STAC_HP_HDX] = "hp-hdx",
+       [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
 };
 
 static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_92HD71BXX_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
-                     "HP dv5", STAC_HP_M4),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
-                     "HP dv7", STAC_HP_M4),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
-                     "HP dv7", STAC_HP_M4),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603,
-                     "HP dv5", STAC_HP_M4),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_92HD71BXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb,
+                     "HP dv4-1222nr", STAC_HP_DV4_1222NR),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
+                     "HP", STAC_HP_DV5),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
+                     "HP dv4-7", STAC_HP_DV5),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3600,
+                     "HP dv4-7", STAC_HP_DV5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610,
+                     "HP HDX", STAC_HP_HDX),  /* HDX18 */
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
-                               "unknown HP", STAC_HP_M4),
+                     "HP mini 1000", STAC_HP_M4),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b,
+                     "HP HDX", STAC_HP_HDX),  /* HDX16 */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
                                "unknown Dell", STAC_DELL_M4_1),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
@@ -1891,6 +2078,7 @@ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
 };
 
 static const char *stac922x_models[STAC_922X_MODELS] = {
+       [STAC_922X_AUTO] = "auto",
        [STAC_D945_REF] = "ref",
        [STAC_D945GTP5] = "5stack",
        [STAC_D945GTP3] = "3stack",
@@ -1918,6 +2106,8 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_D945_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_D945_REF),
        /* Intel 945G based systems */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
                      "Intel D945G", STAC_D945GTP3),
@@ -1971,6 +2161,9 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
                      "Intel D945P", STAC_D945GTP3),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
                      "Intel D945P", STAC_D945GTP5),
+       /* other intel */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204,
+                     "Intel D945", STAC_D945_REF),
        /* other systems  */
        /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
        SND_PCI_QUIRK(0x8384, 0x7680,
@@ -1995,31 +2188,7 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
                      "Dell XPS M1210", STAC_922X_DELL_M82),
        /* ECS/PC Chips boards */
-       SND_PCI_QUIRK(0x1019, 0x2144,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2608,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2633,
-                     "ECS/PC chips P17G/1333", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2811,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2812,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2813,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2814,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2815,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2816,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2817,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2818,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2819,
-                     "ECS/PC chips", STAC_ECS_202),
-       SND_PCI_QUIRK(0x1019, 0x2820,
+       SND_PCI_QUIRK_MASK(0x1019, 0xf000, 0x2000,
                      "ECS/PC chips", STAC_ECS_202),
        {} /* terminator */
 };
@@ -2045,6 +2214,13 @@ static unsigned int d965_5st_pin_configs[14] = {
        0x40000100, 0x40000100
 };
 
+static unsigned int d965_5st_no_fp_pin_configs[14] = {
+       0x40000100, 0x40000100, 0x0181304e, 0x01014010,
+       0x01a19040, 0x01011012, 0x01016011, 0x40000100,
+       0x40000100, 0x40000100, 0x40000100, 0x01442070,
+       0x40000100, 0x40000100
+};
+
 static unsigned int dell_3st_pin_configs[14] = {
        0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
        0x01111212, 0x01116211, 0x01813050, 0x01112214,
@@ -2057,15 +2233,18 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
        [STAC_D965_REF]  = ref927x_pin_configs,
        [STAC_D965_3ST]  = d965_3st_pin_configs,
        [STAC_D965_5ST]  = d965_5st_pin_configs,
+       [STAC_D965_5ST_NO_FP]  = d965_5st_no_fp_pin_configs,
        [STAC_DELL_3ST]  = dell_3st_pin_configs,
        [STAC_DELL_BIOS] = NULL,
 };
 
 static const char *stac927x_models[STAC_927X_MODELS] = {
+       [STAC_927X_AUTO]        = "auto",
        [STAC_D965_REF_NO_JD]   = "ref-no-jd",
        [STAC_D965_REF]         = "ref",
        [STAC_D965_3ST]         = "3stack",
        [STAC_D965_5ST]         = "5stack",
+       [STAC_D965_5ST_NO_FP]   = "5stack-no-fp",
        [STAC_DELL_3ST]         = "dell-3stack",
        [STAC_DELL_BIOS]        = "dell-bios",
 };
@@ -2074,26 +2253,16 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_D965_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_D965_REF),
         /* Intel 946 based systems */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
        /* 965 based 3 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2100,
+                          "Intel D965", STAC_D965_3ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
+                          "Intel D965", STAC_D965_3ST),
        /* Dell 3 stack systems */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
@@ -2103,21 +2272,16 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0242, "Dell     ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0243, "Dell     ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x02ff, "Dell     ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
        /* 965 based 5 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300,
+                          "Intel D965", STAC_D965_5ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
+                          "Intel D965", STAC_D965_5ST),
        {} /* terminator */
 };
 
@@ -2170,19 +2334,27 @@ static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
        [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
        [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
        [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
+       [STAC_9205_EAPD] = NULL,
 };
 
 static const char *stac9205_models[STAC_9205_MODELS] = {
+       [STAC_9205_AUTO] = "auto",
        [STAC_9205_REF] = "ref",
        [STAC_9205_DELL_M42] = "dell-m42",
        [STAC_9205_DELL_M43] = "dell-m43",
        [STAC_9205_DELL_M44] = "dell-m44",
+       [STAC_9205_EAPD] = "eapd",
 };
 
 static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
+                     "SigmaTel", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_9205_REF),
+       /* Dell */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
                      "unknown Dell", STAC_9205_DELL_M42),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
@@ -2213,101 +2385,25 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
                      "Dell Inspiron", STAC_9205_DELL_M44),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
                      "Dell Vostro 1500", STAC_9205_DELL_M42),
+       /* Gateway */
+       SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD),
+       SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
        {} /* terminator */
 };
 
-static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
-{
-       int i;
-       struct sigmatel_spec *spec = codec->spec;
-       
-       kfree(spec->pin_configs);
-       spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs),
-                                   GFP_KERNEL);
-       if (!spec->pin_configs)
-               return -ENOMEM;
-       
-       for (i = 0; i < spec->num_pins; i++) {
-               hda_nid_t nid = spec->pin_nids[i];
-               unsigned int pin_cfg;
-               
-               pin_cfg = snd_hda_codec_read(codec, nid, 0, 
-                       AC_VERB_GET_CONFIG_DEFAULT, 0x00);      
-               snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
-                                       nid, pin_cfg);
-               spec->pin_configs[i] = pin_cfg;
-       }
-       
-       return 0;
-}
-
-static void stac92xx_set_config_reg(struct hda_codec *codec,
-                                   hda_nid_t pin_nid, unsigned int pin_config)
-{
-       int i;
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
-                           pin_config & 0x000000ff);
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
-                           (pin_config & 0x0000ff00) >> 8);
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
-                           (pin_config & 0x00ff0000) >> 16);
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-                           pin_config >> 24);
-       i = snd_hda_codec_read(codec, pin_nid, 0,
-                              AC_VERB_GET_CONFIG_DEFAULT,
-                              0x00);   
-       snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
-                   pin_nid, i);
-}
-
-static void stac92xx_set_config_regs(struct hda_codec *codec)
+static void stac92xx_set_config_regs(struct hda_codec *codec,
+                                    unsigned int *pincfgs)
 {
        int i;
        struct sigmatel_spec *spec = codec->spec;
 
-       if (!spec->pin_configs)
-               return;
+       if (!pincfgs)
+               return;
 
        for (i = 0; i < spec->num_pins; i++)
-               stac92xx_set_config_reg(codec, spec->pin_nids[i],
-                                       spec->pin_configs[i]);
-}
-
-static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (!pins)
-               return stac92xx_save_bios_config_regs(codec);
-
-       kfree(spec->pin_configs);
-       spec->pin_configs = kmemdup(pins,
-                                   spec->num_pins * sizeof(*pins),
-                                   GFP_KERNEL);
-       if (!spec->pin_configs)
-               return -ENOMEM;
-
-       stac92xx_set_config_regs(codec);
-       return 0;
-}
-
-static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid,
-                                  unsigned int cfg)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_pins; i++) {
-               if (spec->pin_nids[i] == nid) {
-                       spec->pin_configs[i] = cfg;
-                       stac92xx_set_config_reg(codec, nid, cfg);
-                       break;
-               }
-       }
+               if (spec->pin_nids[i] && pincfgs[i])
+                       snd_hda_codec_set_pincfg(codec, spec->pin_nids[i],
+                                                pincfgs[i]);
 }
 
 /*
@@ -2372,6 +2468,14 @@ static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                             stream_tag, format, substream);
 }
 
+static int stac92xx_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
+}
+
 
 /*
  * Analog capture callbacks
@@ -2416,7 +2520,8 @@ static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
        .ops = {
                .open = stac92xx_dig_playback_pcm_open,
                .close = stac92xx_dig_playback_pcm_close,
-               .prepare = stac92xx_dig_playback_pcm_prepare
+               .prepare = stac92xx_dig_playback_pcm_prepare,
+               .cleanup = stac92xx_dig_playback_pcm_cleanup
        },
 };
 
@@ -2471,6 +2576,8 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
 
        info->name = "STAC92xx Analog";
        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+               spec->multiout.dac_nids[0];
        info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
        info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
@@ -2486,7 +2593,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
                codec->num_pcms++;
                info++;
                info->name = "STAC92xx Digital";
-               info->pcm_type = HDA_PCM_TYPE_SPDIF;
+               info->pcm_type = spec->autocfg.dig_out_type[0];
                if (spec->multiout.dig_out_nid) {
                        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
                        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
@@ -2500,10 +2607,10 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
        return 0;
 }
 
-static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
+                                       hda_nid_t nid)
 {
-       unsigned int pincap = snd_hda_param_read(codec, nid,
-                                                AC_PAR_PIN_CAP);
+       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
        pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
        if (pincap & AC_PINCAP_VREF_100)
                return AC_PINCTL_VREF_100;
@@ -2555,15 +2662,108 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-#define stac92xx_io_switch_info                snd_ctl_boolean_mono_info
+static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       int i;
+       static char *texts[] = {
+               "Mic In", "Line In", "Line Out"
+       };
+
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = kcontrol->private_value;
+
+       if (nid == spec->mic_switch || nid == spec->line_switch)
+               i = 3;
+       else
+               i = 2;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = i;
+       uinfo->count = 1;
+       if (uinfo->value.enumerated.item >= i)
+               uinfo->value.enumerated.item = i-1;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       unsigned int vref = stac92xx_vref_get(codec, nid);
+
+       if (vref == stac92xx_get_default_vref(codec, nid))
+               ucontrol->value.enumerated.item[0] = 0;
+       else if (vref == AC_PINCTL_VREF_GRD)
+               ucontrol->value.enumerated.item[0] = 1;
+       else if (vref == AC_PINCTL_VREF_HIZ)
+               ucontrol->value.enumerated.item[0] = 2;
+
+       return 0;
+}
+
+static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int new_vref = 0;
+       int error;
+       hda_nid_t nid = kcontrol->private_value;
+
+       if (ucontrol->value.enumerated.item[0] == 0)
+               new_vref = stac92xx_get_default_vref(codec, nid);
+       else if (ucontrol->value.enumerated.item[0] == 1)
+               new_vref = AC_PINCTL_VREF_GRD;
+       else if (ucontrol->value.enumerated.item[0] == 2)
+               new_vref = AC_PINCTL_VREF_HIZ;
+       else
+               return 0;
+
+       if (new_vref != stac92xx_vref_get(codec, nid)) {
+               error = stac92xx_vref_set(codec, nid, new_vref);
+               return error;
+       }
+
+       return 0;
+}
+
+static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[2];
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (kcontrol->private_value == spec->line_switch)
+               texts[0] = "Line In";
+       else
+               texts[0] = "Mic In";
+       texts[1] = "Line Out";
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->value.enumerated.items = 2;
+       uinfo->count = 1;
+
+       if (uinfo->value.enumerated.item >= 2)
+               uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
 
 static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
-       int io_idx = kcontrol-> private_value & 0xff;
+       hda_nid_t nid = kcontrol->private_value;
+       int io_idx = (nid == spec->mic_switch) ? 1 : 0;
 
-       ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
+       ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx];
        return 0;
 }
 
@@ -2571,9 +2771,9 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
 {
         struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
-        hda_nid_t nid = kcontrol->private_value >> 8;
-       int io_idx = kcontrol-> private_value & 0xff;
-       unsigned short val = !!ucontrol->value.integer.value[0];
+       hda_nid_t nid = kcontrol->private_value;
+       int io_idx = (nid == spec->mic_switch) ? 1 : 0;
+       unsigned short val = !!ucontrol->value.enumerated.item[0];
 
        spec->io_switch[io_idx] = val;
 
@@ -2582,7 +2782,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        else {
                unsigned int pinctl = AC_PINCTL_IN_EN;
                if (io_idx) /* set VREF for mic */
-                       pinctl |= stac92xx_get_vref(codec, nid);
+                       pinctl |= stac92xx_get_default_vref(codec, nid);
                stac92xx_auto_set_pinctl(codec, nid, pinctl);
        }
 
@@ -2663,7 +2863,8 @@ enum {
        STAC_CTL_WIDGET_AMP_VOL,
        STAC_CTL_WIDGET_HP_SWITCH,
        STAC_CTL_WIDGET_IO_SWITCH,
-       STAC_CTL_WIDGET_CLFE_SWITCH
+       STAC_CTL_WIDGET_CLFE_SWITCH,
+       STAC_CTL_WIDGET_DC_BIAS
 };
 
 static struct snd_kcontrol_new stac92xx_control_templates[] = {
@@ -2675,25 +2876,41 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
        STAC_CODEC_HP_SWITCH(NULL),
        STAC_CODEC_IO_SWITCH(NULL, 0),
        STAC_CODEC_CLFE_SWITCH(NULL, 0),
+       DC_BIAS(NULL, 0, 0),
 };
 
 /* add dynamic controls */
-static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
-                                    struct snd_kcontrol_new *ktemp,
-                                    int idx, const char *name,
-                                    unsigned long val)
+static struct snd_kcontrol_new *
+stac_control_new(struct sigmatel_spec *spec,
+                struct snd_kcontrol_new *ktemp,
+                const char *name)
 {
        struct snd_kcontrol_new *knew;
 
        snd_array_init(&spec->kctls, sizeof(*knew), 32);
        knew = snd_array_new(&spec->kctls);
        if (!knew)
-               return -ENOMEM;
+               return NULL;
        *knew = *ktemp;
-       knew->index = idx;
        knew->name = kstrdup(name, GFP_KERNEL);
-       if (!knew->name)
+       if (!knew->name) {
+               /* roolback */
+               memset(knew, 0, sizeof(*knew));
+               spec->kctls.alloced--;
+               return NULL;
+       }
+       return knew;
+}
+
+static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
+                                    struct snd_kcontrol_new *ktemp,
+                                    int idx, const char *name,
+                                    unsigned long val)
+{
+       struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name);
+       if (!knew)
                return -ENOMEM;
+       knew->index = idx;
        knew->private_value = val;
        return 0;
 }
@@ -2715,6 +2932,57 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
        return stac92xx_add_control_idx(spec, type, 0, name, val);
 }
 
+static struct snd_kcontrol_new stac_input_src_temp = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Input Source",
+       .info = stac92xx_mux_enum_info,
+       .get = stac92xx_mux_enum_get,
+       .put = stac92xx_mux_enum_put,
+};
+
+static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
+                                               hda_nid_t nid, int idx)
+{
+       int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       int control = 0;
+       struct sigmatel_spec *spec = codec->spec;
+       char name[22];
+
+       if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+               if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
+                       && nid == spec->line_switch)
+                       control = STAC_CTL_WIDGET_IO_SWITCH;
+               else if (snd_hda_query_pin_caps(codec, nid)
+                       & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
+                       control = STAC_CTL_WIDGET_DC_BIAS;
+               else if (nid == spec->mic_switch)
+                       control = STAC_CTL_WIDGET_IO_SWITCH;
+       }
+
+       if (control) {
+               strcpy(name, auto_pin_cfg_labels[idx]);
+               return stac92xx_add_control(codec->spec, control,
+                                       strcat(name, " Jack Mode"), nid);
+       }
+
+       return 0;
+}
+
+static int stac92xx_add_input_source(struct sigmatel_spec *spec)
+{
+       struct snd_kcontrol_new *knew;
+       struct hda_input_mux *imux = &spec->private_imux;
+
+       if (!spec->num_adcs || imux->num_items <= 1)
+               return 0; /* no need for input source control */
+       knew = stac_control_new(spec, &stac_input_src_temp,
+                               stac_input_src_temp.name);
+       if (!knew)
+               return -ENOMEM;
+       knew->count = spec->num_adcs;
+       return 0;
+}
+
 /* check whether the line-input can be used as line-out */
 static hda_nid_t check_line_out_switch(struct hda_codec *codec)
 {
@@ -2726,7 +2994,7 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec)
        if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
                return 0;
        nid = cfg->input_pins[AUTO_PIN_LINE];
-       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+       pincap = snd_hda_query_pin_caps(codec, nid);
        if (pincap & AC_PINCAP_OUT)
                return nid;
        return 0;
@@ -2745,12 +3013,11 @@ static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
        mic_pin = AUTO_PIN_MIC;
        for (;;) {
                hda_nid_t nid = cfg->input_pins[mic_pin];
-               def_conf = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
                /* some laptops have an internal analog microphone
                 * which can't be used as a output */
                if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
-                       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+                       pincap = snd_hda_query_pin_caps(codec, nid);
                        if (pincap & AC_PINCAP_OUT)
                                return nid;
                }
@@ -2798,8 +3065,7 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
        conn_len = snd_hda_get_connections(codec, nid, conn,
                                           HDA_MAX_CONNECTIONS);
        for (j = 0; j < conn_len; j++) {
-               wcaps = snd_hda_param_read(codec, conn[j],
-                                          AC_PAR_AUDIO_WIDGET_CAP);
+               wcaps = get_wcaps(codec, conn[j]);
                wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
                /* we check only analog outputs */
                if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
@@ -2814,6 +3080,16 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
                        return conn[j];
                }
        }
+       /* if all DACs are already assigned, connect to the primary DAC */
+       if (conn_len > 1) {
+               for (j = 0; j < conn_len; j++) {
+                       if (conn[j] == spec->multiout.dac_nids[0]) {
+                               snd_hda_codec_write_cache(codec, nid, 0,
+                                                 AC_VERB_SET_CONNECT_SEL, j);
+                               break;
+                       }
+               }
+       }
        return 0;
 }
 
@@ -2854,15 +3130,35 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
                add_spec_dacs(spec, dac);
        }
 
-       /* add line-in as output */
-       nid = check_line_out_switch(codec);
-       if (nid) {
+       for (i = 0; i < cfg->hp_outs; i++) {
+               nid = cfg->hp_pins[i];
                dac = get_unassigned_dac(codec, nid);
                if (dac) {
-                       snd_printdd("STAC: Add line-in 0x%x as output %d\n",
-                                   nid, cfg->line_outs);
-                       cfg->line_out_pins[cfg->line_outs] = nid;
-                       cfg->line_outs++;
+                       if (!spec->multiout.hp_nid)
+                               spec->multiout.hp_nid = dac;
+                       else
+                               add_spec_extra_dacs(spec, dac);
+               }
+               spec->hp_dacs[i] = dac;
+       }
+
+       for (i = 0; i < cfg->speaker_outs; i++) {
+               nid = cfg->speaker_pins[i];
+               dac = get_unassigned_dac(codec, nid);
+               if (dac)
+                       add_spec_extra_dacs(spec, dac);
+               spec->speaker_dacs[i] = dac;
+       }
+
+       /* add line-in as output */
+       nid = check_line_out_switch(codec);
+       if (nid) {
+               dac = get_unassigned_dac(codec, nid);
+               if (dac) {
+                       snd_printdd("STAC: Add line-in 0x%x as output %d\n",
+                                   nid, cfg->line_outs);
+                       cfg->line_out_pins[cfg->line_outs] = nid;
+                       cfg->line_outs++;
                        spec->line_switch = nid;
                        add_spec_dacs(spec, dac);
                }
@@ -2881,26 +3177,6 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
 
-       for (i = 0; i < cfg->hp_outs; i++) {
-               nid = cfg->hp_pins[i];
-               dac = get_unassigned_dac(codec, nid);
-               if (dac) {
-                       if (!spec->multiout.hp_nid)
-                               spec->multiout.hp_nid = dac;
-                       else
-                               add_spec_extra_dacs(spec, dac);
-               }
-               spec->hp_dacs[i] = dac;
-       }
-
-       for (i = 0; i < cfg->speaker_outs; i++) {
-               nid = cfg->speaker_pins[i];
-               dac = get_unassigned_dac(codec, nid);
-               if (dac)
-                       add_spec_extra_dacs(spec, dac);
-               spec->speaker_dacs[i] = dac;
-       }
-
        snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
                   spec->multiout.num_dacs,
                   spec->multiout.dac_nids[0],
@@ -2913,24 +3189,47 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
 }
 
 /* create volume control/switch for the given prefx type */
-static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
+static int create_controls_idx(struct hda_codec *codec, const char *pfx,
+                              int idx, hda_nid_t nid, int chs)
 {
+       struct sigmatel_spec *spec = codec->spec;
        char name[32];
        int err;
 
+       if (!spec->check_volume_offset) {
+               unsigned int caps, step, nums, db_scale;
+               caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+               step = (caps & AC_AMPCAP_STEP_SIZE) >>
+                       AC_AMPCAP_STEP_SIZE_SHIFT;
+               step = (step + 1) * 25; /* in .01dB unit */
+               nums = (caps & AC_AMPCAP_NUM_STEPS) >>
+                       AC_AMPCAP_NUM_STEPS_SHIFT;
+               db_scale = nums * step;
+               /* if dB scale is over -64dB, and finer enough,
+                * let's reduce it to half
+                */
+               if (db_scale > 6400 && nums >= 0x1f)
+                       spec->volume_offset = nums / 2;
+               spec->check_volume_offset = 1;
+       }
+
        sprintf(name, "%s Playback Volume", pfx);
-       err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
-                                  HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+       err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, idx, name,
+               HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT,
+                                       spec->volume_offset));
        if (err < 0)
                return err;
        sprintf(name, "%s Playback Switch", pfx);
-       err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
+       err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_MUTE, idx, name,
                                   HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
        return 0;
 }
 
+#define create_controls(codec, pfx, nid, chs) \
+       create_controls_idx(codec, pfx, 0, nid, chs)
+
 static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
 {
        if (spec->multiout.num_dacs > 4) {
@@ -2956,40 +3255,37 @@ static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
        return 1;
 }
 
-static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid)
-{
-       int i;
-
-       if (spec->autocfg.line_outs != 1)
-               return 0;
-       if (spec->multiout.hp_nid == nid)
-               return 0;
-       for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
-               if (spec->multiout.extra_out_nid[i] == nid)
-                       return 0;
-       return 1;
-}
-
-/* add playback controls from the parsed DAC table */
-static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
-                                              const struct auto_pin_cfg *cfg)
+/* Create output controls
+ * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT)
+ */
+static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
+                                const hda_nid_t *pins,
+                                const hda_nid_t *dac_nids,
+                                int type)
 {
        struct sigmatel_spec *spec = codec->spec;
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
-       hda_nid_t nid = 0;
+       hda_nid_t nid;
        int i, err;
        unsigned int wid_caps;
 
-       for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) {
-               nid = spec->multiout.dac_nids[i];
-               if (i == 2) {
+       for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
+               if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
+                       wid_caps = get_wcaps(codec, pins[i]);
+                       if (wid_caps & AC_WCAP_UNSOL_CAP)
+                               spec->hp_detect = 1;
+               }
+               nid = dac_nids[i];
+               if (!nid)
+                       continue;
+               if (type != AUTO_PIN_HP_OUT && i == 2) {
                        /* Center/LFE */
-                       err = create_controls(spec, "Center", nid, 1);
+                       err = create_controls(codec, "Center", nid, 1);
                        if (err < 0)
                                return err;
-                       err = create_controls(spec, "LFE", nid, 2);
+                       err = create_controls(codec, "LFE", nid, 2);
                        if (err < 0)
                                return err;
 
@@ -3005,23 +3301,44 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        }
 
                } else {
-                       const char *name = chname[i];
-                       /* if it's a single DAC, assign a better name */
-                       if (!i && is_unique_dac(spec, nid)) {
-                               switch (cfg->line_out_type) {
-                               case AUTO_PIN_HP_OUT:
-                                       name = "Headphone";
-                                       break;
-                               case AUTO_PIN_SPEAKER_OUT:
-                                       name = "Speaker";
-                                       break;
-                               }
+                       const char *name;
+                       int idx;
+                       switch (type) {
+                       case AUTO_PIN_HP_OUT:
+                               name = "Headphone";
+                               idx = i;
+                               break;
+                       case AUTO_PIN_SPEAKER_OUT:
+                               name = "Speaker";
+                               idx = i;
+                               break;
+                       default:
+                               name = chname[i];
+                               idx = 0;
+                               break;
                        }
-                       err = create_controls(spec, name, nid, 3);
+                       err = create_controls_idx(codec, name, idx, nid, 3);
                        if (err < 0)
                                return err;
                }
        }
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
+                                              const struct auto_pin_cfg *cfg)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid;
+       int err;
+       int idx;
+
+       err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
+                                   spec->multiout.dac_nids,
+                                   cfg->line_out_type);
+       if (err < 0)
+               return err;
 
        if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
                err = stac92xx_add_control(spec,
@@ -3032,20 +3349,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        return err;
        }
 
-       if (spec->line_switch) {
-               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
-                                          "Line In as Output Switch",
-                                          spec->line_switch << 8);
-               if (err < 0)
-                       return err;
-       }
-
-       if (spec->mic_switch) {
-               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
-                                          "Mic as Output Switch",
-                                          (spec->mic_switch << 8) | 1);
-               if (err < 0)
-                       return err;
+       for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
+               nid = cfg->input_pins[idx];
+               if (nid) {
+                       err = stac92xx_add_jack_mode_control(codec, nid, idx);
+                       if (err < 0)
+                               return err;
+               }
        }
 
        return 0;
@@ -3056,40 +3366,18 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
                                        struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
-       hda_nid_t nid;
-       int i, err, nums;
+       int err;
+
+       err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins,
+                                   spec->hp_dacs, AUTO_PIN_HP_OUT);
+       if (err < 0)
+               return err;
+
+       err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins,
+                                   spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT);
+       if (err < 0)
+               return err;
 
-       nums = 0;
-       for (i = 0; i < cfg->hp_outs; i++) {
-               static const char *pfxs[] = {
-                       "Headphone", "Headphone2", "Headphone3",
-               };
-               unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
-               if (wid_caps & AC_WCAP_UNSOL_CAP)
-                       spec->hp_detect = 1;
-               if (nums >= ARRAY_SIZE(pfxs))
-                       continue;
-               nid = spec->hp_dacs[i];
-               if (!nid)
-                       continue;
-               err = create_controls(spec, pfxs[nums++], nid, 3);
-               if (err < 0)
-                       return err;
-       }
-       nums = 0;
-       for (i = 0; i < cfg->speaker_outs; i++) {
-               static const char *pfxs[] = {
-                       "Speaker", "External Speaker", "Speaker2",
-               };
-               if (nums >= ARRAY_SIZE(pfxs))
-                       continue;
-               nid = spec->speaker_dacs[i];
-               if (!nid)
-                       continue;
-               err = create_controls(spec, pfxs[nums++], nid, 3);
-               if (err < 0)
-                       return err;
-       }
        return 0;
 }
 
@@ -3298,11 +3586,7 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                unsigned int wcaps;
                unsigned int def_conf;
 
-               def_conf = snd_hda_codec_read(codec,
-                                             spec->dmic_nids[i],
-                                             0,
-                                             AC_VERB_GET_CONFIG_DEFAULT,
-                                             0);
+               def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
                if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
                        continue;
 
@@ -3426,6 +3710,7 @@ static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
 static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
 {
        struct sigmatel_spec *spec = codec->spec;
+       int hp_swap = 0;
        int err;
 
        if ((err = snd_hda_parse_pin_def_config(codec,
@@ -3453,6 +3738,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                spec->autocfg.line_outs = spec->autocfg.hp_outs;
                spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
                spec->autocfg.hp_outs = 0;
+               hp_swap = 1;
        }
        if (spec->autocfg.mono_out_pin) {
                int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
@@ -3508,13 +3794,12 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                err = stac92xx_auto_fill_dac_nids(codec);
                if (err < 0)
                        return err;
+               err = stac92xx_auto_create_multi_out_ctls(codec,
+                                                         &spec->autocfg);
+               if (err < 0)
+                       return err;
        }
 
-       err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
-
-       if (err < 0)
-               return err;
-
        /* setup analog beep controls */
        if (spec->anabeep_nid > 0) {
                err = stac92xx_auto_create_beep_ctls(codec,
@@ -3535,6 +3820,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                err = snd_hda_attach_beep_device(codec, nid);
                if (err < 0)
                        return err;
+               /* IDT/STAC codecs have linear beep tone parameter */
+               codec->beep->linear_tone = 1;
                /* if no beep switch is available, make its own one */
                caps = query_amp_caps(codec, nid, HDA_OUTPUT);
                if (codec->beep &&
@@ -3547,12 +3834,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 #endif
 
        err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
-
        if (err < 0)
                return err;
 
-       err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
+       /* All output parsing done, now restore the swapped hp pins */
+       if (hp_swap) {
+               memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
+                      sizeof(spec->autocfg.hp_pins));
+               spec->autocfg.hp_outs = spec->autocfg.line_outs;
+               spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
+               spec->autocfg.line_outs = 0;
+       }
 
+       err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -3581,11 +3875,15 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                        return err;
        }
 
+       err = stac92xx_add_input_source(spec);
+       if (err < 0)
+               return err;
+
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
        if (spec->multiout.max_channels > 2)
                spec->surr_switch = 1;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = dig_out;
        if (dig_in && spec->autocfg.dig_in_pin)
                spec->dig_in_nid = dig_in;
@@ -3648,9 +3946,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
                for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
                        hda_nid_t pin = spec->autocfg.line_out_pins[i];
                        unsigned int defcfg;
-                       defcfg = snd_hda_codec_read(codec, pin, 0,
-                                                AC_VERB_GET_CONFIG_DEFAULT,
-                                                0x00);
+                       defcfg = snd_hda_codec_get_pincfg(codec, pin);
                        if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
                                unsigned int wcaps = get_wcaps(codec, pin);
                                wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
@@ -3663,7 +3959,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
        }
 
        if (lfe_pin) {
-               err = create_controls(spec, "LFE", lfe_pin, 1);
+               err = create_controls(codec, "LFE", lfe_pin, 1);
                if (err < 0)
                        return err;
        }
@@ -3694,7 +3990,11 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
                        return err;
        }
 
-       if (spec->autocfg.dig_out_pin)
+       err = stac92xx_add_input_source(spec);
+       if (err < 0)
+               return err;
+
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = 0x05;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = 0x04;
@@ -3744,16 +4044,25 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
                           AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+static void stac92xx_free_jack_priv(struct snd_jack *jack)
+{
+       struct sigmatel_jack *jacks = jack->private_data;
+       jacks->nid = 0;
+       jacks->jack = NULL;
+}
+#endif
+
 static int stac92xx_add_jack(struct hda_codec *codec,
                hda_nid_t nid, int type)
 {
-#ifdef CONFIG_SND_JACK
+#ifdef CONFIG_SND_HDA_INPUT_JACK
        struct sigmatel_spec *spec = codec->spec;
        struct sigmatel_jack *jack;
-       int def_conf = snd_hda_codec_read(codec, nid,
-                       0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+       int def_conf = snd_hda_codec_get_pincfg(codec, nid);
        int connectivity = get_defcfg_connect(def_conf);
        char name[32];
+       int err;
 
        if (connectivity && connectivity != AC_JACK_PORT_FIXED)
                return 0;
@@ -3765,15 +4074,20 @@ static int stac92xx_add_jack(struct hda_codec *codec,
        jack->nid = nid;
        jack->type = type;
 
-       sprintf(name, "%s at %s %s Jack",
+       snprintf(name, sizeof(name), "%s at %s %s Jack",
                snd_hda_get_jack_type(def_conf),
                snd_hda_get_jack_connectivity(def_conf),
                snd_hda_get_jack_location(def_conf));
 
-       return snd_jack_new(codec->bus->card, name, type, &jack->jack);
-#else
-       return 0;
+       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+       if (err < 0) {
+               jack->nid = 0;
+               return err;
+       }
+       jack->jack->private_data = jack;
+       jack->jack->private_free = stac92xx_free_jack_priv;
 #endif
+       return 0;
 }
 
 static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
@@ -3866,6 +4180,36 @@ static void stac92xx_power_down(struct hda_codec *codec)
 static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
                                  int enable);
 
+/* override some hints from the hwdep entry */
+static void stac_store_hints(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       const char *p;
+       int val;
+
+       val = snd_hda_get_bool_hint(codec, "hp_detect");
+       if (val >= 0)
+               spec->hp_detect = val;
+       p = snd_hda_get_hint(codec, "gpio_mask");
+       if (p) {
+               spec->gpio_mask = simple_strtoul(p, NULL, 0);
+               spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
+                       spec->gpio_mask;
+       }
+       p = snd_hda_get_hint(codec, "gpio_dir");
+       if (p)
+               spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
+       p = snd_hda_get_hint(codec, "gpio_data");
+       if (p)
+               spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
+       p = snd_hda_get_hint(codec, "eapd_mask");
+       if (p)
+               spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask;
+       val = snd_hda_get_bool_hint(codec, "eapd_switch");
+       if (val >= 0)
+               spec->eapd_switch = val;
+}
+
 static int stac92xx_init(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -3882,6 +4226,9 @@ static int stac92xx_init(struct hda_codec *codec)
                                spec->adc_nids[i], 0,
                                AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 
+       /* override some hints */
+       stac_store_hints(codec);
+
        /* set up GPIO */
        gpio = spec->gpio_data;
        /* turn on EAPD statically when spec->eapd_switch isn't set.
@@ -3918,21 +4265,25 @@ static int stac92xx_init(struct hda_codec *codec)
                        unsigned int pinctl, conf;
                        if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
                                /* for mic pins, force to initialize */
-                               pinctl = stac92xx_get_vref(codec, nid);
+                               pinctl = stac92xx_get_default_vref(codec, nid);
                                pinctl |= AC_PINCTL_IN_EN;
                                stac92xx_auto_set_pinctl(codec, nid, pinctl);
                        } else {
                                pinctl = snd_hda_codec_read(codec, nid, 0,
                                        AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                                /* if PINCTL already set then skip */
-                               if (!(pinctl & AC_PINCTL_IN_EN)) {
+                               /* Also, if both INPUT and OUTPUT are set,
+                                * it must be a BIOS bug; need to override, too
+                                */
+                               if (!(pinctl & AC_PINCTL_IN_EN) ||
+                                   (pinctl & AC_PINCTL_OUT_EN)) {
+                                       pinctl &= ~AC_PINCTL_OUT_EN;
                                        pinctl |= AC_PINCTL_IN_EN;
                                        stac92xx_auto_set_pinctl(codec, nid,
                                                                 pinctl);
                                }
                        }
-                       conf = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+                       conf = snd_hda_codec_get_pincfg(codec, nid);
                        if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
                                enable_pin_detect(codec, nid,
                                                  STAC_INSERT_EVENT);
@@ -3944,8 +4295,8 @@ static int stac92xx_init(struct hda_codec *codec)
        for (i = 0; i < spec->num_dmics; i++)
                stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
                                        AC_PINCTL_IN_EN);
-       if (cfg->dig_out_pin)
-               stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
+       if (cfg->dig_out_pins[0])
+               stac92xx_auto_set_pinctl(codec, cfg->dig_out_pins[0],
                                         AC_PINCTL_OUT_EN);
        if (cfg->dig_in_pin)
                stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
@@ -3973,8 +4324,7 @@ static int stac92xx_init(struct hda_codec *codec)
                        stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
-               def_conf = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+               def_conf = snd_hda_codec_get_pincfg(codec, nid);
                def_conf = get_defcfg_connect(def_conf);
                /* skip any ports that don't have jacks since presence
                 * detection is useless */
@@ -3995,14 +4345,16 @@ static int stac92xx_init(struct hda_codec *codec)
 
 static void stac92xx_free_jacks(struct hda_codec *codec)
 {
-#ifdef CONFIG_SND_JACK
+#ifdef CONFIG_SND_HDA_INPUT_JACK
        /* free jack instances manually when clearing/reconfiguring */
        struct sigmatel_spec *spec = codec->spec;
        if (!codec->bus->shutdown && spec->jacks.list) {
                struct sigmatel_jack *jacks = spec->jacks.list;
                int i;
-               for (i = 0; i < spec->jacks.used; i++)
-                       snd_device_free(codec->bus->card, &jacks[i].jack);
+               for (i = 0; i < spec->jacks.used; i++, jacks++) {
+                       if (jacks->jack)
+                               snd_device_free(codec->bus->card, jacks->jack);
+               }
        }
        snd_array_free(&spec->jacks);
 #endif
@@ -4028,7 +4380,6 @@ static void stac92xx_free(struct hda_codec *codec)
        if (! spec)
                return;
 
-       kfree(spec->pin_configs);
        stac92xx_free_jacks(codec);
        snd_array_free(&spec->events);
 
@@ -4039,7 +4390,9 @@ static void stac92xx_free(struct hda_codec *codec)
 static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
                                unsigned int flag)
 {
-       unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
+       unsigned int old_ctl, pin_ctl;
+
+       pin_ctl = snd_hda_codec_read(codec, nid,
                        0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
 
        if (pin_ctl & AC_PINCTL_IN_EN) {
@@ -4053,14 +4406,17 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
                        return;
        }
 
+       old_ctl = pin_ctl;
        /* if setting pin direction bits, clear the current
           direction bits first */
        if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
                pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
        
-       snd_hda_codec_write_cache(codec, nid, 0,
-                       AC_VERB_SET_PIN_WIDGET_CONTROL,
-                       pin_ctl | flag);
+       pin_ctl |= flag;
+       if (old_ctl != pin_ctl)
+               snd_hda_codec_write_cache(codec, nid, 0,
+                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                         pin_ctl);
 }
 
 static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
@@ -4068,9 +4424,10 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
 {
        unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
                        0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
-       snd_hda_codec_write_cache(codec, nid, 0,
-                       AC_VERB_SET_PIN_WIDGET_CONTROL,
-                       pin_ctl & ~flag);
+       if (pin_ctl & flag)
+               snd_hda_codec_write_cache(codec, nid, 0,
+                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                         pin_ctl & ~flag);
 }
 
 static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
@@ -4165,8 +4522,19 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
                        continue;
                if (presence)
                        stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
+#if 0 /* FIXME */
+/* Resetting the pinctl like below may lead to (a sort of) regressions
+ * on some devices since they use the HP pin actually for line/speaker
+ * outs although the default pin config shows a different pin (that is
+ * wrong and useless).
+ *
+ * So, it's basically a problem of default pin configs, likely a BIOS issue.
+ * But, disabling the code below just works around it, and I'm too tired of
+ * bug reports with such devices... 
+ */
                else
                        stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
+#endif /* FIXME */
        }
 } 
 
@@ -4260,6 +4628,24 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
                if (spec->num_pwrs > 0)
                        stac92xx_pin_sense(codec, event->nid);
                stac92xx_report_jack(codec, event->nid);
+
+               switch (codec->subsystem_id) {
+               case 0x103c308f:
+                       if (event->nid == 0xb) {
+                               int pin = AC_PINCTL_IN_EN;
+
+                               if (get_pin_presence(codec, 0xa)
+                                               && get_pin_presence(codec, 0xb))
+                                       pin |= AC_PINCTL_VREF_80;
+                               if (!get_pin_presence(codec, 0xb))
+                                       pin |= AC_PINCTL_VREF_80;
+
+                               /* toggle VREF state based on mic + hp pin
+                                * status
+                                */
+                               stac92xx_auto_set_pinctl(codec, 0x0a, pin);
+                       }
+               }
                break;
        case STAC_VREF_EVENT:
                data = snd_hda_codec_read(codec, codec->afg, 0,
@@ -4322,7 +4708,6 @@ static int stac92xx_resume(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
 
-       stac92xx_set_config_regs(codec);
        stac92xx_init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
@@ -4333,6 +4718,39 @@ static int stac92xx_resume(struct hda_codec *codec)
        return 0;
 }
 
+/*
+ * using power check for controlling mute led of HP notebooks
+ * check for mute state only on Speakers (nid = 0x10)
+ *
+ * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
+ * the LED is NOT working properly !
+ *
+ * Changed name to reflect that it now works for any designated
+ * model, not just HP HDX.
+ */
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int stac92xx_hp_check_power_status(struct hda_codec *codec,
+                                             hda_nid_t nid)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (nid == 0x10) {
+               if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
+                   HDA_AMP_MUTE)
+                       spec->gpio_data &= ~spec->gpio_led; /* orange */
+               else
+                       spec->gpio_data |= spec->gpio_led; /* white */
+
+               stac_gpio_set(codec, spec->gpio_mask,
+                             spec->gpio_dir,
+                             spec->gpio_data);
+       }
+
+       return 0;
+}
+#endif
+
 static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4371,16 +4789,11 @@ static int patch_stac9200(struct hda_codec *codec)
        spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
                                                        stac9200_models,
                                                        stac9200_cfg_tbl);
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                         stac9200_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = 1;
@@ -4392,7 +4805,8 @@ static int patch_stac9200(struct hda_codec *codec)
        spec->num_adcs = 1;
        spec->num_pwrs = 0;
 
-       if (spec->board_config == STAC_9200_GATEWAY ||
+       if (spec->board_config == STAC_9200_M4 ||
+           spec->board_config == STAC_9200_M4_2 ||
            spec->board_config == STAC_9200_OQO)
                spec->init = stac9200_eapd_init;
        else
@@ -4410,6 +4824,12 @@ static int patch_stac9200(struct hda_codec *codec)
                return err;
        }
 
+       /* CF-74 has no headphone detection, and the driver should *NOT*
+        * do detection and HP/speaker toggle because the hardware does it.
+        */
+       if (spec->board_config == STAC_9200_PANASONIC)
+               spec->hp_detect = 0;
+
        codec->patch_ops = stac92xx_patch_ops;
 
        return 0;
@@ -4427,21 +4847,26 @@ static int patch_stac925x(struct hda_codec *codec)
        codec->spec = spec;
        spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
        spec->pin_nids = stac925x_pin_nids;
-       spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
+
+       /* Check first for codec ID */
+       spec->board_config = snd_hda_check_board_codec_sid_config(codec,
+                                                       STAC_925x_MODELS,
+                                                       stac925x_models,
+                                                       stac925x_codec_id_cfg_tbl);
+
+       /* Now checks for PCI ID, if codec ID is not found */
+       if (spec->board_config < 0)
+               spec->board_config = snd_hda_check_board_config(codec,
+                                                       STAC_925x_MODELS,
                                                        stac925x_models,
                                                        stac925x_cfg_tbl);
  again:
-       if (spec->board_config < 0) {
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," 
+       if (spec->board_config < 0)
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
                                      "using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                         stac925x_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = 1;
@@ -4519,17 +4944,12 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
                                                        stac92hd73xx_models,
                                                        stac92hd73xx_cfg_tbl);
 again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for"
                        " STAC92HD73XX, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                stac92hd73xx_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        num_dacs = snd_hda_get_connections(codec, 0x0a,
                        conn, STAC92HD73_DAC_COUNT + 2) - 1;
@@ -4543,14 +4963,18 @@ again:
        case 0x3: /* 6 Channel */
                spec->mixer = stac92hd73xx_6ch_mixer;
                spec->init = stac92hd73xx_6ch_core_init;
+               spec->aloopback_ctl = stac92hd73xx_6ch_loopback;
                break;
        case 0x4: /* 8 Channel */
                spec->mixer = stac92hd73xx_8ch_mixer;
                spec->init = stac92hd73xx_8ch_core_init;
+               spec->aloopback_ctl = stac92hd73xx_8ch_loopback;
                break;
        case 0x5: /* 10 Channel */
                spec->mixer = stac92hd73xx_10ch_mixer;
                spec->init = stac92hd73xx_10ch_core_init;
+               spec->aloopback_ctl = stac92hd73xx_10ch_loopback;
+               break;
        }
        spec->multiout.dac_nids = spec->dac_nids;
 
@@ -4589,18 +5013,18 @@ again:
                        spec->init = dell_m6_core_init;
                switch (spec->board_config) {
                case STAC_DELL_M6_AMIC: /* Analog Mics */
-                       stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
+                       snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
                        spec->num_dmics = 0;
                        spec->private_dimux.num_items = 1;
                        break;
                case STAC_DELL_M6_DMIC: /* Digital Mics */
-                       stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
+                       snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
                        spec->num_dmics = 1;
                        spec->private_dimux.num_items = 2;
                        break;
                case STAC_DELL_M6_BOTH: /* Both */
-                       stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
-                       stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
+                       snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
+                       snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
                        spec->num_dmics = 1;
                        spec->private_dimux.num_items = 2;
                        break;
@@ -4660,7 +5084,10 @@ static struct hda_input_mux stac92hd83xxx_dmux = {
 static int patch_stac92hd83xxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
+       hda_nid_t conn[STAC92HD83_DAC_COUNT + 1];
        int err;
+       int num_dacs;
+       hda_nid_t nid;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -4674,23 +5101,17 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        spec->dmux_nids = stac92hd83xxx_dmux_nids;
        spec->adc_nids = stac92hd83xxx_adc_nids;
        spec->pwr_nids = stac92hd83xxx_pwr_nids;
+       spec->amp_nids = stac92hd83xxx_amp_nids;
        spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
        spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
        spec->multiout.dac_nids = spec->dac_nids;
 
        spec->init = stac92hd83xxx_core_init;
-       switch (codec->vendor_id) {
-       case 0x111d7605:
-               break;
-       default:
-               spec->num_pwrs--;
-               spec->init++; /* switch to config #2 */
-       }
-
        spec->mixer = stac92hd83xxx_mixer;
        spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
        spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
        spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
+       spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids);
        spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
        spec->dinput_mux = &stac92hd83xxx_dmux;
        spec->pin_nids = stac92hd83xxx_pin_nids;
@@ -4699,16 +5120,21 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
                                                        stac92hd83xxx_models,
                                                        stac92hd83xxx_cfg_tbl);
 again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for"
                        " STAC92HD83XXX, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                stac92hd83xxx_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
+
+       switch (codec->vendor_id) {
+       case 0x111d7604:
+       case 0x111d7605:
+       case 0x111d76d5:
+               if (spec->board_config == STAC_92HD83XXX_PWR_REF)
+                       break;
+               spec->num_pwrs = 0;
+               break;
        }
 
        err = stac92xx_parse_auto_config(codec, 0x1d, 0);
@@ -4727,6 +5153,23 @@ again:
                return err;
        }
 
+       switch (spec->board_config) {
+       case STAC_DELL_S14:
+               nid = 0xf;
+               break;
+       default:
+               nid = 0xe;
+               break;
+       }
+
+       num_dacs = snd_hda_get_connections(codec, nid,
+                               conn, STAC92HD83_DAC_COUNT + 1) - 1;
+
+       /* set port X to select the last DAC
+        */
+       snd_hda_codec_write_cache(codec, nid, 0,
+                       AC_VERB_SET_CONNECT_SEL, num_dacs);
+
        codec->patch_ops = stac92xx_patch_ops;
 
        codec->proc_widget_hook = stac92hd_proc_hook;
@@ -4734,7 +5177,16 @@ again:
        return 0;
 }
 
-static struct hda_input_mux stac92hd71bxx_dmux = {
+static struct hda_input_mux stac92hd71bxx_dmux_nomixer = {
+       .num_items = 3,
+       .items = {
+               { "Analog Inputs", 0x00 },
+               { "Digital Mic 1", 0x02 },
+               { "Digital Mic 2", 0x03 },
+       }
+};
+
+static struct hda_input_mux stac92hd71bxx_dmux_amixer = {
        .num_items = 4,
        .items = {
                { "Analog Inputs", 0x00 },
@@ -4744,10 +5196,67 @@ static struct hda_input_mux stac92hd71bxx_dmux = {
        }
 };
 
+/* get the pin connection (fixed, none, etc) */
+static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int cfg;
+
+       cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
+       return get_defcfg_connect(cfg);
+}
+
+static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
+                                        hda_nid_t *nids, int num_nids)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int idx, num;
+       unsigned int def_conf;
+
+       for (num = 0; num < num_nids; num++) {
+               for (idx = 0; idx < spec->num_pins; idx++)
+                       if (spec->pin_nids[idx] == nids[num])
+                               break;
+               if (idx >= spec->num_pins)
+                       break;
+               def_conf = stac_get_defcfg_connect(codec, idx);
+               if (def_conf == AC_JACK_PORT_NONE)
+                       break;
+       }
+       return num;
+}
+
+static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
+                                         hda_nid_t dig0pin)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int idx;
+
+       for (idx = 0; idx < spec->num_pins; idx++)
+               if (spec->pin_nids[idx] == dig0pin)
+                       break;
+       if ((idx + 2) >= spec->num_pins)
+               return 0;
+
+       /* dig1pin case */
+       if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE)
+               return 2;
+
+       /* dig0pin + dig2pin case */
+       if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE)
+               return 2;
+       if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE)
+               return 1;
+       else
+               return 0;
+}
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
+       struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
        int err = 0;
+       unsigned int ndmic_nids = 0;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -4755,27 +5264,32 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 
        codec->spec = spec;
        codec->patch_ops = stac92xx_patch_ops;
-       spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
+       spec->num_pins = STAC92HD71BXX_NUM_PINS;
+       switch (codec->vendor_id) {
+       case 0x111d76b6:
+       case 0x111d76b7:
+               spec->pin_nids = stac92hd71bxx_pin_nids_4port;
+               break;
+       case 0x111d7603:
+       case 0x111d7608:
+               /* On 92HD75Bx 0x27 isn't a pin nid */
+               spec->num_pins--;
+               /* fallthrough */
+       default:
+               spec->pin_nids = stac92hd71bxx_pin_nids_6port;
+       }
        spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
-       spec->pin_nids = stac92hd71bxx_pin_nids;
-       memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
-                       sizeof(stac92hd71bxx_dmux));
        spec->board_config = snd_hda_check_board_config(codec,
                                                        STAC_92HD71BXX_MODELS,
                                                        stac92hd71bxx_models,
                                                        stac92hd71bxx_cfg_tbl);
 again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for"
                        " STAC92HD71BXX, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                stac92hd71bxx_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        if (spec->board_config > STAC_92HD71BXX_REF) {
                /* GPIO0 = EAPD */
@@ -4784,16 +5298,34 @@ again:
                spec->gpio_data = 0x01;
        }
 
+       spec->dmic_nids = stac92hd71bxx_dmic_nids;
+       spec->dmux_nids = stac92hd71bxx_dmux_nids;
+
        switch (codec->vendor_id) {
        case 0x111d76b6: /* 4 Port without Analog Mixer */
        case 0x111d76b7:
+               unmute_init++;
+               /* fallthru */
        case 0x111d76b4: /* 6 Port without Analog Mixer */
        case 0x111d76b5:
+               memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_nomixer,
+                      sizeof(stac92hd71bxx_dmux_nomixer));
                spec->mixer = stac92hd71bxx_mixer;
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
+               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+                                       stac92hd71bxx_dmic_nids,
+                                       STAC92HD71BXX_NUM_DMICS);
+               if (spec->num_dmics) {
+                       spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+                       spec->dinput_mux = &spec->private_dimux;
+                       ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
+               }
                break;
        case 0x111d7608: /* 5 Port with Analog Mixer */
+               memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
+                      sizeof(stac92hd71bxx_dmux_amixer));
+               spec->private_dimux.num_items--;
                switch (spec->board_config) {
                case STAC_HP_M4:
                        /* Enable VREF power saving on GPIO1 detect */
@@ -4820,7 +5352,15 @@ again:
 
                /* disable VSW */
                spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
-               stac_change_pin_config(codec, 0xf, 0x40f000f0);
+               unmute_init++;
+               snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
+               snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
+               stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
+               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+                                       stac92hd71bxx_dmic_nids,
+                                       STAC92HD71BXX_NUM_DMICS - 1);
+               spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+               ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 2;
                break;
        case 0x111d7603: /* 6 Port with Analog Mixer */
                if ((codec->revision_id & 0xf) == 1)
@@ -4830,12 +5370,32 @@ again:
                spec->num_pwrs = 0;
                /* fallthru */
        default:
+               memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
+                      sizeof(stac92hd71bxx_dmux_amixer));
                spec->dinput_mux = &spec->private_dimux;
                spec->mixer = stac92hd71bxx_analog_mixer;
                spec->init = stac92hd71bxx_analog_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
+               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+                                       stac92hd71bxx_dmic_nids,
+                                       STAC92HD71BXX_NUM_DMICS);
+               spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+               ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
+       }
+
+       if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
+               snd_hda_sequence_write_cache(codec, unmute_init);
+
+       /* Some HP machines seem to have unstable codec communications
+        * especially with ATI fglrx driver.  For recovering from the
+        * CORB/RIRB stall, allow the BUS reset and keep always sync
+        */
+       if (spec->board_config == STAC_HP_DV5) {
+               codec->bus->sync_write = 1;
+               codec->bus->allow_bus_reset = 1;
        }
 
+       spec->aloopback_ctl = stac92hd71bxx_loopback;
        spec->aloopback_mask = 0x50;
        spec->aloopback_shift = 0;
 
@@ -4843,18 +5403,17 @@ again:
        spec->digbeep_nid = 0x26;
        spec->mux_nids = stac92hd71bxx_mux_nids;
        spec->adc_nids = stac92hd71bxx_adc_nids;
-       spec->dmic_nids = stac92hd71bxx_dmic_nids;
-       spec->dmux_nids = stac92hd71bxx_dmux_nids;
        spec->smux_nids = stac92hd71bxx_smux_nids;
        spec->pwr_nids = stac92hd71bxx_pwr_nids;
 
        spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
        spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
+       spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
 
        switch (spec->board_config) {
        case STAC_HP_M4:
                /* enable internal microphone */
-               stac_change_pin_config(codec, 0x0e, 0x01813040);
+               snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040);
                stac92xx_auto_set_pinctl(codec, 0x0e,
                        AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
                /* fallthru */
@@ -4867,21 +5426,46 @@ again:
        case STAC_DELL_M4_3:
                spec->num_dmics = 1;
                spec->num_smuxes = 0;
-               spec->num_dmuxes = 0;
+               spec->num_dmuxes = 1;
                break;
-       default:
-               spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
-               spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
-               spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
-       };
+       case STAC_HP_DV4_1222NR:
+               spec->num_dmics = 1;
+               /* I don't know if it needs 1 or 2 smuxes - will wait for
+                * bug reports to fix if needed
+                */
+               spec->num_smuxes = 1;
+               spec->num_dmuxes = 1;
+               spec->gpio_led = 0x01;
+               /* fallthrough */
+       case STAC_HP_DV5:
+               snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
+               stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN);
+               break;
+       case STAC_HP_HDX:
+               spec->num_dmics = 1;
+               spec->num_dmuxes = 1;
+               spec->num_smuxes = 1;
+               /* orange/white mute led on GPIO3, orange=0, white=1 */
+               spec->gpio_led = 0x08;
+               break;
+       }
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (spec->gpio_led) {
+               spec->gpio_mask |= spec->gpio_led;
+               spec->gpio_dir |= spec->gpio_led;
+               spec->gpio_data |= spec->gpio_led;
+               /* register check_power_status callback. */
+               codec->patch_ops.check_power_status =
+                       stac92xx_hp_check_power_status;
+       }
+#endif 
 
        spec->multiout.dac_nids = spec->dac_nids;
        if (spec->dinput_mux)
-               spec->private_dimux.num_items +=
-                       spec->num_dmics -
-                               (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
+               spec->private_dimux.num_items += spec->num_dmics - ndmic_nids;
 
-       err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
+       err = stac92xx_parse_auto_config(codec, 0x21, 0);
        if (!err) {
                if (spec->board_config < 0) {
                        printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -4900,7 +5484,7 @@ again:
        codec->proc_widget_hook = stac92hd7x_proc_hook;
 
        return 0;
-};
+}
 
 static int patch_stac922x(struct hda_codec *codec)
 {
@@ -4956,17 +5540,12 @@ static int patch_stac922x(struct hda_codec *codec)
        }
 
  again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
                        "using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                stac922x_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->adc_nids = stac922x_adc_nids;
        spec->mux_nids = stac922x_mux_nids;
@@ -5017,24 +5596,19 @@ static int patch_stac927x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+       codec->slave_dig_outs = stac927x_slave_dig_outs;
        spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
        spec->pin_nids = stac927x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
                                                        stac927x_models,
                                                        stac927x_cfg_tbl);
  again:
-       if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
-               if (spec->board_config < 0)
-                       snd_printdd(KERN_INFO "hda_codec: Unknown model for"
-                                   "STAC927x, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       if (spec->board_config < 0)
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+                           "STAC927x, using BIOS defaults\n");
+       else
+               stac92xx_set_config_regs(codec,
                                stac927x_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->digbeep_nid = 0x23;
        spec->adc_nids = stac927x_adc_nids;
@@ -5063,20 +5637,27 @@ static int patch_stac927x(struct hda_codec *codec)
                case 0x10280209:
                case 0x1028022e:
                        /* correct the device field to SPDIF out */
-                       stac_change_pin_config(codec, 0x21, 0x01442070);
+                       snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070);
                        break;
-               };
+               }
                /* configure the analog microphone on some laptops */
-               stac_change_pin_config(codec, 0x0c, 0x90a79130);
+               snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130);
                /* correct the front output jack as a hp out */
-               stac_change_pin_config(codec, 0x0f, 0x0227011f);
+               snd_hda_codec_set_pincfg(codec, 0x0f, 0x0227011f);
                /* correct the front input jack as a mic */
-               stac_change_pin_config(codec, 0x0e, 0x02a79130);
+               snd_hda_codec_set_pincfg(codec, 0x0e, 0x02a79130);
                /* fallthru */
        case STAC_DELL_3ST:
                /* GPIO2 High = Enable EAPD */
                spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
                spec->gpio_data = 0x04;
+               switch (codec->subsystem_id) {
+               case 0x1028022f:
+                       /* correct EAPD to be GPIO0 */
+                       spec->eapd_mask = spec->gpio_mask = 0x01;
+                       spec->gpio_dir = spec->gpio_data = 0x01;
+                       break;
+               };
                spec->dmic_nids = stac927x_dmic_nids;
                spec->num_dmics = STAC927X_NUM_DMICS;
 
@@ -5098,6 +5679,7 @@ static int patch_stac927x(struct hda_codec *codec)
        }
 
        spec->num_pwrs = 0;
+       spec->aloopback_ctl = stac927x_loopback;
        spec->aloopback_mask = 0x40;
        spec->aloopback_shift = 0;
        spec->eapd_switch = 1;
@@ -5156,16 +5738,11 @@ static int patch_stac9205(struct hda_codec *codec)
                                                        stac9205_models,
                                                        stac9205_cfg_tbl);
  again:
-       if (spec->board_config < 0) {
+       if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
-               err = stac92xx_save_bios_config_regs(codec);
-       } else
-               err = stac_save_pin_cfgs(codec,
+       else
+               stac92xx_set_config_regs(codec,
                                         stac9205_brd_tbl[spec->board_config]);
-       if (err < 0) {
-               stac92xx_free(codec);
-               return err;
-       }
 
        spec->digbeep_nid = 0x23;
        spec->adc_nids = stac9205_adc_nids;
@@ -5182,17 +5759,20 @@ static int patch_stac9205(struct hda_codec *codec)
 
        spec->init = stac9205_core_init;
        spec->mixer = stac9205_mixer;
+       spec->aloopback_ctl = stac9205_loopback;
 
        spec->aloopback_mask = 0x40;
        spec->aloopback_shift = 0;
-       spec->eapd_switch = 1;
+       /* Turn on/off EAPD per HP plugging */
+       if (spec->board_config != STAC_9205_EAPD)
+               spec->eapd_switch = 1;
        spec->multiout.dac_nids = spec->dac_nids;
        
        switch (spec->board_config){
        case STAC_9205_DELL_M43:
                /* Enable SPDIF in/out */
-               stac_change_pin_config(codec, 0x1f, 0x01441030);
-               stac_change_pin_config(codec, 0x20, 0x1c410030);
+               snd_hda_codec_set_pincfg(codec, 0x1f, 0x01441030);
+               snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030);
 
                /* Enable unsol response for GPIO4/Dock HP connection */
                err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
@@ -5249,223 +5829,89 @@ static int patch_stac9205(struct hda_codec *codec)
  * STAC9872 hack
  */
 
-/* static config for Sony VAIO FE550G and Sony VAIO AR */
-static hda_nid_t vaio_dacs[] = { 0x2 };
-#define VAIO_HP_DAC    0x5
-static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
-static hda_nid_t vaio_mux_nids[] = { 0x15 };
-
-static struct hda_input_mux vaio_mux = {
-       .num_items = 3,
-       .items = {
-               /* { "HP", 0x0 }, */
-               { "Mic Jack", 0x1 },
-               { "Internal Mic", 0x2 },
-               { "PCM", 0x3 },
-       }
-};
-
-static struct hda_verb vaio_init[] = {
-       {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
-       {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
-       {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
-       {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
+static struct hda_verb stac9872_core_init[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
        {}
 };
 
-static struct hda_verb vaio_ar_init[] = {
-       {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
-       {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
-       {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
-       {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
-/*     {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
-/*     {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
-       {}
-};
-
-static struct snd_kcontrol_new vaio_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
+static struct snd_kcontrol_new stac9872_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .count = 1,
-               .info = stac92xx_mux_enum_info,
-               .get = stac92xx_mux_enum_get,
-               .put = stac92xx_mux_enum_put,
-       },
-       {}
+       { } /* end */
 };
 
-static struct snd_kcontrol_new vaio_ar_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
-       /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .count = 1,
-               .info = stac92xx_mux_enum_info,
-               .get = stac92xx_mux_enum_get,
-               .put = stac92xx_mux_enum_put,
-       },
-       {}
+static hda_nid_t stac9872_pin_nids[] = {
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x11, 0x13, 0x14,
 };
 
-static struct hda_codec_ops stac9872_patch_ops = {
-       .build_controls = stac92xx_build_controls,
-       .build_pcms = stac92xx_build_pcms,
-       .init = stac92xx_init,
-       .free = stac92xx_free,
-#ifdef SND_HDA_NEEDS_RESUME
-       .resume = stac92xx_resume,
-#endif
+static hda_nid_t stac9872_adc_nids[] = {
+       0x8 /*,0x6*/
 };
 
-static int stac9872_vaio_init(struct hda_codec *codec)
-{
-       int err;
-
-       err = stac92xx_init(codec);
-       if (err < 0)
-               return err;
-       if (codec->patch_ops.unsol_event)
-               codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
-       return 0;
-}
-
-static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
-{
-       if (get_pin_presence(codec, 0x0a)) {
-               stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
-               stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
-       } else {
-               stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
-               stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
-       }
-} 
-
-static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (res >> 26) {
-       case STAC_HP_EVENT:
-               stac9872_vaio_hp_detect(codec, res);
-               break;
-       }
-}
-
-static struct hda_codec_ops stac9872_vaio_patch_ops = {
-       .build_controls = stac92xx_build_controls,
-       .build_pcms = stac92xx_build_pcms,
-       .init = stac9872_vaio_init,
-       .free = stac92xx_free,
-       .unsol_event = stac9872_vaio_unsol_event,
-#ifdef CONFIG_PM
-       .resume = stac92xx_resume,
-#endif
+static hda_nid_t stac9872_mux_nids[] = {
+       0x15
 };
 
-enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
-       CXD9872RD_VAIO,
-       /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
-       STAC9872AK_VAIO, 
-       /* Unknown. id=0x83847661 and subsys=0x104D1200. */
-       STAC9872K_VAIO,
-       /* AR Series. id=0x83847664 and subsys=104D1300 */
-       CXD9872AKD_VAIO,
-       STAC_9872_MODELS,
+static unsigned int stac9872_vaio_pin_configs[9] = {
+       0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
+       0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
+       0x90a7013e
 };
 
 static const char *stac9872_models[STAC_9872_MODELS] = {
-       [CXD9872RD_VAIO]        = "vaio",
-       [CXD9872AKD_VAIO]       = "vaio-ar",
+       [STAC_9872_AUTO] = "auto",
+       [STAC_9872_VAIO] = "vaio",
+};
+
+static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
+       [STAC_9872_VAIO] = stac9872_vaio_pin_configs,
 };
 
 static struct snd_pci_quirk stac9872_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
-       SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
-       SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
-       SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
-       {}
+       SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
+                          "Sony VAIO F/S", STAC_9872_VAIO),
+       {} /* terminator */
 };
 
 static int patch_stac9872(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
-       int board_config;
+       int err;
 
-       board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
-                                                 stac9872_models,
-                                                 stac9872_cfg_tbl);
-       if (board_config < 0)
-               /* unknown config, let generic-parser do its job... */
-               return snd_hda_parse_generic_codec(codec);
-       
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
-
        codec->spec = spec;
-       switch (board_config) {
-       case CXD9872RD_VAIO:
-       case STAC9872AK_VAIO:
-       case STAC9872K_VAIO:
-               spec->mixer = vaio_mixer;
-               spec->init = vaio_init;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
-               spec->multiout.dac_nids = vaio_dacs;
-               spec->multiout.hp_nid = VAIO_HP_DAC;
-               spec->num_adcs = ARRAY_SIZE(vaio_adcs);
-               spec->adc_nids = vaio_adcs;
-               spec->num_pwrs = 0;
-               spec->input_mux = &vaio_mux;
-               spec->mux_nids = vaio_mux_nids;
-               codec->patch_ops = stac9872_vaio_patch_ops;
-               break;
-       
-       case CXD9872AKD_VAIO:
-               spec->mixer = vaio_ar_mixer;
-               spec->init = vaio_ar_init;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
-               spec->multiout.dac_nids = vaio_dacs;
-               spec->multiout.hp_nid = VAIO_HP_DAC;
-               spec->num_adcs = ARRAY_SIZE(vaio_adcs);
-               spec->num_pwrs = 0;
-               spec->adc_nids = vaio_adcs;
-               spec->input_mux = &vaio_mux;
-               spec->mux_nids = vaio_mux_nids;
-               codec->patch_ops = stac9872_patch_ops;
-               break;
-       }
+       spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
+       spec->pin_nids = stac9872_pin_nids;
+
+       spec->board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
+                                                       stac9872_models,
+                                                       stac9872_cfg_tbl);
+       if (spec->board_config < 0)
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9872, "
+                           "using BIOS defaults\n");
+       else
+               stac92xx_set_config_regs(codec,
+                                        stac9872_brd_tbl[spec->board_config]);
 
+       spec->multiout.dac_nids = spec->dac_nids;
+       spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids);
+       spec->adc_nids = stac9872_adc_nids;
+       spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
+       spec->mux_nids = stac9872_mux_nids;
+       spec->mixer = stac9872_mixer;
+       spec->init = stac9872_core_init;
+
+       err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
+       if (err < 0) {
+               stac92xx_free(codec);
+               return -EINVAL;
+       }
+       spec->input_mux = &spec->private_imux;
+       codec->patch_ops = stac92xx_patch_ops;
        return 0;
 }
 
@@ -5512,6 +5958,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
        { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
        { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
+       { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 },
        { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
        { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
        { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
@@ -5523,6 +5970,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
        { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
        { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
        { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },