]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - sound/pci/hda/patch_realtek.c
Merge branch 'fix/hda' into topic/hda
[mv-sheeva.git] / sound / pci / hda / patch_realtek.c
index 22c73b78ac6f193b635ef362c026bf51b8fe1da8..65955dabc152b6e35b27f7cf8857c61be3b5335d 100644 (file)
@@ -200,6 +200,8 @@ struct alc_spec {
        hda_nid_t vmaster_nid;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
+       int num_loopbacks;
+       struct hda_amp_list loopback_list[8];
 #endif
 
        /* for PLL fix */
@@ -220,8 +222,6 @@ struct alc_spec {
        struct snd_array bind_ctls;
 };
 
-#define ALC_MODEL_AUTO         0       /* common for all chips */
-
 static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
                           int dir, unsigned int bits)
 {
@@ -300,6 +300,9 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
        int i, type, num_conns;
        hda_nid_t nid;
 
+       if (!spec->input_mux)
+               return 0;
+
        mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
        imux = &spec->input_mux[mux_idx];
        if (!imux->num_items && mux_idx > 0)
@@ -651,15 +654,51 @@ static void alc_exec_unsol_event(struct hda_codec *codec, int action)
        snd_hda_jack_report_sync(codec);
 }
 
+/* update the master volume per volume-knob's unsol event */
+static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int val;
+       struct snd_kcontrol *kctl;
+       struct snd_ctl_elem_value *uctl;
+
+       kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
+       if (!kctl)
+               return;
+       uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
+       if (!uctl)
+               return;
+       val = snd_hda_codec_read(codec, nid, 0,
+                                AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+       val &= HDA_AMP_VOLMASK;
+       uctl->value.integer.value[0] = val;
+       uctl->value.integer.value[1] = val;
+       kctl->put(kctl, uctl);
+       kfree(uctl);
+}
+
 /* unsolicited event for HP jack sensing */
 static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
 {
+       int action;
+
        if (codec->vendor_id == 0x10ec0880)
                res >>= 28;
        else
                res >>= 26;
-       res = snd_hda_jack_get_action(codec, res);
-       alc_exec_unsol_event(codec, res);
+       action = snd_hda_jack_get_action(codec, res);
+       if (action == ALC_DCVOL_EVENT) {
+               /* Execute the dc-vol event here as it requires the NID
+                * but we don't pass NID to alc_exec_unsol_event().
+                * Once when we convert all static quirks to the auto-parser,
+                * this can be integerated into there.
+                */
+               struct hda_jack_tbl *jack;
+               jack = snd_hda_jack_tbl_get_from_tag(codec, res);
+               if (jack)
+                       alc_update_knob_master(codec, jack->nid);
+               return;
+       }
+       alc_exec_unsol_event(codec, action);
 }
 
 /* call init functions of standard auto-mute helpers */
@@ -1033,45 +1072,6 @@ static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
        return true;
 }
 
-/* rebuild imux for matching with the given auto-mic pins (if not yet) */
-static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct hda_input_mux *imux;
-       static char * const texts[3] = {
-               "Mic", "Internal Mic", "Dock Mic"
-       };
-       int i;
-
-       if (!spec->auto_mic)
-               return false;
-       imux = &spec->private_imux[0];
-       if (spec->input_mux == imux)
-               return true;
-       spec->imux_pins[0] = spec->ext_mic_pin;
-       spec->imux_pins[1] = spec->int_mic_pin;
-       spec->imux_pins[2] = spec->dock_mic_pin;
-       for (i = 0; i < 3; i++) {
-               strcpy(imux->items[i].label, texts[i]);
-               if (spec->imux_pins[i]) {
-                       hda_nid_t pin = spec->imux_pins[i];
-                       int c;
-                       for (c = 0; c < spec->num_adc_nids; c++) {
-                               hda_nid_t cap = get_capsrc(spec, c);
-                               int idx = get_connection_index(codec, cap, pin);
-                               if (idx >= 0) {
-                                       imux->items[i].index = idx;
-                                       break;
-                               }
-                       }
-                       imux->num_items = i + 1;
-               }
-       }
-       spec->num_mux_defs = 1;
-       spec->input_mux = imux;
-       return true;
-}
-
 /* check whether all auto-mic pins are valid; setup indices if OK */
 static bool alc_auto_mic_check_imux(struct hda_codec *codec)
 {
@@ -1520,6 +1520,13 @@ static void alc_pick_fixup(struct hda_codec *codec,
        int id = -1;
        const char *name = NULL;
 
+       /* when model=nofixup is given, don't pick up any fixups */
+       if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
+               spec->fixup_list = NULL;
+               spec->fixup_id = -1;
+               return;
+       }
+
        if (codec->modelname && models) {
                while (models->name) {
                        if (!strcmp(codec->modelname, models->name)) {
@@ -1847,36 +1854,10 @@ DEFINE_CAPMIX_NOSRC(3);
 /*
  * slave controls for virtual master
  */
-static const char * const alc_slave_vols[] = {
-       "Front Playback Volume",
-       "Surround Playback Volume",
-       "Center Playback Volume",
-       "LFE Playback Volume",
-       "Side Playback Volume",
-       "Headphone Playback Volume",
-       "Speaker Playback Volume",
-       "Mono Playback Volume",
-       "Line Out Playback Volume",
-       "CLFE Playback Volume",
-       "Bass Speaker Playback Volume",
-       "PCM Playback Volume",
-       NULL,
-};
-
-static const char * const alc_slave_sws[] = {
-       "Front Playback Switch",
-       "Surround Playback Switch",
-       "Center Playback Switch",
-       "LFE Playback Switch",
-       "Side Playback Switch",
-       "Headphone Playback Switch",
-       "Speaker Playback Switch",
-       "Mono Playback Switch",
-       "IEC958 Playback Switch",
-       "Line Out Playback Switch",
-       "CLFE Playback Switch",
-       "Bass Speaker Playback Switch",
-       "PCM Playback Switch",
+static const char * const alc_slave_pfxs[] = {
+       "Front", "Surround", "Center", "LFE", "Side",
+       "Headphone", "Speaker", "Mono", "Line Out",
+       "CLFE", "Bass Speaker", "PCM",
        NULL,
 };
 
@@ -1967,14 +1948,16 @@ static int __alc_build_controls(struct hda_codec *codec)
                snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
                                        HDA_OUTPUT, vmaster_tlv);
                err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-                                         vmaster_tlv, alc_slave_vols);
+                                         vmaster_tlv, alc_slave_pfxs,
+                                         "Playback Volume");
                if (err < 0)
                        return err;
        }
        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);
+                                         NULL, alc_slave_pfxs,
+                                         "Playback Switch");
                if (err < 0)
                        return err;
        }
@@ -2068,6 +2051,7 @@ static int alc_build_controls(struct hda_codec *codec)
  */
 
 static void alc_init_special_input_src(struct hda_codec *codec);
+static void alc_auto_init_std(struct hda_codec *codec);
 static int alc269_fill_coef(struct hda_codec *codec);
 
 static int alc_init(struct hda_codec *codec)
@@ -2084,6 +2068,7 @@ static int alc_init(struct hda_codec *codec)
        for (i = 0; i < spec->num_init_verbs; i++)
                snd_hda_sequence_write(codec, spec->init_verbs[i]);
        alc_init_special_input_src(codec);
+       alc_auto_init_std(codec);
 
        if (spec->init_hook)
                spec->init_hook(codec);
@@ -2675,6 +2660,25 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
        return channel_name[ch];
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+/* add the powersave loopback-list entry */
+static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx)
+{
+       struct hda_amp_list *list;
+
+       if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1)
+               return;
+       list = spec->loopback_list + spec->num_loopbacks;
+       list->nid = mix;
+       list->dir = HDA_INPUT;
+       list->idx = idx;
+       spec->num_loopbacks++;
+       spec->loopback.amplist = spec->loopback_list;
+}
+#else
+#define add_loopback_list(spec, mix, idx) /* NOP */
+#endif
+
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
                            const char *ctlname, int ctlidx,
@@ -2690,6 +2694,7 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
+       add_loopback_list(spec, mix_nid, idx);
        return 0;
 }
 
@@ -2954,10 +2959,27 @@ static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
        return 0;
 }
 
