ALSA: hda/realtek: Remove extra .capsrc_nids initialization for ALC889_INTEL
[sfrench/cifs-2.6.git] / sound / pci / hda / patch_realtek.c
index 70583719282bed6d0e62b44cc1c15127fc0b916e..2d3f4f893ef37a4e4b4e5106ece4b5207ddd255a 100644 (file)
@@ -131,8 +131,8 @@ enum {
 enum {
        ALC269_BASIC,
        ALC269_QUANTA_FL1,
-       ALC269_ASUS_EEEPC_P703,
-       ALC269_ASUS_EEEPC_P901,
+       ALC269_ASUS_AMIC,
+       ALC269_ASUS_DMIC,
        ALC269_FUJITSU,
        ALC269_LIFEBOOK,
        ALC269_AUTO,
@@ -188,6 +188,8 @@ enum {
        ALC663_ASUS_MODE4,
        ALC663_ASUS_MODE5,
        ALC663_ASUS_MODE6,
+       ALC663_ASUS_MODE7,
+       ALC663_ASUS_MODE8,
        ALC272_DELL,
        ALC272_DELL_ZM1,
        ALC272_SAMSUNG_NC10,
@@ -208,6 +210,7 @@ enum {
        ALC885_MBP3,
        ALC885_MB5,
        ALC885_IMAC24,
+       ALC885_IMAC91,
        ALC883_3ST_2ch_DIG,
        ALC883_3ST_6ch_DIG,
        ALC883_3ST_6ch,
@@ -961,18 +964,12 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
 static void alc_automute_pin(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int present, pincap;
        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);
-       present = snd_hda_codec_read(codec, nid, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       spec->jack_present = snd_hda_jack_detect(codec, nid);
        for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
                nid = spec->autocfg.speaker_pins[i];
                if (!nid)
@@ -1012,9 +1009,7 @@ static void alc_mic_automute(struct hda_codec *codec)
 
        cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
 
-       present = snd_hda_codec_read(codec, spec->ext_mic.pin, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       present &= AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
        if (present) {
                alive = &spec->ext_mic;
                dead = &spec->int_mic;
@@ -1402,6 +1397,17 @@ static void alc_pick_fixup(struct hda_codec *codec,
                add_verb(codec->spec, fix->verbs);
 }
 
+static int alc_read_coef_idx(struct hda_codec *codec,
+                       unsigned int coef_idx)
+{
+       unsigned int val;
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
+                               coef_idx);
+       val = snd_hda_codec_read(codec, 0x20, 0,
+                               AC_VERB_GET_PROC_COEF, 0);
+       return val;
+}
+
 /*
  * ALC888
  */
@@ -1513,7 +1519,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 static void alc_automute_amp(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int val, mute, pincap;
+       unsigned int mute;
        hda_nid_t nid;
        int i;
 
@@ -1522,13 +1528,7 @@ static void alc_automute_amp(struct hda_codec *codec)
                nid = spec->autocfg.hp_pins[i];
                if (!nid)
                        break;
-               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);
-               val = snd_hda_codec_read(codec, nid, 0,
-                                        AC_VERB_GET_PIN_SENSE, 0);
-               if (val & AC_PINSENSE_PRESENCE) {
+               if (snd_hda_jack_detect(codec, nid)) {
                        spec->jack_present = 1;
                        break;
                }
@@ -1786,6 +1786,8 @@ static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
 
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
 }
 
 static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
@@ -2401,6 +2403,8 @@ static const char *alc_slave_sws[] = {
        "Speaker Playback Switch",
        "Mono Playback Switch",
        "IEC958 Playback Switch",
+       "Line-Out Playback Switch",
+       "PCM Playback Switch",
        NULL,
 };
 
@@ -2410,12 +2414,14 @@ static const char *alc_slave_sws[] = {
 
 static void alc_free_kctls(struct hda_codec *codec);
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
 static struct snd_kcontrol_new alc_beep_mixer[] = {
        HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT),
+       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
        { } /* end */
 };
+#endif
 
 static int alc_build_controls(struct hda_codec *codec)
 {
@@ -2452,6 +2458,7 @@ static int alc_build_controls(struct hda_codec *codec)
                        return err;
        }
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
        /* create beep controls if needed */
        if (spec->beep_amp) {
                struct snd_kcontrol_new *knew;
@@ -2461,11 +2468,13 @@ static int alc_build_controls(struct hda_codec *codec)
                        if (!kctl)
                                return -ENOMEM;
                        kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec, kctl);
+                       err = snd_hda_ctl_add(codec,
+                                       get_amp_nid_(spec->beep_amp), kctl);
                        if (err < 0)
                                return err;
                }
        }
+#endif
 
        /* if we have no master control, let's create it */
        if (!spec->no_analog &&
@@ -2779,8 +2788,7 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x18);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
 }
@@ -3480,7 +3488,7 @@ static int alc_build_pcms(struct hda_codec *codec)
        snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
                 "%s Analog", codec->chip_name);
        info->name = spec->stream_name_analog;
-       
+
        if (spec->stream_analog_playback) {
                if (snd_BUG_ON(!spec->multiout.dac_nids))
                        return -EINVAL;
@@ -4322,10 +4330,26 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
        knew->name = kstrdup(name, GFP_KERNEL);
        if (!knew->name)
                return -ENOMEM;
+       if (get_amp_nid_(val))
+               knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
        knew->private_value = val;
        return 0;
 }
 
+static int add_control_with_pfx(struct alc_spec *spec, int type,
+                               const char *pfx, const char *dir,
+                               const char *sfx, unsigned long val)
+{
+       char name[32];
+       snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+       return add_control(spec, type, name, val);
+}
+
+#define add_pb_vol_ctrl(spec, type, pfx, val) \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
+#define add_pb_sw_ctrl(spec, type, pfx, val) \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
+
 #define alc880_is_fixed_pin(nid)       ((nid) >= 0x14 && (nid) <= 0x17)
 #define alc880_fixed_pin_idx(nid)      ((nid) - 0x14)
 #define alc880_is_multi_pin(nid)       ((nid) >= 0x18)
@@ -4379,7 +4403,6 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
 static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
 {
-       char name[32];
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
@@ -4392,26 +4415,26 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
                if (i == 2) {
                        /* Center/LFE */
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Center Playback Volume",
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                             "Center",
                                          HDA_COMPOSE_AMP_VAL(nid, 1, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "LFE Playback Volume",
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                             "LFE",
                                          HDA_COMPOSE_AMP_VAL(nid, 2, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "Center Playback Switch",
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                            "Center",
                                          HDA_COMPOSE_AMP_VAL(nid, 1, 2,
                                                              HDA_INPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "LFE Playback Switch",
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                            "LFE",
                                          HDA_COMPOSE_AMP_VAL(nid, 2, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -4423,14 +4446,12 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                                pfx = "Speaker";
                        else
                                pfx = chname[i];
-                       sprintf(name, "%s Playback Volume", pfx);
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                                          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,
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -4446,7 +4467,6 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
 {
        hda_nid_t nid;
        int err;
-       char name[32];
 
        if (!pin)
                return 0;
@@ -4460,21 +4480,18 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
                        spec->multiout.extra_out_nid[0] = nid;
                /* control HP volume/switch on the output mixer amp */
                nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
-               sprintf(name, "%s Playback Volume", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                                  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,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
                                  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 */
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
                                  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
@@ -4487,16 +4504,13 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
                            const char *ctlname,
                            int idx, hda_nid_t mix_nid)
 {
-       char name[32];
        int err;
 
-       sprintf(name, "%s Playback Volume", ctlname);
-       err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
-       sprintf(name, "%s Playback Switch", ctlname);
-       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+       err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
@@ -4773,8 +4787,12 @@ static void set_capture_mixer(struct hda_codec *codec)
        }
 }
 
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
 #define set_beep_amp(spec, nid, idx, dir) \
        ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#endif
 
 /*
  * OK, here we have finally the patch for ALC880
@@ -5087,11 +5105,8 @@ static struct hda_verb alc260_hp_unsol_verbs[] = {
 static void alc260_hp_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x10, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       spec->jack_present = snd_hda_jack_detect(codec, 0x10);
        alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
 }
 
@@ -5156,11 +5171,8 @@ static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
 static void alc260_hp_3013_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       spec->jack_present = snd_hda_jack_detect(codec, 0x15);
        alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
 }
 
@@ -5173,12 +5185,8 @@ static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
 
 static void alc260_hp_3012_automute(struct hda_codec *codec)
 {
-       unsigned int present, bits;
+       unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
 
-       present = snd_hda_codec_read(codec, 0x10, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
-
-       bits = present ? 0 : PIN_OUT;
        snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                            bits);
        snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
@@ -5748,8 +5756,7 @@ static void alc260_replacer_672v_automute(struct hda_codec *codec)
         unsigned int present;
 
        /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
-        present = snd_hda_codec_read(codec, 0x0f, 0,
-                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x0f);
        if (present) {
                snd_hda_codec_write_cache(codec, 0x01, 0,
                                          AC_VERB_SET_GPIO_DATA, 1);
@@ -5989,7 +5996,6 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
 {
        hda_nid_t nid_vol;
        unsigned long vol_val, sw_val;
-       char name[32];
        int err;
 
        if (nid >= 0x0f && nid < 0x11) {
@@ -6009,14 +6015,12 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
 
        if (!(*vol_bits & (1 << nid_vol))) {
                /* first control for the volume widget */
-               snprintf(name, sizeof(name), "%s Playback Volume", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
                if (err < 0)
                        return err;
                *vol_bits |= (1 << nid_vol);
        }
-       snprintf(name, sizeof(name), "%s Playback Switch", pfx);
-       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
+       err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
        if (err < 0)
                return err;
        return 1;
@@ -6246,6 +6250,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = {
 
 static struct snd_pci_quirk alc260_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
+       SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
        SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
        SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
        SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
@@ -6619,7 +6624,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? */
        },
 };
 
@@ -7051,6 +7056,20 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc885_imac91_mixer[] = {
+       HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker 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),
+       HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
+
 static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -7336,8 +7355,8 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
        /* FIXME: this looks suspicious...
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
        */
        { } /* end */
 };
@@ -7506,6 +7525,66 @@ static struct hda_verb alc885_mbp3_init_verbs[] = {
        { }
 };
 
+/* iMac 9,1 */
+static struct hda_verb alc885_imac91_init_verbs[] = {
+       /* Line-Out 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)},
+       /* HP Pin: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       /* Internal Speakers: output 0 (0x0d) */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Mic (rear) pin: input vref at 80% */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Front Mic pin: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Line In pin: use output 1 when in LineOut mode */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Input mixer3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* ADC1: mute amp left and right */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* ADC2: mute amp left and right */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* ADC3: mute amp left and right */
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       { }
+};
+
 /* iMac 24 mixer. */
 static struct snd_kcontrol_new alc885_imac24_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
@@ -7552,6 +7631,26 @@ static void alc885_mbp3_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[0] = 0x14;
 }
 
+static void alc885_imac91_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x14, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+
+}
+
+static void alc885_imac91_unsol_event(struct hda_codec *codec,
+                                   unsigned int res)
+{
+       /* Headphone insertion or removal. */
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc885_imac91_automute(codec);
+}
 
 static struct hda_verb alc882_targa_verbs[] = {
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -8184,12 +8283,8 @@ static void alc883_mitac_setup(struct hda_codec *codec)
 /*
 static void alc883_mitac_mic_automute(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
+       unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
 
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
 }
 */
@@ -8411,10 +8506,8 @@ static struct hda_channel_mode alc888_3st_hp_modes[3] = {
 /* toggle front-jack and RCA according to the hp-jack state */
 static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 {
-       unsigned int present;
+       unsigned int present = snd_hda_jack_detect(codec, 0x1b);
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
@@ -8424,10 +8517,8 @@ static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 /* toggle RCA according to the front-jack state */
 static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
 {
-       unsigned int present;
+       unsigned int present = snd_hda_jack_detect(codec, 0x14);
 
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
@@ -8468,8 +8559,7 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
 {
        unsigned int present;
 
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x18);
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
@@ -8520,24 +8610,16 @@ static void alc883_haier_w66_setup(struct hda_codec *codec)
 
 static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
+       int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
 
-       present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
-       bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
 }
 
 static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
 {
-       unsigned int present;
-       unsigned char bits;
+       int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
@@ -8688,8 +8770,7 @@ static void alc889A_mb31_automute(struct hda_codec *codec)
        /* Mute only in 2ch or 4ch mode */
        if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
            == 0x00) {
-               present = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
+               present = snd_hda_jack_detect(codec, 0x15);
                snd_hda_codec_amp_stereo(codec, 0x14,  HDA_OUTPUT, 0,
                        HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
                snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
@@ -8737,6 +8818,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC885_MB5]            = "mb5",
        [ALC885_MBP3]           = "mbp3",
        [ALC885_IMAC24]         = "imac24",
+       [ALC885_IMAC91]         = "imac91",
        [ALC883_3ST_2ch_DIG]    = "3stack-2ch-dig",
        [ALC883_3ST_6ch_DIG]    = "3stack-6ch-dig",
        [ALC883_3ST_6ch]        = "3stack-6ch",
@@ -8839,7 +8921,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
-       SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
        SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
@@ -8910,6 +8992,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
        SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
        SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
+       SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
        SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
        /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
         * so apparently no perfect solution yet
@@ -9021,6 +9104,20 @@ static struct alc_config_preset alc882_presets[] = {
                .setup = alc885_imac24_setup,
                .init_hook = alc885_imac24_init_hook,
        },
+       [ALC885_IMAC91] = {
+               .mixers = { alc885_imac91_mixer, alc882_chmode_mixer },
+               .init_verbs = { alc885_imac91_init_verbs,
+                               alc880_gpio1_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .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,
+               .unsol_event = alc885_imac91_unsol_event,
+               .init_hook = alc885_imac91_automute,
+       },
        [ALC882_TARGA] = {
                .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
                .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
@@ -9187,6 +9284,7 @@ static struct alc_config_preset alc882_presets[] = {
                .dac_nids = alc883_dac_nids,
                .adc_nids = alc883_adc_nids_alt,
                .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
+               .capsrc_nids = alc883_capsrc_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
@@ -9333,6 +9431,7 @@ static struct alc_config_preset alc882_presets[] = {
                .dac_nids = alc883_dac_nids,
                .adc_nids = alc883_adc_nids_alt,
                .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
+               .capsrc_nids = alc883_capsrc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
                .input_mux = &alc883_capture_source,
@@ -9394,6 +9493,7 @@ static struct alc_config_preset alc882_presets[] = {
                .dac_nids = alc883_dac_nids,
                .adc_nids = alc883_adc_nids_alt,
                .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
+               .capsrc_nids = alc883_capsrc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_lenovo_101e_capture_source,
@@ -9573,6 +9673,7 @@ static struct alc_config_preset alc882_presets[] = {
                        alc880_gpio1_init_verbs },
                .adc_nids = alc883_adc_nids,
                .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .capsrc_nids = alc883_capsrc_nids,
                .dac_nids = alc883_dac_nids,
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .channel_mode = alc889A_mb31_6ch_modes,
@@ -9927,10 +10028,12 @@ static int patch_alc882(struct hda_codec *codec)
                spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
 
        if (!spec->adc_nids && spec->input_mux) {
-               int i;
+               int i, j;
                spec->num_adc_nids = 0;
                for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
+                       const struct hda_input_mux *imux = spec->input_mux;
                        hda_nid_t cap;
+                       hda_nid_t items[16];
                        hda_nid_t nid = alc882_adc_nids[i];
                        unsigned int wcap = get_wcaps(codec, nid);
                        /* get type */
@@ -9941,6 +10044,15 @@ static int patch_alc882(struct hda_codec *codec)
                        err = snd_hda_get_connections(codec, nid, &cap, 1);
                        if (err < 0)
                                continue;
+                       err = snd_hda_get_connections(codec, cap, items,
+                                                     ARRAY_SIZE(items));
+                       if (err < 0)
+                               continue;
+                       for (j = 0; j < imux->num_items; j++)
+                               if (imux->items[j].index >= err)
+                                       break;
+                       if (j < imux->num_items)
+                               continue;
                        spec->private_capsrc_nids[spec->num_adc_nids] = cap;
                        spec->num_adc_nids++;
                }
@@ -10032,10 +10144,8 @@ static void alc262_hp_master_update(struct hda_codec *codec)
 static void alc262_hp_bpc_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int presence;
-       presence = snd_hda_codec_read(codec, 0x1b, 0,
-                                     AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
+
+       spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
        alc262_hp_master_update(codec);
 }
 
@@ -10049,10 +10159,8 @@ static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
 static void alc262_hp_wildwest_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int presence;
-       presence = snd_hda_codec_read(codec, 0x15, 0,
-                                     AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
+
+       spec->jack_present = snd_hda_jack_detect(codec, 0x15);
        alc262_hp_master_update(codec);
 }
 
@@ -10286,13 +10394,8 @@ static void alc262_hippo_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
-       unsigned int present;
 
-       /* need to execute and sync at first */
-       snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
-       present = snd_hda_codec_read(codec, hp_nid, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0);
-       spec->jack_present = (present & 0x80000000) != 0;
+       spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
        alc262_hippo_master_update(codec);
 }
 
@@ -10618,21 +10721,8 @@ static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
        unsigned int mute;
 
        if (force || !spec->sense_updated) {
-               unsigned int present;
-               /* need to execute and sync at first */
-               snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
-               /* check laptop HP jack */
-               present = snd_hda_codec_read(codec, 0x14, 0,
-                                            AC_VERB_GET_PIN_SENSE, 0);
-               /* need to execute and sync at first */
-               snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-               /* check docking HP jack */
-               present |= snd_hda_codec_read(codec, 0x1b, 0,
-                                             AC_VERB_GET_PIN_SENSE, 0);
-               if (present & AC_PINSENSE_PRESENCE)
-                       spec->jack_present = 1;
-               else
-                       spec->jack_present = 0;
+               spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
+                                    snd_hda_jack_detect(codec, 0x1b);
                spec->sense_updated = 1;
        }
        /* unmute internal speaker only if both HPs are unplugged and
@@ -10677,12 +10767,7 @@ static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
        unsigned int mute;
 
        if (force || !spec->sense_updated) {
-               unsigned int present_int_hp;
-               /* need to execute and sync at first */
-               snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
-               present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
-                                       AC_VERB_GET_PIN_SENSE, 0);
-               spec->jack_present = (present_int_hp & 0x80000000) != 0;
+               spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
                spec->sense_updated = 1;
        }
        if (spec->jack_present) {
@@ -10874,12 +10959,7 @@ static void alc262_ultra_automute(struct hda_codec *codec)
        mute = 0;
        /* auto-mute only when HP is used as HP */
        if (!spec->cur_mux[0]) {
-               unsigned int present;
-               /* need to execute and sync at first */
-               snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
-               present = snd_hda_codec_read(codec, 0x15, 0,
-                                            AC_VERB_GET_PIN_SENSE, 0);
-               spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+               spec->jack_present = snd_hda_jack_detect(codec, 0x15);
                if (spec->jack_present)
                        mute = HDA_AMP_MUTE;
        }
@@ -10956,7 +11036,6 @@ static int alc262_check_volbit(hda_nid_t nid)
 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;
 
@@ -10966,28 +11045,25 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
        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);
+       return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, 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);
+       return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
 }
 
 /* add playback controls from the parsed DAC table */
@@ -11463,8 +11539,10 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
        SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
        SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
+#if 0 /* disable the quirk since model=auto works better in recent versions */
        SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
                           ALC262_SONY_ASSAMD),
+#endif
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
                      ALC262_TOSHIBA_RX1),
        SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
@@ -11923,10 +12001,7 @@ static void alc268_acer_automute(struct hda_codec *codec, int force)
        unsigned int mute;
 
        if (force || !spec->sense_updated) {
-               unsigned int present;
-               present = snd_hda_codec_read(codec, 0x14, 0,
-                                        AC_VERB_GET_PIN_SENSE, 0);
-               spec->jack_present = (present & 0x80000000) != 0;
+               spec->jack_present = snd_hda_jack_detect(codec, 0x14);
                spec->sense_updated = 1;
        }
        if (spec->jack_present)
@@ -12045,8 +12120,7 @@ static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -12327,11 +12401,9 @@ static struct snd_kcontrol_new alc268_test_mixer[] = {
 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);
        switch (nid) {
        case 0x14:
        case 0x16:
@@ -12345,7 +12417,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
        }
        if (spec->multiout.dac_nids[0] != dac &&
            spec->multiout.dac_nids[1] != dac) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
                                  HDA_COMPOSE_AMP_VAL(dac, 3, idx,
                                                      HDA_OUTPUT));
                if (err < 0)
@@ -12353,12 +12425,11 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
                spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
        }
 
-       sprintf(name, "%s Playback Switch", ctlname);
        if (nid != 0x16)
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
                          HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
        else /* mono */
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
                          HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
        if (err < 0)
                return err;
@@ -12388,8 +12459,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
 
        nid = cfg->speaker_pins[0];
        if (nid == 0x1d) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Speaker Playback Volume",
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
                if (err < 0)
                        return err;
@@ -12407,8 +12477,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
 
        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",
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
                                  HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
@@ -13034,8 +13103,7 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                        AMP_IN_MUTE(0), bits);
@@ -13060,12 +13128,10 @@ static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
        unsigned char bits;
 
        /* Check laptop headphone socket */
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x15);
 
        /* Check port replicator headphone socket */
-       present |= snd_hda_codec_read(codec, 0x1a, 0,
-                       AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present |= snd_hda_jack_detect(codec, 0x1a);
 
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
@@ -13089,11 +13155,8 @@ static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
        unsigned int present_laptop;
        unsigned int present_dock;
 
-       present_laptop = snd_hda_codec_read(codec, 0x18, 0,
-                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-
-       present_dock = snd_hda_codec_read(codec, 0x1b, 0,
-                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present_laptop  = snd_hda_jack_detect(codec, 0x18);
+       present_dock    = snd_hda_jack_detect(codec, 0x1b);
 
        /* Laptop mic port overrides dock mic port, design decision */
        if (present_dock)
@@ -13175,11 +13238,12 @@ static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
 /* toggle speaker-output according to the hp-jack state */
 static void alc269_speaker_automute(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
+       unsigned int nid = spec->autocfg.hp_pins[0];
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, nid);
        bits = present ? AMP_IN_MUTE(0) : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -13404,8 +13468,8 @@ static void alc269_auto_init(struct hda_codec *codec)
 static const char *alc269_models[ALC269_MODEL_LAST] = {
        [ALC269_BASIC]                  = "basic",
        [ALC269_QUANTA_FL1]             = "quanta",
-       [ALC269_ASUS_EEEPC_P703]        = "eeepc-p703",
-       [ALC269_ASUS_EEEPC_P901]        = "eeepc-p901",
+       [ALC269_ASUS_AMIC]              = "asus-amic",
+       [ALC269_ASUS_DMIC]              = "asus-dmic",
        [ALC269_FUJITSU]                = "fujitsu",
        [ALC269_LIFEBOOK]               = "lifebook",
        [ALC269_AUTO]                   = "auto",
@@ -13414,18 +13478,41 @@ static const char *alc269_models[ALC269_MODEL_LAST] = {
 static struct snd_pci_quirk alc269_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
        SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
-                     ALC269_ASUS_EEEPC_P703),
-        SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_EEEPC_P703),
-        SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_EEEPC_P703),
-        SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_EEEPC_P703),
-        SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_EEEPC_P703),
-        SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_EEEPC_P703),
-        SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_EEEPC_P703),
+                     ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80JT", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_AMIC),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
-                     ALC269_ASUS_EEEPC_P901),
+                     ALC269_ASUS_DMIC),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
-                     ALC269_ASUS_EEEPC_P901),
-        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_EEEPC_P901),
+                     ALC269_ASUS_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_ASUS_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_ASUS_DMIC),
        SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
        SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
        {}
