ALSA: hda - Add debug prints for Realtek auto-init
[pandora-kernel.git] / sound / pci / hda / patch_realtek.c
index 6c26afc..ee92c73 100644 (file)
@@ -30,6 +30,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_beep.h"
 
 #define ALC880_FRONT_EVENT             0x01
 #define ALC880_DCVOL_EVENT             0x02
@@ -77,6 +78,7 @@ enum {
        ALC260_ACER,
        ALC260_WILL,
        ALC260_REPLACER_672V,
+       ALC260_FAVORIT100,
 #ifdef CONFIG_SND_DEBUG
        ALC260_TEST,
 #endif
@@ -103,6 +105,7 @@ enum {
        ALC262_NEC,
        ALC262_TOSHIBA_S06,
        ALC262_TOSHIBA_RX1,
+       ALC262_TYAN,
        ALC262_AUTO,
        ALC262_MODEL_LAST /* last tag */
 };
@@ -238,6 +241,13 @@ enum {
        ALC883_MODEL_LAST,
 };
 
+/* styles of capture selection */
+enum {
+       CAPT_MUX = 0,   /* only mux based */
+       CAPT_MIX,       /* only mixer based */
+       CAPT_1MUX_MIX,  /* first mux and other mixers */
+};
+
 /* for GPIO Poll */
 #define GPIO_MASK      0x03
 
@@ -246,6 +256,7 @@ struct alc_spec {
        struct snd_kcontrol_new *mixers[5];     /* mixer arrays */
        unsigned int num_mixers;
        struct snd_kcontrol_new *cap_mixer;     /* capture mixer */
+       unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
 
        const struct hda_verb *init_verbs[5];   /* initialization verbs
                                                 * don't forget NULL
@@ -269,13 +280,15 @@ struct alc_spec {
                                         * dig_out_nid and hp_nid are optional
                                         */
        hda_nid_t alt_dac_nid;
+       hda_nid_t slave_dig_outs[3];    /* optional - for auto-parsing */
+       int dig_out_type;
 
        /* 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 */
-       unsigned char is_mix_capture;   /* matrix-style capture (non-mux) */
+       int capture_style;              /* capture style (CAPT_*) */
 
        /* capture source */
        unsigned int num_mux_defs;
@@ -293,7 +306,7 @@ struct alc_spec {
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        struct snd_array kctls;
-       struct hda_input_mux private_imux;
+       struct hda_input_mux private_imux[3];
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
 
        /* hooks */
@@ -305,6 +318,9 @@ struct alc_spec {
        unsigned int jack_present: 1;
        unsigned int master_sw: 1;
 
+       /* other flags */
+       unsigned int no_analog :1; /* digital I/O only */
+
        /* for virtual master */
        hda_nid_t vmaster_nid;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -314,13 +330,6 @@ struct alc_spec {
        /* for PLL fix */
        hda_nid_t pll_nid;
        unsigned int pll_coef_idx, pll_coef_bit;
-
-#ifdef SND_HDA_NEEDS_RESUME
-#define ALC_MAX_PINS   16
-       unsigned int num_pins;
-       hda_nid_t pin_nids[ALC_MAX_PINS];
-       unsigned int pin_cfgs[ALC_MAX_PINS];
-#endif
 };
 
 /*
@@ -336,6 +345,7 @@ struct alc_config_preset {
        hda_nid_t *dac_nids;
        hda_nid_t dig_out_nid;          /* optional */
        hda_nid_t hp_nid;               /* optional */
+       hda_nid_t *slave_dig_outs;
        unsigned int num_adc_nids;
        hda_nid_t *adc_nids;
        hda_nid_t *capsrc_nids;
@@ -392,7 +402,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
        mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
        imux = &spec->input_mux[mux_idx];
 
-       if (spec->is_mix_capture) {
+       if (spec->capture_style &&
+           !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
                /* Matrix-mixer style (e.g. ALC882) */
                unsigned int *cur_val = &spec->cur_mux[adc_idx];
                unsigned int i, idx;
@@ -749,6 +760,24 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
          .private_value = nid | (mask<<16) }
 #endif   /* CONFIG_SND_DEBUG */
 
+/*
+ * set up the input pin config (depending on the given auto-pin type)
+ */
+static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
+                             int auto_pin_type)
+{
+       unsigned int val = PIN_IN;
+
+       if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
+               unsigned int pincap;
+               pincap = snd_hda_query_pin_caps(codec, nid);
+               pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+               if (pincap & AC_PINCAP_VREF_80)
+                       val = PIN_VREF80;
+       }
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+}
+
 /*
  */
 static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
@@ -810,6 +839,7 @@ static void setup_preset(struct alc_spec *spec,
        spec->multiout.num_dacs = preset->num_dacs;
        spec->multiout.dac_nids = preset->dac_nids;
        spec->multiout.dig_out_nid = preset->dig_out_nid;
+       spec->multiout.slave_dig_outs = preset->slave_dig_outs;
        spec->multiout.hp_nid = preset->hp_nid;
 
        spec->num_mux_defs = preset->num_mux_defs;
@@ -921,7 +951,7 @@ static void alc_mic_automute(struct hda_codec *codec)
                         HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
 #else
-#define alc_mic_automute(codec) /* NOP */
+#define alc_mic_automute(codec) do {} while(0) /* NOP */
 #endif /* disabled */
 
 /* unsolicited event for HP jack sensing */
@@ -952,7 +982,7 @@ static void alc888_coef_init(struct hda_codec *codec)
        snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
        tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
        snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
-       if ((tmp & 0xf0) == 2)
+       if ((tmp & 0xf0) == 0x20)
                /* alc888S-VC */
                snd_hda_codec_read(codec, 0x20, 0,
                                   AC_VERB_SET_PROC_COEF, 0x830);
@@ -991,8 +1021,10 @@ static void alc_subsystem_id(struct hda_codec *codec,
        nid = 0x1d;
        if (codec->vendor_id == 0x10ec0260)
                nid = 0x17;
-       ass = snd_hda_codec_read(codec, nid, 0,
-                                AC_VERB_GET_CONFIG_DEFAULT, 0);
+       ass = snd_hda_codec_get_pincfg(codec, nid);
+       snd_printd("realtek: No valid SSID, "
+                  "checking pincfg 0x%08x for NID 0x%x\n",
+                  nid, ass);
        if (!(ass & 1) && !(ass & 0x100000))
                return;
        if ((ass >> 30) != 1)   /* no physical connection */
@@ -1007,6 +1039,8 @@ static void alc_subsystem_id(struct hda_codec *codec,
        if (((ass >> 16) & 0xf) != tmp)
                return;
 do_sku:
+       snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+                  ass & 0xffff, codec->vendor_id);
        /*
         * 0 : override
         * 1 :  Swap Jack
@@ -1166,16 +1200,8 @@ static void alc_fix_pincfg(struct hda_codec *codec,
                return;
 
        cfg = pinfix[quirk->value];
-       for (; cfg->nid; cfg++) {
-               int i;
-               u32 val = cfg->val;
-               for (i = 0; i < 4; i++) {
-                       snd_hda_codec_write(codec, cfg->nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
-                                   val & 0xff);
-                       val >>= 8;
-               }
-       }
+       for (; cfg->nid; cfg++)
+               snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
 }
 
 /*
@@ -1375,8 +1401,6 @@ static struct snd_kcontrol_new alc888_base_mixer[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -1483,8 +1507,6 @@ static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1578,8 +1600,7 @@ static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
                                     snd_hda_mixer_amp_switch_put);
 }
 
-#define DEFINE_CAPMIX(num) \
-static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+#define _DEFINE_CAPMIX(num) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                .name = "Capture Switch", \
@@ -1600,7 +1621,9 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
                .get = alc_cap_vol_get, \
                .put = alc_cap_vol_put, \
                .tlv = { .c = alc_cap_vol_tlv }, \
-       }, \
+       }
+
+#define _DEFINE_CAPSRC(num) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                /* .name = "Capture Source", */ \
@@ -1609,15 +1632,28 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
                .info = alc_mux_enum_info, \
                .get = alc_mux_enum_get, \
                .put = alc_mux_enum_put, \
-       }, \
-       { } /* end */ \
+       }
+
+#define DEFINE_CAPMIX(num) \
+static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
+       _DEFINE_CAPMIX(num),                                  \
+       _DEFINE_CAPSRC(num),                                  \
+       { } /* end */                                         \
+}
+
+#define DEFINE_CAPMIX_NOSRC(num) \
+static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
+       _DEFINE_CAPMIX(num),                                        \
+       { } /* end */                                               \
 }
 
 /* up to three ADCs */
 DEFINE_CAPMIX(1);
 DEFINE_CAPMIX(2);
 DEFINE_CAPMIX(3);
-
+DEFINE_CAPMIX_NOSRC(1);
+DEFINE_CAPMIX_NOSRC(2);
+DEFINE_CAPMIX_NOSRC(3);
 
 /*
  * ALC880 5-stack model
@@ -1706,8 +1742,6 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Channel Mode",
@@ -1884,13 +1918,6 @@ static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
        { } /* end */
 };
 