+static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct alc_spec *spec = codec->spec;
+       int i;
+       if (found_in_nid_list(nid, spec->multiout.dac_nids,
+                             ARRAY_SIZE(spec->private_dac_nids)) ||
+           found_in_nid_list(nid, spec->multiout.hp_out_nid,
+                             ARRAY_SIZE(spec->multiout.hp_out_nid)) ||
+           found_in_nid_list(nid, spec->multiout.extra_out_nid,
+                             ARRAY_SIZE(spec->multiout.extra_out_nid)))
+               return true;
+       for (i = 0; i < spec->multi_ios; i++) {
+               if (spec->multi_io[i].dac == nid)
+                       return true;
+       }
+       return false;
+}
+
 /* look for an empty DAC slot */
 static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
 {
-       struct alc_spec *spec = codec->spec;
        hda_nid_t srcs[5];
        int i, num;
 
@@ -2967,16 +2989,8 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
                hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
                if (!nid)
                        continue;
-               if (found_in_nid_list(nid, spec->multiout.dac_nids,
-                                     ARRAY_SIZE(spec->private_dac_nids)))
-                       continue;
-               if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
-                                     ARRAY_SIZE(spec->multiout.hp_out_nid)))
-                   continue;
-               if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
-                                     ARRAY_SIZE(spec->multiout.extra_out_nid)))
-                   continue;
-               return nid;
+               if (!alc_is_dac_already_used(codec, nid))
+                       return nid;
        }
        return 0;
 }
@@ -2988,6 +3002,8 @@ static bool alc_auto_is_dac_reachable(struct hda_codec *codec,
        hda_nid_t srcs[5];
        int i, num;
 
+       if (!pin || !dac)
+               return false;
        pin = alc_go_down_to_selector(codec, pin);
        num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
        for (i = 0; i < num; i++) {
@@ -3000,83 +3016,260 @@ static bool alc_auto_is_dac_reachable(struct hda_codec *codec,
 
 static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
 {
+       struct alc_spec *spec = codec->spec;
        hda_nid_t sel = alc_go_down_to_selector(codec, pin);
-       if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
+       hda_nid_t nid, nid_found, srcs[5];
+       int i, num = snd_hda_get_connections(codec, sel, srcs,
+                                         ARRAY_SIZE(srcs));
+       if (num == 1)
                return alc_auto_look_for_dac(codec, pin);
-       return 0;
+       nid_found = 0;
+       for (i = 0; i < num; i++) {
+               if (srcs[i] == spec->mixer_nid)
+                       continue;
+               nid = alc_auto_mix_to_dac(codec, srcs[i]);
+               if (nid && !alc_is_dac_already_used(codec, nid)) {
+                       if (nid_found)
+                               return 0;
+                       nid_found = nid;
+               }
+       }
+       return nid_found;
 }
 
-/* return 0 if no possible DAC is found, 1 if one or more found */
-static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
-                                   const hda_nid_t *pins, hda_nid_t *dacs)
+/* mark up volume and mute control NIDs: used during badness parsing and
+ * at creating actual controls
+ */
+static inline unsigned int get_ctl_pos(unsigned int data)
 {
-       int i;
+       hda_nid_t nid = get_amp_nid_(data);
+       unsigned int dir;
+       if (snd_BUG_ON(nid >= MAX_VOL_NIDS))
+               return 0;
+       dir = get_amp_direction_(data);
+       return (nid << 1) | dir;
+}
 
-       if (num_outs && !dacs[0]) {
-               dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
-               if (!dacs[0])
-                       return 0;
-       }
+#define is_ctl_used(bits, data) \
+       test_bit(get_ctl_pos(data), bits)
+#define mark_ctl_usage(bits, data) \
+       set_bit(get_ctl_pos(data), bits)
 
-       for (i = 1; i < num_outs; i++)
-               dacs[i] = get_dac_if_single(codec, pins[i]);
-       for (i = 1; i < num_outs; i++) {
+static void clear_vol_marks(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       memset(spec->vol_ctls, 0, sizeof(spec->vol_ctls));
+       memset(spec->sw_ctls, 0, sizeof(spec->sw_ctls));
+}
+
+/* badness definition */
+enum {
+       /* No primary DAC is found for the main output */
+       BAD_NO_PRIMARY_DAC = 0x10000,
+       /* No DAC is found for the extra output */
+       BAD_NO_DAC = 0x4000,
+       /* No possible multi-ios */
+       BAD_MULTI_IO = 0x103,
+       /* No individual DAC for extra output */
+       BAD_NO_EXTRA_DAC = 0x102,
+       /* No individual DAC for extra surrounds */
+       BAD_NO_EXTRA_SURR_DAC = 0x101,
+       /* Primary DAC shared with main surrounds */
+       BAD_SHARED_SURROUND = 0x100,
+       /* Primary DAC shared with main CLFE */
+       BAD_SHARED_CLFE = 0x10,
+       /* Primary DAC shared with extra surrounds */
+       BAD_SHARED_EXTRA_SURROUND = 0x10,
+       /* Volume widget is shared */
+       BAD_SHARED_VOL = 0x10,
+};
+
+static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
+                                          hda_nid_t pin, hda_nid_t dac);
+static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
+                                         hda_nid_t pin, hda_nid_t dac);
+
+static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin,
+                                  hda_nid_t dac)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t nid;
+       unsigned int val;
+       int badness = 0;
+
+       nid = alc_look_for_out_vol_nid(codec, pin, dac);
+       if (nid) {
+               val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+               if (is_ctl_used(spec->vol_ctls, nid))
+                       badness += BAD_SHARED_VOL;
+               else
+                       mark_ctl_usage(spec->vol_ctls, val);
+       } else
+               badness += BAD_SHARED_VOL;
+       nid = alc_look_for_out_mute_nid(codec, pin, dac);
+       if (nid) {
+               unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
+               if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT)
+                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+               else
+                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
+               if (is_ctl_used(spec->sw_ctls, val))
+                       badness += BAD_SHARED_VOL;
+               else
+                       mark_ctl_usage(spec->sw_ctls, val);
+       } else
+               badness += BAD_SHARED_VOL;
+       return badness;
+}
+
+struct badness_table {
+       int no_primary_dac;     /* no primary DAC */
+       int no_dac;             /* no secondary DACs */
+       int shared_primary;     /* primary DAC is shared with main output */
+       int shared_surr;        /* secondary DAC shared with main or primary */
+       int shared_clfe;        /* third DAC shared with main or primary */
+       int shared_surr_main;   /* secondary DAC sahred with main/DAC0 */
+};
+
+static struct badness_table main_out_badness = {
+       .no_primary_dac = BAD_NO_PRIMARY_DAC,
+       .no_dac = BAD_NO_DAC,
+       .shared_primary = BAD_NO_PRIMARY_DAC,
+       .shared_surr = BAD_SHARED_SURROUND,
+       .shared_clfe = BAD_SHARED_CLFE,
+       .shared_surr_main = BAD_SHARED_SURROUND,
+};
+
+static struct badness_table extra_out_badness = {
+       .no_primary_dac = BAD_NO_DAC,
+       .no_dac = BAD_NO_DAC,
+       .shared_primary = BAD_NO_EXTRA_DAC,
+       .shared_surr = BAD_SHARED_EXTRA_SURROUND,
+       .shared_clfe = BAD_SHARED_EXTRA_SURROUND,
+       .shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
+};
+
+/* try to assign DACs to pins and return the resultant badness */
+static int alc_auto_fill_dacs(struct hda_codec *codec, int num_outs,
+                             const hda_nid_t *pins, hda_nid_t *dacs,
+                             const struct badness_table *bad)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, j;
+       int badness = 0;
+       hda_nid_t dac;
+
+       if (!num_outs)
+               return 0;
+
+       for (i = 0; i < num_outs; i++) {
+               hda_nid_t pin = pins[i];
                if (!dacs[i])
-                       dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
+                       dacs[i] = alc_auto_look_for_dac(codec, pin);
+               if (!dacs[i] && !i) {
+                       for (j = 1; j < num_outs; j++) {
+                               if (alc_auto_is_dac_reachable(codec, pin, dacs[j])) {
+                                       dacs[0] = dacs[j];
+                                       dacs[j] = 0;
+                                       break;
+                               }
+                       }
+               }
+               dac = dacs[i];
+               if (!dac) {
+                       if (alc_auto_is_dac_reachable(codec, pin, dacs[0]))
+                               dac = dacs[0];
+                       else if (cfg->line_outs > i &&
+                                alc_auto_is_dac_reachable(codec, pin,
+                                       spec->private_dac_nids[i]))
+                               dac = spec->private_dac_nids[i];
+                       if (dac) {
+                               if (!i)
+                                       badness += bad->shared_primary;
+                               else if (i == 1)
+                                       badness += bad->shared_surr;
+                               else
+                                       badness += bad->shared_clfe;
+                       } else if (alc_auto_is_dac_reachable(codec, pin,
+                                       spec->private_dac_nids[0])) {
+                               dac = spec->private_dac_nids[0];
+                               badness += bad->shared_surr_main;
+                       } else if (!i)
+                               badness += bad->no_primary_dac;
+                       else
+                               badness += bad->no_dac;
+               }
+               if (dac)
+                       badness += eval_shared_vol_badness(codec, pin, dac);
        }
