[ALSA] hda-codec - Fix ALC662 recording
[pandora-kernel.git] / sound / pci / hda / patch_realtek.c
index 33282f9..62e1bd8 100644 (file)
@@ -107,6 +107,7 @@ enum {
        ALC268_TOSHIBA,
        ALC268_ACER,
        ALC268_DELL,
+       ALC268_ZEPTO,
 #ifdef CONFIG_SND_DEBUG
        ALC268_TEST,
 #endif
@@ -237,6 +238,7 @@ struct alc_spec {
        /* capture */
        unsigned int num_adc_nids;
        hda_nid_t *adc_nids;
+       hda_nid_t *capsrc_nids;
        hda_nid_t dig_in_nid;           /* digital-in NID; optional */
 
        /* capture source */
@@ -270,7 +272,6 @@ struct alc_spec {
 
        /* for virtual master */
        hda_nid_t vmaster_nid;
-       u32 vmaster_tlv[4];
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
 #endif
@@ -290,6 +291,7 @@ struct alc_config_preset {
        hda_nid_t hp_nid;               /* optional */
        unsigned int num_adc_nids;
        hda_nid_t *adc_nids;
+       hda_nid_t *capsrc_nids;
        hda_nid_t dig_in_nid;
        unsigned int num_channel_mode;
        const struct hda_channel_mode *channel_mode;
@@ -336,9 +338,10 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
        struct alc_spec *spec = codec->spec;
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+       hda_nid_t nid = spec->capsrc_nids ?
+               spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
        return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
-                                    spec->adc_nids[adc_idx],
-                                    &spec->cur_mux[adc_idx]);
+                                    nid, &spec->cur_mux[adc_idx]);
 }
 
 
@@ -707,6 +710,7 @@ static void setup_preset(struct alc_spec *spec,
 
        spec->num_adc_nids = preset->num_adc_nids;
        spec->adc_nids = preset->adc_nids;
+       spec->capsrc_nids = preset->capsrc_nids;
        spec->dig_in_nid = preset->dig_in_nid;
 
        spec->unsol_event = preset->unsol_event;
@@ -741,7 +745,6 @@ static struct hda_verb alc_gpio3_init_verbs[] = {
 static void alc_sku_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int mute;
        unsigned int present;
        unsigned int hp_nid = spec->autocfg.hp_pins[0];
        unsigned int sp_nid = spec->autocfg.speaker_pins[0];
@@ -751,16 +754,8 @@ static void alc_sku_automute(struct hda_codec *codec)
        present = snd_hda_codec_read(codec, hp_nid, 0,
                                     AC_VERB_GET_PIN_SENSE, 0);
        spec->jack_present = (present & 0x80000000) != 0;
-       if (spec->jack_present) {
-               /* mute internal speaker */
-               snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
-       } else {
-               /* unmute internal speaker if necessary */
-               mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0);
-               snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-       }
+       snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           spec->jack_present ? 0 : PIN_OUT);
 }
 
 /* unsolicited event for HP jack sensing */
@@ -1319,11 +1314,19 @@ static struct snd_kcontrol_new alc880_f1734_mixer[] = {
        HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        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),
-       HDA_CODEC_MUTE("Mic 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 hda_input_mux alc880_f1734_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x1 },
+               { "CD", 0x4 },
+       },
+};
+
 
 /*
  * ALC880 ASUS model
@@ -1516,6 +1519,11 @@ static int alc_build_controls(struct hda_codec *codec)
                                                    spec->multiout.dig_out_nid);
                if (err < 0)
                        return err;
+               err = snd_hda_create_spdif_share_sw(codec,
+                                                   &spec->multiout);
+               if (err < 0)
+                       return err;
+               spec->multiout.share_spdif = 1;
        }
        if (spec->dig_in_nid) {
                err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -1525,10 +1533,11 @@ static int alc_build_controls(struct hda_codec *codec)
 
        /* if we have no master control, let's create it */
        if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+               unsigned int vmaster_tlv[4];
                snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
-                                       HDA_OUTPUT, spec->vmaster_tlv);
+                                       HDA_OUTPUT, vmaster_tlv);
                err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-                                         spec->vmaster_tlv, alc_slave_vols);
