Merge branch 'topic/hda-cirrus' into topic/hda
authorTakashi Iwai <tiwai@suse.de>
Thu, 30 Jul 2009 16:09:04 +0000 (18:09 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 30 Jul 2009 16:09:04 +0000 (18:09 +0200)
17 files changed:
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sound/alsa/HD-Audio.txt
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_intelhdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c

index 4d120a6..775beea 100644 (file)
@@ -155,6 +155,8 @@ ALC882/883/885/888/889
   fujitsu-pi2515 Fujitsu AMILO Pi2515
   fujitsu-xa3530 Fujitsu AMILO XA3530
   3stack-6ch-intel Intel DG33* boards
+  intel-alc889a        Intel IbexPeak with ALC889A
+  intel-x58    Intel DX58 with ALC889
   asus-p5q     ASUS P5Q-EM boards
   mb31         MacBook 3,1
   sony-vaio-tt  Sony VAIO TT
index 0b5b480..7b8a5f9 100644 (file)
@@ -138,6 +138,10 @@ override the BIOS setup or to provide more comprehensive features.
 The driver checks PCI SSID and looks through the static configuration
 table until any matching entry is found.  If you have a new machine,
 you may see a message like below:
+------------------------------------------------------------------------
+    hda_codec: ALC880: BIOS auto-probing.
+------------------------------------------------------------------------
+Meanwhile, in the earlier versions, you would see a message like:
 ------------------------------------------------------------------------
     hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...
 ------------------------------------------------------------------------
index 08fe659..3f51a98 100644 (file)
@@ -51,19 +51,22 @@ static void snd_hda_generate_beep(struct work_struct *work)
  * The tone frequency of beep generator on IDT/STAC codecs is
  * defined from the 8bit tone parameter, in Hz,
  *    freq = 48000 * (257 - tone) / 1024
- * that is from 12kHz to 93.75kHz in step of 46.875 hz
+ * that is from 12kHz to 93.75Hz in steps of 46.875 Hz
  */
 static int beep_linear_tone(struct hda_beep *beep, int hz)
 {
+       if (hz <= 0)
+               return 0;
        hz *= 1000; /* fixed point */
-       hz = hz - DIGBEEP_HZ_MIN;
+       hz = hz - DIGBEEP_HZ_MIN
+               + DIGBEEP_HZ_STEP / 2; /* round to nearest step */
        if (hz < 0)
                hz = 0; /* turn off PC beep*/
        else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
-               hz = 0xff;
+               hz = 1; /* max frequency */
        else {
                hz /= DIGBEEP_HZ_STEP;
-               hz++;
+               hz = 255 - hz;
        }
        return hz;
 }
index eea91c3..a23c27d 100644 (file)
@@ -151,7 +151,14 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
 {
        u32 val;
 
-       val = (u32)(codec->addr & 0x0f) << 28;
+       if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) ||
+           (verb & ~0xfff) || (parm & ~0xffff)) {
+               printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n",
+                      codec->addr, direct, nid, verb, parm);
+               return ~0;
+       }
+
+       val = (u32)codec->addr << 28;
        val |= (u32)direct << 27;
        val |= (u32)nid << 20;
        val |= verb << 8;
@@ -168,6 +175,9 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
        struct hda_bus *bus = codec->bus;
        int err;
 
+       if (cmd == ~0)
+               return -1;
+
        if (res)
                *res = -1;
  again:
@@ -292,11 +302,20 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
        unsigned int parm;
        int i, conn_len, conns;
        unsigned int shift, num_elems, mask;
+       unsigned int wcaps;
        hda_nid_t prev_nid;
 
        if (snd_BUG_ON(!conn_list || max_conns <= 0))
                return -EINVAL;
 
+       wcaps = get_wcaps(codec, nid);
+       if (!(wcaps & AC_WCAP_CONN_LIST) &&
+           get_wcaps_type(wcaps) != AC_WID_VOL_KNB) {
+               snd_printk(KERN_WARNING "hda_codec: "
+                          "connection list not available for 0x%x\n", nid);
+               return -EINVAL;
+       }
+
        parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
        if (parm & AC_CLIST_LONG) {
                /* long form */
@@ -317,6 +336,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
                /* single connection */
                parm = snd_hda_codec_read(codec, nid, 0,
                                          AC_VERB_GET_CONNECT_LIST, 0);
+               if (parm == -1 && codec->bus->rirb_error)
+                       return -EIO;
                conn_list[0] = parm & mask;
                return 1;
        }
@@ -328,11 +349,20 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
                int range_val;
                hda_nid_t val, n;
 
-               if (i % num_elems == 0)
+               if (i % num_elems == 0) {
                        parm = snd_hda_codec_read(codec, nid, 0,
                                                  AC_VERB_GET_CONNECT_LIST, i);
+                       if (parm == -1 && codec->bus->rirb_error)
+                               return -EIO;
+               }
                range_val = !!(parm & (1 << (shift-1))); /* ranges */
                val = parm & mask;
+               if (val == 0) {
+                       snd_printk(KERN_WARNING "hda_codec: "
+                                  "invalid CONNECT_LIST verb %x[%i]:%x\n",
+                                   nid, i, parm);
+                       return 0;
+               }
                parm >>= shift;
                if (range_val) {
                        /* ranges between the previous and this one */
@@ -722,8 +752,7 @@ static int read_pin_defaults(struct hda_codec *codec)
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                struct hda_pincfg *pin;
                unsigned int wcaps = get_wcaps(codec, nid);
-               unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
-                               AC_WCAP_TYPE_SHIFT;
+               unsigned int wid_type = get_wcaps_type(wcaps);
                if (wid_type != AC_WID_PIN)
                        continue;
                pin = snd_array_new(&codec->init_pins);
@@ -2347,16 +2376,20 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
        hda_nid_t nid;
        int i;
 
-       snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+       /* this delay seems necessary to avoid click noise at power-down */
+       if (power_state == AC_PWRST_D3)
+               msleep(100);
+       snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
                            power_state);
-       msleep(10); /* partial workaround for "azx_get_response timeout" */
+       /* partial workaround for "azx_get_response timeout" */
+       if (power_state == AC_PWRST_D0)
+               msleep(10);
 
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                unsigned int wcaps = get_wcaps(codec, nid);
                if (wcaps & AC_WCAP_POWER) {
-                       unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
-                               AC_WCAP_TYPE_SHIFT;
+                       unsigned int wid_type = get_wcaps_type(wcaps);
                        if (power_state == AC_PWRST_D3 &&
                            wid_type == AC_WID_PIN) {
                                unsigned int pincap;
@@ -2564,7 +2597,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
        case 20:
        case 24:
        case 32:
-               if (maxbps >= 32)
+               if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
                        val |= 0x40;
                else if (maxbps >= 24)
                        val |= 0x30;
@@ -2693,7 +2726,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
                }
                if (streams & AC_SUPFMT_FLOAT32) {
                        formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
-                       bps = 32;
+                       if (!bps)
+                               bps = 32;
                }
                if (streams == AC_SUPFMT_AC3) {
                        /* should be exclusive */
@@ -3467,10 +3501,16 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
                }
                mutex_lock(&codec->spdif_mutex);
                if (mout->share_spdif) {
-                       runtime->hw.rates &= mout->spdif_rates;
-                       runtime->hw.formats &= mout->spdif_formats;
-                       if (mout->spdif_maxbps < hinfo->maxbps)
-                               hinfo->maxbps = mout->spdif_maxbps;
+                       if ((runtime->hw.rates & mout->spdif_rates) &&
+                           (runtime->hw.formats & mout->spdif_formats)) {
+                               runtime->hw.rates &= mout->spdif_rates;
+                               runtime->hw.formats &= mout->spdif_formats;
+                               if (mout->spdif_maxbps < hinfo->maxbps)
+                                       hinfo->maxbps = mout->spdif_maxbps;
+                       } else {
+                               mout->share_spdif = 0;
+                               /* FIXME: need notify? */
+                       }
                }
                mutex_unlock(&codec->spdif_mutex);
        }
@@ -3640,8 +3680,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        end_nid = codec->start_nid + codec->num_nodes;
        for (nid = codec->start_nid; nid < end_nid; nid++) {
                unsigned int wid_caps = get_wcaps(codec, nid);
-               unsigned int wid_type =
-                       (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               unsigned int wid_type = get_wcaps_type(wid_caps);
                unsigned int def_conf;
                short assoc, loc;
 
index fcad5ec..9446a5a 100644 (file)
@@ -508,7 +508,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
        char name[64];
        char *sname;
        long long val;
-       int n;
+       unsigned int n;
 
        while (!snd_info_get_line(buffer, line, sizeof(line))) {
                if (sscanf(line, "%s %llx", name, &val) != 2)
@@ -539,7 +539,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
                                sname++;
                                n = 10 * n + name[4] - '0';
                        }
-                       if (n < 0 || n > 31) /* double the CEA limit */
+                       if (n >= ELD_MAX_SAD)
                                continue;
                        if (!strcmp(sname, "_coding_type"))
                                e->sad[n].format = val;
index 1d5797a..b36f6c5 100644 (file)
@@ -121,11 +121,17 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
        if (node == NULL)
                return -ENOMEM;
        node->nid = nid;
-       nconns = snd_hda_get_connections(codec, nid, conn_list,
-                                        HDA_MAX_CONNECTIONS);
-       if (nconns < 0) {
-               kfree(node);
-               return nconns;
+       node->wid_caps = get_wcaps(codec, nid);
+       node->type = get_wcaps_type(node->wid_caps);
+       if (node->wid_caps & AC_WCAP_CONN_LIST) {
+               nconns = snd_hda_get_connections(codec, nid, conn_list,
+                                                HDA_MAX_CONNECTIONS);
+               if (nconns < 0) {
+                       kfree(node);
+                       return nconns;
+               }
+       } else {
+               nconns = 0;
        }
        if (nconns <= ARRAY_SIZE(node->slist))
                node->conn_list = node->slist;
@@ -140,8 +146,6 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid
        }
        memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t));
        node->nconns = nconns;
-       node->wid_caps = get_wcaps(codec, nid);
-       node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
 
        if (node->type == AC_WID_PIN) {
                node->pin_caps = snd_hda_query_pin_caps(codec, node->nid);
index a2f4a11..4db854b 100644 (file)
@@ -1469,6 +1469,18 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
                mutex_unlock(&chip->open_mutex);
                return err;
        }
+       snd_pcm_limit_hw_rates(runtime);
+       /* sanity check */
+       if (snd_BUG_ON(!runtime->hw.channels_min) ||
+           snd_BUG_ON(!runtime->hw.channels_max) ||
+           snd_BUG_ON(!runtime->hw.formats) ||
+           snd_BUG_ON(!runtime->hw.rates)) {
+               azx_release_device(azx_dev);
+               hinfo->ops.close(hinfo, apcm->codec, substream);
+               snd_hda_power_down(apcm->codec);
+               mutex_unlock(&chip->open_mutex);
+               return -EINVAL;
+       }
        spin_lock_irqsave(&chip->reg_lock, flags);
        azx_dev->substream = substream;
        azx_dev->running = 0;
