]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/pci/hda/patch_sigmatel.c
Merge branch 'topic/sound-core-fix' into to-push
[linux-2.6-omap-h63xx.git] / sound / pci / hda / patch_sigmatel.c
index 14db35a61cfead2157e1f8156c341f3a7297005b..35b83dc6e19e5922104f5319302f7e7fa0376d73 100644 (file)
@@ -33,7 +33,6 @@
 #include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
-#include "hda_patch.h"
 #include "hda_beep.h"
 
 enum {
@@ -70,6 +69,7 @@ enum {
 };
 
 enum {
+       STAC_92HD73XX_NO_JD, /* no jack-detection */
        STAC_92HD73XX_REF,
        STAC_DELL_M6_AMIC,
        STAC_DELL_M6_DMIC,
@@ -128,6 +128,7 @@ enum {
 };
 
 enum {
+       STAC_D965_REF_NO_JD, /* no jack-detection */
        STAC_D965_REF,
        STAC_D965_3ST,
        STAC_D965_5ST,
@@ -156,8 +157,6 @@ struct sigmatel_spec {
        int board_config;
        unsigned int eapd_switch: 1;
        unsigned int surr_switch: 1;
-       unsigned int line_switch: 1;
-       unsigned int mic_switch: 1;
        unsigned int alt_switch: 1;
        unsigned int hp_detect: 1;
        unsigned int spdif_mute: 1;
@@ -194,6 +193,8 @@ struct sigmatel_spec {
        unsigned int cur_mmux;
        struct hda_multi_out multiout;
        hda_nid_t dac_nids[5];
+       hda_nid_t hp_dacs[5];
+       hda_nid_t speaker_dacs[5];
 
        /* capture */
        hda_nid_t *adc_nids;
@@ -237,7 +238,9 @@ struct sigmatel_spec {
        /* i/o switches */
        unsigned int io_switch[2];
        unsigned int clfe_swap;
-       unsigned int hp_switch; /* NID of HP as line-out */
+       hda_nid_t line_switch;  /* shared line-in for input and output */
+       hda_nid_t mic_switch;   /* shared mic-in for input and output */
+       hda_nid_t hp_switch; /* NID of HP as line-out */
        unsigned int aloopback;
 
        struct hda_pcm pcm_rec[2];      /* PCM information */
@@ -288,9 +291,6 @@ static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
 };
 
 #define STAC92HD73_DAC_COUNT 5
-static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
-       0x15, 0x16, 0x17, 0x18, 0x19,
-};
 
 static hda_nid_t stac92hd73xx_mux_nids[4] = {
        0x28, 0x29, 0x2a, 0x2b,
@@ -309,11 +309,7 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
        0x11, 0x12, 0
 };
 
-#define STAC92HD81_DAC_COUNT 2
 #define STAC92HD83_DAC_COUNT 3
-static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
-       0x13, 0x14, 0x22,
-};
 
 static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
        0x17, 0x18,
@@ -355,10 +351,6 @@ static hda_nid_t stac92hd71bxx_smux_nids[2] = {
        0x24, 0x25,
 };
 
-static hda_nid_t stac92hd71bxx_dac_nids[1] = {
-       0x10, /*0x11, */
-};
-
 #define STAC92HD71BXX_NUM_DMICS        2
 static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
        0x18, 0x19, 0
@@ -760,10 +752,6 @@ static struct hda_verb stac9200_eapd_init[] = {
 static struct hda_verb stac92hd73xx_6ch_core_init[] = {
        /* set master volume and direct control */
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* setup audio connections */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
-       { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -782,10 +770,6 @@ static struct hda_verb dell_eq_core_init[] = {
        /* set master volume to max value without distortion
         * and direct control */
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
-       /* setup audio connections */
-       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -799,10 +783,6 @@ static struct hda_verb dell_eq_core_init[] = {
 
 static struct hda_verb dell_m6_core_init[] = {
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* setup audio connections */
-       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -817,13 +797,6 @@ static struct hda_verb dell_m6_core_init[] = {
 static struct hda_verb stac92hd73xx_8ch_core_init[] = {
        /* set master volume and direct control */
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* setup audio connections */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
-       { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* connect hp ports to dac3 */
-       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
-       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -841,15 +814,8 @@ static struct hda_verb stac92hd73xx_8ch_core_init[] = {
 static struct hda_verb stac92hd73xx_10ch_core_init[] = {
        /* set master volume and direct control */
        { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* setup audio connections */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
        /* dac3 is connected to import3 mux */
        { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
-       /* connect hp ports to dac4 */
-       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
-       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
        /* setup adcs to point to mixer */
        { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
        { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
@@ -875,17 +841,17 @@ static struct hda_verb stac92hd83xxx_core_init[] = {
 
        /* power state controls amps */
        { 0x01, AC_VERB_SET_EAPD, 1 << 2},
+       {}
 };
 
 static struct hda_verb stac92hd71bxx_core_init[] = {
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* connect headphone jack to dac1 */
-       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
        /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {}
 };
 
 #define HD_DISABLE_PORTF 2
@@ -900,8 +866,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
 
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* connect headphone jack to dac1 */
-       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
        /* unmute right and left channels for nodes 0x0a, 0xd */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1101,21 +1065,21 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
-       HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT),
 
        /*
-       HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT),
        */
        { } /* end */
 };
@@ -1292,7 +1256,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                        spec->spdif_mute = 1;
                }
                stac_smux_mixer.count = spec->num_smuxes;
-               err = snd_ctl_add(codec->bus->card,
+               err = snd_hda_ctl_add(codec,
                                  snd_ctl_new1(&stac_smux_mixer, codec));
                if (err < 0)
                        return err;
@@ -1665,6 +1629,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
 };
 
 static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
+       [STAC_92HD73XX_NO_JD] = "no-jd",
        [STAC_92HD73XX_REF] = "ref",
        [STAC_DELL_M6_AMIC] = "dell-m6-amic",
        [STAC_DELL_M6_DMIC] = "dell-m6-dmic",
@@ -1694,6 +1659,8 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
                                "unknown Dell", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f,
                                "Dell Studio 1537", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
+                               "Dell Studio 17", STAC_DELL_M6_DMIC),
        {} /* terminator */
 };
 
@@ -1716,6 +1683,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_92HD71BXX_REF),
+       {} /* terminator */
 };
 
 static unsigned int ref92hd71bxx_pin_configs[11] = {
@@ -1766,6 +1734,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
                      "HP dv5", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
                      "HP dv7", STAC_HP_M4),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
+                     "HP dv7", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
                                "unknown HP", STAC_HP_M4),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
@@ -2081,6 +2051,7 @@ static unsigned int dell_3st_pin_configs[14] = {
 };
 
 static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
+       [STAC_D965_REF_NO_JD] = ref927x_pin_configs,
        [STAC_D965_REF]  = ref927x_pin_configs,
        [STAC_D965_3ST]  = d965_3st_pin_configs,
        [STAC_D965_5ST]  = d965_5st_pin_configs,
@@ -2089,6 +2060,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
 };
 
 static const char *stac927x_models[STAC_927X_MODELS] = {
+       [STAC_D965_REF_NO_JD]   = "ref-no-jd",
        [STAC_D965_REF]         = "ref",
        [STAC_D965_3ST]         = "3stack",
        [STAC_D965_5ST]         = "5stack",
@@ -2741,70 +2713,53 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
        return stac92xx_add_control_idx(spec, type, 0, name, val);
 }
 
-/* flag inputs as additional dynamic lineouts */
-static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
+/* check whether the line-input can be used as line-out */
+static hda_nid_t check_line_out_switch(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       unsigned int wcaps, wtype;
-       int i, num_dacs = 0;
-       
-       /* use the wcaps cache to count all DACs available for line-outs */
-       for (i = 0; i < codec->num_nodes; i++) {
-               wcaps = codec->wcaps[i];
-               wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid;
+       unsigned int pincap;
 
-               if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
-                       num_dacs++;
-       }
+       if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
+               return 0;
+       nid = cfg->input_pins[AUTO_PIN_LINE];
+       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+       if (pincap & AC_PINCAP_OUT)
+               return nid;
+       return 0;
+}
 
-       snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
-       
-       switch (cfg->line_outs) {
-       case 3:
-               /* add line-in as side */
-               if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
-                       cfg->line_out_pins[cfg->line_outs] =
-                               cfg->input_pins[AUTO_PIN_LINE];
-                       spec->line_switch = 1;
-                       cfg->line_outs++;
-               }
-               break;
-       case 2:
-               /* add line-in as clfe and mic as side */
-               if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
-                       cfg->line_out_pins[cfg->line_outs] =
-                               cfg->input_pins[AUTO_PIN_LINE];
-                       spec->line_switch = 1;
-                       cfg->line_outs++;
-               }
-               if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
-                       cfg->line_out_pins[cfg->line_outs] =
-                               cfg->input_pins[AUTO_PIN_MIC];
-                       spec->mic_switch = 1;
-                       cfg->line_outs++;
-               }
-               break;
-       case 1:
-               /* add line-in as surr and mic as clfe */
-               if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
-                       cfg->line_out_pins[cfg->line_outs] =
-                               cfg->input_pins[AUTO_PIN_LINE];
-                       spec->line_switch = 1;
-                       cfg->line_outs++;
-               }
-               if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
-                       cfg->line_out_pins[cfg->line_outs] =
-                               cfg->input_pins[AUTO_PIN_MIC];
-                       spec->mic_switch = 1;
-                       cfg->line_outs++;
+/* check whether the mic-input can be used as line-out */
+static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int def_conf, pincap;
+       unsigned int mic_pin;
+
+       if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
+               return 0;
+       mic_pin = AUTO_PIN_MIC;
+       for (;;) {
+               hda_nid_t nid = cfg->input_pins[mic_pin];
+               def_conf = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+               /* some laptops have an internal analog microphone
+                * which can't be used as a output */
+               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+                       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+                       if (pincap & AC_PINCAP_OUT)
+                               return nid;
                }
-               break;
+               if (mic_pin == AUTO_PIN_MIC)
+                       mic_pin = AUTO_PIN_FRONT_MIC;
+               else
+                       break;
        }
-
        return 0;
 }
 
-
 static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
 {
        int i;
@@ -2817,6 +2772,52 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
        return 0;
 }
 
+static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+       int i;
+       if (is_in_dac_nids(spec, nid))
+               return 1;
+       for (i = 0; i < spec->autocfg.hp_outs; i++)
+               if (spec->hp_dacs[i] == nid)
+                       return 1;
+       for (i = 0; i < spec->autocfg.speaker_outs; i++)
+               if (spec->speaker_dacs[i] == nid)
+                       return 1;
+       return 0;
+}
+
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int j, conn_len;
+       hda_nid_t conn[HDA_MAX_CONNECTIONS];
+       unsigned int wcaps, wtype;
+
+       conn_len = snd_hda_get_connections(codec, nid, conn,
+                                          HDA_MAX_CONNECTIONS);
+       for (j = 0; j < conn_len; j++) {
+               wcaps = snd_hda_param_read(codec, conn[j],
+                                          AC_PAR_AUDIO_WIDGET_CAP);
+               wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               /* we check only analog outputs */
+               if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
+                       continue;
+               /* if this route has a free DAC, assign it */
+               if (!check_all_dac_nids(spec, conn[j])) {
+                       if (conn_len > 1) {
+                               /* select this DAC in the pin's input mux */
+                               snd_hda_codec_write_cache(codec, nid, 0,
+                                                 AC_VERB_SET_CONNECT_SEL, j);
+                       }
+                       return conn[j];
+               }
+       }
+       return 0;
+}
+
+static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
+static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
+
 /*
  * Fill in the dac_nids table from the parsed pin configuration
  * This function only works when every pin in line_out_pins[]
@@ -2824,31 +2825,17 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
  * codecs are not connected directly to a DAC, such as the 9200
  * and 9202/925x. For those, dac_nids[] must be hard-coded.
  */
-static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
-                                      struct auto_pin_cfg *cfg)
+static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       int i, j, conn_len = 0; 
-       hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
-       unsigned int wcaps, wtype;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+       hda_nid_t nid, dac;
        
        for (i = 0; i < cfg->line_outs; i++) {
                nid = cfg->line_out_pins[i];
-               conn_len = snd_hda_get_connections(codec, nid, conn,
-                                                  HDA_MAX_CONNECTIONS);
-               for (j = 0; j < conn_len; j++) {
-                       wcaps = snd_hda_param_read(codec, conn[j],
-                                                  AC_PAR_AUDIO_WIDGET_CAP);
-                       wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-                       if (wtype != AC_WID_AUD_OUT ||
-                           (wcaps & AC_WCAP_DIGITAL))
-                               continue;
-                       /* conn[j] is a DAC routed to this line-out */
-                       if (!is_in_dac_nids(spec, conn[j]))
-                               break;
-               }
-
-               if (j == conn_len) {
+               dac = get_unassigned_dac(codec, nid);
+               if (!dac) {
                        if (spec->multiout.num_dacs > 0) {
                                /* we have already working output pins,
                                 * so let's drop the broken ones again
@@ -2862,24 +2849,64 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
                                   __func__, nid);
                        return -ENODEV;
                }
+               add_spec_dacs(spec, dac);
+       }
 
-               spec->multiout.dac_nids[i] = conn[j];
-               spec->multiout.num_dacs++;
-               if (conn_len > 1) {
-                       /* select this DAC in the pin's input mux */
-                       snd_hda_codec_write_cache(codec, nid, 0,
-                                                 AC_VERB_SET_CONNECT_SEL, j);
+       /* add line-in as output */
+       nid = check_line_out_switch(codec);
+       if (nid) {
+               dac = get_unassigned_dac(codec, nid);
+               if (dac) {
+                       snd_printdd("STAC: Add line-in 0x%x as output %d\n",
+                                   nid, cfg->line_outs);
+                       cfg->line_out_pins[cfg->line_outs] = nid;
+                       cfg->line_outs++;
+                       spec->line_switch = nid;
+                       add_spec_dacs(spec, dac);
+               }
+       }
+       /* add mic as output */
+       nid = check_mic_out_switch(codec);
+       if (nid) {
+               dac = get_unassigned_dac(codec, nid);
+               if (dac) {
+                       snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
+                                   nid, cfg->line_outs);
+                       cfg->line_out_pins[cfg->line_outs] = nid;
+                       cfg->line_outs++;
+                       spec->mic_switch = nid;
+                       add_spec_dacs(spec, dac);
+               }
+       }
 
+       for (i = 0; i < cfg->hp_outs; i++) {
+               nid = cfg->hp_pins[i];
+               dac = get_unassigned_dac(codec, nid);
+               if (dac) {
+                       if (!spec->multiout.hp_nid)
+                               spec->multiout.hp_nid = dac;
+                       else
+                               add_spec_extra_dacs(spec, dac);
                }
+               spec->hp_dacs[i] = dac;
+       }
+
+       for (i = 0; i < cfg->speaker_outs; i++) {
+               nid = cfg->speaker_pins[i];
+               dac = get_unassigned_dac(codec, nid);
+               if (dac)
+                       add_spec_extra_dacs(spec, dac);
+               spec->speaker_dacs[i] = dac;
        }
 
-       snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+       snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
                   spec->multiout.num_dacs,
                   spec->multiout.dac_nids[0],
                   spec->multiout.dac_nids[1],
                   spec->multiout.dac_nids[2],
                   spec->multiout.dac_nids[3],
                   spec->multiout.dac_nids[4]);
+
        return 0;
 }
 
@@ -2904,9 +2931,7 @@ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_
 
 static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
 {
-       if (!spec->multiout.hp_nid)
-               spec->multiout.hp_nid = nid;
-       else if (spec->multiout.num_dacs > 4) {
+       if (spec->multiout.num_dacs > 4) {
                printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
                return 1;
        } else {
@@ -2916,35 +2941,47 @@ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
        return 0;
 }
 
-static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
+static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
 {
-       if (is_in_dac_nids(spec, nid))
-               return 1;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
+               if (!spec->multiout.extra_out_nid[i]) {
+                       spec->multiout.extra_out_nid[i] = nid;
+                       return 0;
+               }
+       }
+       printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid);
+       return 1;
+}
+
+static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid)
+{
+       int i;
+
+       if (spec->autocfg.line_outs != 1)
+               return 0;
        if (spec->multiout.hp_nid == nid)
-               return 1;
-       return 0;
+               return 0;
+       for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
+               if (spec->multiout.extra_out_nid[i] == nid)
+                       return 0;
+       return 1;
 }
 
 /* add playback controls from the parsed DAC table */
 static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                                               const struct auto_pin_cfg *cfg)
 {
+       struct sigmatel_spec *spec = codec->spec;
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
        hda_nid_t nid = 0;
        int i, err;
+       unsigned int wid_caps;
 
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int wid_caps, pincap;
-
-
-       for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
-               if (!spec->multiout.dac_nids[i])
-                       continue;
-
+       for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) {
                nid = spec->multiout.dac_nids[i];
-
                if (i == 2) {
                        /* Center/LFE */
                        err = create_controls(spec, "Center", nid, 1);
@@ -2966,16 +3003,24 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        }
 
                } else {
-                       err = create_controls(spec, chname[i], nid, 3);
+                       const char *name = chname[i];
+                       /* if it's a single DAC, assign a better name */
+                       if (!i && is_unique_dac(spec, nid)) {
+                               switch (cfg->line_out_type) {
+                               case AUTO_PIN_HP_OUT:
+                                       name = "Headphone";
+                                       break;
+                               case AUTO_PIN_SPEAKER_OUT:
+                                       name = "Speaker";
+                                       break;
+                               }
+                       }
+                       err = create_controls(spec, name, nid, 3);
                        if (err < 0)
                                return err;
                }
        }
 