+                                         vmaster_tlv, alc_slave_vols);
                if (err < 0)
                        return err;
        }
@@ -1935,6 +1944,9 @@ static struct hda_verb alc880_pin_f1734_init_verbs[] = {
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
+
        { }
 };
 
@@ -2318,7 +2330,8 @@ static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
                                    struct snd_pcm_substream *substream)
 {
        struct alc_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
 static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -2498,6 +2511,7 @@ static int alc_build_pcms(struct hda_codec *codec)
                codec->num_pcms = 2;
                info = spec->pcm_rec + 1;
                info->name = spec->stream_name_digital;
+               info->pcm_type = HDA_PCM_TYPE_SPDIF;
                if (spec->multiout.dig_out_nid &&
                    spec->stream_digital_playback) {
                        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
@@ -3057,7 +3071,9 @@ static struct alc_config_preset alc880_presets[] = {
                .hp_nid = 0x02,
                .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
                .channel_mode = alc880_2_jack_modes,
-               .input_mux = &alc880_capture_source,
+               .input_mux = &alc880_f1734_capture_source,
+               .unsol_event = alc880_uniwill_p53_unsol_event,
+               .init_hook = alc880_uniwill_p53_hp_automute,
        },
        [ALC880_ASUS] = {
                .mixers = { alc880_asus_mixer },
@@ -3467,15 +3483,21 @@ static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
        return 0;
 }
 
-static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type,
-                                             int dac_idx)
+static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned int pin_type)
 {
-       /* set as output */
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                            pin_type);
+       /* unmute pin */
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                            AMP_OUT_UNMUTE);
+}
+
+static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
+                                             hda_nid_t nid, int pin_type,
+                                             int dac_idx)
+{
+       alc_set_pin_output(codec, nid, pin_type);
        /* need the manual connection? */
        if (alc880_is_multi_pin(nid)) {
                struct alc_spec *spec = codec->spec;
@@ -3597,9 +3619,12 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
 /* additional initialization for auto-configuration model */
 static void alc880_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc880_auto_init_multi_out(codec);
        alc880_auto_init_extra_out(codec);
        alc880_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 /*
@@ -4795,11 +4820,7 @@ static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
                                              hda_nid_t nid, int pin_type,
                                              int sel_idx)
 {
-       /* set as output */
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_UNMUTE);
+       alc_set_pin_output(codec, nid, pin_type);
        /* need the manual connection? */
        if (nid >= 0x12) {
                int idx = nid - 0x12;
@@ -4946,8 +4967,11 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
 /* additional initialization for auto-configuration model */
 static void alc260_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc260_auto_init_multi_out(codec);
        alc260_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -5204,6 +5228,9 @@ static hda_nid_t alc882_dac_nids[4] = {
 #define alc882_adc_nids                alc880_adc_nids
 #define alc882_adc_nids_alt    alc880_adc_nids_alt
 
+static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
+static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -5226,15 +5253,11 @@ static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
        struct alc_spec *spec = codec->spec;
        const struct hda_input_mux *imux = spec->input_mux;
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
-       hda_nid_t nid;
+       hda_nid_t nid = spec->capsrc_nids ?
+               spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
        unsigned int *cur_val = &spec->cur_mux[adc_idx];
        unsigned int i, idx;
 
-       if (spec->num_adc_nids < 3)
-               nid = capture_mixers[adc_idx + 1];
-       else
-               nid = capture_mixers[adc_idx];
        idx = ucontrol->value.enumerated.item[0];
        if (idx >= imux->num_items)
                idx = imux->num_items - 1;
@@ -6111,6 +6134,7 @@ static struct alc_config_preset alc882_presets[] = {
                .dig_out_nid = ALC882_DIGOUT_NID,
                .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
                .adc_nids = alc882_adc_nids,
+               .capsrc_nids = alc882_capsrc_nids,
                .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
                .channel_mode = alc882_3ST_6ch_modes,
                .need_dac_fix = 1,
@@ -6127,6 +6151,7 @@ static struct alc_config_preset alc882_presets[] = {
                .dig_out_nid = ALC882_DIGOUT_NID,
                .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
                .adc_nids = alc882_adc_nids,
+               .capsrc_nids = alc882_capsrc_nids,
                .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
                .channel_mode = alc882_3ST_6ch_modes,
                .need_dac_fix = 1,
@@ -6182,15 +6207,11 @@ static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
        struct alc_spec *spec = codec->spec;
        int idx;
 
+       alc_set_pin_output(codec, nid, pin_type);
        if (spec->multiout.dac_nids[dac_idx] == 0x25)
                idx = 4;
        else
                idx = spec->multiout.dac_nids[dac_idx] - 2;
-
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_UNMUTE);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
 
 }
@@ -6219,6 +6240,9 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
        if (pin) /* connect to front */
                /* use dac 0 */
                alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+       pin = spec->autocfg.speaker_pins[0];
+       if (pin)
+               alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc882_is_input_pin(nid)       alc880_is_input_pin(nid)
@@ -6294,9 +6318,12 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
 /* additional initialization for auto-configuration model */
 static void alc882_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc882_auto_init_multi_out(codec);
        alc882_auto_init_hp_out(codec);
        alc882_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 static int patch_alc882(struct hda_codec *codec)
@@ -6372,12 +6399,14 @@ static int patch_alc882(struct hda_codec *codec)
                if (wcap != AC_WID_AUD_IN) {
                        spec->adc_nids = alc882_adc_nids_alt;
                        spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
+                       spec->capsrc_nids = alc882_capsrc_nids_alt;
                        spec->mixers[spec->num_mixers] =
                                alc882_capture_alt_mixer;
                        spec->num_mixers++;
                } else {
                        spec->adc_nids = alc882_adc_nids;
                        spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
+                       spec->capsrc_nids = alc882_capsrc_nids;
                        spec->mixers[spec->num_mixers] = alc882_capture_mixer;
                        spec->num_mixers++;
                }
@@ -6420,6 +6449,8 @@ static hda_nid_t alc883_adc_nids[2] = {
        0x08, 0x09,
 };
 
+static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -6453,33 +6484,8 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
 
 #define alc883_mux_enum_info alc_mux_enum_info
 #define alc883_mux_enum_get alc_mux_enum_get
-
-static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = spec->input_mux;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       static hda_nid_t capture_mixers[2] = { 0x23, 0x22 };
-       hda_nid_t nid = capture_mixers[adc_idx];
-       unsigned int *cur_val = &spec->cur_mux[adc_idx];
-       unsigned int i, idx;
-
-       idx = ucontrol->value.enumerated.item[0];
-       if (idx >= imux->num_items)
-               idx = imux->num_items - 1;
-       if (*cur_val == idx)
-               return 0;
-       for (i = 0; i < imux->num_items; i++) {
-               unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-               snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-                                        imux->items[i].index,
-                                        HDA_AMP_MUTE, v);
-       }
-       *cur_val = idx;
-       return 1;
-}
+/* ALC883 has the ALC882-type input selection */
+#define alc883_mux_enum_put alc882_mux_enum_put
 
 /*
  * 2ch mode
@@ -7652,8 +7658,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .dig_in_nid = ALC883_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
@@ -7665,8 +7669,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .dig_in_nid = ALC883_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
                .channel_mode = alc883_3ST_6ch_modes,
@@ -7678,8 +7680,6 @@ static struct alc_config_preset alc883_presets[] = {
                .init_verbs = { alc883_init_verbs },
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
                .channel_mode = alc883_3ST_6ch_modes,
                .need_dac_fix = 1,
@@ -7691,8 +7691,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .dig_in_nid = ALC883_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
@@ -7704,8 +7702,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
                .channel_mode = alc883_3ST_6ch_modes,
                .need_dac_fix = 1,
@@ -7719,8 +7715,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
@@ -7737,8 +7731,6 @@ static struct alc_config_preset alc883_presets[] = {
                .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
@@ -7749,8 +7741,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
@@ -7764,8 +7754,6 @@ static struct alc_config_preset alc883_presets[] = {
                                alc883_medion_eapd_verbs },
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
                .input_mux = &alc883_capture_source,
@@ -7776,8 +7764,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
@@ -7789,8 +7775,6 @@ static struct alc_config_preset alc883_presets[] = {
                .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
@@ -7800,8 +7784,6 @@ static struct alc_config_preset alc883_presets[] = {
                .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_lenovo_101e_capture_source,
@@ -7813,8 +7795,6 @@ static struct alc_config_preset alc883_presets[] = {
                .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .need_dac_fix = 1,
@@ -7828,8 +7808,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
                .channel_mode = alc883_3ST_6ch_modes,
                .need_dac_fix = 1,
@@ -7843,8 +7821,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
@@ -7857,8 +7833,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .dig_in_nid = ALC883_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
@@ -7869,8 +7843,6 @@ static struct alc_config_preset alc883_presets[] = {
                .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
                .channel_mode = alc888_3st_hp_modes,
                .need_dac_fix = 1,
@@ -7882,8 +7854,6 @@ static struct alc_config_preset alc883_presets[] = {
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .dig_in_nid = ALC883_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
@@ -7896,8 +7866,6 @@ static struct alc_config_preset alc883_presets[] = {
                .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
                .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
@@ -7918,15 +7886,11 @@ static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
        struct alc_spec *spec = codec->spec;
        int idx;
 
+       alc_set_pin_output(codec, nid, pin_type);
        if (spec->multiout.dac_nids[dac_idx] == 0x25)
                idx = 4;
        else
                idx = spec->multiout.dac_nids[dac_idx] - 2;
-
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_UNMUTE);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
 
 }
@@ -7955,6 +7919,9 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec)
        if (pin) /* connect to front */
                /* use dac 0 */
                alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+       pin = spec->autocfg.speaker_pins[0];
+       if (pin)
+               alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc883_is_input_pin(nid)       alc880_is_input_pin(nid)
@@ -8006,9 +7973,12 @@ static int alc883_parse_auto_config(struct hda_codec *codec)
 /* additional initialization for auto-configuration model */
 static void alc883_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc883_auto_init_multi_out(codec);
        alc883_auto_init_hp_out(codec);
        alc883_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 static int patch_alc883(struct hda_codec *codec)
@@ -8057,10 +8027,9 @@ static int patch_alc883(struct hda_codec *codec)
        spec->stream_digital_playback = &alc883_pcm_digital_playback;
        spec->stream_digital_capture = &alc883_pcm_digital_capture;
 
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = alc883_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
-       }
+       spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+       spec->adc_nids = alc883_adc_nids;
+       spec->capsrc_nids = alc883_capsrc_nids;
 
        spec->vmaster_nid = 0x0c;
 