@@ -1477,7 +1489,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        runtime->private_data = azx_dev;
        snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
-
        return 0;
 }
 
@@ -2337,9 +2348,19 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        gcap = azx_readw(chip, GCAP);
        snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
 
-       /* ATI chips seems buggy about 64bit DMA addresses */
-       if (chip->driver_type == AZX_DRIVER_ATI)
-               gcap &= ~ICH6_GCAP_64OK;
+       /* disable SB600 64bit support for safety */
+       if ((chip->driver_type == AZX_DRIVER_ATI) ||
+           (chip->driver_type == AZX_DRIVER_ATIHDMI)) {
+               struct pci_dev *p_smbus;
+               p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
+                                        PCI_DEVICE_ID_ATI_SBX00_SMBUS,
+                                        NULL);
+               if (p_smbus) {
+                       if (p_smbus->revision < 0x30)
+                               gcap &= ~ICH6_GCAP_64OK;
+                       pci_dev_put(p_smbus);
+               }
+       }
 
        /* allow 64bit DMA address if supported by H/W */
        if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
@@ -2613,11 +2634,15 @@ static struct pci_device_id azx_ids[] = {
        /* this entry seems still valid -- i.e. without emu20kx chip */
        { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
 #endif
-       /* AMD Generic, PCI class code and Vendor ID for HD Audio */
+       /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
          .driver_data = AZX_DRIVER_GENERIC },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID),
+         .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+         .class_mask = 0xffffff,
+         .driver_data = AZX_DRIVER_GENERIC },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
index 75aa378..fa57cb9 100644 (file)
@@ -407,6 +407,9 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
        return codec->wcaps[nid - codec->start_nid];
 }
 
+/* get the widget type from widget capability bits */
+#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT)
+
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps);
index 418c5d1..a721eb0 100644 (file)
@@ -508,8 +508,7 @@ static void print_codec_info(struct snd_info_entry *entry,
                unsigned int wid_caps =
                        snd_hda_param_read(codec, nid,
                                           AC_PAR_AUDIO_WIDGET_CAP);
-               unsigned int wid_type =
-                       (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               unsigned int wid_type = get_wcaps_type(wid_caps);
                hda_nid_t conn[HDA_MAX_CONNECTIONS];
                int conn_len = 0;
 
index ad70076..ab3bcb7 100644 (file)
@@ -2982,7 +2982,8 @@ static int patch_ad1988(struct hda_codec *codec)
        board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
                                                  ad1988_models, ad1988_cfg_tbl);
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
                board_config = AD1988_AUTO;
        }
 
@@ -3746,9 +3747,30 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
        { } /* end */
 };
 
+static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       int mute = (!ucontrol->value.integer.value[0] &&
+                   !ucontrol->value.integer.value[1]);
+       /* toggle GPIO1 according to the mute state */
+       snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                           mute ? 0x02 : 0x0);
+       return ret;
+}
+
 static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = ad1884a_mobile_master_sw_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+       },
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
@@ -3869,6 +3891,10 @@ static struct hda_verb ad1884a_mobile_verbs[] = {
        /* unsolicited event for pin-sense */
        {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
+       /* allow to touch GPIO1 (for mute control) */
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
        { } /* end */
 };
 
index 019ca7c..d08353d 100644 (file)
@@ -459,8 +459,7 @@ static void parse_input(struct hda_codec *codec)
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                unsigned int wcaps = get_wcaps(codec, nid);
-               unsigned int type = (wcaps & AC_WCAP_TYPE) >>
-                       AC_WCAP_TYPE_SHIFT;
+               unsigned int type = get_wcaps_type(wcaps);
                if (type != AC_WID_AUD_IN)
                        continue;
                if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
index c921264..780e1a7 100644 (file)
@@ -635,7 +635,8 @@ static int patch_cmi9880(struct hda_codec *codec)
                                                        cmi9880_models,
                                                        cmi9880_cfg_tbl);
        if (spec->board_config < 0) {
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
                spec->board_config = CMI_AUTO; /* try everything */
        }
 
index ac868c5..9d899ed 100644 (file)
@@ -108,6 +108,8 @@ struct conexant_spec {
        struct hda_input_mux private_imux;
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
+       unsigned int dell_automute;
+       unsigned int port_d_mode;
 };
 
 static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -1908,6 +1910,480 @@ static int patch_cxt5051(struct hda_codec *codec)
        return 0;
 }
 
+/* Conexant 5066 specific */
+
+static hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
+static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
+static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
+#define CXT5066_SPDIF_OUT      0x21
+
+static struct hda_channel_mode cxt5066_modes[1] = {
+       { 2, NULL },
+};
+
+static void cxt5066_update_speaker(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       unsigned int pinctl;
+
+       snd_printdd("CXT5066: update speaker, hp_present=%d\n",
+               spec->hp_present);
+
+       /* Port A (HP) */
+       pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0;
+       snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                       pinctl);
+
+       /* Port D (HP/LO) */
+       pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
+               ? spec->port_d_mode : 0;
+       snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                       pinctl);
+
+       /* CLASS_D AMP */
+       pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
+       snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                       pinctl);
+
+       if (spec->dell_automute) {
+               /* DELL AIO Port Rule: PortA > PortD > IntSpk */
+               pinctl = (!(spec->hp_present & 1) && spec->cur_eapd)
+                       ? PIN_OUT : 0;
+               snd_hda_codec_write(codec, 0x1c, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+       }
+}
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       if (!cxt_eapd_put(kcontrol, ucontrol))
+               return 0;
+
+       cxt5066_update_speaker(codec);
+       return 1;
+}
+
+/* toggle input of built-in and mic jack appropriately */
+static void cxt5066_automic(struct hda_codec *codec)
+{
+       static struct hda_verb ext_mic_present[] = {
+               /* enable external mic, port B */
+               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+               /* switch to external mic input */
+               {0x17, AC_VERB_SET_CONNECT_SEL, 0},
+
+               /* disable internal mic, port C */
+               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+               {}
+       };
+       static struct hda_verb ext_mic_absent[] = {
+               /* enable internal mic, port C */
+               {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+               /* switch to internal mic input */
+               {0x17, AC_VERB_SET_CONNECT_SEL, 1},
+
+               /* disable external mic, port B */
+               {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+               {}
+       };
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x1a, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       if (present) {
+               snd_printdd("CXT5066: external microphone detected\n");
+               snd_hda_sequence_write(codec, ext_mic_present);
+       } else {
+               snd_printdd("CXT5066: external microphone absent\n");
+               snd_hda_sequence_write(codec, ext_mic_absent);
+       }
+}
+
+/* mute internal speaker if HP is plugged */
+static void cxt5066_hp_automute(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       unsigned int portA, portD;
+
+       /* Port A */
+       portA = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0)
+               & AC_PINSENSE_PRESENCE;
+
+       /* Port D */
+       portD = (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0)
+               & AC_PINSENSE_PRESENCE) << 1;
+
+       spec->hp_present = !!(portA | portD);
+       snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
+               portA, portD, spec->hp_present);
+       cxt5066_update_speaker(codec);
+}
+
+/* unsolicited event for jack sensing */
+static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
+       switch (res >> 26) {
+       case CONEXANT_HP_EVENT:
+               cxt5066_hp_automute(codec);
+               break;
+       case CONEXANT_MIC_EVENT:
+               cxt5066_automic(codec);
+               break;
+       }
+}
+
+static const struct hda_input_mux cxt5066_analog_mic_boost = {
+       .num_items = 5,
+       .items = {
+               { "0dB",  0 },
+               { "10dB", 1 },
+               { "20dB", 2 },
+               { "30dB", 3 },
+               { "40dB", 4 },
+       },
+};
+
+static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_info *uinfo)
+{
+       return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo);
+}
+
+static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int val;
+
+       val = snd_hda_codec_read(codec, 0x17, 0,
+               AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_OUTPUT);
+
+       ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN;
+       return 0;
+}
+
+static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
+       unsigned int idx;
+
+       if (!imux->num_items)
+               return 0;
+       idx = ucontrol->value.enumerated.item[0];
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+
+       snd_hda_codec_write_cache(codec, 0x17, 0,
+               AC_VERB_SET_AMP_GAIN_MUTE,
+               AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
+                       imux->items[idx].index);
+
+       return 1;
+}
+
+static struct hda_input_mux cxt5066_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic B", 0 },
+               { "Mic C", 1 },
+               { "Mic E", 2 },
+               { "Mic F", 3 },
+       },
+};
+
+static struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
+       .ops = &snd_hda_bind_vol,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT),
+               0
+       },
+};
+
+static struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT),
+               0
+       },
+};
+
+static struct snd_kcontrol_new cxt5066_mixer_master[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
+       {}
+};
+
+static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Volume",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                                 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                                 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+               .info = snd_hda_mixer_amp_volume_info,
+               .get = snd_hda_mixer_amp_volume_get,
+               .put = snd_hda_mixer_amp_volume_put,
+               .tlv = { .c = snd_hda_mixer_amp_tlv },
+               /* offset by 28 volume steps to limit minimum gain to -46dB */
+               .private_value =
+                       HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28),
+       },
+       {}
+};
+
+static struct snd_kcontrol_new cxt5066_mixers[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = cxt_eapd_info,
+               .get = cxt_eapd_get,
+               .put = cxt5066_hp_master_sw_put,
+               .private_value = 0x1d,
+       },
+
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Mic Boost Capture Enum",
+               .info = cxt5066_mic_boost_mux_enum_info,
+               .get = cxt5066_mic_boost_mux_enum_get,
+               .put = cxt5066_mic_boost_mux_enum_put,
+       },
+
+       HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others),
+       HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others),
+       {}
+};
+
+static struct hda_verb cxt5066_init_verbs[] = {
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
+       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
+
+       /* Speakers  */
+       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       /* HP, Amp  */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       /* DAC1 */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /* no digital microphone support yet */
+       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* Audio input selector */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
+
+       /* SPDIF route: PCM */
+       {0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* EAPD */
+       {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+
+       /* not handling these yet */
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+       {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+       {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+       {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+       {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
+       { } /* end */
+};
+
+static struct hda_verb cxt5066_init_verbs_olpc[] = {
+       /* Port A: headphones */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       /* Port B: external microphone */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+       /* Port C: internal microphone */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+
+       /* Port D: unused */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* Port E: unused, but has primary EAPD */
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+
+       /* Port F: unused */
+       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* Port G: internal speakers */
+       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
+
+       /* DAC1 */
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+       /* DAC2: unused */
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+
+       /* Disable digital microphone port */
+       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* Audio input selectors */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+
+       /* Disable SPDIF */
+       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+
+       /* enable unsolicited events for Port A and B */
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
+       { } /* end */
+};
+
+static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       { } /* end */
+};
+
+/* initialize jack-sensing, too */
+static int cxt5066_init(struct hda_codec *codec)
+{
+       snd_printdd("CXT5066: init\n");
+       conexant_init(codec);
+       if (codec->patch_ops.unsol_event) {
+               cxt5066_hp_automute(codec);
+               cxt5066_automic(codec);
+       }
+       return 0;
+}
+
+enum {
+       CXT5066_LAPTOP,                 /* Laptops w/ EAPD support */
+       CXT5066_DELL_LAPTOP,    /* Dell Laptop */
+       CXT5066_OLPC_XO_1_5,    /* OLPC XO 1.5 */
+       CXT5066_MODELS
+};
+
+static const char *cxt5066_models[CXT5066_MODELS] = {
+       [CXT5066_LAPTOP]                = "laptop",
+       [CXT5066_DELL_LAPTOP]   = "dell-laptop",
+       [CXT5066_OLPC_XO_1_5]   = "olpc-xo-1_5",
+};
+
+static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
+                     CXT5066_LAPTOP),
+       SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
+                     CXT5066_DELL_LAPTOP),
+       {}
+};
+
+static int patch_cxt5066(struct hda_codec *codec)
+{
+       struct conexant_spec *spec;
+       int board_config;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+
+       codec->patch_ops = conexant_patch_ops;
+       codec->patch_ops.init = cxt5066_init;
+
+       spec->dell_automute = 0;
+       spec->multiout.max_channels = 2;
+       spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids);
+       spec->multiout.dac_nids = cxt5066_dac_nids;
+       spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT;
+       spec->num_adc_nids = 1;
+       spec->adc_nids = cxt5066_adc_nids;
+       spec->capsrc_nids = cxt5066_capsrc_nids;
+       spec->input_mux = &cxt5066_capture_source;
+
+       spec->port_d_mode = PIN_HP;
+
+       spec->num_init_verbs = 1;
+       spec->init_verbs[0] = cxt5066_init_verbs;
+       spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes);
+       spec->channel_mode = cxt5066_modes;
+       spec->cur_adc = 0;
+       spec->cur_adc_idx = 0;
+
+       board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
+                                                 cxt5066_models, cxt5066_cfg_tbl);
+       switch (board_config) {
+       default:
+       case CXT5066_LAPTOP:
+               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+               break;
+       case CXT5066_DELL_LAPTOP:
+               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+
+               spec->port_d_mode = PIN_OUT;
+               spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo;
+               spec->num_init_verbs++;
+               spec->dell_automute = 1;
+               break;
+       case CXT5066_OLPC_XO_1_5:
+               codec->patch_ops.unsol_event = cxt5066_unsol_event;
+               spec->init_verbs[0] = cxt5066_init_verbs_olpc;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
+               spec->mixers[spec->num_mixers++] = cxt5066_mixers;
+               spec->port_d_mode = 0;
+
+               /* no S/PDIF out */
+               spec->multiout.dig_out_nid = 0;
+
+               /* input source automatically selected */
+               spec->input_mux = NULL;
+               break;
+       }
+
+       return 0;
+}
 
 /*
  */
