tree-wide: fix assorted typos all over the place
[safe/jmp/linux-2.6] / sound / pci / hda / patch_realtek.c
index 7ff2934..872731e 100644 (file)
@@ -220,6 +220,7 @@ enum {
        ALC888_ACER_ASPIRE_4930G,
        ALC888_ACER_ASPIRE_6530G,
        ALC888_ACER_ASPIRE_8930G,
+       ALC888_ACER_ASPIRE_7730G,
        ALC883_MEDION,
        ALC883_MEDION_MD2,
        ALC883_LAPTOP_EAPD,
@@ -231,6 +232,7 @@ enum {
        ALC888_3ST_HP,
        ALC888_6ST_DELL,
        ALC883_MITAC,
+       ALC883_CLEVO_M540R,
        ALC883_CLEVO_M720,
        ALC883_FUJITSU_PI2515,
        ALC888_FUJITSU_XA3530,
@@ -273,7 +275,7 @@ struct alc_spec {
        struct snd_kcontrol_new *cap_mixer;     /* capture mixer */
        unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
 
-       const struct hda_verb *init_verbs[5];   /* initialization verbs
+       const struct hda_verb *init_verbs[10];  /* initialization verbs
                                                 * don't forget NULL
                                                 * termination!
                                                 */
@@ -963,6 +965,8 @@ static void alc_automute_pin(struct hda_codec *codec)
        unsigned int nid = spec->autocfg.hp_pins[0];
        int i;
 
+       if (!nid)
+               return;
        pincap = snd_hda_query_pin_caps(codec, nid);
        if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
                snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
@@ -1330,15 +1334,20 @@ do_sku:
         *              when the external headphone out jack is plugged"
         */
        if (!spec->autocfg.hp_pins[0]) {
+               hda_nid_t nid;
                tmp = (ass >> 11) & 0x3;        /* HP to chassis */
                if (tmp == 0)
-                       spec->autocfg.hp_pins[0] = porta;
+                       nid = porta;
                else if (tmp == 1)
-                       spec->autocfg.hp_pins[0] = porte;
+                       nid = porte;
                else if (tmp == 2)
-                       spec->autocfg.hp_pins[0] = portd;
+                       nid = portd;
                else
                        return 1;
+               for (i = 0; i < spec->autocfg.line_outs; i++)
+                       if (spec->autocfg.line_out_pins[i] == nid)
+                               return 1;
+               spec->autocfg.hp_pins[0] = nid;
        }
 
        alc_init_auto_hp(codec);
@@ -1360,7 +1369,7 @@ static void alc_ssid_check(struct hda_codec *codec,
 }
 
 /*
- * Fix-up pin default configurations
+ * Fix-up pin default configurations and add default verbs
  */
 
 struct alc_pincfg {
@@ -1368,9 +1377,14 @@ struct alc_pincfg {
        u32 val;
 };
 
-static void alc_fix_pincfg(struct hda_codec *codec,
+struct alc_fixup {
+       const struct alc_pincfg *pins;
+       const struct hda_verb *verbs;
+};
+
+static void alc_pick_fixup(struct hda_codec *codec,
                           const struct snd_pci_quirk *quirk,
-                          const struct alc_pincfg **pinfix)
+                          const struct alc_fixup *fix)
 {
        const struct alc_pincfg *cfg;
 
@@ -1378,9 +1392,14 @@ static void alc_fix_pincfg(struct hda_codec *codec,
        if (!quirk)
                return;
 
-       cfg = pinfix[quirk->value];
-       for (; cfg->nid; cfg++)
-               snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+       fix += quirk->value;
+       cfg = fix->pins;
+       if (cfg) {
+               for (; cfg->nid; cfg++)
+                       snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+       }
+       if (fix->verbs)
+               add_verb(codec->spec, fix->verbs);
 }
 
 /*
@@ -4311,8 +4330,6 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
 #define alc880_fixed_pin_idx(nid)      ((nid) - 0x14)
 #define alc880_is_multi_pin(nid)       ((nid) >= 0x18)
 #define alc880_multi_pin_idx(nid)      ((nid) - 0x18)
-#define alc880_is_input_pin(nid)       ((nid) >= 0x18)
-#define alc880_input_pin_idx(nid)      ((nid) - 0x18)
 #define alc880_idx_to_dac(nid)         ((nid) + 0x02)
 #define alc880_dac_to_idx(nid)         ((nid) - 0x02)
 #define alc880_idx_to_mixer(nid)       ((nid) + 0x0c)
@@ -4400,13 +4417,19 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
+                       const char *pfx;
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                               pfx = "Speaker";
+                       else
+                               pfx = chname[i];
+                       sprintf(name, "%s Playback Volume", pfx);
                        err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
+                       sprintf(name, "%s Playback Switch", pfx);
                        err = add_control(spec, ALC_CTL_BIND_MUTE, name,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 2,
                                                              HDA_INPUT));
@@ -4480,31 +4503,61 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
        return 0;
 }
 
+static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
+       return (pincap & AC_PINCAP_IN) != 0;
+}
+
 /* create playback/capture controls for input pins */
-static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
-                                               const struct auto_pin_cfg *cfg)
+static int alc_auto_create_input_ctls(struct hda_codec *codec,
+                                     const struct auto_pin_cfg *cfg,
+                                     hda_nid_t mixer,
+                                     hda_nid_t cap1, hda_nid_t cap2)
 {
+       struct alc_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (alc880_is_input_pin(cfg->input_pins[i])) {
-                       idx = alc880_input_pin_idx(cfg->input_pins[i]);
-                       err = new_analog_input(spec, cfg->input_pins[i],
-                                              auto_pin_cfg_labels[i],
-                                              idx, 0x0b);
-                       if (err < 0)
-                               return err;
+               hda_nid_t pin;
+
+               pin = cfg->input_pins[i];
+               if (!alc_is_input_pin(codec, pin))
+                       continue;
+
+               if (mixer) {
+                       idx = get_connection_index(codec, mixer, pin);
+                       if (idx >= 0) {
+                               err = new_analog_input(spec, pin,
+                                                      auto_pin_cfg_labels[i],
+                                                      idx, mixer);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+
+               if (!cap1)
+                       continue;
+               idx = get_connection_index(codec, cap1, pin);
+               if (idx < 0 && cap2)
+                       idx = get_connection_index(codec, cap2, pin);
+               if (idx >= 0) {
                        imux->items[imux->num_items].label =
                                auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index =
-                               alc880_input_pin_idx(cfg->input_pins[i]);
+                       imux->items[imux->num_items].index = idx;
                        imux->num_items++;
                }
        }
        return 0;
 }
 
+static int alc880_auto_create_input_ctls(struct hda_codec *codec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
+}
+
 static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
                               unsigned int pin_type)
 {
@@ -4570,7 +4623,7 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (alc880_is_input_pin(nid)) {
+               if (alc_is_input_pin(codec, nid)) {
                        alc_set_input_pin(codec, nid, i);
                        if (nid != ALC880_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
@@ -4613,7 +4666,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
                                           "Headphone");
        if (err < 0)
                return err;
-       err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -5983,7 +6036,14 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
 
        nid = cfg->line_out_pins[0];
        if (nid) {
-               err = alc260_add_playback_controls(spec, nid, "Front", &vols);
+               const char *pfx;
+               if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
+                       pfx = "Master";
+               else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                       pfx = "Speaker";
+               else
+                       pfx = "Front";
+               err = alc260_add_playback_controls(spec, nid, pfx, &vols);
                if (err < 0)
                        return err;
        }
@@ -6006,39 +6066,10 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
 }
 
 /* create playback/capture controls for input pins */
-static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
+static int alc260_auto_create_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (cfg->input_pins[i] >= 0x12) {
-                       idx = cfg->input_pins[i] - 0x12;
-                       err = new_analog_input(spec, cfg->input_pins[i],
-                                              auto_pin_cfg_labels[i], idx,
-                                              0x07);
-                       if (err < 0)
-                               return err;
-                       imux->items[imux->num_items].label =
-                               auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index = idx;
-                       imux->num_items++;
-               }
-               if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
-                       idx = cfg->input_pins[i] - 0x09;
-                       err = new_analog_input(spec, cfg->input_pins[i],
-                                              auto_pin_cfg_labels[i], idx,
-                                              0x07);
-                       if (err < 0)
-                               return err;
-                       imux->items[imux->num_items].label =
-                               auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index = idx;
-                       imux->num_items++;
-               }
-       }
-       return 0;
+       return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
 }
 
 static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
@@ -6152,7 +6183,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
                return err;
        if (!spec->kctls.list)
                return 0; /* can't find valid BIOS pin config */
-       err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -6588,7 +6619,7 @@ static struct hda_input_mux alc889A_mb31_capture_source = {
                /* Front Mic (0x01) unused */
                { "Line", 0x2 },
                /* Line 2 (0x03) unused */
-               /* CD (0x04) unsused? */
+               /* CD (0x04) unused? */
        },
 };
 
@@ -6644,6 +6675,52 @@ static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
 #define alc883_3ST_6ch_modes   alc882_3ST_6ch_modes
 
 /*
+ * 2ch mode
+ */
+static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
+       { 2, alc883_3ST_ch2_clevo_init },
+       { 4, alc883_3ST_ch4_clevo_init },
+       { 6, alc883_3ST_ch6_clevo_init },
+};
+
+
+/*
  * 6ch mode
  */
 static struct hda_verb alc882_sixstack_ch6_init[] = {
@@ -6685,9 +6762,9 @@ static struct hda_verb alc885_mbp_ch2_init[] = {
 };
 
 /*
- * 6ch mode
+ * 4ch mode
  */
-static struct hda_verb alc885_mbp_ch6_init[] = {
+static struct hda_verb alc885_mbp_ch4_init[] = {
        { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
        { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
@@ -6696,9 +6773,9 @@ static struct hda_verb alc885_mbp_ch6_init[] = {
        { } /* end */
 };
 
-static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
+static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
        { 2, alc885_mbp_ch2_init },
-       { 6, alc885_mbp_ch6_init },
+       { 4, alc885_mbp_ch4_init },
 };
 
 /*
@@ -6942,10 +7019,11 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, 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, 0x00, HDA_INPUT),
@@ -7374,14 +7452,18 @@ static struct hda_verb alc885_mbp3_init_verbs[] = {
        {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)},
+       /* HP 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)},
        /* 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},
-       /* HP Pin: output 0 (0x0d) */
+       /* HP Pin: output 0 (0x0e) */
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
        {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
        /* Mic (rear) pin: input vref at 80% */
        {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -7862,8 +7944,9 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
 
 static struct snd_kcontrol_new alc883_targa_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        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),
@@ -7882,8 +7965,9 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = {
 
 static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -7895,6 +7979,15 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -8116,6 +8209,22 @@ static struct hda_verb alc883_mitac_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb alc883_clevo_m540r_verbs[] = {
+       /* HP */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Int speaker */
+       /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
+
+       /* enable unsolicited event */
+       /*
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+       */
+
+       { } /* end */
+};
+
 static struct hda_verb alc883_clevo_m720_verbs[] = {
        /* HP */
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -8472,6 +8581,13 @@ static struct hda_verb alc883_acer_eapd_verbs[] = {
        { }
 };
 
+static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
 static void alc888_6st_dell_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -8633,6 +8749,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC888_ACER_ASPIRE_4930G]      = "acer-aspire-4930g",
        [ALC888_ACER_ASPIRE_6530G]      = "acer-aspire-6530g",
        [ALC888_ACER_ASPIRE_8930G]      = "acer-aspire-8930g",
+       [ALC888_ACER_ASPIRE_7730G]      = "acer-aspire-7730g",
        [ALC883_MEDION]         = "medion",
        [ALC883_MEDION_MD2]     = "medion-md2",
        [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
@@ -8644,6 +8761,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC888_3ST_HP]         = "3stack-hp",
        [ALC888_6ST_DELL]       = "6stack-dell",
        [ALC883_MITAC]          = "mitac",
+       [ALC883_CLEVO_M540R]    = "clevo-m540r",
        [ALC883_CLEVO_M720]     = "clevo-m720",
        [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
        [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
@@ -8679,6 +8797,8 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
                ALC888_ACER_ASPIRE_6530G),
        SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
                ALC888_ACER_ASPIRE_6530G),
+       SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
+               ALC888_ACER_ASPIRE_7730G),
        /* default Acer -- disabled as it causes more problems.
         *    model=auto should work fine now
         */
@@ -8748,6 +8868,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
        SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
+       SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
        SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
        /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
@@ -8849,10 +8970,11 @@ static struct alc_config_preset alc882_presets[] = {
                .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
                .init_verbs = { alc885_mbp3_init_verbs,
                                alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .num_dacs = 2,
                .dac_nids = alc882_dac_nids,
-               .channel_mode = alc885_mbp_6ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
+               .hp_nid = 0x04,
+               .channel_mode = alc885_mbp_4ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
                .input_mux = &alc882_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
@@ -9073,7 +9195,8 @@ static struct alc_config_preset alc882_presets[] = {
                .init_hook = alc882_targa_automute,
        },
        [ALC883_TARGA_8ch_DIG] = {
-               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+               .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
+                           alc883_chmode_mixer },
                .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
                                alc883_targa_verbs },
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
@@ -9180,6 +9303,26 @@ static struct alc_config_preset alc882_presets[] = {
                .setup = alc889_acer_aspire_8930g_setup,
                .init_hook = alc_automute_amp,
        },
+       [ALC888_ACER_ASPIRE_7730G] = {
+               .mixers = { alc883_3ST_6ch_mixer,
+                               alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+                               alc888_acer_aspire_7730G_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .const_channel_count = 6,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .setup = alc888_acer_aspire_6530g_setup,
+               .init_hook = alc_automute_amp,
+       },
        [ALC883_MEDION] = {
                .mixers = { alc883_fivestack_mixer,
                            alc883_chmode_mixer },
@@ -9215,6 +9358,21 @@ static struct alc_config_preset alc882_presets[] = {
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
        },
+       [ALC883_CLEVO_M540R] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
+               .channel_mode = alc883_3ST_6ch_clevo_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+               /* This machine has the hardware HP auto-muting, thus
+                * we need no software mute via unsol event
+                */
+       },
        [ALC883_CLEVO_M720] = {
                .mixers = { alc883_clevo_m720_mixer },
                .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
@@ -9452,11 +9610,13 @@ static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
        { }
 };
 
-static const struct alc_pincfg *alc882_pin_fixes[] = {
-       [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+static const struct alc_fixup alc882_fixups[] = {
+       [PINFIX_ABIT_AW9D_MAX] = {
+               .pins = alc882_abit_aw9d_pinfix
+       },
 };
 
-static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+static struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
        {}
 };
@@ -9464,6 +9624,12 @@ static struct snd_pci_quirk alc882_pinfix_tbl[] = {
 /*
  * BIOS auto configuration
  */
+static int alc882_auto_create_input_ctls(struct hda_codec *codec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
+}
+
 static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
                                              hda_nid_t nid, int pin_type,
                                              int dac_idx)
@@ -9604,44 +9770,73 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
 static int alc882_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *autocfg = &spec->autocfg;
-       unsigned int wcap;
-       int i;
-       int err = alc880_parse_auto_config(codec);
+       static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
+       int i, err;
 
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+                                          alc882_ignore);
        if (err < 0)
                return err;
-       else if (!err)
-               return 0; /* no config found */
+       if (!spec->autocfg.line_outs)
+               return 0; /* can't find valid BIOS pin config */
 
-       err = alc_auto_add_mic_boost(codec);
+       err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
+       err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = alc880_auto_create_extra_out(spec,
+                                          spec->autocfg.speaker_pins[0],
+                                          "Speaker");
+       if (err < 0)
+               return err;
+       err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
+                                          "Headphone");
+       if (err < 0)
+               return err;
+       err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       /* hack - override the init verbs */
-       spec->init_verbs[0] = alc883_auto_init_verbs;
+       /* check multiple SPDIF-out (for recent codecs) */
+       for (i = 0; i < spec->autocfg.dig_outs; i++) {
+               hda_nid_t dig_nid;
+               err = snd_hda_get_connections(codec,
+                                             spec->autocfg.dig_out_pins[i],
+                                             &dig_nid, 1);
+               if (err < 0)
+                       continue;
+               if (!i)
+                       spec->multiout.dig_out_nid = dig_nid;
+               else {
+                       spec->multiout.slave_dig_outs = spec->slave_dig_outs;
+                       spec->slave_dig_outs[i - 1] = dig_nid;
+                       if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1)
+                               break;
+               }
+       }
+       if (spec->autocfg.dig_in_pin)
+               spec->dig_in_nid = ALC880_DIGIN_NID;
+
+       if (spec->kctls.list)
+               add_mixer(spec, spec->kctls.list);
+
+       add_verb(spec, alc883_auto_init_verbs);
        /* if ADC 0x07 is available, initialize it, too */
-       wcap = get_wcaps(codec, 0x07);
-       wcap = get_wcaps_type(wcap);
-       if (wcap == AC_WID_AUD_IN)
+       if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
                add_verb(spec, alc882_adc1_init_verbs);
 
-       /* digital-mic input pin is excluded in alc880_auto_create..()
-        * because it's under 0x18
-        */
-       if (autocfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
-           autocfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
-               struct hda_input_mux *imux = &spec->private_imux[0];
-               for (i = 1; i < 3; i++)
-                       memcpy(&spec->private_imux[i],
-                              &spec->private_imux[0],
-                              sizeof(spec->private_imux[0]));
-               imux->items[imux->num_items].label = "Int DMic";
-               imux->items[imux->num_items].index = 0x0b;
-               imux->num_items++;
-               spec->num_mux_defs = 3;
-               spec->input_mux = spec->private_imux;
-       }
+       spec->num_mux_defs = 1;
+       spec->input_mux = &spec->private_imux[0];
+
+       alc_ssid_check(codec, 0x15, 0x1b, 0x14);
+
+       err = alc_auto_add_mic_boost(codec);
+       if (err < 0)
+               return err;
 
        return 1; /* config found */
 }
@@ -9693,7 +9888,7 @@ static int patch_alc882(struct hda_codec *codec)
                board_config = ALC882_AUTO;
        }
 
-       alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+       alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups);
 
        if (board_config == ALC882_AUTO) {
                /* automatic parse from the BIOS config */
@@ -10743,104 +10938,111 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
        { } /* end */
 };
 
+/* We use two mixers depending on the output pin; 0x16 is a mono output
+ * and thus it's bound with a different mixer.
+ * This function returns which mixer amp should be used.
+ */
+static int alc262_check_volbit(hda_nid_t nid)
+{
+       if (!nid)
+               return 0;
+       else if (nid == 0x16)
+               return 2;
+       else
+               return 1;
+}
+
+static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
+                                 const char *pfx, int *vbits)
+{
+       char name[32];
+       unsigned long val;
+       int vbit;
+
+       vbit = alc262_check_volbit(nid);
+       if (!vbit)
+               return 0;
+       if (*vbits & vbit) /* a volume control for this mixer already there */
+               return 0;
+       *vbits |= vbit;
+       snprintf(name, sizeof(name), "%s Playback Volume", pfx);
+       if (vbit == 2)
+               val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
+       else
+               val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
+       return add_control(spec, ALC_CTL_WIDGET_VOL, name, val);
+}
+
+static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
+                                const char *pfx)
+{
+       char name[32];
+       unsigned long val;
+
+       if (!nid)
+               return 0;
+       snprintf(name, sizeof(name), "%s Playback Switch", pfx);
+       if (nid == 0x16)
+               val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
+       else
+               val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+       return add_control(spec, ALC_CTL_WIDGET_MUTE, name, val);
+}
+
 /* add playback controls from the parsed DAC table */
 static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
 {
-       hda_nid_t nid;
+       const char *pfx;
+       int vbits;
        int err;
 
        spec->multiout.num_dacs = 1;    /* only use one dac */
        spec->multiout.dac_nids = spec->private_dac_nids;
        spec->multiout.dac_nids[0] = 2;
 
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Front Playback Volume",
-                                 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                 "Front Playback Switch",
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->speaker_pins[0];
-       if (nid) {
-               if (nid == 0x16) {
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Speaker Playback Volume",
-                                         HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Speaker Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Speaker Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               /* spec->multiout.hp_nid = 2; */
-               if (nid == 0x16) {
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Headphone Playback Volume",
-                                         HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Headphone Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       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;
-               }
-       }
-       return 0;
-}
-
-static int alc262_auto_create_analog_input_ctls(struct alc_spec *spec,
-                                               const struct auto_pin_cfg *cfg)
-{
-       int err;
+       if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
+               pfx = "Master";
+       else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+               pfx = "Speaker";
+       else
+               pfx = "Front";
+       err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
+       if (err < 0)
+               return err;
+       err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
+       if (err < 0)
+               return err;
+       err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
+       if (err < 0)
+               return err;
 
-       err = alc880_auto_create_analog_input_ctls(spec, cfg);
+       vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
+               alc262_check_volbit(cfg->speaker_pins[0]) |
+               alc262_check_volbit(cfg->hp_pins[0]);
+       if (vbits == 1 || vbits == 2)
+               pfx = "Master"; /* only one mixer is used */
+       else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+               pfx = "Speaker";
+       else
+               pfx = "Front";
+       vbits = 0;
+       err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
+       if (err < 0)
+               return err;
+       err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
+                                    &vbits);
+       if (err < 0)
+               return err;
+       err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
+                                    &vbits);
        if (err < 0)
                return err;
-       /* digital-mic input pin is excluded in alc880_auto_create..()
-        * because it's under 0x18
-        */
-       if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
-           cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
-               struct hda_input_mux *imux = &spec->private_imux[0];
-               imux->items[imux->num_items].label = "Int Mic";
-               imux->items[imux->num_items].index = 0x09;
-               imux->num_items++;
-       }
        return 0;
 }
 