-       if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
-                       cfg->hp_outs && !spec->multiout.hp_nid)
-               spec->multiout.hp_nid = nid;
-
        if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
                err = stac92xx_add_control(spec,
                        STAC_CTL_WIDGET_HP_SWITCH,
@@ -2986,45 +3031,19 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
        }
 
        if (spec->line_switch) {
-               nid = cfg->input_pins[AUTO_PIN_LINE];
-               pincap = snd_hda_param_read(codec, nid,
-                                               AC_PAR_PIN_CAP);
-               if (pincap & AC_PINCAP_OUT) {
-                       err = stac92xx_add_control(spec,
-                               STAC_CTL_WIDGET_IO_SWITCH,
-                               "Line In as Output Switch", nid << 8);
-                       if (err < 0)
-                               return err;
-               }
+               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
+                                          "Line In as Output Switch",
+                                          spec->line_switch << 8);
+               if (err < 0)
+                       return err;
        }
 
        if (spec->mic_switch) {
-               unsigned int def_conf;
-               unsigned int mic_pin = AUTO_PIN_MIC;
-again:
-               nid = cfg->input_pins[mic_pin];
-               def_conf = snd_hda_codec_read(codec, nid, 0,
-                                               AC_VERB_GET_CONFIG_DEFAULT, 0);
-               /* some laptops have an internal analog microphone
-                * which can't be used as a output */
-               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
-                       pincap = snd_hda_param_read(codec, nid,
-                                                       AC_PAR_PIN_CAP);
-                       if (pincap & AC_PINCAP_OUT) {
-                               err = stac92xx_add_control(spec,
-                                       STAC_CTL_WIDGET_IO_SWITCH,
-                                       "Mic as Output Switch", (nid << 8) | 1);
-                               nid = snd_hda_codec_read(codec, nid, 0,
-                                        AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-                               if (!check_in_dac_nids(spec, nid))
-                                       add_spec_dacs(spec, nid);
-                               if (err < 0)
-                                       return err;
-                       }
-               } else if (mic_pin == AUTO_PIN_MIC) {
-                       mic_pin = AUTO_PIN_FRONT_MIC;
-                       goto again;
-               }
+               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
+                                          "Mic as Output Switch",
+                                          (spec->mic_switch << 8) | 1);
+               if (err < 0)
+                       return err;
        }
 
        return 0;