@@ -1919,12 +2395,15 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
          .patch = patch_cxt5047 },
        { .id = 0x14f15051, .name = "CX20561 (Hermosa)",
          .patch = patch_cxt5051 },
+       { .id = 0x14f15066, .name = "CX20582 (Pebble)",
+         .patch = patch_cxt5066 },
        {} /* terminator */
 };
 
 MODULE_ALIAS("snd-hda-codec-id:14f15045");
 MODULE_ALIAS("snd-hda-codec-id:14f15047");
 MODULE_ALIAS("snd-hda-codec-id:14f15051");
+MODULE_ALIAS("snd-hda-codec-id:14f15066");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
index fcc77fe..032850e 100644 (file)
@@ -685,6 +685,7 @@ static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
        { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
        { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
        { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi },
+       { .id = 0x80860054, .name = "G45 DEVIBX", .patch = patch_intel_hdmi },
        { .id = 0x10951392, .name = "SiI1392 HDMI",     .patch = patch_intel_hdmi },
        {} /* terminator */
 };
@@ -694,6 +695,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862801");
 MODULE_ALIAS("snd-hda-codec-id:80862802");
 MODULE_ALIAS("snd-hda-codec-id:80862803");
 MODULE_ALIAS("snd-hda-codec-id:80862804");
+MODULE_ALIAS("snd-hda-codec-id:80860054");
 MODULE_ALIAS("snd-hda-codec-id:10951392");
 
 MODULE_LICENSE("GPL");
index 0f6b6a6..587d94f 100644 (file)
@@ -235,6 +235,8 @@ enum {
        ALC883_FUJITSU_PI2515,
        ALC888_FUJITSU_XA3530,
        ALC883_3ST_6ch_INTEL,
+       ALC889A_INTEL,
+       ALC889_INTEL,
        ALC888_ASUS_M90V,
        ALC888_ASUS_EEE1601,
        ALC889A_MB31,
@@ -413,7 +415,7 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
        mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
        imux = &spec->input_mux[mux_idx];
 
-       type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+       type = get_wcaps_type(get_wcaps(codec, nid));
        if (type == AC_WID_AUD_MIX) {
                /* Matrix-mixer style (e.g. ALC882) */
                unsigned int *cur_val = &spec->cur_mux[adc_idx];
@@ -1027,6 +1029,16 @@ static void alc888_coef_init(struct hda_codec *codec)
                                    AC_VERB_SET_PROC_COEF, 0x3030);
 }
 
+static void alc889_coef_init(struct hda_codec *codec)
+{
+       unsigned int tmp;
+
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
+       tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
+}
+
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
        unsigned int tmp;
@@ -1084,15 +1096,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
                case 0x10ec0885:
                case 0x10ec0887:
                case 0x10ec0889:
-                       snd_hda_codec_write(codec, 0x20, 0,
-                                           AC_VERB_SET_COEF_INDEX, 7);
-                       tmp = snd_hda_codec_read(codec, 0x20, 0,
-                                                AC_VERB_GET_PROC_COEF, 0);
-                       snd_hda_codec_write(codec, 0x20, 0,
-                                           AC_VERB_SET_COEF_INDEX, 7);
-                       snd_hda_codec_write(codec, 0x20, 0,
-                                           AC_VERB_SET_PROC_COEF,
-                                           tmp | 0x2010);
+                       alc889_coef_init(codec);
                        break;
                case 0x10ec0888:
                        alc888_coef_init(codec);
@@ -1432,6 +1436,25 @@ static void alc_automute_amp_unsol_event(struct hda_codec *codec,
                alc_automute_amp(codec);
 }
 
+static void alc889_automute_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
+       spec->autocfg.speaker_pins[3] = 0x19;
+       spec->autocfg.speaker_pins[4] = 0x1a;
+       alc_automute_amp(codec);
+}
+
+static void alc889_intel_init_hook(struct hda_codec *codec)
+{
+       alc889_coef_init(codec);
+       alc889_automute_init(codec);
+}
+
 static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -4580,8 +4603,8 @@ static int patch_alc880(struct hda_codec *codec)
                                                  alc880_models,
                                                  alc880_cfg_tbl);
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for %s, "
-                      "trying auto-probe from BIOS...\n", codec->chip_name);
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
                board_config = ALC880_AUTO;
        }
 
@@ -4619,7 +4642,7 @@ static int patch_alc880(struct hda_codec *codec)
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
                /* get type */
-               wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               wcap = get_wcaps_type(wcap);
                if (wcap != AC_WID_AUD_IN) {
                        spec->adc_nids = alc880_adc_nids_alt;
                        spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
@@ -6224,8 +6247,7 @@ static int patch_alc260(struct hda_codec *codec)
                                                  alc260_models,
                                                  alc260_cfg_tbl);
        if (board_config < 0) {
-               snd_printd(KERN_INFO "hda_codec: Unknown model for %s, "
-                          "trying auto-probe from BIOS...\n",
+               snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
                           codec->chip_name);
                board_config = ALC260_AUTO;
        }