@@ -8085,6 +8054,8 @@ static int patch_alc883(struct hda_codec *codec)
 #define alc262_dac_nids                alc260_dac_nids
 #define alc262_adc_nids                alc882_adc_nids
 #define alc262_adc_nids_alt    alc882_adc_nids_alt
+#define alc262_capsrc_nids     alc882_capsrc_nids
+#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
 
 #define alc262_modes           alc260_modes
 #define alc262_capture_source  alc882_capture_source
@@ -9185,9 +9156,12 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc262_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc262_auto_init_multi_out(codec);
        alc262_auto_init_hp_out(codec);
        alc262_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 /*
@@ -9472,12 +9446,14 @@ static int patch_alc262(struct hda_codec *codec)
                if (wcap != AC_WID_AUD_IN) {
                        spec->adc_nids = alc262_adc_nids_alt;
                        spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
+                       spec->capsrc_nids = alc262_capsrc_nids_alt;
                        spec->mixers[spec->num_mixers] =
                                alc262_capture_alt_mixer;
                        spec->num_mixers++;
                } else {
                        spec->adc_nids = alc262_adc_nids;
                        spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
+                       spec->capsrc_nids = alc262_capsrc_nids;
                        spec->mixers[spec->num_mixers] = alc262_capture_mixer;
                        spec->num_mixers++;
                }
@@ -9517,6 +9493,8 @@ static hda_nid_t alc268_adc_nids_alt[1] = {
        0x08
 };
 
+static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
+
 static struct snd_kcontrol_new alc268_base_mixer[] = {
        /* output mixer control */
        HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