+#define alc262_auto_create_input_ctls \
+       alc880_auto_create_input_ctls
 
 /*
  * generic initialization of ADC, input mixers and output mixers
@@ -11158,7 +11360,7 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
        err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -12018,21 +12220,16 @@ static struct hda_verb alc268_volume_init_verbs[] = {
        { }
 };
 
+static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = alc_mux_enum_info,
-               .get = alc_mux_enum_get,
-               .put = alc_mux_enum_put,
-       },
+       _DEFINE_CAPSRC(1),
        { } /* end */
 };
 
@@ -12041,18 +12238,7 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = {
        HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = alc_mux_enum_info,
-               .get = alc_mux_enum_get,
-               .put = alc_mux_enum_put,
-       },
+       _DEFINE_CAPSRC(2),
        { } /* end */
 };
 
@@ -12228,46 +12414,46 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
 }
 
 /* create playback/capture controls for input pins */
-static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
+static int alc268_auto_create_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, idx1, dmic_nid;
-
-       dmic_nid = 0x12;
-       while (dmic_nid <= 0x13) {
-               for (i = 0; i < AUTO_PIN_LAST; i++) {
-                       switch (cfg->input_pins[i]) {
-                       case 0x18:
-                               idx1 = 0;       /* Mic 1 */
-                               break;
-                       case 0x19:
-                               idx1 = 1;       /* Mic 2 */
-                               break;
-                       case 0x1a:
-                               idx1 = 2;       /* Line In */
-                               break;
-                       case 0x1c:
-                               idx1 = 3;       /* CD */
-                               break;
-                       case 0x12:
-                       case 0x13:
-                               if (cfg->input_pins[i] != dmic_nid)
-                                       continue;
-                               idx1 = 6;       /* digital mics */
-                               break;
-                       default:
-                               continue;
-                       }
-                       imux->items[imux->num_items].label =
-                               auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index = idx1;
-                       imux->num_items++;
-               }
-               imux++;
-               dmic_nid++;
+       return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
+}
+
+static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
+                                             hda_nid_t nid, int pin_type)
+{
+       int idx;
+
+       alc_set_pin_output(codec, nid, pin_type);
+       if (nid == 0x14 || nid == 0x16)
+               idx = 0;
+       else
+               idx = 1;
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
+}
+
+static void alc268_auto_init_multi_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t nid = spec->autocfg.line_out_pins[0];
+       if (nid) {
+               int pin_type = get_pin_type(spec->autocfg.line_out_type);
+               alc268_auto_set_output_and_unmute(codec, nid, pin_type);
        }