-/* additional mixers to alc880_asus_mixer */
-static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-       { } /* end */
-};
-
 /* TCL S700 */
 static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -1923,8 +1950,6 @@ static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Channel Mode",
@@ -1999,6 +2024,13 @@ static const char *alc_slave_sws[] = {
 
 static void alc_free_kctls(struct hda_codec *codec);
 
+/* 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),
+       { } /* end */
+};
+
 static int alc_build_controls(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -2020,11 +2052,13 @@ 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->no_analog) {
+                       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);
@@ -2032,8 +2066,24 @@ static int alc_build_controls(struct hda_codec *codec)
                        return err;
        }
 
+       /* create beep controls if needed */
+       if (spec->beep_amp) {
+               struct snd_kcontrol_new *knew;
+               for (knew = alc_beep_mixer; knew->name; knew++) {
+                       struct snd_kcontrol *kctl;
+                       kctl = snd_ctl_new1(knew, codec);
+                       if (!kctl)
+                               return -ENOMEM;
+                       kctl->private_value = spec->beep_amp;
+                       err = snd_hda_ctl_add(codec, kctl);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
        /* if we have no master control, let's create it */
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+       if (!spec->no_analog &&
+           !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, vmaster_tlv);
@@ -2042,7 +2092,8 @@ static int alc_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+       if (!spec->no_analog &&
+           !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
                err = snd_hda_add_vmaster(codec, "Master Playback Switch",
                                          NULL, alc_slave_sws);
                if (err < 0)
@@ -2951,6 +3002,14 @@ static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                                             stream_tag, format, substream);
 }
 
+static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          struct snd_pcm_substream *substream)
+{
+       struct alc_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
+}
+
 static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
                                         struct hda_codec *codec,
                                         struct snd_pcm_substream *substream)
@@ -3034,7 +3093,8 @@ static struct hda_pcm_stream alc880_pcm_digital_playback = {
        .ops = {
                .open = alc880_dig_playback_pcm_open,
                .close = alc880_dig_playback_pcm_close,
-               .prepare = alc880_dig_playback_pcm_prepare
+               .prepare = alc880_dig_playback_pcm_prepare,
+               .cleanup = alc880_dig_playback_pcm_cleanup
        },
 };
 
@@ -3061,6 +3121,9 @@ static int alc_build_pcms(struct hda_codec *codec)
        codec->num_pcms = 1;
        codec->pcm_info = info;
 
+       if (spec->no_analog)
+               goto skip_analog;
+
        info->name = spec->stream_name_analog;
        if (spec->stream_analog_playback) {
                if (snd_BUG_ON(!spec->multiout.dac_nids))
@@ -3084,12 +3147,17 @@ static int alc_build_pcms(struct hda_codec *codec)
                }
        }
 
+ skip_analog:
        /* SPDIF for stream index #1 */
        if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
                codec->num_pcms = 2;
+               codec->slave_dig_outs = spec->multiout.slave_dig_outs;
                info = spec->pcm_rec + 1;
                info->name = spec->stream_name_digital;
-               info->pcm_type = HDA_PCM_TYPE_SPDIF;
+               if (spec->dig_out_type)
+                       info->pcm_type = spec->dig_out_type;
+               else
+                       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);
@@ -3104,6 +3172,9 @@ static int alc_build_pcms(struct hda_codec *codec)
                codec->spdif_status_reset = 1;
        }
 
+       if (spec->no_analog)
+               return 0;
+
        /* If the use of more than one ADC is requested for the current
         * model, configure a second analog capture-only PCM.
         */
@@ -3162,65 +3233,17 @@ static void alc_free(struct hda_codec *codec)
 
        alc_free_kctls(codec);
        kfree(spec);
-       codec->spec = NULL; /* to be sure */
+       snd_hda_detach_beep_device(codec);
 }
 
 #ifdef SND_HDA_NEEDS_RESUME