@@ -3036,55 +3055,39 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
 {
        struct sigmatel_spec *spec = codec->spec;
        hda_nid_t nid;
-       int i, old_num_dacs, err;
+       int i, err, nums;
 
-       old_num_dacs = spec->multiout.num_dacs;
+       nums = 0;
        for (i = 0; i < cfg->hp_outs; i++) {
+               static const char *pfxs[] = {
+                       "Headphone", "Headphone2", "Headphone3",
+               };
                unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
                if (wid_caps & AC_WCAP_UNSOL_CAP)
                        spec->hp_detect = 1;
-               nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
-                                        AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-               if (check_in_dac_nids(spec, nid))
-                       nid = 0;
-               if (! nid)
-                       continue;
-               add_spec_dacs(spec, nid);
-       }
-       for (i = 0; i < cfg->speaker_outs; i++) {
-               nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
-                                        AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-               if (check_in_dac_nids(spec, nid))
-                       nid = 0;
-               if (! nid)
+               if (nums >= ARRAY_SIZE(pfxs))
                        continue;
-               add_spec_dacs(spec, nid);
-       }
-       for (i = 0; i < cfg->line_outs; i++) {
-               nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
-                                       AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-               if (check_in_dac_nids(spec, nid))
-                       nid = 0;
-               if (! nid)
+               nid = spec->hp_dacs[i];
+               if (!nid)
                        continue;
-               add_spec_dacs(spec, nid);
+               err = create_controls(spec, pfxs[nums++], nid, 3);
+               if (err < 0)
+                       return err;
        }
-       for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
+       nums = 0;
+       for (i = 0; i < cfg->speaker_outs; i++) {
                static const char *pfxs[] = {
                        "Speaker", "External Speaker", "Speaker2",
                };
-               err = create_controls(spec, pfxs[i - old_num_dacs],
-                                     spec->multiout.dac_nids[i], 3);
-               if (err < 0)
-                       return err;
-       }
-       if (spec->multiout.hp_nid) {
-               err = create_controls(spec, "Headphone",
-                                     spec->multiout.hp_nid, 3);
+               if (nums >= ARRAY_SIZE(pfxs))
+                       continue;
+               nid = spec->speaker_dacs[i];
+               if (!nid)
+                       continue;
+               err = create_controls(spec, pfxs[nums++], nid, 3);
                if (err < 0)
                        return err;
        }
-
        return 0;
 }
 