-       return 0;
+}
+
+static void alc268_auto_init_hp_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t pin;
+
+       pin = spec->autocfg.hp_pins[0];
+       if (pin)
+               alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
+       pin = spec->autocfg.speaker_pins[0];
+       if (pin)
+               alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
 }
 
 static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
@@ -12278,9 +12464,10 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
        hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
        unsigned int    dac_vol1, dac_vol2;
 
-       if (speaker_nid) {
+       if (line_nid == 0x1d || speaker_nid == 0x1d) {
                snd_hda_codec_write(codec, speaker_nid, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               /* mute mixer inputs from 0x1d */
                snd_hda_codec_write(codec, 0x0f, 0,
                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_IN_UNMUTE(1));
@@ -12288,6 +12475,7 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_IN_UNMUTE(1));
        } else {
+               /* unmute mixer inputs from 0x1d */
                snd_hda_codec_write(codec, 0x0f, 0,
                                    AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
                snd_hda_codec_write(codec, 0x10, 0,
@@ -12344,7 +12532,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -12375,8 +12563,6 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-#define alc268_auto_init_multi_out     alc882_auto_init_multi_out
-#define alc268_auto_init_hp_out                alc882_auto_init_hp_out
 #define alc268_auto_init_analog_input  alc882_auto_init_analog_input
 
 /* init callback for auto-configuration model -- overriding the default init */
@@ -12418,13 +12604,15 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
                                                ALC268_ACER_ASPIRE_ONE),
        SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
-       SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
+       SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
+                       "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
+       /* almost compatible with toshiba but with optional digital outs;
+        * auto-probing seems working fine
+        */
        SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
-                          ALC268_TOSHIBA),
+                          ALC268_AUTO),
        SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
        SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
-       SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
-                          ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
        SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
@@ -12432,9 +12620,19 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
        {}
 };
 