-static void store_pin_configs(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid, end_nid;
-
-       end_nid = codec->start_nid + codec->num_nodes;
-       for (nid = codec->start_nid; nid < end_nid; nid++) {
-               unsigned int wid_caps = get_wcaps(codec, nid);
-               unsigned int wid_type =
-                       (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-               if (wid_type != AC_WID_PIN)
-                       continue;
-               if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids))
-                       break;
-               spec->pin_nids[spec->num_pins] = nid;
-               spec->pin_cfgs[spec->num_pins] =
-                       snd_hda_codec_read(codec, nid, 0,
-                                          AC_VERB_GET_CONFIG_DEFAULT, 0);
-               spec->num_pins++;
-       }
-}
-
-static void resume_pin_configs(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_pins; i++) {
-               hda_nid_t pin_nid = spec->pin_nids[i];
-               unsigned int pin_config = spec->pin_cfgs[i];
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
-                                   pin_config & 0x000000ff);
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
-                                   (pin_config & 0x0000ff00) >> 8);
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
-                                   (pin_config & 0x00ff0000) >> 16);
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-                                   pin_config >> 24);
-       }
-}
-
 static int alc_resume(struct hda_codec *codec)
 {
-       resume_pin_configs(codec);
        codec->patch_ops.init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
        return 0;
 }
-#else
-#define store_pin_configs(codec)
 #endif
 
 /*
@@ -3559,7 +3582,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
        SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
        SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
-       SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
+       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
        SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
        SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
        SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
@@ -3602,7 +3625,8 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
        SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
+       /* default Intel */
+       SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
        SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
        {}
@@ -3782,7 +3806,7 @@ static struct alc_config_preset alc880_presets[] = {
                .input_mux = &alc880_capture_source,
        },
        [ALC880_UNIWILL_DIG] = {
-               .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
+               .mixers = { alc880_asus_mixer },
                .init_verbs = { alc880_volume_init_verbs,
                                alc880_pin_asus_init_verbs },
                .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
@@ -3820,8 +3844,7 @@ static struct alc_config_preset alc880_presets[] = {
                .init_hook = alc880_uniwill_p53_hp_automute,
        },
        [ALC880_FUJITSU] = {
-               .mixers = { alc880_fujitsu_mixer,
-                           alc880_pcbeep_mixer, },
+               .mixers = { alc880_fujitsu_mixer },
                .init_verbs = { alc880_volume_init_verbs,
                                alc880_uniwill_p53_init_verbs,
                                alc880_beep_init_verbs },
@@ -4114,7 +4137,7 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
 static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -4202,11 +4225,9 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc880_is_input_pin(nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           i <= AUTO_PIN_FRONT_MIC ?
-                                           PIN_VREF80 : PIN_IN);
-                       if (nid != ALC880_PIN_CD_NID)
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC880_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -4221,7 +4242,7 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec)
 static int alc880_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       int err;
+       int i, err;
        static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -4252,8 +4273,23 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
-               spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
+       /* check multiple SPDIF-out (for recent codecs) */
+       for (i = 0; i < spec->autocfg.dig_outs; i++) {
+               hda_nid_t dig_nid;
+               err = snd_hda_get_connections(codec,
+                                             spec->autocfg.dig_out_pins[i],
+                                             &dig_nid, 1);
+               if (err < 0)
+                       continue;
+               if (!i)
+                       spec->multiout.dig_out_nid = dig_nid;
+               else {
+                       spec->multiout.slave_dig_outs = spec->slave_dig_outs;
+                       spec->slave_dig_outs[i - 1] = dig_nid;
+                       if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1)
+                               break;
+               }
+       }
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = ALC880_DIGIN_NID;
 
@@ -4263,9 +4299,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
        add_verb(spec, alc880_volume_init_verbs);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -4280,21 +4315,33 @@ static void alc880_auto_init(struct hda_codec *codec)
                alc_inithook(codec);
 }
 
-/*
- * OK, here we have finally the patch for ALC880
- */
-
 static void set_capture_mixer(struct alc_spec *spec)
 {
-       static struct snd_kcontrol_new *caps[3] = {
-               alc_capture_mixer1,
-               alc_capture_mixer2,
-               alc_capture_mixer3,
+       static struct snd_kcontrol_new *caps[2][3] = {
+               { alc_capture_mixer_nosrc1,
+                 alc_capture_mixer_nosrc2,
+                 alc_capture_mixer_nosrc3 },
+               { alc_capture_mixer1,
+                 alc_capture_mixer2,
+                 alc_capture_mixer3 },
        };
-       if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3)
-               spec->cap_mixer = caps[spec->num_adc_nids - 1];
+       if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
+               int mux;
+               if (spec->input_mux && spec->input_mux->num_items > 1)
+                       mux = 1;
+               else
+                       mux = 0;
+               spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
+       }
 }
 
+#define set_beep_amp(spec, nid, idx, dir) \
+       ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+
+/*
+ * OK, here we have finally the patch for ALC880
+ */
+
 static int patch_alc880(struct hda_codec *codec)
 {
        struct alc_spec *spec;
@@ -4330,6 +4377,12 @@ static int patch_alc880(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC880_AUTO)
                setup_preset(spec, &alc880_presets[board_config]);
 
@@ -4356,6 +4409,7 @@ static int patch_alc880(struct hda_codec *codec)
                }
        }
        set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
 
@@ -4463,6 +4517,26 @@ static struct hda_input_mux alc260_acer_capture_sources[2] = {
                },
        },
 };
+
+/* Maxdata Favorit 100XS */
+static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
+       {
+               .num_items = 2,
+               .items = {
+                       { "Line/Mic", 0x0 },
+                       { "CD", 0x4 },
+               },
+       },
+       {
+               .num_items = 3,
+               .items = {
+                       { "Line/Mic", 0x0 },
+                       { "CD", 0x4 },
+                       { "Mixer", 0x5 },
+               },
+       },
+};
+
 /*
  * This is just place-holder, so there's something for alc_build_pcms to look
  * at when it calculates the maximum number of channels. ALC260 has no mixer
@@ -4505,12 +4579,6 @@ static struct snd_kcontrol_new alc260_input_mixer[] = {
        { } /* end */
 };
 
-static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
-       { } /* end */
-};
-
 /* update HP, line and mono out pins according to the master switch */
 static void alc260_hp_master_update(struct hda_codec *codec,
                                    hda_nid_t hp, hda_nid_t line,
@@ -4702,8 +4770,6 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
        HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
        ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
        { } /* end */
@@ -4748,8 +4814,18 @@ static struct snd_kcontrol_new alc260_acer_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
        ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
+       { } /* end */
+};
+
+/* Maxdata Favorit 100XS: one output and one input (0x12) jack
+ */
+static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
+       ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
+       HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+       ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
        { } /* end */
 };
 