@@ -3422,7 +3425,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 {
        struct sigmatel_spec *spec = codec->spec;
        int err;
-       int hp_speaker_swap = 0;
 
        if ((err = snd_hda_parse_pin_def_config(codec,
                                                &spec->autocfg,
@@ -3440,13 +3442,15 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                 * speaker_outs so that the following routines can handle
                 * HP pins as primary outputs.
                 */
+               snd_printdd("stac92xx: Enabling multi-HPs workaround\n");
                memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
                       sizeof(spec->autocfg.line_out_pins));
                spec->autocfg.speaker_outs = spec->autocfg.line_outs;
                memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
                       sizeof(spec->autocfg.hp_pins));
                spec->autocfg.line_outs = spec->autocfg.hp_outs;
-               hp_speaker_swap = 1;
+               spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
+               spec->autocfg.hp_outs = 0;
        }
        if (spec->autocfg.mono_out_pin) {
                int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
@@ -3498,11 +3502,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                                         AC_PINCTL_OUT_EN);
        }
 
-       if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
-               return err;
-       if (spec->multiout.num_dacs == 0)
-               if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+       if (!spec->multiout.num_dacs) {
+               err = stac92xx_auto_fill_dac_nids(codec);
+               if (err < 0)
                        return err;
+       }
 
        err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
 