+/* Toshiba laptops have no unique PCI SSID but only codec SSID */
+static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
+       SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
+       SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
+                          ALC268_TOSHIBA),
+       {}
+};
+
 static struct alc_config_preset alc268_presets[] = {
        [ALC267_QUANTA_IL1] = {
-               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
+               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
+                           alc268_capture_nosrc_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc267_quanta_il1_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -12444,7 +12642,6 @@ static struct alc_config_preset alc268_presets[] = {
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
-               .input_mux = &alc268_capture_source,
                .unsol_event = alc_sku_unsol_event,
                .setup = alc267_quanta_il1_setup,
                .init_hook = alc_inithook,
@@ -12519,7 +12716,7 @@ static struct alc_config_preset alc268_presets[] = {
        [ALC268_ACER_ASPIRE_ONE] = {
                .mixers = { alc268_acer_aspire_one_mixer,
                            alc268_beep_mixer,
-                           alc268_capture_alt_mixer },
+                           alc268_capture_nosrc_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_aspire_one_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -12535,11 +12732,15 @@ static struct alc_config_preset alc268_presets[] = {
                .init_hook = alc268_acer_lc_init_hook,
        },
        [ALC268_DELL] = {
-               .mixers = { alc268_dell_mixer, alc268_beep_mixer },
+               .mixers = { alc268_dell_mixer, alc268_beep_mixer,
+                           alc268_capture_nosrc_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_dell_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
                .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .capsrc_nids = alc268_capsrc_nids,
                .hp_nid = 0x02,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
@@ -12600,6 +12801,10 @@ static int patch_alc268(struct hda_codec *codec)
                                                  alc268_models,
                                                  alc268_cfg_tbl);
 
+       if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
+               board_config = snd_hda_check_board_codec_sid_config(codec,
+                       ALC882_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
+
        if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
                printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
                       codec->chip_name);
@@ -12657,18 +12862,24 @@ static int patch_alc268(struct hda_codec *codec)
                unsigned int wcap = get_wcaps(codec, 0x07);
                int i;
 
+               spec->capsrc_nids = alc268_capsrc_nids;
                /* get type */
                wcap = get_wcaps_type(wcap);
-               if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
+               if (spec->auto_mic ||
+                   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);
-                       add_mixer(spec, alc268_capture_alt_mixer);
+                       if (spec->auto_mic)
+                               fixup_automic_adc(codec);
+                       if (spec->auto_mic || spec->input_mux->num_items == 1)
+                               add_mixer(spec, alc268_capture_nosrc_mixer);
+                       else
+                               add_mixer(spec, alc268_capture_alt_mixer);
                } else {
                        spec->adc_nids = alc268_adc_nids;
                        spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
                        add_mixer(spec, alc268_capture_mixer);
                }
-               spec->capsrc_nids = alc268_capsrc_nids;
                /* set default input source */
                for (i = 0; i < spec->num_adc_nids; i++)
                        snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
@@ -13083,89 +13294,10 @@ static struct hda_verb alc269_init_verbs[] = {
        { }
 };
 
-/* add playback controls from the parsed DAC table */
-static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int err;
-
-       spec->multiout.num_dacs = 1;    /* only use one dac */
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       spec->multiout.dac_nids[0] = 2;
-
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Front Playback Volume",
-                                 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                 "Front Playback Switch",
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->speaker_pins[0];
-       if (nid) {
-               if (!cfg->line_out_pins[0]) {
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Speaker Playback Volume",
-                                         HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-               if (nid == 0x16) {
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Speaker Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Speaker Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               /* spec->multiout.hp_nid = 2; */
-               if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Headphone Playback Volume",
-                                         HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-               if (nid == 0x16) {
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Headphone Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       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;
-               }
-       }
-       return 0;
-}
-
-#define alc269_auto_create_analog_input_ctls \
-       alc262_auto_create_analog_input_ctls
+#define alc269_auto_create_multi_out_ctls \
+       alc268_auto_create_multi_out_ctls
+#define alc269_auto_create_input_ctls \
+       alc268_auto_create_input_ctls
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc269_loopbacks       alc880_loopbacks
@@ -13215,7 +13347,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -13247,8 +13379,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-#define alc269_auto_init_multi_out     alc882_auto_init_multi_out
-#define alc269_auto_init_hp_out                alc882_auto_init_hp_out
+#define alc269_auto_init_multi_out     alc268_auto_init_multi_out
+#define alc269_auto_init_hp_out                alc268_auto_init_hp_out
 #define alc269_auto_init_analog_input  alc882_auto_init_analog_input
 
 
@@ -13272,7 +13404,8 @@ static const char *alc269_models[ALC269_MODEL_LAST] = {
        [ALC269_ASUS_EEEPC_P703]        = "eeepc-p703",
        [ALC269_ASUS_EEEPC_P901]        = "eeepc-p901",
        [ALC269_FUJITSU]                = "fujitsu",
-       [ALC269_LIFEBOOK]               = "lifebook"
+       [ALC269_LIFEBOOK]               = "lifebook",
+       [ALC269_AUTO]                   = "auto",
 };
 
 static struct snd_pci_quirk alc269_cfg_tbl[] = {
@@ -14196,49 +14329,10 @@ static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int alc861_auto_create_analog_input_ctls(struct hda_codec *codec,
+static int alc861_auto_create_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;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               switch (cfg->input_pins[i]) {
-               case 0x0c:
-                       idx1 = 1;
-                       idx = 2;        /* Line In */
-                       break;
-               case 0x0f:
-                       idx1 = 2;
-                       idx = 2;        /* Line In */
-                       break;
-               case 0x0d:
-                       idx1 = 0;
-                       idx = 1;        /* Mic In */
-                       break;
-               case 0x10:
-                       idx1 = 3;
-                       idx = 1;        /* Mic In */
-                       break;
-               case 0x11:
-                       idx1 = 4;
-                       idx = 0;        /* CD */
-                       break;
-               default:
-                       continue;
-               }
-
-               err = new_analog_input(spec, cfg->input_pins[i],
-                                      auto_pin_cfg_labels[i], idx, 0x15);
-               if (err < 0)
-                       return err;
-
-               imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-               imux->items[imux->num_items].index = idx1;
-               imux->num_items++;
-       }
-       return 0;
+       return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
 }
 
 static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
@@ -14285,15 +14379,16 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec)
 static void alc861_auto_init_hp_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
 
-       pin = spec->autocfg.hp_pins[0];
-       if (pin)
-               alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
+       if (spec->autocfg.hp_outs)
+               alc861_auto_set_output_and_unmute(codec,
+                                                 spec->autocfg.hp_pins[0],
+                                                 PIN_HP,
                                                  spec->multiout.hp_nid);
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin)
-               alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT,
+       if (spec->autocfg.speaker_outs)
+               alc861_auto_set_output_and_unmute(codec,
+                                                 spec->autocfg.speaker_pins[0],
+                                                 PIN_OUT,
                                                  spec->multiout.dac_nids[0]);
 }
 
@@ -14335,7 +14430,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = alc861_auto_create_analog_input_ctls(codec, &spec->autocfg);
+       err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -15086,7 +15181,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
        SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
        SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
-       SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
+       /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
        SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
        SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
@@ -15216,6 +15311,13 @@ static struct alc_config_preset alc861vd_presets[] = {
 /*
  * BIOS auto configuration
  */
+static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
+}
+
+
 static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
                                hda_nid_t nid, int pin_type, int dac_idx)
 {
@@ -15250,7 +15352,6 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
                alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
-#define alc861vd_is_input_pin(nid)     alc880_is_input_pin(nid)
 #define ALC861VD_PIN_CD_NID            ALC880_PIN_CD_NID
 
 static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
@@ -15260,7 +15361,7 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (alc861vd_is_input_pin(nid)) {
+               if (alc_is_input_pin(codec, nid)) {
                        alc_set_input_pin(codec, nid, i);
                        if (nid != ALC861VD_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
@@ -15324,13 +15425,25 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
+                       const char *pfx;
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+                               if (!cfg->hp_pins)
+                                       pfx = "Speaker";
+                               else
+                                       pfx = "PCM";
+                       } else
+                               pfx = chname[i];
+                       sprintf(name, "%s Playback Volume", pfx);
                        err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
                                          HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                               pfx = "Speaker";
+                       sprintf(name, "%s Playback Switch", pfx);
                        err = add_control(spec, ALC_CTL_BIND_MUTE, name,
                                          HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
                                                              HDA_INPUT));
@@ -15423,7 +15536,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
                                             "Headphone");
        if (err < 0)
                return err;
-       err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -15461,6 +15574,29 @@ static void alc861vd_auto_init(struct hda_codec *codec)
                alc_inithook(codec);
 }
 
+enum {
+       ALC660VD_FIX_ASUS_GPIO1
+};
+
+/* reset GPIO1 */
+static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+       { }
+};
+
+static const struct alc_fixup alc861vd_fixups[] = {
+       [ALC660VD_FIX_ASUS_GPIO1] = {
+               .verbs = alc660vd_fix_asus_gpio1_verbs,
+       },
+};
+
+static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+       {}
+};
+
 static int patch_alc861vd(struct hda_codec *codec)
 {
        struct alc_spec *spec;
@@ -15482,6 +15618,8 @@ static int patch_alc861vd(struct hda_codec *codec)
                board_config = ALC861VD_AUTO;
        }
 