-       return 1;
+
+       return badness;
 }
 
 static int alc_auto_fill_multi_ios(struct hda_codec *codec,
-                                  unsigned int location, int offset);
-static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
-                                         hda_nid_t pin, hda_nid_t dac);
+                                  hda_nid_t reference_pin,
+                                  bool hardwired, int offset);
+
+static bool alc_map_singles(struct hda_codec *codec, int outs,
+                           const hda_nid_t *pins, hda_nid_t *dacs)
+{
+       int i;
+       bool found = false;
+       for (i = 0; i < outs; i++) {
+               if (dacs[i])
+                       continue;
+               dacs[i] = get_dac_if_single(codec, pins[i]);
+               if (dacs[i])
+                       found = true;
+       }
+       return found;
+}
 
 /* fill in the dac_nids table from the parsed pin configuration */
-static int alc_auto_fill_dac_nids(struct hda_codec *codec)
+static int fill_and_eval_dacs(struct hda_codec *codec,
+                             bool fill_hardwired,
+                             bool fill_mio_first)
 {
        struct alc_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int location, defcfg;
-       int num_pins;
-       bool redone = false;
-       int i;
+       int i, err, badness;
 
- again:
        /* set num_dacs once to full for alc_auto_look_for_dac() */
        spec->multiout.num_dacs = cfg->line_outs;
-       spec->multiout.hp_out_nid[0] = 0;
-       spec->multiout.extra_out_nid[0] = 0;
-       memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
        spec->multiout.dac_nids = spec->private_dac_nids;
+       memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
+       memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
+       memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
        spec->multi_ios = 0;
+       clear_vol_marks(codec);
+       badness = 0;
 
        /* fill hard-wired DACs first */
-       if (!redone) {
-               for (i = 0; i < cfg->line_outs; i++)
-                       spec->private_dac_nids[i] =
-                               get_dac_if_single(codec, cfg->line_out_pins[i]);
-               if (cfg->hp_outs)
-                       spec->multiout.hp_out_nid[0] =
-                               get_dac_if_single(codec, cfg->hp_pins[0]);
-               if (cfg->speaker_outs)
-                       spec->multiout.extra_out_nid[0] =
-                               get_dac_if_single(codec, cfg->speaker_pins[0]);
+       if (fill_hardwired) {
+               bool mapped;
+               do {
+                       mapped = alc_map_singles(codec, cfg->line_outs,
+                                                cfg->line_out_pins,
+                                                spec->private_dac_nids);
+                       mapped |= alc_map_singles(codec, cfg->hp_outs,
+                                                 cfg->hp_pins,
+                                                 spec->multiout.hp_out_nid);
+                       mapped |= alc_map_singles(codec, cfg->speaker_outs,
+                                                 cfg->speaker_pins,
+                                                 spec->multiout.extra_out_nid);
+                       if (fill_mio_first && cfg->line_outs == 1 &&
+                           cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+                               err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0);
+                               if (!err)
+                                       mapped = true;
+                       }
+               } while (mapped);
        }
 
-       for (i = 0; i < cfg->line_outs; i++) {
-               hda_nid_t pin = cfg->line_out_pins[i];
-               if (spec->private_dac_nids[i])
-                       continue;
-               spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
-               if (!spec->private_dac_nids[i] && !redone) {
-                       /* if we can't find primary DACs, re-probe without
-                        * checking the hard-wired DACs
-                        */
-                       redone = true;
-                       goto again;
-               }
-       }
+       badness += alc_auto_fill_dacs(codec, cfg->line_outs, cfg->line_out_pins,
+                                     spec->private_dac_nids,
+                                     &main_out_badness);
 
        /* re-count num_dacs and squash invalid entries */
        spec->multiout.num_dacs = 0;
@@ -3091,30 +3284,144 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
 
-       if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+       if (fill_mio_first &&
+           cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
                /* try to fill multi-io first */
-               defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
-               location = get_defcfg_location(defcfg);
-
-               num_pins = alc_auto_fill_multi_ios(codec, location, 0);
-               if (num_pins > 0) {
-                       spec->multi_ios = num_pins;
-                       spec->ext_channel_count = 2;
-                       spec->multiout.num_dacs = num_pins + 1;
-               }
+               err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
+               if (err < 0)
+                       return err;
+               /* we don't count badness at this stage yet */
        }
 
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-               alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
-                                spec->multiout.hp_out_nid);
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+               err = alc_auto_fill_dacs(codec, cfg->hp_outs, cfg->hp_pins,
+                                        spec->multiout.hp_out_nid,
+                                        &extra_out_badness);
+               if (err < 0)
+                       return err;
+               badness += err;
+       }
        if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-               int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs,