@@ -3540,19 +3544,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
        }
 #endif
 
-       if (hp_speaker_swap == 1) {
-               /* Restore the hp_outs and line_outs */
-               memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
-                      sizeof(spec->autocfg.line_out_pins));
-               spec->autocfg.hp_outs = spec->autocfg.line_outs;
-               memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
-                      sizeof(spec->autocfg.speaker_pins));
-               spec->autocfg.line_outs = spec->autocfg.speaker_outs;
-               memset(spec->autocfg.speaker_pins, 0,
-                      sizeof(spec->autocfg.speaker_pins));
-               spec->autocfg.speaker_outs = 0;
-       }
-
        err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
 
        if (err < 0)
@@ -3601,7 +3592,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                spec->mixers[spec->num_mixers++] = spec->kctls.list;
 
        spec->input_mux = &spec->private_imux;
-       spec->dinput_mux = &spec->private_dimux;
+       if (!spec->dinput_mux)
+               spec->dinput_mux = &spec->private_dimux;
        spec->sinput_mux = &spec->private_smux;
        spec->mono_mux = &spec->private_mono_mux;
        spec->amp_mux = &spec->private_amp_mux;
@@ -3864,8 +3856,7 @@ static void stac92xx_power_down(struct hda_codec *codec)
        /* power down inactive DACs */
        hda_nid_t *dac;
        for (dac = spec->dac_list; *dac; dac++)