@@ -13455,7 +13542,7 @@ static struct alc_config_preset alc269_presets[] = {
                .setup = alc269_quanta_fl1_setup,
                .init_hook = alc269_quanta_fl1_init_hook,
        },
-       [ALC269_ASUS_EEEPC_P703] = {
+       [ALC269_ASUS_AMIC] = {
                .mixers = { alc269_eeepc_mixer },
                .cap_mixer = alc269_epc_capture_mixer,
                .init_verbs = { alc269_init_verbs,
@@ -13469,7 +13556,7 @@ static struct alc_config_preset alc269_presets[] = {
                .setup = alc269_eeepc_amic_setup,
                .init_hook = alc269_eeepc_inithook,
        },
-       [ALC269_ASUS_EEEPC_P901] = {
+       [ALC269_ASUS_DMIC] = {
                .mixers = { alc269_eeepc_mixer },
                .cap_mixer = alc269_epc_capture_mixer,
                .init_verbs = { alc269_init_verbs,
@@ -13525,6 +13612,15 @@ static int patch_alc269(struct hda_codec *codec)
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+       if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("ALC259", GFP_KERNEL);
+               if (!codec->chip_name) {
+                       alc_free(codec);
+                       return -ENOMEM;
+               }
+       }
+
        board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
                                                  alc269_models,
                                                  alc269_cfg_tbl);
@@ -14157,10 +14253,8 @@ static struct hda_verb alc861_toshiba_init_verbs[] = {
 /* toggle speaker-output according to the hp-jack state */
 static void alc861_toshiba_automute(struct hda_codec *codec)
 {
-       unsigned int present;
+       unsigned int present = snd_hda_jack_detect(codec, 0x0f);
 
-       present = snd_hda_codec_read(codec, 0x0f, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
        snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
                                 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
        snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
@@ -14260,9 +14354,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
 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,
+       return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
 }
 
@@ -14627,6 +14719,27 @@ static struct alc_config_preset alc861_presets[] = {
        },
 };
 
+/* Pin config fixes */
+enum {
+       PINFIX_FSC_AMILO_PI1505,
+};
+
+static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
+       { 0x0b, 0x0221101f }, /* HP */
+       { 0x0f, 0x90170310 }, /* speaker */
+       { }
+};
+
+static const struct alc_fixup alc861_fixups[] = {
+       [PINFIX_FSC_AMILO_PI1505] = {
+               .pins = alc861_fsc_amilo_pi1505_pinfix
+       },
+};
+
+static struct snd_pci_quirk alc861_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
+       {}
+};
 
 static int patch_alc861(struct hda_codec *codec)
 {
@@ -14650,6 +14763,8 @@ static int patch_alc861(struct hda_codec *codec)
                board_config = ALC861_AUTO;
        }
 
+       alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups);
+
        if (board_config == ALC861_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc861_parse_auto_config(codec);
@@ -15067,9 +15182,9 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x18, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x18);
        bits = present ? HDA_AMP_MUTE : 0;
+
        snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
                                 HDA_AMP_MUTE, bits);
 }