@@ -6262,7 +6284,7 @@ static int patch_alc260(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x04 is valid */
                unsigned int wcap = get_wcaps(codec, 0x04);
-               wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               wcap = get_wcaps_type(wcap);
                /* get type */
                if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
                        spec->adc_nids = alc260_adc_nids_alt;
@@ -6348,6 +6370,15 @@ static struct hda_input_mux alc882_capture_source = {
 
 #define alc883_capture_source  alc882_capture_source
 
+static struct hda_input_mux alc889_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Front Mic", 0x0 },
+               { "Mic", 0x3 },
+               { "Line", 0x2 },
+       },
+};
+
 static struct hda_input_mux mb5_capture_source = {
        .num_items = 3,
        .items = {
@@ -6668,6 +6699,52 @@ static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
        { 6, alc883_3ST_ch6_intel_init },
 };
 
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc889_ch2_intel_init[] = {
+       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc889_ch6_intel_init[] = {
+       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 8ch mode
+ */
+static struct hda_verb alc889_ch8_intel_init[] = {
+       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { } /* end */
+};
+
+static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
+       { 2, alc889_ch2_intel_init },
+       { 6, alc889_ch6_intel_init },
+       { 8, alc889_ch8_intel_init },
+};
+
 /*
  * 6ch mode
  */
@@ -6849,6 +6926,13 @@ static struct hda_verb alc882_base_init_verbs[] = {
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 
+       /* mute analog input loopbacks */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
        /* Front Pin: output 0 (0x0c) */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
@@ -6915,9 +6999,6 @@ static struct hda_verb alc882_adc1_init_verbs[] = {
        { }
 };
 
-/* HACK - expand to two elements */
-#define alc882_init_verbs      alc882_base_init_verbs, alc882_adc1_init_verbs
-
 static struct hda_verb alc882_eapd_verbs[] = {
        /* change to EAPD mode */
        {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
@@ -6925,6 +7006,108 @@ static struct hda_verb alc882_eapd_verbs[] = {
        { }
 };
 
+static struct hda_verb alc889_eapd_verbs[] = {
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+static struct hda_verb alc_hp15_unsol_verbs[] = {
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {}
+};
+
+static struct hda_verb alc885_init_verbs[] = {
+       /* Front mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Rear mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* CLFE mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Side mixer */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+
+       /* mute analog input loopbacks */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+
+       /* Front HP Pin: output 0 (0x0c) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Front Pin: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Rear Pin: output 1 (0x0d) */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
+       /* CLFE Pin: output 2 (0x0e) */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* Side Pin: output 3 (0x0f) */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
+       /* Mic (rear) pin: input vref at 80% */
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: input */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       /* Mixer elements: 0x18, , 0x1a, 0x1b */
+       /* Input mixer1 */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       /* ADC2: mute amp left and right */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* ADC3: mute amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+
+       { }
+};
+
+static struct hda_verb alc885_init_input_verbs[] = {
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       { }
+};
+
+
+/* Unmute Selector 24h and set the default input to front mic */
+static struct hda_verb alc889_init_input_verbs[] = {
+       {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       { }
+};
+
+
 #define alc883_init_verbs      alc882_base_init_verbs
 
 /* Mac Pro test */
@@ -7162,9 +7345,6 @@ static struct hda_verb alc882_targa_verbs[] = {
        {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
 
        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
        { } /* end */
 };
 
@@ -7496,6 +7676,30 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+                             HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -8339,6 +8543,8 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
        [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
        [ALC883_3ST_6ch_INTEL]  = "3stack-6ch-intel",
+       [ALC889A_INTEL]         = "intel-alc889a",
+       [ALC889_INTEL]          = "intel-x58",
        [ALC1200_ASUS_P5Q]      = "asus-p5q",
        [ALC889A_MB31]          = "mb31",
        [ALC883_SONY_VAIO_TT]   = "sony-vaio-tt",
@@ -8418,6 +8624,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
@@ -8431,6 +8638,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
 
        SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
@@ -8456,7 +8664,9 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
        SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
        SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
-       SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
+       SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
+       SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
+       SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
        SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
 
        {}
@@ -8485,7 +8695,8 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
 static struct alc_config_preset alc882_presets[] = {
        [ALC882_3ST_DIG] = {
                .mixers = { alc882_base_mixer },
-               .init_verbs = { alc882_init_verbs },
+               .init_verbs = { alc882_base_init_verbs,
+                               alc882_adc1_init_verbs },
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .dig_out_nid = ALC882_DIGOUT_NID,
@@ -8497,7 +8708,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC882_6ST_DIG] = {
                .mixers = { alc882_base_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_init_verbs },
+               .init_verbs = { alc882_base_init_verbs,
+                               alc882_adc1_init_verbs },
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .dig_out_nid = ALC882_DIGOUT_NID,
@@ -8508,7 +8720,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC882_ARIMA] = {
                .mixers = { alc882_base_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc882_eapd_verbs },
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
@@ -8517,8 +8730,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC882_W2JC] = {
                .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
-                               alc880_gpio1_init_verbs },
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc882_eapd_verbs, alc880_gpio1_init_verbs },
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
@@ -8580,7 +8793,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC882_TARGA] = {
                .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc880_gpio3_init_verbs, alc882_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .dig_out_nid = ALC882_DIGOUT_NID,
@@ -8596,7 +8810,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC882_ASUS_A7J] = {
                .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc882_asus_a7j_verbs},
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .dig_out_nid = ALC882_DIGOUT_NID,
@@ -8610,8 +8825,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC882_ASUS_A7M] = {
                .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
-                               alc880_gpio1_init_verbs,
+               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
+                               alc882_eapd_verbs, alc880_gpio1_init_verbs,
                                alc882_asus_a7m_verbs },
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
@@ -8667,6 +8882,44 @@ static struct alc_config_preset alc882_presets[] = {
                .need_dac_fix = 1,
                .input_mux = &alc883_3stack_6ch_intel,
        },
+       [ALC889A_INTEL] = {
+               .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
+                               alc_hp15_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+               .adc_nids = alc889_adc_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .slave_dig_outs = alc883_slave_dig_outs,
+               .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
+               .channel_mode = alc889_8ch_intel_modes,
+               .capsrc_nids = alc889_capsrc_nids,
+               .input_mux = &alc889_capture_source,
+               .init_hook = alc889_automute_init,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .need_dac_fix = 1,
+       },
+       [ALC889_INTEL] = {
+               .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
+                               alc889_eapd_verbs, alc_hp15_unsol_verbs},
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
+               .adc_nids = alc889_adc_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .slave_dig_outs = alc883_slave_dig_outs,
+               .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
+               .channel_mode = alc889_8ch_intel_modes,
+               .capsrc_nids = alc889_capsrc_nids,
+               .input_mux = &alc889_capture_source,
+               .init_hook = alc889_intel_init_hook,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .need_dac_fix = 1,
+       },
        [ALC883_6ST_DIG] = {
                .mixers = { alc883_base_mixer, alc883_chmode_mixer },
                .init_verbs = { alc883_init_verbs },
@@ -8680,7 +8933,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC883_TARGA_DIG] = {
                .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_targa_verbs},
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
@@ -8693,7 +8947,8 @@ static struct alc_config_preset alc882_presets[] = {
        },
        [ALC883_TARGA_2ch_DIG] = {
                .mixers = { alc883_targa_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc883_targa_verbs},
+               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
+                               alc883_targa_verbs},
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .adc_nids = alc883_adc_nids_alt,
@@ -9238,7 +9493,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
        spec->init_verbs[0] = alc883_auto_init_verbs;
        /* if ADC 0x07 is available, initialize it, too */
        wcap = get_wcaps(codec, 0x07);
-       wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+       wcap = get_wcaps_type(wcap);
        if (wcap == AC_WID_AUD_IN)
                add_verb(spec, alc882_adc1_init_verbs);
 
@@ -9304,8 +9559,7 @@ static int patch_alc882(struct hda_codec *codec)
                        ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
 
        if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for %s, "
-                      "trying auto-probe from BIOS...\n",
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
                       codec->chip_name);
                board_config = ALC882_AUTO;
        }
@@ -9355,7 +9609,7 @@ static int patch_alc882(struct hda_codec *codec)
                        hda_nid_t nid = alc882_adc_nids[i];
                        unsigned int wcap = get_wcaps(codec, nid);
                        /* get type */
-                       wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+                       wcap = get_wcaps_type(wcap);
                        if (wcap != AC_WID_AUD_IN)
                                continue;
                        spec->private_adc_nids[spec->num_adc_nids] = nid;
@@ -9895,12 +10149,6 @@ static struct hda_verb alc262_eapd_verbs[] = {
        { }
 };
 
-static struct hda_verb alc262_hippo_unsol_verbs[] = {
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
 static struct hda_verb alc262_hippo1_unsol_verbs[] = {
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
        {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -10167,6 +10415,18 @@ static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
        alc262_lenovo_3000_automute(codec, 1);
 }
 
+static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
+                                 int dir, int idx, long *valp)
+{
+       int i, change = 0;
+
+       for (i = 0; i < 2; i++, valp++)
+               change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
+                                                  HDA_AMP_MUTE,
+                                                  *valp ? 0 : HDA_AMP_MUTE);
+       return change;
+}
+
 /* bind hp and internal speaker mute (with plug check) */
 static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
@@ -10175,13 +10435,8 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int change;
 
-       change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE,
-                                                valp ? 0 : HDA_AMP_MUTE);
-       change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE,
-                                                valp ? 0 : HDA_AMP_MUTE);
-
+       change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
+       change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
        if (change)
                alc262_fujitsu_automute(codec, 0);
        return change;
@@ -10216,10 +10471,7 @@ static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int change;
 
-       change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                                HDA_AMP_MUTE,
-                                                valp ? 0 : HDA_AMP_MUTE);
-
+       change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
        if (change)
                alc262_lenovo_3000_automute(codec, 0);
        return change;
@@ -10938,7 +11190,7 @@ static struct alc_config_preset alc262_presets[] = {
        },
        [ALC262_HIPPO] = {
                .mixers = { alc262_hippo_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
+               .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
                .num_dacs = ARRAY_SIZE(alc262_dac_nids),
                .dac_nids = alc262_dac_nids,
                .hp_nid = 0x03,
@@ -11058,7 +11310,8 @@ static struct alc_config_preset alc262_presets[] = {
        },
        [ALC262_BENQ_T31] = {
                .mixers = { alc262_benq_t31_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
+               .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
+                               alc_hp15_unsol_verbs },
                .num_dacs = ARRAY_SIZE(alc262_dac_nids),
                .dac_nids = alc262_dac_nids,
                .hp_nid = 0x03,
@@ -11180,8 +11433,8 @@ static int patch_alc262(struct hda_codec *codec)
                                                  alc262_cfg_tbl);
 
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for %s, "
-                      "trying auto-probe from BIOS...\n", codec->chip_name);
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
                board_config = ALC262_AUTO;
        }
 
@@ -11234,7 +11487,7 @@ static int patch_alc262(struct hda_codec *codec)
                        unsigned int wcap = get_wcaps(codec, 0x07);
 
                        /* get type */
-                       wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+                       wcap = get_wcaps_type(wcap);
                        if (wcap != AC_WID_AUD_IN) {
                                spec->adc_nids = alc262_adc_nids_alt;
                                spec->num_adc_nids =
@@ -11390,12 +11643,7 @@ static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int change;
 
-       change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
-                                         HDA_AMP_MUTE,
-                                         valp[0] ? 0 : HDA_AMP_MUTE);
-       change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
-                                          HDA_AMP_MUTE,
-                                          valp[1] ? 0 : HDA_AMP_MUTE);
+       change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
        if (change)
                alc268_acer_automute(codec, 0);
        return change;
@@ -11806,26 +12054,38 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
                                    const char *ctlname, int idx)
 {
        char name[32];
+       hda_nid_t dac;
        int err;
 
        sprintf(name, "%s Playback Volume", ctlname);
-       if (nid == 0x14) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
-                                 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
-                                                     HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-       } else if (nid == 0x15) {
+       switch (nid) {
+       case 0x14:
+       case 0x16:
+               dac = 0x02;
+               break;
+       case 0x15:
+               dac = 0x03;
+               break;
+       default:
+               return 0;
+       }
+       if (spec->multiout.dac_nids[0] != dac &&
+           spec->multiout.dac_nids[1] != dac) {
                err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
-                                 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
+                                 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
                                                      HDA_OUTPUT));
                if (err < 0)
                        return err;
-       } else
-               return -1;
+               spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+       }
+
        sprintf(name, "%s Playback Switch", ctlname);
-       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+       if (nid != 0x16)
+               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
                          HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
+       else /* mono */
+               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+                         HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
        if (err < 0)
                return err;
        return 0;
@@ -11838,14 +12098,19 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
        hda_nid_t nid;
        int err;
 
-       spec->multiout.num_dacs = 2;    /* only use one dac */
        spec->multiout.dac_nids = spec->private_dac_nids;
-       spec->multiout.dac_nids[0] = 2;
-       spec->multiout.dac_nids[1] = 3;
 
        nid = cfg->line_out_pins[0];
-       if (nid)
-               alc268_new_analog_output(spec, nid, "Front", 0);
+       if (nid) {
+               const char *name;
+               if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                       name = "Speaker";
+               else
+                       name = "Front";
+               err = alc268_new_analog_output(spec, nid, name, 0);
+               if (err < 0)
+                       return err;
+       }
 
        nid = cfg->speaker_pins[0];
        if (nid == 0x1d) {
@@ -11854,16 +12119,23 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
                if (err < 0)
                        return err;
+       } else {
+               err = alc268_new_analog_output(spec, nid, "Speaker", 0);
+               if (err < 0)
+                       return err;
        }
        nid = cfg->hp_pins[0];
-       if (nid)
-               alc268_new_analog_output(spec, nid, "Headphone", 0);
+       if (nid) {
+               err = alc268_new_analog_output(spec, nid, "Headphone", 0);
+               if (err < 0)
+                       return err;
+       }
 
        nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
        if (nid == 0x16) {
                err = add_control(spec, ALC_CTL_WIDGET_MUTE,
                                  "Mono Playback Switch",
-                                 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
+                                 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
        }
@@ -12234,8 +12506,8 @@ static int patch_alc268(struct hda_codec *codec)
                                                  alc268_cfg_tbl);
 
        if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for %s, "
-                      "trying auto-probe from BIOS...\n", codec->chip_name);
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
                board_config = ALC268_AUTO;
        }
 