-                                       cfg->speaker_pins,
-                                       spec->multiout.extra_out_nid);
-               /* if no speaker volume is assigned, try again as the primary
-                * output
-                */
-               if (!err && cfg->speaker_outs > 0 &&
+               err = alc_auto_fill_dacs(codec, cfg->speaker_outs,
+                                        cfg->speaker_pins,
+                                        spec->multiout.extra_out_nid,
+                                        &extra_out_badness);
+               if (err < 0)
+                       return err;
+               badness += err;
+       }
+       if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
+               if (err < 0)
+                       return err;
+               badness += err;
+       }
+       if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+               /* try multi-ios with HP + inputs */
+               int offset = 0;
+               if (cfg->line_outs >= 3)
+                       offset = 1;
+               err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false,
+                                             offset);
+               if (err < 0)
+                       return err;
+               badness += err;
+       }
+
+       if (spec->multi_ios == 2) {
+               for (i = 0; i < 2; i++)
+                       spec->private_dac_nids[spec->multiout.num_dacs++] =
+                               spec->multi_io[i].dac;
+               spec->ext_channel_count = 2;
+       } else if (spec->multi_ios) {
+               spec->multi_ios = 0;
+               badness += BAD_MULTI_IO;
+       }
+
+       return badness;
+}
+
+#define DEBUG_BADNESS
+
+#ifdef DEBUG_BADNESS
+#define debug_badness  snd_printdd
+#else
+#define debug_badness(...)
+#endif
+
+static void debug_show_configs(struct alc_spec *spec, struct auto_pin_cfg *cfg)
+{
+       debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+                     cfg->line_out_pins[0], cfg->line_out_pins[1],
+                     cfg->line_out_pins[2], cfg->line_out_pins[2],
+                     spec->multiout.dac_nids[0],
+                     spec->multiout.dac_nids[1],
+                     spec->multiout.dac_nids[2],
+                     spec->multiout.dac_nids[3]);
+       if (spec->multi_ios > 0)
+               debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
+                             spec->multi_ios,
+                             spec->multi_io[0].pin, spec->multi_io[1].pin,
+                             spec->multi_io[0].dac, spec->multi_io[1].dac);
+       debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+                     cfg->hp_pins[0], cfg->hp_pins[1],
+                     cfg->hp_pins[2], cfg->hp_pins[2],
+                     spec->multiout.hp_out_nid[0],
+                     spec->multiout.hp_out_nid[1],
+                     spec->multiout.hp_out_nid[2],
+                     spec->multiout.hp_out_nid[3]);
+       debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+                     cfg->speaker_pins[0], cfg->speaker_pins[1],
+                     cfg->speaker_pins[2], cfg->speaker_pins[3],
+                     spec->multiout.extra_out_nid[0],
+                     spec->multiout.extra_out_nid[1],
+                     spec->multiout.extra_out_nid[2],
+                     spec->multiout.extra_out_nid[3]);
+}
+
+static int alc_auto_fill_dac_nids(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct auto_pin_cfg *best_cfg;
+       int best_badness = INT_MAX;
+       int badness;
+       bool fill_hardwired = true, fill_mio_first = true;
+       bool best_wired = true, best_mio = true;
+       bool hp_spk_swapped = false;
+
+       best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
+       if (!best_cfg)
+               return -ENOMEM;
+       *best_cfg = *cfg;
+
+       for (;;) {
+               badness = fill_and_eval_dacs(codec, fill_hardwired,
+                                            fill_mio_first);
+               if (badness < 0)
+                       return badness;
+               debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
+                             cfg->line_out_type, fill_hardwired, fill_mio_first,
+                             badness);
+               debug_show_configs(spec, cfg);
+               if (badness < best_badness) {
+                       best_badness = badness;
+                       *best_cfg = *cfg;
+                       best_wired = fill_hardwired;
+                       best_mio = fill_mio_first;
+               }
+               if (!badness)
+                       break;
+               fill_mio_first = !fill_mio_first;
+               if (!fill_mio_first)
+                       continue;
+               fill_hardwired = !fill_hardwired;
+               if (!fill_hardwired)
+                       continue;
+               if (hp_spk_swapped)
+                       break;
+               hp_spk_swapped = true;
+               if (cfg->speaker_outs > 0 &&
                    cfg->line_out_type == AUTO_PIN_HP_OUT) {
                        cfg->hp_outs = cfg->line_outs;
                        memcpy(cfg->hp_pins, cfg->line_out_pins,
@@ -3125,48 +3432,45 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
                        cfg->speaker_outs = 0;
                        memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
                        cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
-                       redone = false;
-                       goto again;
-               }
+                       fill_hardwired = true;
+                       continue;
+               } 
+               if (cfg->hp_outs > 0 &&
+                   cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+                       cfg->speaker_outs = cfg->line_outs;
+                       memcpy(cfg->speaker_pins, cfg->line_out_pins,
+                              sizeof(cfg->speaker_pins));
+                       cfg->line_outs = cfg->hp_outs;
+                       memcpy(cfg->line_out_pins, cfg->hp_pins,
+                              sizeof(cfg->hp_pins));
+                       cfg->hp_outs = 0;
+                       memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+                       cfg->line_out_type = AUTO_PIN_HP_OUT;
+                       fill_hardwired = true;
+                       continue;
+               } 
+               break;
        }
 
-       if (!spec->multi_ios &&
-           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
-           cfg->hp_outs) {
-               /* try multi-ios with HP + inputs */
-               defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]);
-               location = get_defcfg_location(defcfg);
-
-               num_pins = alc_auto_fill_multi_ios(codec, location, 1);
-               if (num_pins > 0) {
-                       spec->multi_ios = num_pins;
-                       spec->ext_channel_count = 2;
-                       spec->multiout.num_dacs = num_pins + 1;
-               }
+       if (badness) {
+               *cfg = *best_cfg;
+               fill_and_eval_dacs(codec, best_wired, best_mio);
        }
+       debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
+                     cfg->line_out_type, best_wired, best_mio);
+       debug_show_configs(spec, cfg);
 
        if (cfg->line_out_pins[0])
                spec->vmaster_nid =
                        alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0],
                                                 spec->multiout.dac_nids[0]);
-       return 0;
-}
 
-static inline unsigned int get_ctl_pos(unsigned int data)
-{
-       hda_nid_t nid = get_amp_nid_(data);
-       unsigned int dir;
-       if (snd_BUG_ON(nid >= MAX_VOL_NIDS))
-               return 0;
-       dir = get_amp_direction_(data);
-       return (nid << 1) | dir;
+       /* clear the bitmap flags for creating controls */
+       clear_vol_marks(codec);
+       kfree(best_cfg);
+       return 0;
 }
 
-#define is_ctl_used(bits, data) \
-       test_bit(get_ctl_pos(data), bits)
-#define mark_ctl_usage(bits, data) \
-       set_bit(get_ctl_pos(data), bits)
-
 static int alc_auto_add_vol_ctl(struct hda_codec *codec,
                              const char *pfx, int cidx,
                              hda_nid_t nid, unsigned int chs)
@@ -3278,14 +3582,17 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
                dac = spec->multiout.dac_nids[i];
                if (!dac)
                        continue;
-               if (i >= cfg->line_outs)
+               if (i >= cfg->line_outs) {
                        pin = spec->multi_io[i - 1].pin;
-               else
+                       index = 0;
+                       name = channel_name[i];
+               } else {
                        pin = cfg->line_out_pins[i];
+                       name = alc_get_line_out_pfx(spec, i, true, &index);
+               }
 
                sw = alc_look_for_out_mute_nid(codec, pin, dac);
                vol = alc_look_for_out_vol_nid(codec, pin, dac);
-               name = alc_get_line_out_pfx(spec, i, true, &index);
                if (!name || !strcmp(name, "CLFE")) {
                        /* Center/LFE */
                        err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1);
@@ -3382,41 +3689,31 @@ static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
                return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0);
        }
 
-       if (dacs[num_pins - 1]) {
-               /* OK, we have a multi-output system with individual volumes */
-               for (i = 0; i < num_pins; i++) {
-                       if (num_pins >= 3) {
-                               snprintf(name, sizeof(name), "%s %s",
-                                        pfx, channel_name[i]);
-                               err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
-                                                               name, 0);
-                       } else {
-                               err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
-                                                               pfx, i);
-                       }
-                       if (err < 0)
-                               return err;
-               }
-               return 0;
-       }
-
-       /* Let's create a bind-controls */
-       ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw);
-       if (!ctl)
-               return -ENOMEM;
-       n = 0;
        for (i = 0; i < num_pins; i++) {
-               if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP)
-                       ctl->values[n++] =
-                               HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT);
-       }
-       if (n) {
-               snprintf(name, sizeof(name), "%s Playback Switch", pfx);
-               err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl);
+               hda_nid_t dac;
+               if (dacs[num_pins - 1])
+                       dac = dacs[i]; /* with individual volumes */
+               else
+                       dac = 0;
+               if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) {
+                       err = alc_auto_create_extra_out(codec, pins[i], dac,
+                                                       "Bass Speaker", 0);
+               } else if (num_pins >= 3) {
+                       snprintf(name, sizeof(name), "%s %s",
+                                pfx, channel_name[i]);
+                       err = alc_auto_create_extra_out(codec, pins[i], dac,
+                                                       name, 0);
+               } else {
+                       err = alc_auto_create_extra_out(codec, pins[i], dac,
+                                                       pfx, i);
+               }
                if (err < 0)
                        return err;
        }
+       if (dacs[num_pins - 1])
+               return 0;
 
+       /* Let's create a bind-controls for volumes */
        ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
        if (!ctl)
                return -ENOMEM;
@@ -3552,58 +3849,111 @@ static void alc_auto_init_extra_out(struct hda_codec *codec)
        }
 }
 