@@ -4767,8 +4843,6 @@ static struct snd_kcontrol_new alc260_will_mixer[] = {
        ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -5126,6 +5200,89 @@ static struct hda_verb alc260_acer_init_verbs[] = {
        { }
 };
 
+/* Initialisation sequence for Maxdata Favorit 100XS
+ * (adapted from Acer init verbs).
+ */
+static struct hda_verb alc260_favorit100_init_verbs[] = {
+       /* GPIO 0 enables the output jack.
+        * Turn this on and rely on the standard mute
+        * methods whenever the user wants to turn these outputs off.
+        */
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+       /* Line/Mic input jack is connected to Mic1 pin */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+       /* Ensure all other unused pins are disabled and muted. */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Disable digital (SPDIF) pins */
+       {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+       {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+       /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
+        * bus when acting as outputs.
+        */
+       {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
+       {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
+
+       /* Start with output sum widgets muted and their output gains at min */
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* Unmute Line-out pin widget amp left and right
+        * (no equiv mixer ctrl)
+        */
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Unmute Mic1 and Line1 pin widget input buffers since they start as
+        * inputs. If the pin mode is changed by the user the pin mode control
+        * will take care of enabling the pin's input/output buffers as needed.
+        * Therefore there's no need to enable the input buffer at this
+        * stage.
+        */
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute capture amp left and right */
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       /* Set ADC connection select to match default mixer setting - mic
+        * (on mic1 pin)
+        */
+       {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Do similar with the second ADC: mute capture input amp and
+        * set ADC connection to mic to match ALSA's default state.
+        */
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* Mute all inputs to mixer widget (even unconnected ones) */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+       { }
+};
+
 static struct hda_verb alc260_will_verbs[] = {
        {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -5272,8 +5429,6 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
        HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
        HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
        HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
@@ -5471,7 +5626,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
 static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -5546,11 +5701,9 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (nid >= 0x12) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           i <= AUTO_PIN_FRONT_MIC ?
-                                           PIN_VREF80 : PIN_IN);
-                       if (nid != ALC260_PIN_CD_NID)
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC260_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -5623,7 +5776,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
@@ -5631,9 +5784,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
        add_verb(spec, alc260_volume_init_verbs);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -5670,6 +5822,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = {
        [ALC260_ACER]           = "acer",
        [ALC260_WILL]           = "will",
        [ALC260_REPLACER_672V]  = "replacer",
+       [ALC260_FAVORIT100]     = "favorit100",
 #ifdef CONFIG_SND_DEBUG
        [ALC260_TEST]           = "test",
 #endif
@@ -5679,6 +5832,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, 0x008f, "Acer", ALC260_ACER),
+       SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
        SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
@@ -5701,8 +5855,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
 static struct alc_config_preset alc260_presets[] = {
        [ALC260_BASIC] = {
                .mixers = { alc260_base_output_mixer,
-                           alc260_input_mixer,
-                           alc260_pc_beep_mixer },
+                           alc260_input_mixer },
                .init_verbs = { alc260_init_verbs },
                .num_dacs = ARRAY_SIZE(alc260_dac_nids),
                .dac_nids = alc260_dac_nids,
@@ -5781,6 +5934,18 @@ static struct alc_config_preset alc260_presets[] = {
                .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
                .input_mux = alc260_acer_capture_sources,
        },
+       [ALC260_FAVORIT100] = {
+               .mixers = { alc260_favorit100_mixer },
+               .init_verbs = { alc260_favorit100_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc260_dac_nids),
+               .dac_nids = alc260_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
+               .adc_nids = alc260_dual_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc260_modes),
+               .channel_mode = alc260_modes,
+               .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
+               .input_mux = alc260_favorit100_capture_sources,
+       },
        [ALC260_WILL] = {
                .mixers = { alc260_will_mixer },
                .init_verbs = { alc260_init_verbs, alc260_will_verbs },
@@ -5857,6 +6022,12 @@ static int patch_alc260(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC260_AUTO)
                setup_preset(spec, &alc260_presets[board_config]);
 
@@ -5882,6 +6053,7 @@ static int patch_alc260(struct hda_codec *codec)
                }
        }
        set_capture_mixer(spec);
+       set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x08;
 
@@ -6053,8 +6225,6 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -6081,8 +6251,6 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -6134,8 +6302,6 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -6244,8 +6410,10 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = {
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
        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),
+       */
        { } /* end */
 };
 
@@ -6877,19 +7045,9 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               unsigned int vref;
                if (!nid)
                        continue;
-               vref = PIN_IN;
-               if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
-                       unsigned int pincap;
-                       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
-                       if ((pincap >> AC_PINCAP_VREF_SHIFT) &
-                           AC_PINCAP_VREF_80)
-                               vref = PIN_VREF80;
-               }
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
+               alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
                if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_write(codec, nid, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
@@ -6900,18 +7058,21 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec)
 static void alc882_auto_init_input_src(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = spec->input_mux;
        int c;
 
        for (c = 0; c < spec->num_adc_nids; c++) {
                hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
                hda_nid_t nid = spec->capsrc_nids[c];
+               unsigned int mux_idx;
+               const struct hda_input_mux *imux;
                int conns, mute, idx, item;
 
                conns = snd_hda_get_connections(codec, nid, conn_list,
                                                ARRAY_SIZE(conn_list));
                if (conns < 0)
                        continue;
+               mux_idx = c >= spec->num_mux_defs ? 0 : c;
+               imux = &spec->input_mux[mux_idx];
                for (idx = 0; idx < conns; idx++) {
                        /* if the current connection is the selected one,
                         * unmute it as default - otherwise mute it
@@ -6924,8 +7085,20 @@ static void alc882_auto_init_input_src(struct hda_codec *codec)
                                        break;
                                }
                        }
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_AMP_GAIN_MUTE, mute);
+                       /* check if we have a selector or mixer
+                        * we could check for the widget type instead, but
+                        * just check for Amp-In presence (in case of mixer
+                        * without amp-in there is something wrong, this
+                        * function shouldn't be used or capsrc nid is wrong)
+                        */
+                       if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+                               snd_hda_codec_write(codec, nid, 0,
+                                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                                   mute);
+                       else if (mute != AMP_IN_MUTE(idx))
+                               snd_hda_codec_write(codec, nid, 0,
+                                                   AC_VERB_SET_CONNECT_SEL,
+                                                   idx);
                }
        }
 }
@@ -7054,6 +7227,12 @@ static int patch_alc882(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC882_AUTO)
                setup_preset(spec, &alc882_presets[board_config]);
 
@@ -7074,7 +7253,7 @@ static int patch_alc882(struct hda_codec *codec)
        spec->stream_digital_playback = &alc882_pcm_digital_playback;
        spec->stream_digital_capture = &alc882_pcm_digital_capture;
 
-       spec->is_mix_capture = 1; /* matrix-style capture */
+       spec->capture_style = CAPT_MIX; /* matrix-style capture */
        if (!spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
@@ -7091,6 +7270,7 @@ static int patch_alc882(struct hda_codec *codec)
                }
        }
        set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
 
@@ -7142,10 +7322,14 @@ static hda_nid_t alc883_adc_nids_rev[2] = {
        0x09, 0x08
 };
 
+#define alc889_adc_nids                alc880_adc_nids
+
 static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
 
 static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
 
+#define alc889_capsrc_nids     alc882_capsrc_nids
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -7363,8 +7547,6 @@ static struct snd_kcontrol_new alc883_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7427,8 +7609,6 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7452,8 +7632,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7478,8 +7656,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7503,8 +7679,6 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -7912,36 +8086,83 @@ static struct hda_verb alc888_lenovo_sky_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb alc888_6st_dell_verbs[] = {
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+static void alc888_3st_hp_front_automute(struct hda_codec *codec)
+{
+       unsigned int present, bits;
+
+       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, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+       snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+}
+
+static void alc888_3st_hp_unsol_event(struct hda_codec *codec,
+                                     unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc888_3st_hp_front_automute(codec);
+               break;
+       }
+}
+
 static struct hda_verb alc888_3st_hp_verbs[] = {
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
        {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},  /* CLFE : output 2 (0x0e) */
-       { }
-};
-
-static struct hda_verb alc888_6st_dell_verbs[] = {
        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { }
+       { } /* end */
 };
 
+/*
+ * 2ch mode
+ */
 static struct hda_verb alc888_3st_hp_2ch_init[] = {
        { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
        { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
        { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
        { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { }
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc888_3st_hp_4ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
 };
 
+/*
+ * 6ch mode
+ */
 static struct hda_verb alc888_3st_hp_6ch_init[] = {
        { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
        { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
        { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
        { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { }
+       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
 };
 
-static struct hda_channel_mode alc888_3st_hp_modes[2] = {
+static struct hda_channel_mode alc888_3st_hp_modes[3] = {
        { 2, alc888_3st_hp_2ch_init },
+       { 4, alc888_3st_hp_4ch_init },
        { 6, alc888_3st_hp_6ch_init },
 };
 
@@ -8202,7 +8423,7 @@ static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
 {
        switch (res >> 26) {
        case ALC880_HP_EVENT:
-               printk("hp_event\n");
+               /* printk(KERN_DEBUG "hp_event\n"); */
                alc888_6st_dell_front_automute(codec);
                break;
        }
@@ -8461,6 +8682,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
@@ -8468,17 +8690,21 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
                ALC888_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
+       SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
                ALC888_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
+       /* default Acer */
+       SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER),
        SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
        SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
        SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
@@ -8518,7 +8744,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
        SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
-       SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
+       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
        SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550",
@@ -8543,6 +8769,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        {}
 };
 
+static hda_nid_t alc1200_slave_dig_outs[] = {
+       ALC883_DIGOUT_NID, 0,
+};
+
 static struct alc_config_preset alc883_presets[] = {
        [ALC883_3ST_2ch_DIG] = {
                .mixers = { alc883_3ST_2ch_mixer },
@@ -8778,6 +9008,8 @@ static struct alc_config_preset alc883_presets[] = {
                .channel_mode = alc888_3st_hp_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
+               .unsol_event = alc888_3st_hp_unsol_event,
+               .init_hook = alc888_3st_hp_front_automute,
        },
        [ALC888_6ST_DELL] = {
                .mixers = { alc883_base_mixer, alc883_chmode_mixer },
@@ -8883,6 +9115,7 @@ static struct alc_config_preset alc883_presets[] = {
                .dac_nids = alc883_dac_nids,
                .dig_out_nid = ALC1200_DIGOUT_NID,
                .dig_in_nid = ALC883_DIGIN_NID,
+               .slave_dig_outs = alc1200_slave_dig_outs,
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
                .input_mux = &alc883_capture_source,
@@ -8950,11 +9183,9 @@ static void alc883_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc883_is_input_pin(nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           (i <= AUTO_PIN_FRONT_MIC ?
-                                            PIN_VREF80 : PIN_IN));
-                       if (nid != ALC883_PIN_CD_NID)
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC883_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -8969,6 +9200,8 @@ static int alc883_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        int err = alc880_parse_auto_config(codec);
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
 
        if (err < 0)
                return err;
@@ -8982,6 +9215,26 @@ static int alc883_parse_auto_config(struct hda_codec *codec)
        /* hack - override the init verbs */
        spec->init_verbs[0] = alc883_auto_init_verbs;
 
+       /* setup input_mux for ALC889 */
+       if (codec->vendor_id == 0x10ec0889) {
+               /* digital-mic input pin is excluded in alc880_auto_create..()
+                * because it's under 0x18
+                */
+               if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
+                   cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
+                       struct hda_input_mux *imux = &spec->private_imux[0];
+                       for (i = 1; i < 3; i++)
+                               memcpy(&spec->private_imux[i],
+                                      &spec->private_imux[0],
+                                      sizeof(spec->private_imux[0]));
+                       imux->items[imux->num_items].label = "Int DMic";
+                       imux->items[imux->num_items].index = 0x0b;
+                       imux->num_items++;
+                       spec->num_mux_defs = 3;
+                       spec->input_mux = spec->private_imux;
+               }
+       }
+
        return 1; /* config found */
 }
 
@@ -9033,6 +9286,12 @@ static int patch_alc883(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC883_AUTO)
                setup_preset(spec, &alc883_presets[board_config]);
 
@@ -9045,14 +9304,36 @@ static int patch_alc883(struct hda_codec *codec)
                        spec->stream_name_analog = "ALC888 Analog";
                        spec->stream_name_digital = "ALC888 Digital";
                }
+               if (!spec->num_adc_nids) {
+                       spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+                       spec->adc_nids = alc883_adc_nids;
+               }
+               if (!spec->capsrc_nids)
+                       spec->capsrc_nids = alc883_capsrc_nids;
+               spec->capture_style = CAPT_MIX; /* matrix-style capture */
                break;
        case 0x10ec0889:
                spec->stream_name_analog = "ALC889 Analog";
                spec->stream_name_digital = "ALC889 Digital";
+               if (!spec->num_adc_nids) {
+                       spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
+                       spec->adc_nids = alc889_adc_nids;
+               }
+               if (!spec->capsrc_nids)
+                       spec->capsrc_nids = alc889_capsrc_nids;
+               spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
+                                                       capture */
                break;
        default:
                spec->stream_name_analog = "ALC883 Analog";
                spec->stream_name_digital = "ALC883 Digital";
+               if (!spec->num_adc_nids) {
+                       spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+                       spec->adc_nids = alc883_adc_nids;
+               }
+               if (!spec->capsrc_nids)
+                       spec->capsrc_nids = alc883_capsrc_nids;
+               spec->capture_style = CAPT_MIX; /* matrix-style capture */
                break;
        }
 
@@ -9063,15 +9344,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->num_adc_nids) {
-               spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
-               spec->adc_nids = alc883_adc_nids;
-       }
-       if (!spec->capsrc_nids)
-               spec->capsrc_nids = alc883_capsrc_nids;
-       spec->is_mix_capture = 1; /* matrix-style capture */
        if (!spec->cap_mixer)
                set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
 
@@ -9124,8 +9399,6 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-       /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-          HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
@@ -9146,8 +9419,6 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-       /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-          HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
        /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        { } /* end */
@@ -9256,8 +9527,6 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, 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("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
        HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
        { } /* end */
@@ -9286,8 +9555,6 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, 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("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -9435,6 +9702,67 @@ static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc262_tyan_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
+       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, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static struct hda_verb alc262_tyan_verbs[] = {
+       /* Headphone automute */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* P11 AUX_IN, white 4-pin connector */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
+       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
+
+       {}
+};
+
+/* unsolicited event for HP jack sensing */
+static void alc262_tyan_automute(struct hda_codec *codec)
+{
+       unsigned int mute;
+       unsigned int present;
+
+       snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
+       present = snd_hda_codec_read(codec, 0x1b, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0);
+       present = (present & 0x80000000) != 0;
+       if (present) {
+               /* mute line output on ATX panel */
+               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+       } else {
+               /* unmute line output if necessary */
+               mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
+               snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       }
+}
+
+static void alc262_tyan_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) != ALC880_HP_EVENT)
+               return;
+       alc262_tyan_automute(codec);
+}
+
 #define alc262_capture_mixer           alc882_capture_mixer
 #define alc262_capture_alt_mixer       alc882_capture_alt_mixer
 
@@ -9901,8 +10229,6 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
        },
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
@@ -10474,8 +10800,14 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
                                           alc262_ignore);
        if (err < 0)
                return err;
-       if (!spec->autocfg.line_outs)
+       if (!spec->autocfg.line_outs) {
+               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
+                       spec->multiout.max_channels = 2;
+                       spec->no_analog = 1;
+                       goto dig_only;
+               }
                return 0; /* can't find valid BIOS pin config */
+       }
        err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
@@ -10485,8 +10817,11 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+ dig_only:
+       if (spec->autocfg.dig_outs) {
                spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
+               spec->dig_out_type = spec->autocfg.dig_out_type[0];
+       }
        if (spec->autocfg.dig_in_pin)
                spec->dig_in_nid = ALC262_DIGIN_NID;
 
@@ -10495,13 +10830,12 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
 
        add_verb(spec, alc262_volume_init_verbs);
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -10543,21 +10877,19 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
        [ALC262_ULTRA]          = "ultra",
        [ALC262_LENOVO_3000]    = "lenovo-3000",
        [ALC262_NEC]            = "nec",
+       [ALC262_TYAN]           = "tyan",
        [ALC262_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
        SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
-       SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x170b, "HP xw*", ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
+                          ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
+                          ALC262_HP_BPC),
+       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
+                          ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
        SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -10575,17 +10907,17 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
        SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN",
-                     ALC262_SONY_ASSAMD),
+       SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
+       SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
+                          ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
                      ALC262_TOSHIBA_RX1),
        SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
        SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
-       SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
-       SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
+       SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
+       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
+                          ALC262_ULTRA),
        SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
        SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
        SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
@@ -10802,6 +11134,19 @@ static struct alc_config_preset alc262_presets[] = {
                .unsol_event = alc262_hippo_unsol_event,
                .init_hook = alc262_hippo_automute,
        },
+       [ALC262_TYAN] = {
+               .mixers = { alc262_tyan_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x02,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc262_tyan_unsol_event,
+               .init_hook = alc262_tyan_automute,
+       },
 };
 
 static int patch_alc262(struct hda_codec *codec)
@@ -10854,6 +11199,14 @@ static int patch_alc262(struct hda_codec *codec)
                }
        }
 
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+       }
+
        if (board_config != ALC262_AUTO)
                setup_preset(spec, &alc262_presets[board_config]);
 