@@ -12291,7 +12563,7 @@ static int patch_alc268(struct hda_codec *codec)
                int i;
 
                /* get type */
-               wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               wcap = get_wcaps_type(wcap);
                if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
                        spec->adc_nids = alc268_adc_nids_alt;
                        spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
@@ -12418,20 +12690,11 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
        { }
 };
 
-/* bind volumes of both NID 0x0c and 0x0d */
-static struct hda_bind_ctls alc269_epc_bind_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
 static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
-       HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
-       HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -12444,12 +12707,7 @@ static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
 };
 
 /* FSC amilo */
-static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
-       { } /* end */
-};
+#define alc269_fujitsu_mixer   alc269_eeepc_mixer
 
 static struct hda_verb alc269_quanta_fl1_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
@@ -13066,8 +13324,8 @@ static int patch_alc269(struct hda_codec *codec)
                                                  alc269_cfg_tbl);
 
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for %s, "
-                      "trying auto-probe from BIOS...\n", codec->chip_name);
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
                board_config = ALC269_AUTO;
        }
 
@@ -13659,23 +13917,23 @@ static struct hda_verb alc861_auto_init_verbs[] = {
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
 
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
 
        {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},  /* set Mic 1 */
 
@@ -13747,64 +14005,96 @@ static struct hda_input_mux alc861_capture_source = {
        },
 };
 
+static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t mix, srcs[5];
+       int i, j, num;
+
+       if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
+               return 0;
+       num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
+       if (num < 0)
+               return 0;
+       for (i = 0; i < num; i++) {
+               unsigned int type;
+               type = get_wcaps_type(get_wcaps(codec, srcs[i]));
+               if (type != AC_WID_AUD_OUT)
+                       continue;
+               for (j = 0; j < spec->multiout.num_dacs; j++)
+                       if (spec->multiout.dac_nids[j] == srcs[i])
+                               break;
+               if (j >= spec->multiout.num_dacs)
+                       return srcs[i];
+       }
+       return 0;
+}
+
 /* fill in the dac_nids table from the parsed pin configuration */
-static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
+static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
                                     const struct auto_pin_cfg *cfg)
 {
+       struct alc_spec *spec = codec->spec;
        int i;
-       hda_nid_t nid;
+       hda_nid_t nid, dac;
 
        spec->multiout.dac_nids = spec->private_dac_nids;
        for (i = 0; i < cfg->line_outs; i++) {
                nid = cfg->line_out_pins[i];
-               if (nid) {
-                       if (i >= ARRAY_SIZE(alc861_dac_nids))
-                               continue;
-                       spec->multiout.dac_nids[i] = alc861_dac_nids[i];
-               }
+               dac = alc861_look_for_dac(codec, nid);
+               if (!dac)
+                       continue;
+               spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
        }
-       spec->multiout.num_dacs = cfg->line_outs;
        return 0;
 }
 
+static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
+                               hda_nid_t nid, unsigned int chs)
+{
+       char name[32];
+       snprintf(name, sizeof(name), "%s Playback Switch", pfx);
+       return add_control(codec->spec, ALC_CTL_WIDGET_MUTE, name,
+                          HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+}
+
 /* add playback controls from the parsed DAC table */
-static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
+static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
                                             const struct auto_pin_cfg *cfg)
 {
-       char name[32];
+       struct alc_spec *spec = codec->spec;
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
        hda_nid_t nid;
-       int i, idx, err;
+       int i, err;
+
+       if (cfg->line_outs == 1) {
+               const char *pfx = NULL;
+               if (!cfg->hp_outs)
+                       pfx = "Master";
+               else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                       pfx = "Speaker";
+               if (pfx) {
+                       nid = spec->multiout.dac_nids[0];
+                       return alc861_create_out_sw(codec, pfx, nid, 3);
+               }
+       }
 
        for (i = 0; i < cfg->line_outs; i++) {
                nid = spec->multiout.dac_nids[i];
                if (!nid)
                        continue;
-               if (nid == 0x05) {
+               if (i == 2) {
                        /* Center/LFE */
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "Center Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 1, 0,
-                                                             HDA_OUTPUT));
+                       err = alc861_create_out_sw(codec, "Center", nid, 1);
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "LFE Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
+                       err = alc861_create_out_sw(codec, "LFE", nid, 2);
                        if (err < 0)
                                return err;
                } else {
-                       for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
-                            idx++)
-                               if (nid == alc861_dac_nids[idx])
-                                       break;
-                       sprintf(name, "%s Playback Switch", chname[idx]);
-                       err = add_control(spec, ALC_CTL_BIND_MUTE, name,
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                             HDA_OUTPUT));
+                       err = alc861_create_out_sw(codec, chname[i], nid, 3);
                        if (err < 0)
                                return err;
                }
@@ -13812,8 +14102,9 @@ static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
        return 0;
 }
 
-static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
+static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
 {
+       struct alc_spec *spec = codec->spec;
        int err;
        hda_nid_t nid;
 
@@ -13821,21 +14112,22 @@ static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
                return 0;
 
        if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
-               nid = 0x03;
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                 "Headphone Playback Switch",
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               spec->multiout.hp_nid = nid;
+               nid = alc861_look_for_dac(codec, pin);
+               if (nid) {
+                       err = alc861_create_out_sw(codec, "Headphone", nid, 3);
+                       if (err < 0)
+                               return err;
+                       spec->multiout.hp_nid = nid;
+               }
        }
        return 0;
 }
 
 /* create playback/capture controls for input pins */
-static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
+static int alc861_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
+       struct alc_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx, idx1;
 
@@ -13879,12 +14171,29 @@ static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
 
 static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
                                              hda_nid_t nid,
-                                             int pin_type, int dac_idx)
+                                             int pin_type, hda_nid_t dac)
 {
+       hda_nid_t mix, srcs[5];
+       int i, num;
+
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                            pin_type);
-       snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+       snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                            AMP_OUT_UNMUTE);
+       if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
+               return;
+       num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
+       if (num < 0)
+               return;
+       for (i = 0; i < num; i++) {
+               unsigned int mute;
+               if (srcs[i] == dac || srcs[i] == 0x15)
+                       mute = AMP_IN_UNMUTE(i);
+               else
+                       mute = AMP_IN_MUTE(i);
+               snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   mute);
+       }
 }
 
 static void alc861_auto_init_multi_out(struct hda_codec *codec)
@@ -13907,12 +14216,13 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
        hda_nid_t pin;
 
        pin = spec->autocfg.hp_pins[0];
-       if (pin) /* connect to front */
+       if (pin)
                alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
-                                                 spec->multiout.dac_nids[0]);
+                                                 spec->multiout.hp_nid);
        pin = spec->autocfg.speaker_pins[0];
        if (pin)
-               alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+               alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT,
+                                                 spec->multiout.dac_nids[0]);
 }
 
 static void alc861_auto_init_analog_input(struct hda_codec *codec)
@@ -13944,16 +14254,16 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        if (!spec->autocfg.line_outs)
                return 0; /* can't find valid BIOS pin config */
 
-       err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
+       err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc861_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -14165,8 +14475,8 @@ static int patch_alc861(struct hda_codec *codec)
                                                  alc861_cfg_tbl);
 
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for %s, "
-                      "trying auto-probe from BIOS...\n", codec->chip_name);
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
                board_config = ALC861_AUTO;
        }
 
@@ -15089,8 +15399,8 @@ static int patch_alc861vd(struct hda_codec *codec)
                                                  alc861vd_cfg_tbl);
 
        if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for %s, "
-                      "trying auto-probe from BIOS...\n", codec->chip_name);
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
                board_config = ALC861VD_AUTO;
        }
 
@@ -17013,8 +17323,8 @@ static int patch_alc662(struct hda_codec *codec)
                                                  alc662_models,
                                                  alc662_cfg_tbl);
        if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: Unknown model for %s, "
-                      "trying auto-probe from BIOS...\n", codec->chip_name);
+               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                      codec->chip_name);
                board_config = ALC662_AUTO;
        }
 
index 14f3c3e..e5fbec3 100644 (file)
@@ -40,6 +40,8 @@ enum {
        STAC_INSERT_EVENT,
        STAC_PWR_EVENT,
        STAC_HP_EVENT,
+       STAC_LO_EVENT,
+       STAC_MIC_EVENT,
 };
 
 enum {
@@ -176,6 +178,12 @@ struct sigmatel_jack {
        struct snd_jack *jack;
 };
 
+struct sigmatel_mic_route {
+       hda_nid_t pin;
+       unsigned char mux_idx;
+       unsigned char dmux_idx;
+};
+
 struct sigmatel_spec {
        struct snd_kcontrol_new *mixers[4];
        unsigned int num_mixers;
@@ -187,6 +195,7 @@ struct sigmatel_spec {
        unsigned int hp_detect: 1;
        unsigned int spdif_mute: 1;
        unsigned int check_volume_offset:1;
+       unsigned int auto_mic:1;
 
        /* gpio lines */
        unsigned int eapd_mask;
@@ -238,6 +247,14 @@ struct sigmatel_spec {
        unsigned int num_dmuxes;
        hda_nid_t *smux_nids;
        unsigned int num_smuxes;
+
+       unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
+       unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
+       unsigned int num_caps; /* number of capture volume/switch elements */
+
+       struct sigmatel_mic_route ext_mic;
+       struct sigmatel_mic_route int_mic;
+
        const char **spdif_labels;
 
        hda_nid_t dig_in_nid;
@@ -334,6 +351,13 @@ static hda_nid_t stac92hd73xx_smux_nids[2] = {
        0x22, 0x23,
 };
 
+#define STAC92HD73XX_NUM_CAPS  2
+static unsigned long stac92hd73xx_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd73xx_capsws    stac92hd73xx_capvols
+
 #define STAC92HD83XXX_NUM_DMICS        2
 static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
        0x11, 0x12, 0
@@ -365,6 +389,13 @@ static hda_nid_t stac92hd83xxx_amp_nids[1] = {
        0xc,
 };
 
+#define STAC92HD83XXX_NUM_CAPS 2
+static unsigned long stac92hd83xxx_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd83xxx_capsws   stac92hd83xxx_capvols
+
 static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
        0x0a, 0x0d, 0x0f
 };
@@ -394,6 +425,13 @@ static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
        0x22, 0
 };
 
+#define STAC92HD71BXX_NUM_CAPS         2
+static unsigned long stac92hd71bxx_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+};
+#define stac92hd71bxx_capsws   stac92hd71bxx_capvols
+
 static hda_nid_t stac925x_adc_nids[1] = {
         0x03,
 };
@@ -415,6 +453,13 @@ static hda_nid_t stac925x_dmux_nids[1] = {
        0x14,
 };
 
+static unsigned long stac925x_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
+};
+static unsigned long stac925x_capsws[] = {
+       HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+};
+
 static hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
 };
@@ -423,6 +468,13 @@ static hda_nid_t stac922x_mux_nids[2] = {
         0x12, 0x13,
 };
 
+#define STAC922X_NUM_CAPS      2
+static unsigned long stac922x_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
+       HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
+};
+#define stac922x_capsws                stac922x_capvols
+
 static hda_nid_t stac927x_slave_dig_outs[2] = {
        0x1f, 0,
 };