+       alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups);
+
        if (board_config == ALC861VD_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc861vd_parse_auto_config(codec);
@@ -16762,6 +16900,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
        SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
        SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
                      ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4),
        SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
                      ALC662_3ST_6ch_DIG),
@@ -17055,58 +17194,145 @@ static struct alc_config_preset alc662_presets[] = {
  * BIOS auto configuration
  */
 
+/* convert from MIX nid to DAC */
+static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
+{
+       if (nid == 0x0f)
+               return 0x02;
+       else if (nid >= 0x0c && nid <= 0x0e)
+               return nid - 0x0c + 0x02;
+       else
+               return 0;
+}
+
+/* get MIX nid connected to the given pin targeted to DAC */
+static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
+                                  hda_nid_t dac)
+{
+       hda_nid_t mix[4];
+       int i, num;
+
+       num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
+       for (i = 0; i < num; i++) {
+               if (alc662_mix_to_dac(mix[i]) == dac)
+                       return mix[i];
+       }
+       return 0;
+}
+
+/* look for an empty DAC slot */
+static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t srcs[5];
+       int i, j, num;
+
+       num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
+       if (num < 0)
+               return 0;
+       for (i = 0; i < num; i++) {
+               hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
+               if (!nid)
+                       continue;
+               for (j = 0; j < spec->multiout.num_dacs; j++)
+                       if (spec->multiout.dac_nids[j] == nid)
+                               break;
+               if (j >= spec->multiout.num_dacs)
+                       return nid;
+       }
+       return 0;
+}
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int alc662_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 dac;
+
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       for (i = 0; i < cfg->line_outs; i++) {
+               dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
+               if (!dac)
+                       continue;
+               spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
+       }
+       return 0;
+}
+
+static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
+                             hda_nid_t nid, unsigned int chs)
+{
+       char name[32];
+       sprintf(name, "%s Playback Volume", pfx);
+       return add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                          HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+}
+
+static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
+                            hda_nid_t nid, unsigned int chs)
+{
+       char name[32];
+       sprintf(name, "%s Playback Switch", pfx);
+       return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+                          HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
+}
+
+#define alc662_add_stereo_vol(spec, pfx, nid) \
+       alc662_add_vol_ctl(spec, pfx, nid, 3)
+#define alc662_add_stereo_sw(spec, pfx, nid) \
+       alc662_add_sw_ctl(spec, pfx, nid, 3)
+
 /* add playback controls from the parsed DAC table */