@@ -10865,7 +11218,7 @@ static int patch_alc262(struct hda_codec *codec)
        spec->stream_digital_playback = &alc262_pcm_digital_playback;
        spec->stream_digital_capture = &alc262_pcm_digital_capture;
 
-       spec->is_mix_capture = 1;
+       spec->capture_style = CAPT_MIX;
        if (!spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
@@ -10882,8 +11235,10 @@ static int patch_alc262(struct hda_codec *codec)
                        spec->capsrc_nids = alc262_capsrc_nids;
                }
        }
-       if (!spec->cap_mixer)
+       if (!spec->cap_mixer && !spec->no_analog)
                set_capture_mixer(spec);
+       if (!spec->no_analog)
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x0c;
 
@@ -11263,19 +11618,13 @@ static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
 static struct hda_verb alc268_base_init_verbs[] = {
        /* Unmute DAC0-1 and set vol = 0 */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
        /*
         * Set up output mixers (0x0c - 0x0e)
         */
        /* set vol=0 to output mixers */
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
         {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
 
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11294,9 +11643,7 @@ static struct hda_verb alc268_base_init_verbs[] = {
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 
        /* set PCBEEP vol = 0, mute connections */
        {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11318,10 +11665,8 @@ static struct hda_verb alc268_base_init_verbs[] = {
  */
 static struct hda_verb alc268_volume_init_verbs[] = {
        /* set output DAC */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 
        {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
@@ -11329,16 +11674,12 @@ static struct hda_verb alc268_volume_init_verbs[] = {
        {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
        {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
 
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
        {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 
        /* set PCBEEP vol = 0, mute connections */
        {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -11537,7 +11878,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
 static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, idx1;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -11631,9 +11972,14 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
                                           alc268_ignore);
        if (err < 0)
                return err;
-       if (!spec->autocfg.line_outs)
+       if (!spec->autocfg.line_outs) {
+               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
+                       spec->multiout.max_channels = 2;
+                       spec->no_analog = 1;
+                       goto dig_only;
+               }
                return 0; /* can't find valid BIOS pin config */
-
+       }
        err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
@@ -11643,25 +11989,26 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = 2;
 
+ dig_only:
        /* digital only support output */
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs) {
                spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
-
+               spec->dig_out_type = spec->autocfg.dig_out_type[0];
+       }
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
-       if (spec->autocfg.speaker_pins[0] != 0x1d)
+       if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
                add_mixer(spec, alc268_beep_mixer);
 
        add_verb(spec, alc268_volume_init_verbs);
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -11723,7 +12070,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
 
 static struct alc_config_preset alc268_presets[] = {
        [ALC267_QUANTA_IL1] = {
-               .mixers = { alc267_quanta_il1_mixer },
+               .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc267_quanta_il1_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -11805,7 +12152,8 @@ static struct alc_config_preset alc268_presets[] = {
        },
        [ALC268_ACER_ASPIRE_ONE] = {
                .mixers = { alc268_acer_aspire_one_mixer,
-                               alc268_capture_alt_mixer },
+                           alc268_beep_mixer,
+                           alc268_capture_alt_mixer },
                .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
                                alc268_acer_aspire_one_verbs },
                .num_dacs = ARRAY_SIZE(alc268_dac_nids),
@@ -11874,7 +12222,7 @@ static int patch_alc268(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int board_config;
-       int err;
+       int i, has_beep, err;
 
        spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -11923,15 +12271,30 @@ static int patch_alc268(struct hda_codec *codec)
 
        spec->stream_digital_playback = &alc268_pcm_digital_playback;
 
-       if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
-               /* override the amp caps for beep generator */
-               snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
+       has_beep = 0;
+       for (i = 0; i < spec->num_mixers; i++) {
+               if (spec->mixers[i] == alc268_beep_mixer) {
+                       has_beep = 1;
+                       break;
+               }
+       }
+
+       if (has_beep) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
+                       /* override the amp caps for beep generator */
+                       snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
                                          (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
                                          (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
                                          (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
                                          (0 << AC_AMPCAP_MUTE_SHIFT));
+       }
 
-       if (!spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
                /* check whether NID 0x07 is valid */
                unsigned int wcap = get_wcaps(codec, 0x07);
                int i;
@@ -12012,8 +12375,6 @@ static struct snd_kcontrol_new alc269_base_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, 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("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
@@ -12040,8 +12401,6 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
        { }
 };
 
@@ -12065,8 +12424,6 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
        HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
        HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
        { }
 };
 
@@ -12103,13 +12460,6 @@ static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
        { } /* end */
 };
 
-/* beep control */
-static struct snd_kcontrol_new alc269_beep_mixer[] = {
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
-       { } /* end */
-};
-
 static struct hda_verb alc269_quanta_fl1_verbs[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -12509,7 +12859,7 @@ static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
         */
        if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
            cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
-               struct hda_input_mux *imux = &spec->private_imux;
+               struct hda_input_mux *imux = &spec->private_imux[0];
                imux->items[imux->num_items].label = "Int Mic";
                imux->items[imux->num_items].index = 0x05;
                imux->num_items++;
@@ -12527,13 +12877,34 @@ static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
 #define alc269_pcm_digital_playback    alc880_pcm_digital_playback
 #define alc269_pcm_digital_capture     alc880_pcm_digital_capture
 
+static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+       /* NID is set in alc_build_pcms */
+       .ops = {
+               .open = alc880_playback_pcm_open,
+               .prepare = alc880_playback_pcm_prepare,
+               .cleanup = alc880_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+       /* NID is set in alc_build_pcms */
+};
+
 /*
  * BIOS auto configuration
  */
 static int alc269_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       int i, err;
+       int err;
        static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
@@ -12550,22 +12921,15 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
 
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
-       /* create a beep mixer control if the pin 0x1d isn't assigned */
-       for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
-               if (spec->autocfg.input_pins[i] == 0x1d)
-                       break;
-       if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
-               add_mixer(spec, alc269_beep_mixer);
-
        add_verb(spec, alc269_init_verbs);
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
        /* set default input source */
        snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
                                  0, AC_VERB_SET_CONNECT_SEL,
@@ -12575,10 +12939,9 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       if (!spec->cap_mixer)
+       if (!spec->cap_mixer && !spec->no_analog)
                set_capture_mixer(spec);
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -12675,7 +13038,7 @@ static struct alc_config_preset alc269_presets[] = {
                .init_hook = alc269_eeepc_dmic_inithook,
        },
        [ALC269_FUJITSU] = {
-               .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer },
+               .mixers = { alc269_fujitsu_mixer },
                .cap_mixer = alc269_epc_capture_mixer,
                .init_verbs = { alc269_init_verbs,
                                alc269_eeepc_dmic_init_verbs },
@@ -12740,13 +13103,26 @@ static int patch_alc269(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC269_AUTO)
                setup_preset(spec, &alc269_presets[board_config]);
 
        spec->stream_name_analog = "ALC269 Analog";
-       spec->stream_analog_playback = &alc269_pcm_analog_playback;
-       spec->stream_analog_capture = &alc269_pcm_analog_capture;
-
+       if (codec->subsystem_id == 0x17aa3bf8) {
+               /* Due to a hardware problem on Lenovo Ideadpad, we need to
+                * fix the sample rate of analog I/O to 44.1kHz
+                */
+               spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
+               spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
+       } else {
+               spec->stream_analog_playback = &alc269_pcm_analog_playback;
+               spec->stream_analog_capture = &alc269_pcm_analog_capture;
+       }
        spec->stream_name_digital = "ALC269 Digital";
        spec->stream_digital_playback = &alc269_pcm_digital_playback;
        spec->stream_digital_capture = &alc269_pcm_digital_capture;
@@ -12756,6 +13132,7 @@ static int patch_alc269(struct hda_codec *codec)
        spec->capsrc_nids = alc269_capsrc_nids;
        if (!spec->cap_mixer)
                set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC269_AUTO)
@@ -13006,8 +13383,6 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = {
 static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
        { }
 };
 
@@ -13481,7 +13856,7 @@ static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
 static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx, idx1;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
@@ -13568,12 +13943,8 @@ static void alc861_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (nid >= 0x0c && nid <= 0x11) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           i <= AUTO_PIN_FRONT_MIC ?
-                                           PIN_VREF80 : PIN_IN);
-               }
+               if (nid >= 0x0c && nid <= 0x11)
+                       alc_set_input_pin(codec, nid, i);
        }
 }
 
@@ -13609,7 +13980,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
 
        if (spec->kctls.list)
@@ -13618,13 +13989,12 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        add_verb(spec, alc861_auto_init_verbs);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        spec->adc_nids = alc861_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
        set_capture_mixer(spec);
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -13833,6 +14203,12 @@ static int patch_alc861(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x23);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC861_AUTO)
                setup_preset(spec, &alc861_presets[board_config]);
 
@@ -13844,6 +14220,8 @@ static int patch_alc861(struct hda_codec *codec)
        spec->stream_digital_playback = &alc861_pcm_digital_playback;
        spec->stream_digital_capture = &alc861_pcm_digital_capture;
 
+       set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+
        spec->vmaster_nid = 0x03;
 
        codec->patch_ops = alc_patch_ops;
@@ -14000,9 +14378,6 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-
        { } /* end */
 };
 
@@ -14026,9 +14401,6 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-
        { } /* end */
 };
 
@@ -14067,8 +14439,6 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
        HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -14379,9 +14749,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
        SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
-       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
        {}
 };
@@ -14543,11 +14911,9 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
                if (alc861vd_is_input_pin(nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                       i <= AUTO_PIN_FRONT_MIC ?
-                                                       PIN_VREF80 : PIN_IN);
-                       if (nid != ALC861VD_PIN_CD_NID)
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC861VD_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                AC_VERB_SET_AMP_GAIN_MUTE,
                                                AMP_OUT_MUTE);
@@ -14713,7 +15079,7 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
 
        if (spec->kctls.list)
@@ -14722,13 +15088,12 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
        add_verb(spec, alc861vd_volume_init_verbs);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -14779,6 +15144,12 @@ static int patch_alc861vd(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x23);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC861VD_AUTO)
                setup_preset(spec, &alc861vd_presets[board_config]);
 
@@ -14801,9 +15172,10 @@ 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->is_mix_capture = 1;
+       spec->capture_style = CAPT_MIX;
 
        set_capture_mixer(spec);
+       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
        spec->vmaster_nid = 0x02;
 
@@ -14992,8 +15364,6 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -15015,8 +15385,6 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
        { } /* end */
 };
 
@@ -15992,56 +16360,55 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
 };
 
 static struct snd_pci_quirk alc662_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