@@ -452,6 +504,18 @@ static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
        0x13, 0x14, 0
 };
 
+#define STAC927X_NUM_CAPS      3
+static unsigned long stac927x_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
+       HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
+       HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
+};
+static unsigned long stac927x_capsws[] = {
+       HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+};
+
 static const char *stac927x_spdif_labels[5] = {
        "Digital Playback", "ADAT", "Analog Mux 1",
        "Analog Mux 2", "Analog Mux 3"
@@ -478,6 +542,16 @@ static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
         0x17, 0x18, 0
 };
 
+#define STAC9205_NUM_CAPS      2
+static unsigned long stac9205_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
+       HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
+};
+static unsigned long stac9205_capsws[] = {
+       HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
+       HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
+};
+
 static hda_nid_t stac9200_pin_nids[8] = {
        0x08, 0x09, 0x0d, 0x0e, 
        0x0f, 0x10, 0x11, 0x12,
@@ -924,19 +998,6 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
        {}
 };
 
-#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},
-       /* start of config #2 */
-
-       /* set master volume and direct control */
-       { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       {}
-};
-
 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)},
@@ -1069,12 +1130,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),
 
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
        { } /* end */
 };
 
@@ -1094,12 +1149,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
 };
 
 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),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
 
@@ -1118,12 +1167,6 @@ static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
 
@@ -1143,12 +1186,6 @@ static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
 
 
 static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
-
        HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT),
 
@@ -1169,17 +1206,6 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       /* analog pc-beep replaced with digital beep support */
-       /*
-       HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
-       */
-
        HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
 
@@ -1198,29 +1224,9 @@ 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),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
 static struct snd_kcontrol_new stac925x_mixer[] = {
        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[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -1229,29 +1235,6 @@ static struct snd_kcontrol_new stac9205_loopback[] = {
        {}
 };
 
-/* This needs to be generated dynamically based on sequence */
-static struct snd_kcontrol_new stac922x_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-
-static struct snd_kcontrol_new stac927x_mixer[] = {
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
 static struct snd_kcontrol_new stac927x_loopback[] = {
        STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
        {}
@@ -1309,16 +1292,18 @@ static int stac92xx_build_controls(struct hda_codec *codec)
        int err;
        int i;
 
-       err = snd_hda_add_new_ctls(codec, spec->mixer);
-       if (err < 0)
-               return err;
+       if (spec->mixer) {
+               err = snd_hda_add_new_ctls(codec, spec->mixer);
+               if (err < 0)
+                       return err;
+       }
 
        for (i = 0; i < spec->num_mixers; i++) {
                err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
                if (err < 0)
                        return err;
        }
-       if (spec->num_dmuxes > 0) {
+       if (!spec->auto_mic && spec->num_dmuxes > 0) {
                stac_dmux_mixer.count = spec->num_dmuxes;
                err = snd_hda_ctl_add(codec,
                                  snd_ctl_new1(&stac_dmux_mixer, codec));
@@ -1590,8 +1575,6 @@ 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_INTEL, 0xfb30,
-                     "SigmaTel",STAC_9205_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
                      "DFI LanParty", STAC_REF),
        /* Dell laptops have BIOS problem */
@@ -1811,6 +1794,8 @@ 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 */
 };
 
@@ -2344,6 +2329,8 @@ 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 */
@@ -2378,6 +2365,7 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        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 */
 };
@@ -2633,8 +2621,7 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
-                                  unsigned char type);
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid);
 
 static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
@@ -2648,7 +2635,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
        /* check to be sure that the ports are upto date with
         * switch changes
         */
-       stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
+       stac_issue_unsol_event(codec, nid);
 
        return 1;
 }
@@ -2781,7 +2768,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
         * appropriately according to the pin direction
         */
        if (spec->hp_detect)
-               stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
+               stac_issue_unsol_event(codec, nid);
 
         return 1;
 }
@@ -2964,6 +2951,8 @@ 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->auto_mic)
+               return 0; /* no need for input source */
        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,
@@ -3057,7 +3046,7 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
                                           HDA_MAX_CONNECTIONS);
        for (j = 0; j < conn_len; j++) {
                wcaps = get_wcaps(codec, conn[j]);
-               wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               wtype = get_wcaps_type(wcaps);
                /* we check only analog outputs */
                if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
                        continue;
@@ -3316,6 +3305,21 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
        return 0;
 }
 
+static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
+                                   unsigned long sw, int idx)
+{
+       int err;
+       err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
+                                      "Capture Volume", vol);
+       if (err < 0)
+               return err;
+       err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx,
+                                      "Capture Switch", sw);
+       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)
@@ -3389,7 +3393,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
                                spec->mono_nid,
                                con_lst,
                                HDA_MAX_NUM_INPUTS);
-       if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
+       if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
                return -EINVAL;
 
        for (i = 0; i < num_cons; i++) {
@@ -3535,7 +3539,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
                                spec->smux_nids[0],
                                con_lst,
                                HDA_MAX_NUM_INPUTS);
-       if (!num_cons)
+       if (num_cons <= 0)
                return -EINVAL;
 
        if (!labels)
@@ -3556,14 +3560,26 @@ static const char *stac92xx_dmic_labels[5] = {
        "Digital Mic 3", "Digital Mic 4"
 };
 
+static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
+                               hda_nid_t nid)
+{
+       hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+       int i, nums;
+
+       nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+       for (i = 0; i < nums; i++)
+               if (conn[i] == nid)
+                       return i;
+       return -1;
+}
+
 /* create playback/capture controls for input pins on dmic capable codecs */
 static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *dimux = &spec->private_dimux;
-       hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
-       int err, i, j;
+       int err, i;
        char name[32];
 
        dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
@@ -3573,7 +3589,6 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
        for (i = 0; i < spec->num_dmics; i++) {
                hda_nid_t nid;
                int index;
-               int num_cons;
                unsigned int wcaps;
                unsigned int def_conf;
 
@@ -3582,17 +3597,10 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                        continue;
 
                nid = spec->dmic_nids[i];
-               num_cons = snd_hda_get_connections(codec,
-                               spec->dmux_nids[0],
-                               con_lst,
-                               HDA_MAX_NUM_INPUTS);
-               for (j = 0; j < num_cons; j++)
-                       if (con_lst[j] == nid) {
-                               index = j;
-                               goto found;
-                       }
-               continue;
-found:
+               index = get_connection_index(codec, spec->dmux_nids[0], nid);
+               if (index < 0)
+                       continue;
+
                wcaps = get_wcaps(codec, nid) &
                        (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
 
@@ -3619,6 +3627,88 @@ found:
        return 0;
 }
 
+static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
+                        hda_nid_t *fixed, hda_nid_t *ext)
+{
+       unsigned int cfg;
+
+       if (!nid)
+               return 0;
+       cfg = snd_hda_codec_get_pincfg(codec, nid);
+       switch (get_defcfg_connect(cfg)) {
+       case AC_JACK_PORT_FIXED:
+               if (*fixed)
+                       return 1; /* already occupied */
+               *fixed = nid;
+               break;
+       case AC_JACK_PORT_COMPLEX:
+               if (*ext)
+                       return 1; /* already occupied */
+               *ext = nid;
+               break;
+       }
+       return 0;
+}
+
+static int set_mic_route(struct hda_codec *codec,
+                        struct sigmatel_mic_route *mic,
+                        hda_nid_t pin)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       mic->pin = pin;
+       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
+               if (pin == cfg->input_pins[i])
+                       break;
+       if (i <= AUTO_PIN_FRONT_MIC) {
+               /* analog pin */
+               mic->dmux_idx = 0;
+               i = get_connection_index(codec, spec->mux_nids[0], pin);
+               if (i < 0)
+                       return -1;
+               mic->mux_idx = i;
+       }  else {
+               /* digital pin */
+               mic->mux_idx = 0;
+               i = get_connection_index(codec, spec->dmux_nids[0], pin);
+               if (i < 0)
+                       return -1;
+               mic->dmux_idx = i;
+       }
+       return 0;
+}
+
+/* return non-zero if the device is for automatic mic switch */
+static int stac_check_auto_mic(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t fixed, ext;
+       int i;
+
+       for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
+               if (cfg->input_pins[i])
+                       return 0; /* must be exclusively mics */
+       }
+       fixed = ext = 0;
+       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
+               if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
+                       return 0;
+       for (i = 0; i < spec->num_dmics; i++)
+               if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
+                       return 0;
+       if (!fixed || !ext)
+               return 0;
+       if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
+               return 0; /* no unsol support */
+       if (set_mic_route(codec, &spec->ext_mic, ext) ||
+           set_mic_route(codec, &spec->int_mic, fixed))
+               return 0; /* something is wrong */
+       return 1;
+}
+
 /* create playback/capture controls for input pins */
 static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
 {
@@ -3702,7 +3792,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 {
        struct sigmatel_spec *spec = codec->spec;
        int hp_swap = 0;
-       int err;
+       int i, err;
 
        if ((err = snd_hda_parse_pin_def_config(codec,
                                                &spec->autocfg,
@@ -3742,11 +3832,10 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                if (snd_hda_get_connections(codec,
                                spec->autocfg.mono_out_pin, conn_list, 1) &&
                                snd_hda_get_connections(codec, conn_list[0],
-                               conn_list, 1)) {
+                               conn_list, 1) > 0) {
 
                                int wcaps = get_wcaps(codec, conn_list[0]);
-                               int wid_type = (wcaps & AC_WCAP_TYPE)
-                                       >> AC_WCAP_TYPE_SHIFT;
+                               int wid_type = get_wcaps_type(wcaps);
                                /* LR swap check, some stac925x have a mux that
                                 * changes the DACs output path instead of the
                                 * mono-mux path.
@@ -3837,6 +3926,21 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                spec->autocfg.line_outs = 0;
        }
 
+       if (stac_check_auto_mic(codec)) {
+               spec->auto_mic = 1;
+               /* only one capture for auto-mic */
+               spec->num_adcs = 1;
+               spec->num_caps = 1;
+               spec->num_muxes = 1;
+       }
+
+       for (i = 0; i < spec->num_caps; i++) {
+               err = stac92xx_add_capvol_ctls(codec, spec->capvols[i],
+                                              spec->capsws[i], i);
+               if (err < 0)
+                       return err;
+       }
+
        err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
@@ -4065,7 +4169,7 @@ 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));
@@ -4099,14 +4203,14 @@ static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
 }
 
 static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
-                                            hda_nid_t nid, unsigned char type)
+                                            hda_nid_t nid)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct sigmatel_event *event = spec->events.list;
        int i;
 
        for (i = 0; i < spec->events.used; i++, event++) {
-               if (event->nid == nid && event->type == type)
+               if (event->nid == nid)
                        return event;
        }
        return NULL;
@@ -4126,24 +4230,32 @@ static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
        return NULL;
 }
 