-static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
+static int alc662_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;
+       hda_nid_t nid, mix;
        int i, err;
 
        for (i = 0; i < cfg->line_outs; i++) {
-               if (!spec->multiout.dac_nids[i])
+               nid = spec->multiout.dac_nids[i];
+               if (!nid)
+                       continue;
+               mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
+               if (!mix)
                        continue;
-               nid = alc880_idx_to_dac(i);
                if (i == 2) {
                        /* Center/LFE */
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Center Playback Volume",
-                                         HDA_COMPOSE_AMP_VAL(nid, 1, 0,
-                                                             HDA_OUTPUT));
+                       err = alc662_add_vol_ctl(spec, "Center", nid, 1);
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "LFE Playback Volume",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
+                       err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Center Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
-                                                             HDA_INPUT));
+                       err = alc662_add_sw_ctl(spec, "Center", mix, 1);
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "LFE Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
-                                                             HDA_INPUT));
+                       err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
                        if (err < 0)
                                return err;
                } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                             HDA_OUTPUT));
+                       const char *pfx;
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+                               if (cfg->hp_outs)
+                                       pfx = "Speaker";
+                               else
+                                       pfx = "PCM";
+                       } else
+                               pfx = chname[i];
+                       err = alc662_add_vol_ctl(spec, pfx, nid, 3);
                        if (err < 0)
                                return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