-               if (!is_in_dac_nids(spec, *dac) &&
-                       spec->multiout.hp_nid != *dac)
+               if (!check_all_dac_nids(spec, *dac))
                        snd_hda_codec_write(codec, *dac, 0,
                                        AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 }
@@ -3916,24 +3907,36 @@ static int stac92xx_init(struct hda_codec *codec)
        } else {
                stac92xx_auto_init_multi_out(codec);
                stac92xx_auto_init_hp_out(codec);
+               for (i = 0; i < cfg->hp_outs; i++)
+                       stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
        }
        for (i = 0; i < AUTO_PIN_LAST; i++) {
                hda_nid_t nid = cfg->input_pins[i];
                if (nid) {
-                       unsigned int pinctl;
+                       unsigned int pinctl, conf;
                        if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
                                /* for mic pins, force to initialize */
                                pinctl = stac92xx_get_vref(codec, nid);
+                               pinctl |= AC_PINCTL_IN_EN;
+                               stac92xx_auto_set_pinctl(codec, nid, pinctl);
                        } else {
                                pinctl = snd_hda_codec_read(codec, nid, 0,
                                        AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                                /* if PINCTL already set then skip */
-                               if (pinctl & AC_PINCTL_IN_EN)
-                                       continue;
+                               if (!(pinctl & AC_PINCTL_IN_EN)) {
+                                       pinctl |= AC_PINCTL_IN_EN;
+                                       stac92xx_auto_set_pinctl(codec, nid,
+                                                                pinctl);
+                               }
+                       }
+                       conf = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_CONFIG_DEFAULT, 0);
+                       if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
+                               enable_pin_detect(codec, nid,
+                                                 STAC_INSERT_EVENT);
+                               stac_issue_unsol_event(codec, nid,
+                                                      STAC_INSERT_EVENT);
                        }