@@ -15386,7 +15501,6 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
 {
-       char name[32];
        static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
        hda_nid_t nid_v, nid_s;
        int i, err;
@@ -15403,26 +15517,26 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
 
                if (i == 2) {
                        /* Center/LFE */
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Center Playback Volume",
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                             "Center",
                                          HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "LFE Playback Volume",
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                             "LFE",
                                          HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "Center Playback Switch",
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                            "Center",
                                          HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
                                                              HDA_INPUT));
                        if (err < 0)
                                return err;
-                       err = add_control(spec, ALC_CTL_BIND_MUTE,
-                                         "LFE Playback Switch",
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                            "LFE",
                                          HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -15437,8 +15551,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                        pfx = "PCM";
                        } else
                                pfx = chname[i];
-                       sprintf(name, "%s Playback Volume", pfx);
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                                          HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
@@ -15446,8 +15559,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                        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,
+                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
                                          HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -15465,7 +15577,6 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
 {
        hda_nid_t nid_v, nid_s;
        int err;
-       char name[32];
 
        if (!pin)
                return 0;
@@ -15483,21 +15594,18 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
                nid_s = alc861vd_idx_to_mixer_switch(
                                alc880_fixed_pin_idx(pin));
 
-               sprintf(name, "%s Playback Volume", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                                  HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
                                  HDA_COMPOSE_AMP_VAL(nid_s, 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 */
-               sprintf(name, "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
                                  HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
                if (err < 0)
                        return err;
@@ -16083,6 +16191,52 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = {
        { } /* end */
 };
 
+static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
+       .ops = &snd_hda_bind_sw,
+       .values = {
+               HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+               HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
+               0
+       },
+};
+
+static struct snd_kcontrol_new alc663_mode7_mixer[] = {
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
+       HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
+       HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc663_mode8_mixer[] = {
+       HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
+       HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
+       HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
+       HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+
 static struct snd_kcontrol_new alc662_chmode_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -16370,6 +16524,45 @@ static struct hda_verb alc272_dell_init_verbs[] = {
        {}
 };
 
+static struct hda_verb alc663_mode7_init_verbs[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
+static struct hda_verb alc663_mode8_init_verbs[] = {
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {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, 0x01},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Headphone */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
 static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
@@ -16387,9 +16580,9 @@ static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x14, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x14);
        bits = present ? HDA_AMP_MUTE : 0;
+
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
 }
@@ -16399,9 +16592,9 @@ static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       present = snd_hda_jack_detect(codec, 0x1b);
        bits = present ? HDA_AMP_MUTE : 0;
+
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
@@ -16460,9 +16653,7 @@ static void alc663_m51va_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x21, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x21);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -16475,9 +16666,7 @@ static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x21, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x21);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -16494,9 +16683,7 @@ static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
                                AMP_IN_MUTE(0), bits);
@@ -16513,9 +16700,7 @@ static void alc662_f5z_speaker_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x1b, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x1b);
        bits = present ? 0 : PIN_OUT;
        snd_hda_codec_write(codec, 0x14, 0,
                         AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
@@ -16525,12 +16710,8 @@ static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
 {
        unsigned int present1, present2;
 
-       present1 = snd_hda_codec_read(codec, 0x21, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
-       present2 = snd_hda_codec_read(codec, 0x15, 0,
-                       AC_VERB_GET_PIN_SENSE, 0)
-                       & AC_PINSENSE_PRESENCE;
+       present1 = snd_hda_jack_detect(codec, 0x21);
+       present2 = snd_hda_jack_detect(codec, 0x15);
 
        if (present1 || present2) {
                snd_hda_codec_write_cache(codec, 0x14, 0,
@@ -16545,12 +16726,8 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
 {
        unsigned int present1, present2;
 
-       present1 = snd_hda_codec_read(codec, 0x1b, 0,
-                               AC_VERB_GET_PIN_SENSE, 0)
-                               & AC_PINSENSE_PRESENCE;
-       present2 = snd_hda_codec_read(codec, 0x15, 0,
-                               AC_VERB_GET_PIN_SENSE, 0)
-                               & AC_PINSENSE_PRESENCE;
+       present1 = snd_hda_jack_detect(codec, 0x1b);
+       present2 = snd_hda_jack_detect(codec, 0x15);
 
        if (present1 || present2) {
                snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
@@ -16565,6 +16742,54 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
        }
 }
 
+static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present1, present2;
+
+       present1 = snd_hda_codec_read(codec, 0x1b, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+       present2 = snd_hda_codec_read(codec, 0x21, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+
+       if (present1 || present2) {
+               snd_hda_codec_write_cache(codec, 0x14, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_codec_write_cache(codec, 0x17, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       } else {
+               snd_hda_codec_write_cache(codec, 0x14, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               snd_hda_codec_write_cache(codec, 0x17, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       }
+}
+
+static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present1, present2;
+
+       present1 = snd_hda_codec_read(codec, 0x21, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+       present2 = snd_hda_codec_read(codec, 0x15, 0,
+                       AC_VERB_GET_PIN_SENSE, 0)
+                       & AC_PINSENSE_PRESENCE;
+
+       if (present1 || present2) {
+               snd_hda_codec_write_cache(codec, 0x14, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_codec_write_cache(codec, 0x17, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       } else {
+               snd_hda_codec_write_cache(codec, 0x14, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               snd_hda_codec_write_cache(codec, 0x17, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       }
+}
+
 static void alc663_m51va_unsol_event(struct hda_codec *codec,
                                           unsigned int res)
 {
@@ -16584,7 +16809,7 @@ static void alc663_m51va_setup(struct hda_codec *codec)
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x12;
-       spec->int_mic.mux_idx = 1;
+       spec->int_mic.mux_idx = 9;
        spec->auto_mic = 1;
 }
 
@@ -16596,7 +16821,17 @@ static void alc663_m51va_inithook(struct hda_codec *codec)
 
 /* ***************** Mode1 ******************************/
 #define alc663_mode1_unsol_event       alc663_m51va_unsol_event
-#define alc663_mode1_setup             alc663_m51va_setup
+
+static void alc663_mode1_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->ext_mic.pin = 0x18;
+       spec->ext_mic.mux_idx = 0;
+       spec->int_mic.pin = 0x19;
+       spec->int_mic.mux_idx = 1;
+       spec->auto_mic = 1;
+}
+
 #define alc663_mode1_inithook          alc663_m51va_inithook
 
 /* ***************** Mode2 ******************************/
@@ -16613,7 +16848,7 @@ static void alc662_mode2_unsol_event(struct hda_codec *codec,
        }
 }
 
-#define alc662_mode2_setup     alc663_m51va_setup
+#define alc662_mode2_setup     alc663_mode1_setup
 
 static void alc662_mode2_inithook(struct hda_codec *codec)
 {
@@ -16634,7 +16869,7 @@ static void alc663_mode3_unsol_event(struct hda_codec *codec,
        }
 }
 
-#define alc663_mode3_setup     alc663_m51va_setup
+#define alc663_mode3_setup     alc663_mode1_setup
 
 static void alc663_mode3_inithook(struct hda_codec *codec)
 {
@@ -16655,7 +16890,7 @@ static void alc663_mode4_unsol_event(struct hda_codec *codec,
        }
 }
 
-#define alc663_mode4_setup     alc663_m51va_setup
+#define alc663_mode4_setup     alc663_mode1_setup
 
 static void alc663_mode4_inithook(struct hda_codec *codec)
 {
@@ -16676,7 +16911,7 @@ static void alc663_mode5_unsol_event(struct hda_codec *codec,
        }
 }
 
-#define alc663_mode5_setup     alc663_m51va_setup
+#define alc663_mode5_setup     alc663_mode1_setup
 
 static void alc663_mode5_inithook(struct hda_codec *codec)
 {
@@ -16697,7 +16932,7 @@ static void alc663_mode6_unsol_event(struct hda_codec *codec,
        }
 }
 
-#define alc663_mode6_setup     alc663_m51va_setup
+#define alc663_mode6_setup     alc663_mode1_setup
 
 static void alc663_mode6_inithook(struct hda_codec *codec)
 {
@@ -16705,14 +16940,56 @@ static void alc663_mode6_inithook(struct hda_codec *codec)
        alc_mic_automute(codec);
 }
 
+/* ***************** Mode7 ******************************/
+static void alc663_mode7_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_two_hp_m7_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc_mic_automute(codec);
+               break;
+       }
+}
+
+#define alc663_mode7_setup     alc663_mode1_setup
+
+static void alc663_mode7_inithook(struct hda_codec *codec)
+{
+       alc663_two_hp_m7_speaker_automute(codec);
+       alc_mic_automute(codec);
+}
+
+/* ***************** Mode8 ******************************/
+static void alc663_mode8_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_two_hp_m8_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc_mic_automute(codec);
+               break;
+       }
+}
+
+#define alc663_mode8_setup     alc663_m51va_setup
+
+static void alc663_mode8_inithook(struct hda_codec *codec)
+{
+       alc663_two_hp_m8_speaker_automute(codec);
+       alc_mic_automute(codec);
+}
+
 static void alc663_g71v_hp_automute(struct hda_codec *codec)
 {
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x21, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x21);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
@@ -16725,9 +17002,7 @@ static void alc663_g71v_front_automute(struct hda_codec *codec)
        unsigned int present;
        unsigned char bits;
 
-       present = snd_hda_codec_read(codec, 0x15, 0,
-                                    AC_VERB_GET_PIN_SENSE, 0)
-               & AC_PINSENSE_PRESENCE;
+       present = snd_hda_jack_detect(codec, 0x15);
        bits = present ? HDA_AMP_MUTE : 0;
        snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
                                 HDA_AMP_MUTE, bits);
@@ -16843,6 +17118,8 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
        [ALC663_ASUS_MODE4] = "asus-mode4",
        [ALC663_ASUS_MODE5] = "asus-mode5",
        [ALC663_ASUS_MODE6] = "asus-mode6",
+       [ALC663_ASUS_MODE7] = "asus-mode7",
+       [ALC663_ASUS_MODE8] = "asus-mode8",
        [ALC272_DELL]           = "dell",
        [ALC272_DELL_ZM1]       = "dell-zm1",
        [ALC272_SAMSUNG_NC10]   = "samsung-nc10",
@@ -16859,12 +17136,22 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
+       SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
+       SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
+       SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
        SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
        SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
        SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
@@ -16914,6 +17201,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
                                        ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
                           ALC663_ASUS_H13),
+       SND_PCI_QUIRK(0x8086, 0xd604, "Intel mobo", ALC662_3ST_2ch_DIG),
        {}
 };
 
@@ -17147,6 +17435,36 @@ static struct alc_config_preset alc662_presets[] = {
                .setup = alc663_mode6_setup,
                .init_hook = alc663_mode6_inithook,
        },
+       [ALC663_ASUS_MODE7] = {
+               .mixers = { alc663_mode7_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc663_mode7_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc663_mode7_unsol_event,
+               .setup = alc663_mode7_setup,
+               .init_hook = alc663_mode7_inithook,
+       },
+       [ALC663_ASUS_MODE8] = {
+               .mixers = { alc663_mode8_mixer },
+               .cap_mixer = alc662_auto_capture_mixer,
+               .init_verbs = { alc662_init_verbs,
+                               alc663_mode8_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .hp_nid = 0x03,
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .unsol_event = alc663_mode8_unsol_event,
+               .setup = alc663_mode8_setup,
+               .init_hook = alc663_mode8_inithook,
+       },
        [ALC272_DELL] = {
                .mixers = { alc663_m51va_mixer },
                .cap_mixer = alc272_auto_capture_mixer,
@@ -17264,21 +17582,17 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
        return 0;
 }
 
-static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
+static inline 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,
+       return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
 }
 
-static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
+static inline 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,
+       return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
 }
 
@@ -17356,13 +17670,11 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
                return 0;
        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);
-               return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+               return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
                                   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
        }
 
@@ -17538,6 +17850,15 @@ static int patch_alc662(struct hda_codec *codec)
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+       if (alc_read_coef_idx(codec, 0)==0x8020){
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("ALC661", GFP_KERNEL);
+               if (!codec->chip_name) {
+                       alc_free(codec);
+                       return -ENOMEM;
+               }
+       }
+
        board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
                                                  alc662_models,
                                                  alc662_cfg_tbl);
@@ -17604,6 +17925,20 @@ static int patch_alc662(struct hda_codec *codec)
        return 0;
 }
 
+static int patch_alc888(struct hda_codec *codec)
+{
+       if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
+               kfree(codec->chip_name);
+               codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
+               if (!codec->chip_name) {
+                       alc_free(codec);
+                       return -ENOMEM;
+               }
+               return patch_alc662(codec);
+       }
+       return patch_alc882(codec);
+}
+
 /*
  * patch entries
  */
@@ -17613,7 +17948,9 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
        { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
        { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
+       { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
        { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
+       { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
          .patch = patch_alc861 },
        { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
@@ -17635,8 +17972,9 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
        { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
          .patch = patch_alc882 },
-       { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
+       { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
        { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
+       { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
        {} /* terminator */
 };