+/* check whether the given pin can be a multi-io pin */
+static bool can_be_multiio_pin(struct hda_codec *codec,
+                              unsigned int location, hda_nid_t nid)
+{
+       unsigned int defcfg, caps;
+
+       defcfg = snd_hda_codec_get_pincfg(codec, nid);
+       if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+               return false;
+       if (location && get_defcfg_location(defcfg) != location)
+               return false;
+       caps = snd_hda_query_pin_caps(codec, nid);
+       if (!(caps & AC_PINCAP_OUT))
+               return false;
+       return true;
+}
+
 /*
  * multi-io helper
+ *
+ * When hardwired is set, try to fill ony hardwired pins, and returns
+ * zero if any pins are filled, non-zero if nothing found.
+ * When hardwired is off, try to fill possible input pins, and returns
+ * the badness value.
  */
 static int alc_auto_fill_multi_ios(struct hda_codec *codec,
-                                  unsigned int location,
-                                  int offset)
+                                  hda_nid_t reference_pin,
+                                  bool hardwired, int offset)
 {
        struct alc_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t prime_dac = spec->private_dac_nids[0];
-       int type, i, dacs, num_pins = 0;
+       int type, i, j, dacs, num_pins, old_pins;
+       unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
+       unsigned int location = get_defcfg_location(defcfg);
+       int badness = 0;
+
+       old_pins = spec->multi_ios;
+       if (old_pins >= 2)
+               goto end_fill;
+
+       num_pins = 0;
+       for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+               for (i = 0; i < cfg->num_inputs; i++) {
+                       if (cfg->inputs[i].type != type)
+                               continue;
+                       if (can_be_multiio_pin(codec, location,
+                                              cfg->inputs[i].pin))
+                               num_pins++;
+               }
+       }
+       if (num_pins < 2)
+               goto end_fill;
 
        dacs = spec->multiout.num_dacs;
        for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
                for (i = 0; i < cfg->num_inputs; i++) {
                        hda_nid_t nid = cfg->inputs[i].pin;
                        hda_nid_t dac = 0;
-                       unsigned int defcfg, caps;
+
                        if (cfg->inputs[i].type != type)
                                continue;
-                       defcfg = snd_hda_codec_get_pincfg(codec, nid);
-                       if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+                       if (!can_be_multiio_pin(codec, location, nid))
                                continue;
-                       if (location && get_defcfg_location(defcfg) != location)
-                               continue;
-                       caps = snd_hda_query_pin_caps(codec, nid);
-                       if (!(caps & AC_PINCAP_OUT))
+                       for (j = 0; j < spec->multi_ios; j++) {
+                               if (nid == spec->multi_io[j].pin)
+                                       break;
+                       }
+                       if (j < spec->multi_ios)
                                continue;
-                       if (offset && offset + num_pins < dacs) {
-                               dac = spec->private_dac_nids[offset + num_pins];
+
+                       if (offset && offset + spec->multi_ios < dacs) {
+                               dac = spec->private_dac_nids[offset + spec->multi_ios];
                                if (!alc_auto_is_dac_reachable(codec, nid, dac))
                                        dac = 0;
                        }
-                       if (!dac)
+                       if (hardwired)
+                               dac = get_dac_if_single(codec, nid);
+                       else if (!dac)
                                dac = alc_auto_look_for_dac(codec, nid);
-                       if (!dac)
+                       if (!dac) {
+                               badness++;
                                continue;
-                       spec->multi_io[num_pins].pin = nid;
-                       spec->multi_io[num_pins].dac = dac;
-                       num_pins++;
-                       spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+                       }
+                       spec->multi_io[spec->multi_ios].pin = nid;
+                       spec->multi_io[spec->multi_ios].dac = dac;
+                       spec->multi_ios++;
+                       if (spec->multi_ios >= 2)
+                               break;
                }
        }
-       spec->multiout.num_dacs = dacs;
-       if (num_pins < 2) {
-               /* clear up again */
-               memset(spec->private_dac_nids + dacs, 0,
-                      sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs));
-               spec->private_dac_nids[0] = prime_dac;
-               return 0;
+ end_fill:
+       if (badness)
+               badness = BAD_MULTI_IO;
+       if (old_pins == spec->multi_ios) {
+               if (hardwired)
+                       return 1; /* nothing found */
+               else
+                       return badness; /* no badness if nothing found */
        }
-       return num_pins;
+       if (!hardwired && spec->multi_ios < 2) {
+               spec->multi_ios = old_pins;
+               return badness;
+       }
+
+       return 0;
 }
 
 static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
@@ -3958,6 +4308,7 @@ static const struct snd_pci_quirk beep_white_list[] = {
        SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
        SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
        SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
+       SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
        SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
        {}
 };
@@ -4057,6 +4408,9 @@ static int alc_parse_auto_config(struct hda_codec *codec,
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
+
        return 1;
 }
 
@@ -4067,26 +4421,47 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
        return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc880_loopbacks[] = {
-       { 0x0b, HDA_INPUT, 0 },
-       { 0x0b, HDA_INPUT, 1 },
-       { 0x0b, HDA_INPUT, 2 },
-       { 0x0b, HDA_INPUT, 3 },
-       { 0x0b, HDA_INPUT, 4 },
-       { } /* end */
-};
-#endif
-
 /*
  * ALC880 fix-ups
  */
 enum {
+       ALC880_FIXUP_GPIO1,
        ALC880_FIXUP_GPIO2,
        ALC880_FIXUP_MEDION_RIM,
+       ALC880_FIXUP_LG,
+       ALC880_FIXUP_W810,
+       ALC880_FIXUP_EAPD_COEF,
+       ALC880_FIXUP_TCL_S700,
+       ALC880_FIXUP_VOL_KNOB,
+       ALC880_FIXUP_FUJITSU,
+       ALC880_FIXUP_F1734,
+       ALC880_FIXUP_UNIWILL,
+       ALC880_FIXUP_UNIWILL_DIG,
+       ALC880_FIXUP_Z71V,
+       ALC880_FIXUP_3ST_BASE,
+       ALC880_FIXUP_3ST,
+       ALC880_FIXUP_3ST_DIG,
+       ALC880_FIXUP_5ST_BASE,
+       ALC880_FIXUP_5ST,
+       ALC880_FIXUP_5ST_DIG,
+       ALC880_FIXUP_6ST_BASE,
+       ALC880_FIXUP_6ST,
+       ALC880_FIXUP_6ST_DIG,
 };
 