-                       pinctl |= AC_PINCTL_IN_EN;
-                       stac92xx_auto_set_pinctl(codec, nid, pinctl);
-                       enable_pin_detect(codec, nid, STAC_INSERT_EVENT);
                }
        }
        for (i = 0; i < spec->num_dmics; i++)
@@ -3949,7 +3952,13 @@ static int stac92xx_init(struct hda_codec *codec)
                hda_nid_t nid = spec->pwr_nids[i];
                int pinctl, def_conf;
 
-               if (is_nid_hp_pin(cfg, nid) && spec->hp_detect)
+               /* power on when no jack detection is available */
+               if (!spec->hp_detect) {
+                       stac_toggle_power_map(codec, nid, 1);
+                       continue;
+               }
+
+               if (is_nid_hp_pin(cfg, nid))
                        continue; /* already has an unsol event */
 
                pinctl = snd_hda_codec_read(codec, nid, 0,
@@ -3958,8 +3967,10 @@ static int stac92xx_init(struct hda_codec *codec)
                 * any attempts on powering down a input port cause the
                 * referenced VREF to act quirky.
                 */
-               if (pinctl & AC_PINCTL_IN_EN)
+               if (pinctl & AC_PINCTL_IN_EN) {
+                       stac_toggle_power_map(codec, nid, 1);
                        continue;
+               }
                def_conf = snd_hda_codec_read(codec, nid, 0,
                                              AC_VERB_GET_CONFIG_DEFAULT, 0);
                def_conf = get_defcfg_connect(def_conf);
@@ -3970,8 +3981,10 @@ static int stac92xx_init(struct hda_codec *codec)
                                stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
-               enable_pin_detect(codec, nid, STAC_PWR_EVENT);
-               stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
+               if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) {
+                       enable_pin_detect(codec, nid, STAC_PWR_EVENT);
+                       stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
+               }
        }
        if (spec->dac_list)
                stac92xx_power_down(codec);
@@ -4034,11 +4047,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
                 * "xxx as Output" mixer switch
                 */
                struct sigmatel_spec *spec = codec->spec;
-               struct auto_pin_cfg *cfg = &spec->autocfg;
-               if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
-                    spec->line_switch) ||
-                   (nid == cfg->input_pins[AUTO_PIN_MIC] &&
-                    spec->mic_switch))
+               if (nid == spec->line_switch || nid == spec->mic_switch)
                        return;
        }
 
@@ -4062,20 +4071,13 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
                        pin_ctl & ~flag);
 }
 
-static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
+static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
 {
        if (!nid)
                return 0;
        if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
-           & (1 << 31)) {
-               unsigned int pinctl;
-               pinctl = snd_hda_codec_read(codec, nid, 0,
-                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               if (pinctl & AC_PINCTL_IN_EN)
-                       return 0; /* mic- or line-input */
-               else
-                       return 1; /* HP-output */
-       }
+           & (1 << 31))
+               return 1;
        return 0;
 }
 
@@ -4087,11 +4089,9 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i)
        struct auto_pin_cfg *cfg = &spec->autocfg;
 
        /* ignore sensing of shared line and mic jacks */
-       if (spec->line_switch &&
-           cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
+       if (cfg->hp_pins[i] == spec->line_switch)
                return 1;
-       if (spec->mic_switch &&
-           cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
+       if (cfg->hp_pins[i] == spec->mic_switch)
                return 1;
        /* ignore if the pin is set as line-out */
        if (cfg->hp_pins[i] == spec->hp_switch)
@@ -4115,7 +4115,14 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
                        break;
                if (no_hp_sensing(spec, i))
                        continue;
-               presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
+               presence = get_pin_presence(codec, cfg->hp_pins[i]);
+               if (presence) {
+                       unsigned int pinctl;
+                       pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
+                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       if (pinctl & AC_PINCTL_IN_EN)
+                               presence = 0; /* mic- or line-input */
+               }
        }
 
        if (presence) {
@@ -4192,7 +4199,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
 
 static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
 {
-       stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid));
+       stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
 }
 
 static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
@@ -4214,7 +4221,7 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
                                        type = (pin_ctl & AC_PINCTL_HP_EN)
                                        ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
                                snd_jack_report(jacks->jack,
-                                       get_hp_pin_presence(codec, nid)
+                                       get_pin_presence(codec, nid)
                                        ? type : 0);
                        }
                        jacks++;
@@ -4495,6 +4502,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
        struct sigmatel_spec *spec;
        hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
        int err = 0;