@@ -9772,21 +9750,7 @@ static struct hda_verb alc268_volume_init_verbs[] = {
 
 #define alc268_mux_enum_info alc_mux_enum_info
 #define alc268_mux_enum_get alc_mux_enum_get
-
-static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
-       hda_nid_t nid = capture_mixers[adc_idx];
-
-       return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                    nid,
-                                    &spec->cur_mux[adc_idx]);
-}
+#define alc268_mux_enum_put alc_mux_enum_put
 
 static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
@@ -9838,11 +9802,6 @@ static struct hda_input_mux alc268_capture_source = {
 
 #ifdef CONFIG_SND_DEBUG
 static struct snd_kcontrol_new alc268_test_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-
        /* Volume widgets */
        HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
@@ -10091,10 +10050,13 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc268_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc268_auto_init_multi_out(codec);
        alc268_auto_init_hp_out(codec);
        alc268_auto_init_mono_speaker_out(codec);
        alc268_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 /*
@@ -10105,6 +10067,7 @@ static const char *alc268_models[ALC268_MODEL_LAST] = {
        [ALC268_TOSHIBA]        = "toshiba",
        [ALC268_ACER]           = "acer",
        [ALC268_DELL]           = "dell",
+       [ALC268_ZEPTO]          = "zepto",
 #ifdef CONFIG_SND_DEBUG
        [ALC268_TEST]           = "test",
 #endif
@@ -10122,6 +10085,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
        SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
+       SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
        {}
 };
 
@@ -10133,6 +10097,7 @@ static struct alc_config_preset alc268_presets[] = {
                .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 = 0x03,
                .dig_out_nid = ALC268_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
@@ -10147,6 +10112,7 @@ static struct alc_config_preset alc268_presets[] = {
                .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 = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
@@ -10162,6 +10128,7 @@ static struct alc_config_preset alc268_presets[] = {
                .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,
@@ -10182,6 +10149,23 @@ static struct alc_config_preset alc268_presets[] = {
                .init_hook = alc268_dell_init_hook,
                .input_mux = &alc268_capture_source,
        },
+       [ALC268_ZEPTO] = {
+               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_toshiba_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 = 0x03,
+               .dig_out_nid = ALC268_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+               .unsol_event = alc268_toshiba_unsol_event,
+               .init_hook = alc268_toshiba_automute
+       },
 #ifdef CONFIG_SND_DEBUG
        [ALC268_TEST] = {
                .mixers = { alc268_test_mixer, alc268_capture_mixer },
@@ -10191,6 +10175,7 @@ static struct alc_config_preset alc268_presets[] = {
                .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 = 0x03,
                .dig_out_nid = ALC268_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
@@ -10266,6 +10251,7 @@ static int patch_alc268(struct hda_codec *codec)
                                alc268_capture_mixer;
                        spec->num_mixers++;
                }
+               spec->capsrc_nids = alc268_capsrc_nids;
        }
 
        spec->vmaster_nid = 0x02;
@@ -10539,9 +10525,12 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc269_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc269_auto_init_multi_out(codec);
        alc269_auto_init_hp_out(codec);
        alc269_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 /*
@@ -11463,13 +11452,7 @@ static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
                                              hda_nid_t nid,
                                              int pin_type, int dac_idx)
 {
-       /* set as output */
-
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
-       snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_UNMUTE);
-
+       alc_set_pin_output(codec, nid, pin_type);
 }
 
 static void alc861_auto_init_multi_out(struct hda_codec *codec)