-                               HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
-                                                   3, 0, HDA_INPUT));
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                               pfx = "Speaker";
+                       err = alc662_add_sw_ctl(spec, pfx, mix, 3);
                        if (err < 0)
                                return err;
                }
@@ -17115,120 +17341,75 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
 }
 
 /* add playback controls for speaker and HP outputs */
-static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
+/* return DAC nid if any new DAC is assigned */
+static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
                                        const char *pfx)
 {
-       hda_nid_t nid;
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t nid, mix;
        int err;
-       char name[32];
 
        if (!pin)
                return 0;
-
-       if (pin == 0x17) {
-               /* ALC663 has a mono output pin on 0x17 */
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
-                                 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
-               return err;
-       }
-
-       if (alc880_is_fixed_pin(pin)) {
-               nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
-               /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
-               /* specify the DAC as the extra output */
-               if (!spec->multiout.hp_nid)
-                       spec->multiout.hp_nid = nid;
-               else
-                       spec->multiout.extra_out_nid[0] = nid;
-               /* control HP volume/switch on the output mixer amp */
-               nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
-               sprintf(name, "%s Playback Volume", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_BIND_MUTE, name,
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
-               if (err < 0)
-                       return err;
-       } else if (alc880_is_multi_pin(pin)) {
-               /* set manual connection */
-               /* we have only a switch on HP-out PIN */
+       nid = alc662_look_for_dac(codec, pin);
+       if (!nid) {
+               char name[32];
+               /* the corresponding DAC is already occupied */
+               if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
+                       return 0; /* no way */
+               /* create a switch only */
                sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
-                                 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
+               return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+                                  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
        }
-       return 0;
-}
 
-static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
-       return (pincap & AC_PINCAP_IN) != 0;
+       mix = alc662_dac_to_mix(codec, pin, nid);
+       if (!mix)
+               return 0;
+       err = alc662_add_vol_ctl(spec, pfx, nid, 3);
+       if (err < 0)
+               return err;
+       err = alc662_add_sw_ctl(spec, pfx, mix, 3);
+       if (err < 0)
+               return err;
+       return nid;
 }
 
 /* create playback/capture controls for input pins */
-static int alc662_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;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
-                       idx = get_connection_index(codec, 0x0b,
-                                                  cfg->input_pins[i]);
-                       if (idx >= 0) {
-                               err = new_analog_input(spec, cfg->input_pins[i],
-                                                      auto_pin_cfg_labels[i],
-                                                      idx, 0x0b);
-                               if (err < 0)
-                                       return err;
-                       }
-                       idx = get_connection_index(codec, 0x22,
-                                                  cfg->input_pins[i]);
-                       if (idx >= 0) {
-                               imux->items[imux->num_items].label =
-                                       auto_pin_cfg_labels[i];
-                               imux->items[imux->num_items].index = idx;
-                               imux->num_items++;
-                       }
-               }
-       }
-       return 0;
-}
+#define alc662_auto_create_input_ctls \
+       alc882_auto_create_input_ctls
 
 static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
                                              hda_nid_t nid, int pin_type,