-       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
-       SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
-       SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
-       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
        SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
        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, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
+       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, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
+       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
        SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
+       /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
        SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
        SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
+       /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
+       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
        SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
-       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
-       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
+       SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
+       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
        SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
                      ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
-       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
-       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
                      ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
        SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
                                        ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
-       SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
-       SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
+       SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
+                          ALC663_ASUS_H13),
        {}
 };
 
@@ -16361,7 +16728,7 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
 
        if (alc880_is_fixed_pin(pin)) {
                nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
-                /* printk("DAC nid=%x\n",nid); */
+               /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
                /* specify the DAC as the extra output */
                if (!spec->multiout.hp_nid)
                        spec->multiout.hp_nid = nid;
@@ -16391,26 +16758,58 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
        return 0;
 }
 
+/* return the index of the src widget from the connection list of the nid.
+ * return -1 if not found
+ */
+static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid,
+                               hda_nid_t src)
+{
+       hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
+       int i, conns;
+
+       conns = snd_hda_get_connections(codec, nid, conn_list,
+                                       ARRAY_SIZE(conn_list));
+       if (conns < 0)
+               return -1;
+       for (i = 0; i < conns; i++)
+               if (conn_list[i] == src)
+                       return i;
+       return -1;
+}
+
+static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
+       return (pincap & AC_PINCAP_IN) != 0;
+}
+
 /* create playback/capture controls for input pins */