+/* enable the volume-knob widget support on NID 0x21 */
+static void alc880_fixup_vol_knob(struct hda_codec *codec,
+                                 const struct alc_fixup *fix, int action)
+{
+       if (action == ALC_FIXUP_ACT_PROBE)
+               snd_hda_jack_detect_enable(codec, 0x21, ALC_DCVOL_EVENT);
+}
+
 static const struct alc_fixup alc880_fixups[] = {
+       [ALC880_FIXUP_GPIO1] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = alc_gpio1_init_verbs,
+       },
        [ALC880_FIXUP_GPIO2] = {
                .type = ALC_FIXUP_VERBS,
                .v.verbs = alc_gpio2_init_verbs,
@@ -4101,40 +4476,323 @@ static const struct alc_fixup alc880_fixups[] = {
                .chained = true,
                .chain_id = ALC880_FIXUP_GPIO2,
        },
+       [ALC880_FIXUP_LG] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       /* disable bogus unused pins */
+                       { 0x16, 0x411111f0 },
+                       { 0x18, 0x411111f0 },
+                       { 0x1a, 0x411111f0 },
+                       { }
+               }
+       },
+       [ALC880_FIXUP_W810] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       /* disable bogus unused pins */
+                       { 0x17, 0x411111f0 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_GPIO2,
+       },
+       [ALC880_FIXUP_EAPD_COEF] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
+                       {}
+               },
+       },
+       [ALC880_FIXUP_TCL_S700] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3070 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_GPIO2,
+       },
+       [ALC880_FIXUP_VOL_KNOB] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc880_fixup_vol_knob,
+       },
+       [ALC880_FIXUP_FUJITSU] = {
+               /* override all pins as BIOS on old Amilo is broken */
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x0121411f }, /* HP */
+                       { 0x15, 0x99030120 }, /* speaker */
+                       { 0x16, 0x99030130 }, /* bass speaker */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x411111f0 }, /* N/A */
+                       { 0x19, 0x01a19950 }, /* mic-in */
+                       { 0x1a, 0x411111f0 }, /* N/A */
+                       { 0x1b, 0x411111f0 }, /* N/A */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x01454140 }, /* SPDIF out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_VOL_KNOB,
+       },
+       [ALC880_FIXUP_F1734] = {
+               /* almost compatible with FUJITSU, but no bass and SPDIF */
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x0121411f }, /* HP */
+                       { 0x15, 0x99030120 }, /* speaker */
+                       { 0x16, 0x411111f0 }, /* N/A */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x411111f0 }, /* N/A */
+                       { 0x19, 0x01a19950 }, /* mic-in */
+                       { 0x1a, 0x411111f0 }, /* N/A */
+                       { 0x1b, 0x411111f0 }, /* N/A */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_VOL_KNOB,
+       },
+       [ALC880_FIXUP_UNIWILL] = {
+               /* need to fix HP and speaker pins to be parsed correctly */
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x0121411f }, /* HP */
+                       { 0x15, 0x99030120 }, /* speaker */
+                       { 0x16, 0x99030130 }, /* bass speaker */
+                       { }
+               },
+       },
+       [ALC880_FIXUP_UNIWILL_DIG] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       /* disable bogus unused pins */
+                       { 0x17, 0x411111f0 },
+                       { 0x19, 0x411111f0 },
+                       { 0x1b, 0x411111f0 },
+                       { 0x1f, 0x411111f0 },
+                       { }
+               }
+       },
+       [ALC880_FIXUP_Z71V] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       /* set up the whole pins as BIOS is utterly broken */
+                       { 0x14, 0x99030120 }, /* speaker */
+                       { 0x15, 0x0121411f }, /* HP */
+                       { 0x16, 0x411111f0 }, /* N/A */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x01a19950 }, /* mic-in */
+                       { 0x19, 0x411111f0 }, /* N/A */
+                       { 0x1a, 0x01813031 }, /* line-in */
+                       { 0x1b, 0x411111f0 }, /* N/A */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x0144111e }, /* SPDIF */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_3ST_BASE] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x01014010 }, /* line-out */
+                       { 0x15, 0x411111f0 }, /* N/A */
+                       { 0x16, 0x411111f0 }, /* N/A */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x01a19c30 }, /* mic-in */
+                       { 0x19, 0x0121411f }, /* HP */
+                       { 0x1a, 0x01813031 }, /* line-in */
+                       { 0x1b, 0x02a19c40 }, /* front-mic */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       /* 0x1e is filled in below */
+                       { 0x1f, 0x411111f0 }, /* N/A */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_3ST] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_3ST_BASE,
+       },
+       [ALC880_FIXUP_3ST_DIG] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x1e, 0x0144111e }, /* SPDIF */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_3ST_BASE,
+       },
+       [ALC880_FIXUP_5ST_BASE] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x01014010 }, /* front */
+                       { 0x15, 0x411111f0 }, /* N/A */
+                       { 0x16, 0x01011411 }, /* CLFE */
+                       { 0x17, 0x01016412 }, /* surr */
+                       { 0x18, 0x01a19c30 }, /* mic-in */
+                       { 0x19, 0x0121411f }, /* HP */
+                       { 0x1a, 0x01813031 }, /* line-in */
+                       { 0x1b, 0x02a19c40 }, /* front-mic */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       /* 0x1e is filled in below */
+                       { 0x1f, 0x411111f0 }, /* N/A */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_5ST] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_5ST_BASE,
+       },
+       [ALC880_FIXUP_5ST_DIG] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x1e, 0x0144111e }, /* SPDIF */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_5ST_BASE,
+       },
+       [ALC880_FIXUP_6ST_BASE] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x01014010 }, /* front */
+                       { 0x15, 0x01016412 }, /* surr */
+                       { 0x16, 0x01011411 }, /* CLFE */
+                       { 0x17, 0x01012414 }, /* side */
+                       { 0x18, 0x01a19c30 }, /* mic-in */
+                       { 0x19, 0x02a19c40 }, /* front-mic */
+                       { 0x1a, 0x01813031 }, /* line-in */
+                       { 0x1b, 0x0121411f }, /* HP */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       /* 0x1e is filled in below */
+                       { 0x1f, 0x411111f0 }, /* N/A */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_6ST] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_6ST_BASE,
+       },
+       [ALC880_FIXUP_6ST_DIG] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x1e, 0x0144111e }, /* SPDIF */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_6ST_BASE,
+       },
 };
 
 static const struct snd_pci_quirk alc880_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
+       SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
+       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
+       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
+       SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
+       SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
+       SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
+       SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
+       SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
        SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
+       SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734),
+       SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
+       SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
+       SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
+       SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
+       SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
+       SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
+       SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
+
+       /* Below is the copied entries from alc880_quirks.c.
+        * It's not quite sure whether BIOS sets the correct pin-config table
+        * on these machines, thus they are kept to be compatible with
+        * the old static quirks.  Once when it's confirmed to work without
+        * these overrides, it'd be better to remove.
+        */
+       SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
+       SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
+       SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
+       SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
+       SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
+       SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
+       SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
+       SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
+       SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       /* default Intel */
+       SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
+       SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
        {}
 };
 
+static const struct alc_model_fixup alc880_fixup_models[] = {
+       {.id = ALC880_FIXUP_3ST, .name = "3stack"},
+       {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
+       {.id = ALC880_FIXUP_5ST, .name = "5stack"},
+       {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
+       {.id = ALC880_FIXUP_6ST, .name = "6stack"},
+       {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
+       {}
+};
 
-/*
- * board setups
- */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#define alc_board_config \
-       snd_hda_check_board_config
-#define alc_board_codec_sid_config \
-       snd_hda_check_board_codec_sid_config
-#include "alc_quirks.c"
-#else
-#define alc_board_config(codec, nums, models, tbl)     -1
-#define alc_board_codec_sid_config(codec, nums, models, tbl)   -1
-#define setup_preset(codec, x) /* NOP */
-#endif
 
 /*
  * OK, here we have finally the patch for ALC880
  */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#include "alc880_quirks.c"
-#endif
-
 static int patch_alc880(struct hda_codec *codec)
 {
        struct alc_spec *spec;
-       int board_config;
        int err;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -4146,47 +4804,14 @@ static int patch_alc880(struct hda_codec *codec)
        spec->mixer_nid = 0x0b;
        spec->need_dac_fix = 1;
 
-       board_config = alc_board_config(codec, ALC880_MODEL_LAST,
-                                       alc880_models, alc880_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = ALC_MODEL_AUTO;
-       }
-
-       if (board_config == ALC_MODEL_AUTO) {
-               alc_pick_fixup(codec, NULL, alc880_fixup_tbl, alc880_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-       }
-
-       if (board_config == ALC_MODEL_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc880_parse_auto_config(codec);
-               if (err < 0)
-                       goto error;
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-               else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using 3-stack mode...\n");
-                       board_config = ALC880_3ST;
-               }
-#endif
-       }
-
-       if (board_config != ALC_MODEL_AUTO) {
-               spec->vmaster_nid = 0x0c;
-               setup_preset(codec, &alc880_presets[board_config]);
-       }
-
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
+       alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
+                      alc880_fixups);
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
 
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
+       /* automatic parse from the BIOS config */
+       err = alc880_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
 
        if (!spec->no_analog) {
                err = snd_hda_attach_beep_device(codec, 0x1);
@@ -4195,17 +4820,9 @@ static int patch_alc880(struct hda_codec *codec)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
        }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc_auto_init_std;
-       else
-               codec->patch_ops.build_controls = __alc_build_controls;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc880_loopbacks;
-#endif
+
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        return 0;
 
@@ -4225,49 +4842,115 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
        return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc260_loopbacks[] = {
-       { 0x07, HDA_INPUT, 0 },
-       { 0x07, HDA_INPUT, 1 },
-       { 0x07, HDA_INPUT, 2 },
-       { 0x07, HDA_INPUT, 3 },
-       { 0x07, HDA_INPUT, 4 },
-       { } /* end */
-};
-#endif
-
 /*
  * Pin config fixes
  */
 enum {
-       PINFIX_HP_DC5750,
+       ALC260_FIXUP_HP_DC5750,
+       ALC260_FIXUP_HP_PIN_0F,
+       ALC260_FIXUP_COEF,
+       ALC260_FIXUP_GPIO1,
+       ALC260_FIXUP_GPIO1_TOGGLE,
+       ALC260_FIXUP_REPLACER,
+       ALC260_FIXUP_HP_B1900,
 };
 
+static void alc260_gpio1_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                           spec->hp_jack_present);
+}
+
+static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
+                                     const struct alc_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == ALC_FIXUP_ACT_PROBE) {
+               /* although the machine has only one output pin, we need to
+                * toggle GPIO1 according to the jack state
+                */
+               spec->automute_hook = alc260_gpio1_automute;
+               spec->detect_hp = 1;
+               spec->automute_speaker = 1;
+               spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
+               snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
+               spec->unsol_event = alc_sku_unsol_event;
+               add_verb(codec->spec, alc_gpio1_init_verbs);
+       }
+}
+
 static const struct alc_fixup alc260_fixups[] = {
-       [PINFIX_HP_DC5750] = {
+       [ALC260_FIXUP_HP_DC5750] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
                        { 0x11, 0x90130110 }, /* speaker */
                        { }
                }
        },