-static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
-                             unsigned int type)
+/* check if given nid is a valid pin and no other events are assigned
+ * to it.  If OK, assign the event, set the unsol flag, and returns 1.
+ * Otherwise, returns zero.
+ */
+static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
+                            unsigned int type)
 {
        struct sigmatel_event *event;
        int tag;
 
        if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
-               return;
-       event = stac_get_event(codec, nid, type);
-       if (event)
+               return 0;
+       event = stac_get_event(codec, nid);
+       if (event) {
+               if (event->type != type)
+                       return 0;
                tag = event->tag;
-       else
+       } else {
                tag = stac_add_event(codec->spec, nid, type, 0);
-       if (tag < 0)
-               return;
+               if (tag < 0)
+                       return 0;
+       }
        snd_hda_codec_write_cache(codec, nid, 0,
                                  AC_VERB_SET_UNSOLICITED_ENABLE,
                                  AC_USRSP_EN | tag);
+       return 1;
 }
 
 static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
@@ -4236,20 +4348,34 @@ static int stac92xx_init(struct hda_codec *codec)
                        hda_nid_t nid = cfg->hp_pins[i];
                        enable_pin_detect(codec, nid, STAC_HP_EVENT);
                }
+               if (cfg->line_out_type == AUTO_PIN_LINE_OUT) {
+                       /* enable pin-detect for line-outs as well */
+                       for (i = 0; i < cfg->hp_outs; i++) {
+                               hda_nid_t nid = cfg->hp_pins[i];
+                               enable_pin_detect(codec, nid, STAC_LO_EVENT);
+                       }
+               }
+
                /* force to enable the first line-out; the others are set up
                 * in unsol_event
                 */
                stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
                                AC_PINCTL_OUT_EN);
                /* fake event to set up pins */
-               stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
-                                      STAC_HP_EVENT);
+               stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
        } else {
                stac92xx_auto_init_multi_out(codec);
                stac92xx_auto_init_hp_out(codec);
                for (i = 0; i < cfg->hp_outs; i++)
                        stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
        }
+       if (spec->auto_mic) {
+               /* initialize connection to analog input */
+               snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
+                                         AC_VERB_SET_CONNECT_SEL, 0);
+               if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
+                       stac_issue_unsol_event(codec, spec->ext_mic.pin);
+       }
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = cfg->input_pins[i];
                if (nid) {
@@ -4276,10 +4402,9 @@ static int stac92xx_init(struct hda_codec *codec)
                        }
                        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);
-                               stac_issue_unsol_event(codec, nid,
-                                                      STAC_INSERT_EVENT);
+                               if (enable_pin_detect(codec, nid,
+                                                     STAC_INSERT_EVENT))
+                                       stac_issue_unsol_event(codec, nid);
                        }
                }
        }
@@ -4324,10 +4449,8 @@ static int stac92xx_init(struct hda_codec *codec)
                                stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
-               if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) {
-                       enable_pin_detect(codec, nid, STAC_PWR_EVENT);
-                       stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
-               }
+               if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
+                       stac_issue_unsol_event(codec, nid);
        }
        if (spec->dac_list)
                stac92xx_power_down(codec);
@@ -4431,6 +4554,48 @@ static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
        return 0;
 }
 
+static void stac92xx_line_out_detect(struct hda_codec *codec,
+                                    int presence)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < cfg->line_outs; i++) {
+               if (presence)
+                       break;
+               presence = get_pin_presence(codec, cfg->line_out_pins[i]);
+               if (presence) {
+                       unsigned int pinctl;
+                       pinctl = snd_hda_codec_read(codec,
+                                                   cfg->line_out_pins[i], 0,
+                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       if (pinctl & AC_PINCTL_IN_EN)
+                               presence = 0; /* mic- or line-input */
+               }
+       }
+
+       if (presence) {
+               /* disable speakers */
+               for (i = 0; i < cfg->speaker_outs; i++)
+                       stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
+                                               AC_PINCTL_OUT_EN);
+               if (spec->eapd_mask && spec->eapd_switch)
+                       stac_gpio_set(codec, spec->gpio_mask,
+                               spec->gpio_dir, spec->gpio_data &
+                               ~spec->eapd_mask);
+       } else {
+               /* enable speakers */
+               for (i = 0; i < cfg->speaker_outs; i++)
+                       stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
+                                               AC_PINCTL_OUT_EN);
+               if (spec->eapd_mask && spec->eapd_switch)
+                       stac_gpio_set(codec, spec->gpio_mask,
+                               spec->gpio_dir, spec->gpio_data |
+                               spec->eapd_mask);
+       }
+} 
+
 /* return non-zero if the hp-pin of the given array index isn't
  * a jack-detection target
  */
@@ -4483,13 +4648,6 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
                for (i = 0; i < cfg->line_outs; i++)
                        stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
                                                AC_PINCTL_OUT_EN);
-               for (i = 0; i < cfg->speaker_outs; i++)
-                       stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
-                                               AC_PINCTL_OUT_EN);
-               if (spec->eapd_mask && spec->eapd_switch)
-                       stac_gpio_set(codec, spec->gpio_mask,
-                               spec->gpio_dir, spec->gpio_data &
-                               ~spec->eapd_mask);
        } else {
                /* enable lineouts */
                if (spec->hp_switch)
@@ -4498,14 +4656,8 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
                for (i = 0; i < cfg->line_outs; i++)
                        stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
                                                AC_PINCTL_OUT_EN);
-               for (i = 0; i < cfg->speaker_outs; i++)
-                       stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
-                                               AC_PINCTL_OUT_EN);
-               if (spec->eapd_mask && spec->eapd_switch)
-                       stac_gpio_set(codec, spec->gpio_mask,
-                               spec->gpio_dir, spec->gpio_data |
-                               spec->eapd_mask);
        }
+       stac92xx_line_out_detect(codec, presence);
        /* toggle hp outs */
        for (i = 0; i < cfg->hp_outs; i++) {
                unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
@@ -4590,10 +4742,28 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
        }
 }
 
-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
-                                  unsigned char type)
+static void stac92xx_mic_detect(struct hda_codec *codec)
 {
-       struct sigmatel_event *event = stac_get_event(codec, nid, type);
+       struct sigmatel_spec *spec = codec->spec;
+       struct sigmatel_mic_route *mic;
+
+       if (get_pin_presence(codec, spec->ext_mic.pin))
+               mic = &spec->ext_mic;
+       else
+               mic = &spec->int_mic;
+       if (mic->dmux_idx)
+               snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
+                                         AC_VERB_SET_CONNECT_SEL,
+                                         mic->dmux_idx);
+       else
+               snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0,
+                                         AC_VERB_SET_CONNECT_SEL,
+                                         mic->mux_idx);
+}
+
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct sigmatel_event *event = stac_get_event(codec, nid);
        if (!event)
                return;
        codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
@@ -4613,7 +4783,19 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
        switch (event->type) {
        case STAC_HP_EVENT:
                stac92xx_hp_detect(codec);
-               /* fallthru */
+               break;
+       case STAC_LO_EVENT:
+               stac92xx_line_out_detect(codec, 0);
+               break;
+       case STAC_MIC_EVENT:
+               stac92xx_mic_detect(codec);
+               break;
+       }
+
+       switch (event->type) {
+       case STAC_HP_EVENT:
+       case STAC_LO_EVENT:
+       case STAC_MIC_EVENT:
        case STAC_INSERT_EVENT:
        case STAC_PWR_EVENT:
                if (spec->num_pwrs > 0)
@@ -4704,8 +4886,7 @@ static int stac92xx_resume(struct hda_codec *codec)
        snd_hda_codec_resume_cache(codec);
        /* fake event to set up pins again to override cached values */
        if (spec->hp_detect)
-               stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
-                                      STAC_HP_EVENT);
+               stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
        return 0;
 }
 
@@ -4745,6 +4926,19 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
 static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
 {
        struct sigmatel_spec *spec = codec->spec;
+       int i;
+       hda_nid_t nid;
+
+       /* reset each pin before powering down DAC/ADC to avoid click noise */
+       nid = codec->start_nid;
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int wid_type = get_wcaps_type(wcaps);
+               if (wid_type == AC_WID_PIN)
+                       snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+
        if (spec->eapd_mask)
                stac_gpio_set(codec, spec->gpio_mask,
                                spec->gpio_dir, spec->gpio_data &
@@ -4781,7 +4975,8 @@ static int patch_stac9200(struct hda_codec *codec)
                                                        stac9200_models,
                                                        stac9200_cfg_tbl);
        if (spec->board_config < 0)
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                         stac9200_brd_tbl[spec->board_config]);
@@ -4853,8 +5048,8 @@ static int patch_stac925x(struct hda_codec *codec)
                                                        stac925x_cfg_tbl);
  again:
        if (spec->board_config < 0)
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
-                                     "using BIOS defaults\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                         stac925x_brd_tbl[spec->board_config]);
@@ -4884,6 +5079,9 @@ static int patch_stac925x(struct hda_codec *codec)
 
        spec->init = stac925x_core_init;
        spec->mixer = stac925x_mixer;
+       spec->num_caps = 1;
+       spec->capvols = stac925x_capvols;
+       spec->capsws = stac925x_capsws;
 
        err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
        if (!err) {
@@ -4936,8 +5134,8 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
                                                        stac92hd73xx_cfg_tbl);
 again:
        if (spec->board_config < 0)
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
-                       " STAC92HD73XX, using BIOS defaults\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac92hd73xx_brd_tbl[spec->board_config]);
@@ -4987,6 +5185,10 @@ again:
        memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
                        sizeof(stac92hd73xx_dmux));
 
+       spec->num_caps = STAC92HD73XX_NUM_CAPS;
+       spec->capvols = stac92hd73xx_capvols;
+       spec->capsws = stac92hd73xx_capsws;
+
        switch (spec->board_config) {
        case STAC_DELL_EQ:
                spec->init = dell_eq_core_init;
@@ -5106,14 +5308,18 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
        spec->dinput_mux = &stac92hd83xxx_dmux;
        spec->pin_nids = stac92hd83xxx_pin_nids;
+       spec->num_caps = STAC92HD83XXX_NUM_CAPS;
+       spec->capvols = stac92hd83xxx_capvols;
+       spec->capsws = stac92hd83xxx_capsws;
+
        spec->board_config = snd_hda_check_board_config(codec,
                                                        STAC_92HD83XXX_MODELS,
                                                        stac92hd83xxx_models,
                                                        stac92hd83xxx_cfg_tbl);
 again:
        if (spec->board_config < 0)
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
-                       " STAC92HD83XXX, using BIOS defaults\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac92hd83xxx_brd_tbl[spec->board_config]);
@@ -5155,6 +5361,8 @@ again:
 
        num_dacs = snd_hda_get_connections(codec, nid,
                                conn, STAC92HD83_DAC_COUNT + 1) - 1;
+       if (num_dacs < 0)
+               num_dacs = STAC92HD83_DAC_COUNT;
 
        /* set port X to select the last DAC
         */
@@ -5276,8 +5484,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
                                                        stac92hd71bxx_cfg_tbl);
 again:
        if (spec->board_config < 0)
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
-                       " STAC92HD71BXX, using BIOS defaults\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac92hd71bxx_brd_tbl[spec->board_config]);
@@ -5292,6 +5500,10 @@ again:
        spec->dmic_nids = stac92hd71bxx_dmic_nids;
        spec->dmux_nids = stac92hd71bxx_dmux_nids;
 