+       int num_dacs;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -4521,16 +4529,15 @@ again:
                return err;
        }
 
-       spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
+       num_dacs = snd_hda_get_connections(codec, 0x0a,
                        conn, STAC92HD73_DAC_COUNT + 2) - 1;
 
-       if (spec->multiout.num_dacs < 0) {
+       if (num_dacs < 3 || num_dacs > 5) {
                printk(KERN_WARNING "hda_codec: Could not determine "
                       "number of channels defaulting to DAC count\n");
-               spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
+               num_dacs = STAC92HD73_DAC_COUNT;
        }
-
-       switch (spec->multiout.num_dacs) {
+       switch (num_dacs) {
        case 0x3: /* 6 Channel */
                spec->mixer = stac92hd73xx_6ch_mixer;
                spec->init = stac92hd73xx_6ch_core_init;
@@ -4542,9 +4549,9 @@ again:
        case 0x5: /* 10 Channel */
                spec->mixer = stac92hd73xx_10ch_mixer;
                spec->init = stac92hd73xx_10ch_core_init;
-       };
+       }
+       spec->multiout.dac_nids = spec->dac_nids;
 
-       spec->multiout.dac_nids = stac92hd73xx_dac_nids;
        spec->aloopback_mask = 0x01;
        spec->aloopback_shift = 8;
 
@@ -4576,7 +4583,7 @@ again:
                spec->eapd_switch = 0;
                spec->num_amps = 1;
 
-               if (!spec->init)
+               if (spec->board_config != STAC_DELL_EQ)
                        spec->init = dell_m6_core_init;
                switch (spec->board_config) {
                case STAC_DELL_M6_AMIC: /* Analog Mics */
@@ -4629,6 +4636,9 @@ again:
                return err;
        }
 
+       if (spec->board_config == STAC_92HD73XX_NO_JD)
+               spec->hp_detect = 0;
+
        codec->patch_ops = stac92xx_patch_ops;
 
        codec->proc_widget_hook = stac92hd7x_proc_hook;
@@ -4664,17 +4674,15 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        spec->pwr_nids = stac92hd83xxx_pwr_nids;
        spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
        spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
-       spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
+       spec->multiout.dac_nids = spec->dac_nids;
 
        spec->init = stac92hd83xxx_core_init;
        switch (codec->vendor_id) {
        case 0x111d7605:
-               spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
                break;
        default:
                spec->num_pwrs--;
                spec->init++; /* switch to config #2 */
-               spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
        }
 
        spec->mixer = stac92hd83xxx_mixer;
@@ -4865,9 +4873,7 @@ again:
                spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
        };
 
-       spec->multiout.num_dacs = 1;
-       spec->multiout.hp_nid = 0x11;
-       spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+       spec->multiout.dac_nids = spec->dac_nids;
        if (spec->dinput_mux)
                spec->private_dimux.num_items +=
                        spec->num_dmics -
@@ -5125,6 +5131,10 @@ static int patch_stac927x(struct hda_codec *codec)
         */
        codec->bus->needs_damn_long_delay = 1;
 
+       /* no jack detecion for ref-no-jd model */
+       if (spec->board_config == STAC_D965_REF_NO_JD)
+               spec->hp_detect = 0;
+
        return 0;
 }
 
@@ -5350,7 +5360,7 @@ static int stac9872_vaio_init(struct hda_codec *codec)
 
 static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
 {
-       if (get_hp_pin_presence(codec, 0x0a)) {
+       if (get_pin_presence(codec, 0x0a)) {
                stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
                stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
        } else {
@@ -5461,7 +5471,7 @@ static int patch_stac9872(struct hda_codec *codec)
 /*
  * patch entries
  */
-struct hda_codec_preset snd_hda_preset_sigmatel[] = {
+static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
        { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
        { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
@@ -5525,3 +5535,27 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
        {} /* terminator */
 };
+
+MODULE_ALIAS("snd-hda-codec-id:8384*");
+MODULE_ALIAS("snd-hda-codec-id:111d*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
+
+static struct hda_codec_preset_list sigmatel_list = {
+       .preset = snd_hda_preset_sigmatel,
+       .owner = THIS_MODULE,
+};
+
+static int __init patch_sigmatel_init(void)
+{
+       return snd_hda_add_codec_preset(&sigmatel_list);
+}
+
+static void __exit patch_sigmatel_exit(void)
+{
+       snd_hda_delete_codec_preset(&sigmatel_list);
+}
+
+module_init(patch_sigmatel_init)
+module_exit(patch_sigmatel_exit)