+       [ALC260_FIXUP_HP_PIN_0F] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x0f, 0x01214000 }, /* HP */
+                       { }
+               }
+       },
+       [ALC260_FIXUP_COEF] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3040 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC260_FIXUP_HP_PIN_0F,
+       },
+       [ALC260_FIXUP_GPIO1] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = alc_gpio1_init_verbs,
+       },
+       [ALC260_FIXUP_GPIO1_TOGGLE] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc260_fixup_gpio1_toggle,
+               .chained = true,
+               .chain_id = ALC260_FIXUP_HP_PIN_0F,
+       },
+       [ALC260_FIXUP_REPLACER] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3050 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
+       },
+       [ALC260_FIXUP_HP_B1900] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc260_fixup_gpio1_toggle,
+               .chained = true,
+               .chain_id = ALC260_FIXUP_COEF,
+       }
 };
 
 static const struct snd_pci_quirk alc260_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
+       SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
+       SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
+       SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
+       SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
+       SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
        {}
 };
 
 /*
  */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#include "alc260_quirks.c"
-#endif
-
 static int patch_alc260(struct hda_codec *codec)
 {
        struct alc_spec *spec;
-       int err, board_config;
+       int err;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -4277,47 +4960,13 @@ static int patch_alc260(struct hda_codec *codec)
 
        spec->mixer_nid = 0x07;
 
-       board_config = alc_board_config(codec, ALC260_MODEL_LAST,
-                                       alc260_models, alc260_cfg_tbl);
-       if (board_config < 0) {
-               snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                          codec->chip_name);
-               board_config = ALC_MODEL_AUTO;
-       }
-
-       if (board_config == ALC_MODEL_AUTO) {
-               alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-       }
-
-       if (board_config == ALC_MODEL_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc260_parse_auto_config(codec);
-               if (err < 0)
-                       goto error;
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-               else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                       board_config = ALC260_BASIC;
-               }
-#endif
-       }
-
-       if (board_config != ALC_MODEL_AUTO) {
-               setup_preset(codec, &alc260_presets[board_config]);
-               spec->vmaster_nid = 0x08;
-       }
-
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
+       alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
 
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
+       /* automatic parse from the BIOS config */
+       err = alc260_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
 
        if (!spec->no_analog) {
                err = snd_hda_attach_beep_device(codec, 0x1);
@@ -4326,18 +4975,10 @@ static int patch_alc260(struct hda_codec *codec)
                set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
        }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc_auto_init_std;
-       else
-               codec->patch_ops.build_controls = __alc_build_controls;
        spec->shutup = alc_eapd_shutup;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc260_loopbacks;
-#endif
+
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        return 0;
 
@@ -4358,9 +4999,6 @@ static int patch_alc260(struct hda_codec *codec)
  * In addition, an independent DAC for the multi-playback (not used in this
  * driver yet).
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc882_loopbacks       alc880_loopbacks
-#endif
 
 /*
  * Pin config fixes
@@ -4377,6 +5015,8 @@ enum {
        ALC882_FIXUP_EAPD,
        ALC883_FIXUP_EAPD,
        ALC883_FIXUP_ACER_EAPD,
+       ALC882_FIXUP_GPIO1,
+       ALC882_FIXUP_GPIO2,
        ALC882_FIXUP_GPIO3,
        ALC889_FIXUP_COEF,
        ALC882_FIXUP_ASUS_W2JC,
@@ -4385,6 +5025,8 @@ enum {
        ALC882_FIXUP_ASPIRE_8930G_VERBS,
        ALC885_FIXUP_MACPRO_GPIO,
        ALC889_FIXUP_DAC_ROUTE,
+       ALC889_FIXUP_MBP_VREF,
+       ALC889_FIXUP_IMAC91_VREF,
 };
 
 static void alc889_fixup_coef(struct hda_codec *codec,
@@ -4463,6 +5105,51 @@ static void alc889_fixup_dac_route(struct hda_codec *codec,
        }
 }
 
+/* Set VREF on HP pin */
+static void alc889_fixup_mbp_vref(struct hda_codec *codec,
+                                 const struct alc_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static hda_nid_t nids[2] = { 0x14, 0x15 };
+       int i;
+
+       if (action != ALC_FIXUP_ACT_INIT)
+               return;
+       for (i = 0; i < ARRAY_SIZE(nids); i++) {
+               unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
+               if (get_defcfg_device(val) != AC_JACK_HP_OUT)
+                       continue;
+               val = snd_hda_codec_read(codec, nids[i], 0,
+                                        AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               val |= AC_PINCTL_VREF_80;
+               snd_hda_codec_write(codec, nids[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+               spec->keep_vref_in_automute = 1;
+               break;
+       }
+}
+
+/* Set VREF on speaker pins on imac91 */
+static void alc889_fixup_imac91_vref(struct hda_codec *codec,
+                                    const struct alc_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static hda_nid_t nids[2] = { 0x18, 0x1a };
+       int i;
+
+       if (action != ALC_FIXUP_ACT_INIT)
+               return;
+       for (i = 0; i < ARRAY_SIZE(nids); i++) {
+               unsigned int val;
+               val = snd_hda_codec_read(codec, nids[i], 0,
+                                        AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               val |= AC_PINCTL_VREF_50;
+               snd_hda_codec_write(codec, nids[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+       }
+       spec->keep_vref_in_automute = 1;
+}
+
 static const struct alc_fixup alc882_fixups[] = {
        [ALC882_FIXUP_ABIT_AW9D_MAX] = {
                .type = ALC_FIXUP_PINS,
@@ -4548,6 +5235,14 @@ static const struct alc_fixup alc882_fixups[] = {
                        { }
                }
        },
+       [ALC882_FIXUP_GPIO1] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = alc_gpio1_init_verbs,
+       },
+       [ALC882_FIXUP_GPIO2] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = alc_gpio2_init_verbs,
+       },
        [ALC882_FIXUP_GPIO3] = {
                .type = ALC_FIXUP_VERBS,
                .v.verbs = alc_gpio3_init_verbs,
@@ -4621,6 +5316,18 @@ static const struct alc_fixup alc882_fixups[] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc889_fixup_dac_route,
        },
+       [ALC889_FIXUP_MBP_VREF] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc889_fixup_mbp_vref,
+               .chained = true,
+               .chain_id = ALC882_FIXUP_GPIO1,
+       },
+       [ALC889_FIXUP_IMAC91_VREF] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc889_fixup_imac91_vref,
+               .chained = true,
+               .chain_id = ALC882_FIXUP_GPIO1,
+       },
 };
 
 static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -4654,11 +5361,26 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
 
        /* All Apple entries are in codec SSIDs */
+       SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
        SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO),
        SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
        SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
        SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
        SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF),
 
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
@@ -4684,14 +5406,10 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
 
 /*
  */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#include "alc882_quirks.c"
-#endif
-
 static int patch_alc882(struct hda_codec *codec)
 {
        struct alc_spec *spec;
-       int err, board_config;
+       int err;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -4715,45 +5433,15 @@ static int patch_alc882(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       board_config = alc_board_config(codec, ALC882_MODEL_LAST,
-                                       alc882_models, NULL);
-       if (board_config < 0)
-               board_config = alc_board_codec_sid_config(codec,
-                       ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
-
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = ALC_MODEL_AUTO;
-       }
-
-       if (board_config == ALC_MODEL_AUTO) {
-               alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-       }
+       alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
 
        alc_auto_parse_customize_define(codec);
 
-       if (board_config == ALC_MODEL_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc882_parse_auto_config(codec);
-               if (err < 0)
-                       goto error;
-       }
-
-       if (board_config != ALC_MODEL_AUTO) {
-               setup_preset(codec, &alc882_presets[board_config]);
-               spec->vmaster_nid = 0x0c;
-       }
-
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
-
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
+       /* automatic parse from the BIOS config */
+       err = alc882_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
 
        if (!spec->no_analog && has_cdefine_beep(codec)) {
                err = snd_hda_attach_beep_device(codec, 0x1);
@@ -4762,18 +5450,9 @@ static int patch_alc882(struct hda_codec *codec)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
        }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc_auto_init_std;
-       else
-               codec->patch_ops.build_controls = __alc_build_controls;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc882_loopbacks;
-#endif
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        return 0;
 
@@ -4869,10 +5548,6 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
 };
 
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc262_loopbacks       alc880_loopbacks
-#endif
-
 /*
  */
 static int patch_alc262(struct hda_codec *codec)
@@ -4912,15 +5587,6 @@ static int patch_alc262(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
-
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
-
        if (!spec->no_analog && has_cdefine_beep(codec)) {
                err = snd_hda_attach_beep_device(codec, 0x1);
                if (err < 0)
@@ -4928,16 +5594,10 @@ static int patch_alc262(struct hda_codec *codec)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
        }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
        codec->patch_ops = alc_patch_ops;
-       spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc262_loopbacks;
-#endif
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        return 0;
 
@@ -5031,17 +5691,7 @@ static int patch_alc268(struct hda_codec *codec)
                                          (0 << AC_AMPCAP_MUTE_SHIFT));
        }
 
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
-
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
-
        codec->patch_ops = alc_patch_ops;