+       spec->num_caps = STAC92HD71BXX_NUM_CAPS;
+       spec->capvols = stac92hd71bxx_capvols;
+       spec->capsws = stac92hd71bxx_capsws;
+
        switch (codec->vendor_id) {
        case 0x111d76b6: /* 4 Port without Analog Mixer */
        case 0x111d76b7:
@@ -5301,7 +5513,6 @@ again:
        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,
@@ -5314,8 +5525,6 @@ again:
                }
                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:
@@ -5338,11 +5547,17 @@ again:
 
                /* no output amps */
                spec->num_pwrs = 0;
-               spec->mixer = stac92hd71bxx_analog_mixer;
-               spec->dinput_mux = &spec->private_dimux;
-
+               if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) {
+                       spec->mixer = stac92hd71bxx_analog_mixer;
+                       memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
+                              sizeof(stac92hd71bxx_dmux_amixer));
+               } else {
+                       memcpy(&spec->private_dimux,
+                              &stac92hd71bxx_dmux_nomixer,
+                              sizeof(stac92hd71bxx_dmux_nomixer));
+               }
                /* disable VSW */
-               spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
+               spec->init = stac92hd71bxx_core_init;
                unmute_init++;
                snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
                snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
@@ -5350,8 +5565,11 @@ again:
                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;
+               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) - 2;
+               }
                break;
        case 0x111d7603: /* 6 Port with Analog Mixer */
                if ((codec->revision_id & 0xf) == 1)
@@ -5361,17 +5579,25 @@ 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;
+               if (snd_hda_get_bool_hint(codec, "analog_mixer") == 1) {
+                       spec->mixer = stac92hd71bxx_analog_mixer;
+                       memcpy(&spec->private_dimux, &stac92hd71bxx_dmux_amixer,
+                              sizeof(stac92hd71bxx_dmux_amixer));
+               } else {
+                       memcpy(&spec->private_dimux,
+                              &stac92hd71bxx_dmux_nomixer,
+                              sizeof(stac92hd71bxx_dmux_nomixer));
+               }
+               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);
-               spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
-               ndmic_nids = ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1;
+               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;
+               }
        }
 
        if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
@@ -5532,8 +5758,8 @@ static int patch_stac922x(struct hda_codec *codec)
 
  again:
        if (spec->board_config < 0)
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
-                       "using BIOS defaults\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac922x_brd_tbl[spec->board_config]);
@@ -5546,7 +5772,10 @@ static int patch_stac922x(struct hda_codec *codec)
        spec->num_pwrs = 0;
 
        spec->init = stac922x_core_init;
-       spec->mixer = stac922x_mixer;
+
+       spec->num_caps = STAC922X_NUM_CAPS;
+       spec->capvols = stac922x_capvols;
+       spec->capsws = stac922x_capsws;
 
        spec->multiout.dac_nids = spec->dac_nids;
        
@@ -5595,8 +5824,8 @@ static int patch_stac927x(struct hda_codec *codec)
                                                        stac927x_cfg_tbl);
  again:
        if (spec->board_config < 0)
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
-                           "STAC927x, using BIOS defaults\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                stac927x_brd_tbl[spec->board_config]);
@@ -5621,7 +5850,6 @@ static int patch_stac927x(struct hda_codec *codec)
                spec->num_dmics = 0;
 
                spec->init = d965_core_init;
-               spec->mixer = stac927x_mixer;
                break;
        case STAC_DELL_BIOS:
                switch (codec->subsystem_id) {
@@ -5646,7 +5874,6 @@ static int patch_stac927x(struct hda_codec *codec)
                spec->num_dmics = STAC927X_NUM_DMICS;
 
                spec->init = d965_core_init;
-               spec->mixer = stac927x_mixer;
                spec->dmux_nids = stac927x_dmux_nids;
                spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
                break;
@@ -5659,9 +5886,12 @@ static int patch_stac927x(struct hda_codec *codec)
                spec->num_dmics = 0;
 
                spec->init = stac927x_core_init;
-               spec->mixer = stac927x_mixer;
        }
 
+       spec->num_caps = STAC927X_NUM_CAPS;
+       spec->capvols = stac927x_capvols;
+       spec->capsws = stac927x_capsws;
+
        spec->num_pwrs = 0;
        spec->aloopback_ctl = stac927x_loopback;
        spec->aloopback_mask = 0x40;
@@ -5723,7 +5953,8 @@ static int patch_stac9205(struct hda_codec *codec)
                                                        stac9205_cfg_tbl);
  again:
        if (spec->board_config < 0)
-               snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                         stac9205_brd_tbl[spec->board_config]);
@@ -5742,9 +5973,12 @@ static int patch_stac9205(struct hda_codec *codec)
        spec->num_pwrs = 0;
 
        spec->init = stac9205_core_init;
-       spec->mixer = stac9205_mixer;
        spec->aloopback_ctl = stac9205_loopback;
 
+       spec->num_caps = STAC9205_NUM_CAPS;
+       spec->capvols = stac9205_capvols;
+       spec->capsws = stac9205_capsws;
+
        spec->aloopback_mask = 0x40;
        spec->aloopback_shift = 0;
        /* Turn on/off EAPD per HP plugging */
@@ -5819,12 +6053,6 @@ static struct hda_verb stac9872_core_init[] = {
        {}
 };
 
-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),
-       { } /* end */
-};
-
 static hda_nid_t stac9872_pin_nids[] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x11, 0x13, 0x14,
@@ -5838,6 +6066,11 @@ static hda_nid_t stac9872_mux_nids[] = {
        0x15
 };
 
+static unsigned long stac9872_capvols[] = {
+       HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
+};
+#define stac9872_capsws                stac9872_capvols
+
 static unsigned int stac9872_vaio_pin_configs[9] = {
        0x03211020, 0x411111f0, 0x411111f0, 0x03a15030,
        0x411111f0, 0x90170110, 0x411111f0, 0x411111f0,
@@ -5854,6 +6087,8 @@ static unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = {
 };
 
 static struct snd_pci_quirk stac9872_cfg_tbl[] = {
+       SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
+                          "Sony VAIO F/S", STAC_9872_VAIO),
        {} /* terminator */
 };
 
@@ -5866,26 +6101,28 @@ static int patch_stac9872(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
        codec->spec = spec;
+       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");
+               snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+                           codec->chip_name);
        else
                stac92xx_set_config_regs(codec,
                                         stac9872_brd_tbl[spec->board_config]);
 
-       spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
-       spec->pin_nids = stac9872_pin_nids;
        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;
+       spec->num_caps = 1;
+       spec->capvols = stac9872_capvols;
+       spec->capsws = stac9872_capsws;
 
        err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
        if (err < 0) {
index 8e004fb..ab90abb 100644 (file)
@@ -210,7 +210,9 @@ struct via_spec {
        /* capture */
        unsigned int num_adc_nids;
        hda_nid_t *adc_nids;
+       hda_nid_t mux_nids[3];
        hda_nid_t dig_in_nid;
+       hda_nid_t dig_in_pin;
 
        /* capture source */
        const struct hda_input_mux *input_mux;
@@ -319,6 +321,9 @@ static void via_auto_set_output_and_unmute(struct hda_codec *codec,
                            pin_type);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                            AMP_OUT_UNMUTE);
+       if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, nid, 0, 
+                                   AC_VERB_SET_EAPD_BTLENABLE, 0x02);
 }
 
 
@@ -387,27 +392,12 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       unsigned int vendor_id = codec->vendor_id;
-
-       /* AIW0  lydia 060801 add for correct sw0 input select */
-       if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x18, &spec->cur_mux[adc_idx]);
-       else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
-                 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x19, &spec->cur_mux[adc_idx]);
-       else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
-                 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x17, &spec->cur_mux[adc_idx]);
-       else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            0x13, &spec->cur_mux[adc_idx]);
-       else
-               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                            spec->adc_nids[adc_idx],
-                                            &spec->cur_mux[adc_idx]);
+
+       if (!spec->mux_nids[adc_idx])
+               return -EINVAL;
+       return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+                                    spec->mux_nids[adc_idx],
+                                    &spec->cur_mux[adc_idx]);
 }
 
 static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
@@ -998,25 +988,11 @@ static int via_init(struct hda_codec *codec)
 
        /* Lydia Add for EAPD enable */
        if (!spec->dig_in_nid) { /* No Digital In connection */
-               if (IS_VT1708_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           PIN_OUT);
-                       snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-               } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
-                          IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
+               if (spec->dig_in_pin) {
+                       snd_hda_codec_write(codec, spec->dig_in_pin, 0,
                                            AC_VERB_SET_PIN_WIDGET_CONTROL,
                                            PIN_OUT);
-                       snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-               } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
-                          IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
-                       snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           PIN_OUT);
-                       snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
+                       snd_hda_codec_write(codec, spec->dig_in_pin, 0,
                                            AC_VERB_SET_EAPD_BTLENABLE, 0x02);
                }
        } else /* enable SPDIF-input pin */
@@ -1326,6 +1302,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
+       spec->dig_in_pin = VT1708_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1708_DIGIN_NID;
 
@@ -1352,6 +1329,33 @@ static int via_auto_init(struct hda_codec *codec)
        return 0;
 }
 
+static int get_mux_nids(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       hda_nid_t nid, conn[8];
+       unsigned int type;
+       int i, n;
+
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               nid = spec->adc_nids[i];
+               while (nid) {
+                       type = get_wcaps_type(get_wcaps(codec, nid));
+                       if (type == AC_WID_PIN)
+                               break;
+                       n = snd_hda_get_connections(codec, nid, conn,
+                                                   ARRAY_SIZE(conn));
+                       if (n <= 0)
+                               break;
+                       if (n > 1) {
+                               spec->mux_nids[i] = nid;
+                               break;
+                       }
+                       nid = conn[0];
+               }
+       }
+       return 0;
+}
+
 static int patch_vt1708(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -1799,6 +1803,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
+       spec->dig_in_pin = VT1709_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1709_DIGIN_NID;
 
@@ -1859,6 +1864,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1709_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
                spec->num_mixers++;
        }
@@ -1952,6 +1958,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1709_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
                spec->num_mixers++;
        }
@@ -2344,6 +2351,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
 
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
+       spec->dig_in_pin = VT1708B_DIGIN_PIN;
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = VT1708B_DIGIN_NID;
 
@@ -2404,6 +2412,7 @@ static int patch_vt1708B_8ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708B_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
                spec->num_mixers++;
        }
@@ -2455,6 +2464,7 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708B_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
                spec->num_mixers++;
        }
@@ -2889,6 +2899,7 @@ static int patch_vt1708S(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1708S_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
                spec->num_mixers++;
        }
@@ -3206,6 +3217,7 @@ static int patch_vt1702(struct hda_codec *codec)
        if (!spec->adc_nids && spec->input_mux) {
                spec->adc_nids = vt1702_adc_nids;
                spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
+               get_mux_nids(codec);
                spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
                spec->num_mixers++;
        }