-static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
+static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       struct hda_input_mux *imux = &spec->private_imux;
+       struct alc_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->private_imux[0];
        int i, err, idx;
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (alc880_is_input_pin(cfg->input_pins[i])) {
-                       idx = alc880_input_pin_idx(cfg->input_pins[i]);
-                       err = new_analog_input(spec, cfg->input_pins[i],
-                                              auto_pin_cfg_labels[i],
-                                              idx, 0x0b);
-                       if (err < 0)
-                               return err;
-                       imux->items[imux->num_items].label =
-                               auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index =
-                               alc880_input_pin_idx(cfg->input_pins[i]);
-                       imux->num_items++;
+               if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
+                       idx = alc662_input_pin_idx(codec, 0x0b,
+                                                  cfg->input_pins[i]);
+                       if (idx >= 0) {
+                               err = new_analog_input(spec, cfg->input_pins[i],
+                                                      auto_pin_cfg_labels[i],
+                                                      idx, 0x0b);
+                               if (err < 0)
+                                       return err;
+                       }
+                       idx = alc662_input_pin_idx(codec, 0x22,
+                                                  cfg->input_pins[i]);
+                       if (idx >= 0) {
+                               imux->items[imux->num_items].label =
+                                       auto_pin_cfg_labels[i];
+                               imux->items[imux->num_items].index = idx;
+                               imux->num_items++;
+                       }
                }
        }
        return 0;