@@ -11496,6 +11479,9 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
        if (pin) /* connect to front */
                alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
                                                  spec->multiout.dac_nids[0]);
+       pin = spec->autocfg.speaker_pins[0];
+       if (pin)
+               alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 static void alc861_auto_init_analog_input(struct hda_codec *codec)
@@ -11568,9 +11554,12 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
 /* additional initialization for auto-configuration model */
 static void alc861_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc861_auto_init_multi_out(codec);
        alc861_auto_init_hp_out(codec);
        alc861_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -11822,6 +11811,8 @@ static hda_nid_t alc861vd_adc_nids[1] = {
        0x09,
 };
 
+static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 static struct hda_input_mux alc861vd_capture_source = {
@@ -11853,33 +11844,8 @@ static struct hda_input_mux alc861vd_hp_capture_source = {
 
 #define alc861vd_mux_enum_info alc_mux_enum_info
 #define alc861vd_mux_enum_get alc_mux_enum_get
-
-static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = spec->input_mux;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       static hda_nid_t capture_mixers[1] = { 0x22 };
-       hda_nid_t nid = capture_mixers[adc_idx];
-       unsigned int *cur_val = &spec->cur_mux[adc_idx];
-       unsigned int i, idx;
-
-       idx = ucontrol->value.enumerated.item[0];
-       if (idx >= imux->num_items)
-               idx = imux->num_items - 1;
-       if (*cur_val == idx)
-               return 0;
-       for (i = 0; i < imux->num_items; i++) {
-               unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-               snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-                                        imux->items[i].index,
-                                        HDA_AMP_MUTE, v);
-       }
-       *cur_val = idx;
-       return 1;
-}
+/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
+#define alc861vd_mux_enum_put alc882_mux_enum_put
 
 /*
  * 2ch mode
@@ -12362,8 +12328,6 @@ static struct alc_config_preset alc861vd_presets[] = {
                                 alc861vd_3stack_init_verbs },
                .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
                .dac_nids = alc660vd_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-               .adc_nids = alc861vd_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_capture_source,
@@ -12375,8 +12339,6 @@ static struct alc_config_preset alc861vd_presets[] = {
                .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
                .dac_nids = alc660vd_dac_nids,
                .dig_out_nid = ALC861VD_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-               .adc_nids = alc861vd_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_capture_source,
@@ -12421,8 +12383,6 @@ static struct alc_config_preset alc861vd_presets[] = {
                                alc861vd_lenovo_unsol_verbs },
                .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
                .dac_nids = alc660vd_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-               .adc_nids = alc861vd_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_capture_source,
@@ -12434,8 +12394,6 @@ static struct alc_config_preset alc861vd_presets[] = {
                .init_verbs = { alc861vd_dallas_verbs },
                .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
                .dac_nids = alc861vd_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-               .adc_nids = alc861vd_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_dallas_capture_source,
@@ -12447,9 +12405,7 @@ static struct alc_config_preset alc861vd_presets[] = {
                .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
                .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
                .dac_nids = alc861vd_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
                .dig_out_nid = ALC861VD_DIGOUT_NID,
-               .adc_nids = alc861vd_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_hp_capture_source,
@@ -12464,11 +12420,7 @@ static struct alc_config_preset alc861vd_presets[] = {
 static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
                                hda_nid_t nid, int pin_type, int dac_idx)
 {
-       /* set as output */
-       snd_hda_codec_write(codec, nid, 0,
-                               AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
-       snd_hda_codec_write(codec, nid, 0,
-                               AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+       alc_set_pin_output(codec, nid, pin_type);
 }
 
 static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
@@ -12495,6 +12447,9 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
        pin = spec->autocfg.hp_pins[0];
        if (pin) /* connect to front and  use dac 0 */
                alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+       pin = spec->autocfg.speaker_pins[0];
+       if (pin)
+               alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc861vd_is_input_pin(nid)     alc880_is_input_pin(nid)
@@ -12698,9 +12653,12 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
 /* additional initialization for auto-configuration model */
 static void alc861vd_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc861vd_auto_init_multi_out(codec);
        alc861vd_auto_init_hp_out(codec);
        alc861vd_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 static int patch_alc861vd(struct hda_codec *codec)
@@ -12751,6 +12709,7 @@ static int patch_alc861vd(struct hda_codec *codec)
 
        spec->adc_nids = alc861vd_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
+       spec->capsrc_nids = alc861vd_capsrc_nids;
 
        spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
        spec->num_mixers++;
@@ -12792,9 +12751,11 @@ static hda_nid_t alc662_adc_nids[1] = {
        /* ADC1-2 */
        0x09,
 };
+
+static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
-
 static struct hda_input_mux alc662_capture_source = {
        .num_items = 4,
        .items = {
@@ -12823,33 +12784,8 @@ static struct hda_input_mux alc662_eeepc_capture_source = {
 
 #define alc662_mux_enum_info alc_mux_enum_info
 #define alc662_mux_enum_get alc_mux_enum_get
+#define alc662_mux_enum_put alc882_mux_enum_put
 
-static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = spec->input_mux;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       static hda_nid_t capture_mixers[2] = { 0x23, 0x22 };
-       hda_nid_t nid = capture_mixers[adc_idx];
-       unsigned int *cur_val = &spec->cur_mux[adc_idx];
-       unsigned int i, idx;
-
-       idx = ucontrol->value.enumerated.item[0];
-       if (idx >= imux->num_items)
-               idx = imux->num_items - 1;
-       if (*cur_val == idx)
-               return 0;
-       for (i = 0; i < imux->num_items; i++) {
-               unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-               snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-                                        imux->items[i].index,
-                                        HDA_AMP_MUTE, v);
-       }
-       *cur_val = idx;
-       return 1;
-}
 /*
  * 2ch mode
  */
@@ -13326,8 +13262,6 @@ static struct alc_config_preset alc662_presets[] = {
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-               .adc_nids = alc662_adc_nids,
                .dig_in_nid = ALC662_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
@@ -13340,8 +13274,6 @@ static struct alc_config_preset alc662_presets[] = {
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-               .adc_nids = alc662_adc_nids,
                .dig_in_nid = ALC662_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
                .channel_mode = alc662_3ST_6ch_modes,
@@ -13354,8 +13286,6 @@ static struct alc_config_preset alc662_presets[] = {
                .init_verbs = { alc662_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-               .adc_nids = alc662_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
                .channel_mode = alc662_3ST_6ch_modes,
                .need_dac_fix = 1,
@@ -13368,8 +13298,6 @@ static struct alc_config_preset alc662_presets[] = {
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-               .adc_nids = alc662_adc_nids,
                .dig_in_nid = ALC662_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
                .channel_mode = alc662_5stack_modes,
@@ -13380,8 +13308,6 @@ static struct alc_config_preset alc662_presets[] = {
                .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-               .adc_nids = alc662_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
                .input_mux = &alc662_lenovo_101e_capture_source,
@@ -13394,8 +13320,6 @@ static struct alc_config_preset alc662_presets[] = {
                                alc662_eeepc_sue_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-               .adc_nids = alc662_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
                .input_mux = &alc662_eeepc_capture_source,
@@ -13409,8 +13333,6 @@ static struct alc_config_preset alc662_presets[] = {
                                alc662_eeepc_ep20_sue_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-               .adc_nids = alc662_adc_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
                .channel_mode = alc662_3ST_6ch_modes,
                .input_mux = &alc662_lenovo_101e_capture_source,
@@ -13556,11 +13478,7 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
                                              hda_nid_t nid, int pin_type,
                                              int dac_idx)
 {
-       /* set as output */
-       snd_hda_codec_write(codec, nid, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
-       snd_hda_codec_write(codec, nid, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+       alc_set_pin_output(codec, nid, pin_type);
        /* need the manual connection? */
        if (alc880_is_multi_pin(nid)) {
                struct alc_spec *spec = codec->spec;
@@ -13595,6 +13513,9 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
        if (pin) /* connect to front */
                /* use dac 0 */
                alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+       pin = spec->autocfg.speaker_pins[0];
+       if (pin)
+               alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc662_is_input_pin(nid)       alc880_is_input_pin(nid)
@@ -13672,9 +13593,12 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
 /* additional initialization for auto-configuration model */
 static void alc662_auto_init(struct hda_codec *codec)
 {
+       struct alc_spec *spec = codec->spec;
        alc662_auto_init_multi_out(codec);
        alc662_auto_init_hp_out(codec);
        alc662_auto_init_analog_input(codec);
+       if (spec->unsol_event)
+               alc_sku_automute(codec);
 }
 
 static int patch_alc662(struct hda_codec *codec)
@@ -13722,10 +13646,9 @@ static int patch_alc662(struct hda_codec *codec)
        spec->stream_digital_playback = &alc662_pcm_digital_playback;
        spec->stream_digital_capture = &alc662_pcm_digital_capture;
 
-       if (!spec->adc_nids && spec->input_mux) {
-               spec->adc_nids = alc662_adc_nids;
-               spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
-       }
+       spec->adc_nids = alc662_adc_nids;
+       spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
+       spec->capsrc_nids = alc662_capsrc_nids;
 
        spec->vmaster_nid = 0x02;