-       spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
        return 0;
@@ -5054,10 +5704,6 @@ static int patch_alc268(struct hda_codec *codec)
 /*
  * ALC269
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc269_loopbacks       alc880_loopbacks
-#endif
-
 static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
        .substreams = 1,
        .channels_min = 2,
@@ -5420,7 +6066,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 
-#if 1
+#if 0
        /* Below is a quirk table taken from the old code.
         * Basically the device should work as is without the fixup table.
         * If BIOS doesn't give a proper info, enable the corresponding
@@ -5577,15 +6223,6 @@ static int patch_alc269(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
-
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
-
        if (!spec->no_analog && has_cdefine_beep(codec)) {
                err = snd_hda_attach_beep_device(codec, 0x1);
                if (err < 0)
@@ -5593,22 +6230,19 @@ static int patch_alc269(struct hda_codec *codec)
                set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
        }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
        codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
        codec->patch_ops.resume = alc269_resume;
 #endif
-       spec->init_hook = alc_auto_init_std;
        spec->shutup = alc269_shutup;
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc269_loopbacks;
        if (alc269_mic2_for_mute_led(codec))
                codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
 #endif
 
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+
        return 0;
 
  error:
@@ -5627,21 +6261,12 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc861_loopbacks[] = {
-       { 0x15, HDA_INPUT, 0 },
-       { 0x15, HDA_INPUT, 1 },
-       { 0x15, HDA_INPUT, 2 },
-       { 0x15, HDA_INPUT, 3 },
-       { } /* end */
-};
-#endif
-
-
 /* Pin config fixes */
 enum {
-       PINFIX_FSC_AMILO_PI1505,
-       PINFIX_ASUS_A6RP,
+       ALC861_FIXUP_FSC_AMILO_PI1505,
+       ALC861_FIXUP_AMP_VREF_0F,
+       ALC861_FIXUP_NO_JACK_DETECT,
+       ALC861_FIXUP_ASUS_A6RP,
 };
 
 /* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
@@ -5663,8 +6288,16 @@ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
        spec->keep_vref_in_automute = 1;
 }
 
+/* suppress the jack-detection */
+static void alc_fixup_no_jack_detect(struct hda_codec *codec,
+                                    const struct alc_fixup *fix, int action)
+{
+       if (action == ALC_FIXUP_ACT_PRE_PROBE)
+               codec->no_jack_detect = 1;
+}      
+
 static const struct alc_fixup alc861_fixups[] = {
-       [PINFIX_FSC_AMILO_PI1505] = {
+       [ALC861_FIXUP_FSC_AMILO_PI1505] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
                        { 0x0b, 0x0221101f }, /* HP */
@@ -5672,17 +6305,29 @@ static const struct alc_fixup alc861_fixups[] = {
                        { }
                }
        },
-       [PINFIX_ASUS_A6RP] = {
+       [ALC861_FIXUP_AMP_VREF_0F] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc861_fixup_asus_amp_vref_0f,
        },
+       [ALC861_FIXUP_NO_JACK_DETECT] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc_fixup_no_jack_detect,
+       },
+       [ALC861_FIXUP_ASUS_A6RP] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc861_fixup_asus_amp_vref_0f,
+               .chained = true,
+               .chain_id = ALC861_FIXUP_NO_JACK_DETECT,
+       }
 };
 
 static const struct snd_pci_quirk alc861_fixup_tbl[] = {
-       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", PINFIX_ASUS_A6RP),
-       SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", PINFIX_ASUS_A6RP),   
-       SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP),
-       SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
+       SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
+       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
+       SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
+       SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", ALC861_FIXUP_AMP_VREF_0F),
+       SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", ALC861_FIXUP_AMP_VREF_0F),
+       SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
        {}
 };
 
@@ -5709,15 +6354,6 @@ static int patch_alc861(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
-
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
-
        if (!spec->no_analog) {
                err = snd_hda_attach_beep_device(codec, 0x23);
                if (err < 0)
@@ -5725,16 +6361,13 @@ static int patch_alc861(struct hda_codec *codec)
                set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
        }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
        codec->patch_ops = alc_patch_ops;
-       spec->init_hook = alc_auto_init_std;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->power_hook = alc_power_eapd;
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc861_loopbacks;
 #endif
 
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+
        return 0;
 
  error:
@@ -5749,10 +6382,6 @@ static int patch_alc861(struct hda_codec *codec)
  *
  * In addition, an independent DAC
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc861vd_loopbacks     alc880_loopbacks
-#endif
-
 static int alc861vd_parse_auto_config(struct hda_codec *codec)
 {
        static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
@@ -5833,15 +6462,6 @@ static int patch_alc861vd(struct hda_codec *codec)
                add_verb(spec, alc660vd_eapd_verbs);
        }
 
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
-
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
-
        if (!spec->no_analog) {
                err = snd_hda_attach_beep_device(codec, 0x23);
                if (err < 0)
@@ -5849,16 +6469,11 @@ static int patch_alc861vd(struct hda_codec *codec)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
        }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
        codec->patch_ops = alc_patch_ops;
 
-       spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc861vd_loopbacks;
-#endif
+
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        return 0;
 
@@ -5878,9 +6493,6 @@ static int patch_alc861vd(struct hda_codec *codec)
  * In addition, an independent DAC for the multi-playback (not used in this
  * driver yet).
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-#define alc662_loopbacks       alc880_loopbacks
-#endif
 
 /*
  * BIOS auto configuration
@@ -5930,6 +6542,7 @@ enum {
        ALC662_FIXUP_ASUS_MODE6,
        ALC662_FIXUP_ASUS_MODE7,
        ALC662_FIXUP_ASUS_MODE8,
+       ALC662_FIXUP_NO_JACK_DETECT,
 };
 
 static const struct alc_fixup alc662_fixups[] = {
@@ -6075,6 +6688,10 @@ static const struct alc_fixup alc662_fixups[] = {
                .chained = true,
                .chain_id = ALC662_FIXUP_SKU_IGNORE
        },
+       [ALC662_FIXUP_NO_JACK_DETECT] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc_fixup_no_jack_detect,
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -6083,6 +6700,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+       SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
        SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
@@ -6204,15 +6822,6 @@ static int patch_alc662(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
-       if (!spec->no_analog && !spec->adc_nids) {
-               alc_auto_fill_adc_caps(codec);
-               alc_rebuild_imux_for_auto_mic(codec);
-               alc_remove_invalid_adc_nids(codec);
-       }
-
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
-
        if (!spec->no_analog && has_cdefine_beep(codec)) {
                err = snd_hda_attach_beep_device(codec, 0x1);
                if (err < 0)
@@ -6232,16 +6841,10 @@ static int patch_alc662(struct hda_codec *codec)
                }
        }
 
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
-
        codec->patch_ops = alc_patch_ops;
-       spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (!spec->loopback.amplist)
-               spec->loopback.amplist = alc662_loopbacks;
-#endif
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        return 0;
 
@@ -6281,11 +6884,7 @@ static int patch_alc680(struct hda_codec *codec)
                return err;
        }
 
-       if (!spec->no_analog && !spec->cap_mixer)
-               set_capture_mixer(codec);
-
        codec->patch_ops = alc_patch_ops;
-       spec->init_hook = alc_auto_init_std;
 
        return 0;
 }