-                                             int dac_idx)
+                                             hda_nid_t dac)
 {
+       int i, num;
+       hda_nid_t srcs[4];
+
        alc_set_pin_output(codec, nid, pin_type);
        /* need the manual connection? */
-       if (alc880_is_multi_pin(nid)) {
-               struct alc_spec *spec = codec->spec;
-               int idx = alc880_multi_pin_idx(nid);
-               snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
-                                   AC_VERB_SET_CONNECT_SEL,
-                                   alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
+       num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
+       if (num <= 1)
+               return;
+       for (i = 0; i < num; i++) {
+               if (alc662_mix_to_dac(srcs[i]) != dac)
+                       continue;
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
+               return;
        }
 }
 
 static void alc662_auto_init_multi_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       int pin_type = get_pin_type(spec->autocfg.line_out_type);
        int i;
 
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
                if (nid)
                        alc662_auto_set_output_and_unmute(codec, nid, pin_type,
-                                                         i);
+                                       spec->multiout.dac_nids[i]);
        }
 }
 
@@ -17238,12 +17419,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
        hda_nid_t pin;
 
        pin = spec->autocfg.hp_pins[0];
-       if (pin) /* connect to front */
-               /* use dac 0 */
-               alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+       if (pin)
+               alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
+                                                 spec->multiout.hp_nid);
        pin = spec->autocfg.speaker_pins[0];
        if (pin)
-               alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
+               alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
+                                       spec->multiout.extra_out_nid[0]);
 }
 
 #define ALC662_PIN_CD_NID              ALC880_PIN_CD_NID
@@ -17255,7 +17437,7 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (alc662_is_input_pin(codec, nid)) {
+               if (alc_is_input_pin(codec, nid)) {
                        alc_set_input_pin(codec, nid, i);
                        if (nid != ALC662_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
@@ -17281,22 +17463,26 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        if (!spec->autocfg.line_outs)
                return 0; /* can't find valid BIOS pin config */
 
-       err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
+       err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc662_auto_create_extra_out(spec,
+       err = alc662_auto_create_extra_out(codec,
                                           spec->autocfg.speaker_pins[0],
                                           "Speaker");
        if (err < 0)
                return err;
-       err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
+       if (err)
+               spec->multiout.extra_out_nid[0] = err;
+       err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
                                           "Headphone");
        if (err < 0)
                return err;
-       err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg);
+       if (err)
+               spec->multiout.hp_nid = err;
+       err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;