@@ -16460,7 +16859,6 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
                alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
-#define alc662_is_input_pin(nid)       alc880_is_input_pin(nid)
 #define ALC662_PIN_CD_NID              ALC880_PIN_CD_NID
 
 static void alc662_auto_init_analog_input(struct hda_codec *codec)
@@ -16470,12 +16868,10 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec)
 
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (alc662_is_input_pin(nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           (i <= AUTO_PIN_FRONT_MIC ?
-                                            PIN_VREF80 : PIN_IN));
-                       if (nid != ALC662_PIN_CD_NID)
+               if (alc662_is_input_pin(codec, nid)) {
+                       alc_set_input_pin(codec, nid, i);
+                       if (nid != ALC662_PIN_CD_NID &&
+                           (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
                                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                                    AMP_OUT_MUTE);
@@ -16513,20 +16909,20 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
                                           "Headphone");
        if (err < 0)
                return err;
-       err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       if (spec->autocfg.dig_out_pin)
+       if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
 
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
        spec->num_mux_defs = 1;
-       spec->input_mux = &spec->private_imux;
+       spec->input_mux = &spec->private_imux[0];
 
        add_verb(spec, alc662_auto_init_verbs);
        if (codec->vendor_id == 0x10ec0663)
@@ -16536,7 +16932,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       store_pin_configs(codec);
        return 1;
 }
 
@@ -16588,6 +16983,12 @@ static int patch_alc662(struct hda_codec *codec)
                }
        }
 
+       err = snd_hda_attach_beep_device(codec, 0x1);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
        if (board_config != ALC662_AUTO)
                setup_preset(spec, &alc662_presets[board_config]);
 
@@ -16611,10 +17012,14 @@ static int patch_alc662(struct hda_codec *codec)
        spec->adc_nids = alc662_adc_nids;
        spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
        spec->capsrc_nids = alc662_capsrc_nids;
-       spec->is_mix_capture = 1;
+       spec->capture_style = CAPT_MIX;
 
        if (!spec->cap_mixer)
                set_capture_mixer(spec);
+       if (codec->vendor_id == 0x10ec0662)
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       else
+               set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
 
        spec->vmaster_nid = 0x02;