]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update
Revert "Move xen patchset to new version's subdir."
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / alsa-post-ga-hda-sigmatel-update
diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update
deleted file mode 100644 (file)
index 9826d53..0000000
+++ /dev/null
@@ -1,1583 +0,0 @@
-From: Takashi Iwai <tiwai@suse.de>
-Subject: Backport fixes for patch_sigmatel.c from 2.6.29
-Patch-mainline: 2.6.29
-References: bcn#457472, bnc#462913, bnc#467381, bnc#479558, bnc#480617, bnc#480809 
-
-Backport patch_sigmatel fixes from 2.6.29.
-This includes fixes for multiple Dell and HP laptops.
-
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-
----
- sound/pci/hda/patch_sigmatel.c |  896 +++++++++++++++++++++--------------------
- 1 file changed, 480 insertions(+), 416 deletions(-)
-
---- a/sound/pci/hda/patch_sigmatel.c
-+++ b/sound/pci/hda/patch_sigmatel.c
-@@ -82,6 +82,7 @@
- enum {
-       STAC_92HD83XXX_REF,
-+      STAC_92HD83XXX_PWR_REF,
-       STAC_92HD83XXX_MODELS
- };
-@@ -144,6 +145,13 @@
-       STAC_927X_MODELS
- };
-+struct sigmatel_event {
-+      hda_nid_t nid;
-+      unsigned char type;
-+      unsigned char tag;
-+      int data;
-+};
-+
- struct sigmatel_spec {
-       struct snd_kcontrol_new *mixers[4];
-       unsigned int num_mixers;
-@@ -151,8 +159,6 @@
-       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;
-@@ -178,12 +184,18 @@
-       hda_nid_t *pwr_nids;
-       hda_nid_t *dac_list;
-+      /* events */
-+      int num_events;
-+      struct sigmatel_event events[32];
-+
-       /* playback */
-       struct hda_input_mux *mono_mux;
-       struct hda_input_mux *amp_mux;
-       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];
-       int volume_offset;
-@@ -230,7 +242,9 @@
-       /* 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 */
-@@ -282,9 +296,6 @@
- };
- #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,
-@@ -303,11 +314,7 @@
-       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,
-@@ -326,7 +333,11 @@
- };
- static unsigned int stac92hd83xxx_pwr_mapping[4] = {
--      0x03, 0x0c, 0x10, 0x40,
-+      0x03, 0x0c, 0x20, 0x40,
-+};
-+
-+static hda_nid_t stac92hd83xxx_amp_nids[1] = {
-+      0xc,
- };
- static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
-@@ -349,10 +360,6 @@
-       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
-@@ -584,12 +591,12 @@
-               else
-                       nid = codec->slave_dig_outs[smux_idx - 1];
-               if (spec->cur_smux[smux_idx] == smux->num_items - 1)
--                      val = AMP_OUT_MUTE;
-+                      val = HDA_AMP_MUTE;
-               else
--                      val = AMP_OUT_UNMUTE;
-+                      val = 0;
-               /* un/mute SPDIF out */
--              snd_hda_codec_write_cache(codec, nid, 0,
--                      AC_VERB_SET_AMP_GAIN_MUTE, val);
-+              snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-+                                       HDA_AMP_MUTE, val);
-       }
-       return 0;
- }
-@@ -754,10 +761,6 @@
- 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},
-@@ -776,10 +779,6 @@
-       /* 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},
-@@ -793,10 +792,6 @@
- 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},
-@@ -811,13 +806,6 @@
- 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},
-@@ -835,15 +823,8 @@
- 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},
-@@ -859,10 +840,6 @@
- };
- static struct hda_verb stac92hd83xxx_core_init[] = {
--      /* start of config #1 */
--      { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
--
--      /* start of config #2 */
-       { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
-       { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
-       { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
-@@ -875,8 +852,6 @@
- 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)},
-@@ -896,8 +871,6 @@
-       /* 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)},
-@@ -1099,21 +1072,21 @@
-       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 */
- };
-@@ -1726,10 +1699,12 @@
- static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
-       [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
-+      [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
- };
- static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
-       [STAC_92HD83XXX_REF] = "ref",
-+      [STAC_92HD83XXX_PWR_REF] = "mic-ref",
- };
- static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
-@@ -1788,11 +1763,13 @@
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
-                     "HP dv5", STAC_HP_M4),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
--                    "HP dv7", STAC_HP_M4),
-+                    "HP dv7", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7,
-                     "HP dv4", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
-                     "HP dv7", STAC_HP_M4),
-+      SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3600,
-+                    "HP dv5", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603,
-                     "HP dv5", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
-@@ -2419,7 +2396,7 @@
-       if (spec->powerdown_adcs) {
-               msleep(40);
--              snd_hda_codec_write_cache(codec, nid, 0,
-+              snd_hda_codec_write(codec, nid, 0,
-                       AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-       }
-       snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
-@@ -2435,7 +2412,7 @@
-       snd_hda_codec_cleanup_stream(codec, nid);
-       if (spec->powerdown_adcs)
--              snd_hda_codec_write_cache(codec, nid, 0,
-+              snd_hda_codec_write(codec, nid, 0,
-                       AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-       return 0;
- }
-@@ -2569,6 +2546,9 @@
-       return 0;
- }
-+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
-+                                 unsigned char type);
-+
- static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
- {
-@@ -2581,8 +2561,7 @@
-       /* check to be sure that the ports are upto date with
-        * switch changes
-        */
--      codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
--
-+      stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
-       return 1;
- }
-@@ -2621,7 +2600,7 @@
-        * appropriately according to the pin direction
-        */
-       if (spec->hp_detect)
--              codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
-+              stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
-         return 1;
- }
-@@ -2758,70 +2737,53 @@
-       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;
-@@ -2834,6 +2796,52 @@
-       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[]
-@@ -2841,31 +2849,17 @@
-  * 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
-@@ -2879,24 +2873,64 @@
-                                  __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;
-       }
--      snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
-+      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("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;
- }
-@@ -2941,9 +2975,7 @@
- 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 {
-@@ -2953,35 +2985,47 @@
-       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(codec, "Center", nid, 1);
-@@ -3003,16 +3047,24 @@
-                       }
-               } else {
--                      err = create_controls(codec, 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(codec, name, nid, 3);
-                       if (err < 0)
-                               return err;
-               }
-       }
--      if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
--          cfg->hp_outs == 1 && !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,
-@@ -3023,45 +3075,19 @@
-       }
-       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;
-@@ -3073,55 +3099,39 @@
- {
-       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)
-+              if (nums >= ARRAY_SIZE(pfxs))
-                       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)
-+              nid = spec->hp_dacs[i];
-+              if (!nid)
-                       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)
--                      continue;
--              add_spec_dacs(spec, nid);
-+              err = create_controls(codec, 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(codec, pfxs[i - old_num_dacs],
--                                    spec->multiout.dac_nids[i], 3);
--              if (err < 0)
--                      return err;
--      }
--      if (spec->multiout.hp_nid) {
--              err = create_controls(codec, "Headphone",
--                                    spec->multiout.hp_nid, 3);
-+              if (nums >= ARRAY_SIZE(pfxs))
-+                      continue;
-+              nid = spec->speaker_dacs[i];
-+              if (!nid)
-+                      continue;
-+              err = create_controls(codec, pfxs[nums++], nid, 3);
-               if (err < 0)
-                       return err;
-       }
--
-       return 0;
- }
-@@ -3459,7 +3469,6 @@
- {
-       struct sigmatel_spec *spec = codec->spec;
-       int err;
--      int hp_speaker_swap = 0;
-       if ((err = snd_hda_parse_pin_def_config(codec,
-                                               &spec->autocfg,
-@@ -3477,13 +3486,15 @@
-                * 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) &
-@@ -3535,10 +3546,9 @@
-                                        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);
-@@ -3577,19 +3587,6 @@
-       }
- #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)
-@@ -3638,7 +3635,8 @@
-               spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
-       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;
-@@ -3787,13 +3785,68 @@
-                          AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
- }
-+static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
-+                        unsigned char type, int data)
-+{
-+      struct sigmatel_event *event;
-+
-+      if (spec->num_events >= ARRAY_SIZE(spec->events))
-+              return -ENOMEM;
-+      event = &spec->events[spec->num_events++];
-+      event->nid = nid;
-+      event->type = type;
-+      event->tag = spec->num_events;
-+      event->data = data;
-+
-+      return event->tag;
-+}
-+
-+static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
-+                                           hda_nid_t nid, unsigned char type)
-+{
-+      struct sigmatel_spec *spec = codec->spec;
-+      struct sigmatel_event *event = spec->events;
-+      int i;
-+
-+      for (i = 0; i < spec->num_events; i++, event++) {
-+              if (event->nid == nid && event->type == type)
-+                      return event;
-+      }
-+      return NULL;
-+}
-+
-+static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
-+                                                    unsigned char tag)
-+{
-+      struct sigmatel_spec *spec = codec->spec;
-+      struct sigmatel_event *event = spec->events;
-+      int i;
-+
-+      for (i = 0; i < spec->num_events; i++, event++) {
-+              if (event->tag == tag)
-+                      return event;
-+      }
-+      return NULL;
-+}
-+
- static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
--                            unsigned int event)
-+                            unsigned int type)
- {
--      if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
--              snd_hda_codec_write_cache(codec, nid, 0,
--                                        AC_VERB_SET_UNSOLICITED_ENABLE,
--                                        (AC_USRSP_EN | event));
-+      struct sigmatel_event *event;
-+      int tag;
-+
-+      if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
-+              return;
-+      event = stac_get_event(codec, nid, type);
-+      if (event)
-+              tag = event->tag;
-+      else
-+              tag = stac_add_event(codec->spec, nid, type, 0);
-+      if (tag < 0)
-+              return;
-+      snd_hda_codec_write_cache(codec, nid, 0,
-+                                AC_VERB_SET_UNSOLICITED_ENABLE,
-+                                AC_USRSP_EN | tag);
- }
- static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
-@@ -3813,9 +3866,8 @@
-       /* 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)
--                      snd_hda_codec_write_cache(codec, *dac, 0,
-+              if (!check_all_dac_nids(spec, *dac))
-+                      snd_hda_codec_write(codec, *dac, 0,
-                                       AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
- }
-@@ -3834,7 +3886,7 @@
-       /* power down adcs initially */
-       if (spec->powerdown_adcs)
-               for (i = 0; i < spec->num_adcs; i++)
--                      snd_hda_codec_write_cache(codec,
-+                      snd_hda_codec_write(codec,
-                               spec->adc_nids[i], 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-@@ -3850,37 +3902,51 @@
-       /* set up pins */
-       if (spec->hp_detect) {
-               /* Enable unsolicited responses on the HP widget */
--              for (i = 0; i < cfg->hp_outs; i++)
--                      enable_pin_detect(codec, cfg->hp_pins[i],
--                                        STAC_HP_EVENT);
-+              for (i = 0; i < cfg->hp_outs; i++) {
-+                      hda_nid_t nid = cfg->hp_pins[i];
-+                      enable_pin_detect(codec, nid, STAC_HP_EVENT);
-+              }
-               /* force to enable the first line-out; the others are set up
-                * in unsol_event
-                */
-               stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
-                                        AC_PINCTL_OUT_EN);
--              stac92xx_auto_init_hp_out(codec);
-               /* fake event to set up pins */
--              codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
-+              stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
-+                                     STAC_HP_EVENT);
-       } 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);
-               }
-       }
-       for (i = 0; i < spec->num_dmics; i++)
-@@ -3895,9 +3961,14 @@
-       for (i = 0; i < spec->num_pwrs; i++)  {
-               hda_nid_t nid = spec->pwr_nids[i];
-               int pinctl, def_conf;
--              int event = STAC_PWR_EVENT;
--              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,
-@@ -3906,8 +3977,10 @@
-                * 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);
-@@ -3918,8 +3991,10 @@
-                               stac_toggle_power_map(codec, nid, 1);
-                       continue;
-               }
--              enable_pin_detect(codec, spec->pwr_nids[i], event | i);
--              codec->patch_ops.unsol_event(codec, (event | i) << 26);
-+              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);
-@@ -3960,11 +4035,7 @@
-                * "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;
-       }
-@@ -3988,20 +4059,13 @@
-                       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;
- }
-@@ -4013,11 +4077,9 @@
-       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)
-@@ -4025,7 +4087,7 @@
-       return 0;
- }
--static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
-+static void stac92xx_hp_detect(struct hda_codec *codec)
- {
-       struct sigmatel_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-@@ -4041,7 +4103,14 @@
-                       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) {
-@@ -4082,8 +4151,19 @@
-                       continue;
-               if (presence)
-                       stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
-+#if 0 /* FIXME */
-+/* Resetting the pinctl like below may lead to (a sort of) regressions
-+ * on some devices since they use the HP pin actually for line/speaker
-+ * outs although the default pin config shows a different pin (that is
-+ * wrong and useless).
-+ *
-+ * So, it's basically a problem of default pin configs, likely a BIOS issue.
-+ * But, disabling the code below just works around it, and I'm too tired of
-+ * bug reports with such devices... 
-+ */
-               else
-                       stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
-+#endif /* FIXME */
-       }
- } 
-@@ -4118,30 +4198,45 @@
- 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 stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
-+                                 unsigned char type)
-+{
-+      struct sigmatel_event *event = stac_get_event(codec, nid, type);
-+      if (!event)
-+              return;
-+      codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
- }
- static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
- {
-       struct sigmatel_spec *spec = codec->spec;
--      int idx = res >> 26 & 0x0f;
-+      struct sigmatel_event *event;
-+      int tag, data;
-+
-+      tag = (res >> 26) & 0x7f;
-+      event = stac_get_event_from_tag(codec, tag);
-+      if (!event)
-+              return;
--      switch ((res >> 26) & 0x70) {
-+      switch (event->type) {
-       case STAC_HP_EVENT:
--              stac92xx_hp_detect(codec, res);
-+              stac92xx_hp_detect(codec);
-               /* fallthru */
-+      case STAC_INSERT_EVENT:
-       case STAC_PWR_EVENT:
-               if (spec->num_pwrs > 0)
--                      stac92xx_pin_sense(codec, idx);
-+                      stac92xx_pin_sense(codec, event->nid);
-               break;
--      case STAC_VREF_EVENT: {
--              int data = snd_hda_codec_read(codec, codec->afg, 0,
--                      AC_VERB_GET_GPIO_DATA, 0);
-+      case STAC_VREF_EVENT:
-+              data = snd_hda_codec_read(codec, codec->afg, 0,
-+                                        AC_VERB_GET_GPIO_DATA, 0);
-               /* toggle VREF state based on GPIOx status */
-               snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
--                      !!(data & (1 << idx)));
-+                                  !!(data & (1 << event->data)));
-               break;
--              }
-       }
- }
-@@ -4151,17 +4246,23 @@
-       struct sigmatel_spec *spec = codec->spec;
-       stac92xx_set_config_regs(codec);
--      snd_hda_sequence_write(codec, spec->init);
--      stac_gpio_set(codec, spec->gpio_mask,
--              spec->gpio_dir, spec->gpio_data);
-+      stac92xx_init(codec);
-       snd_hda_codec_resume_amp(codec);
-       snd_hda_codec_resume_cache(codec);
--      /* power down inactive DACs */
--      if (spec->dac_list)
--              stac92xx_power_down(codec);
--      /* invoke unsolicited event to reset the HP state */
-+      /* fake event to set up pins again to override cached values */
-       if (spec->hp_detect)
--              codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
-+              stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
-+                                     STAC_HP_EVENT);
-+      return 0;
-+}
-+
-+static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
-+{
-+      struct sigmatel_spec *spec = codec->spec;
-+      if (spec->eapd_mask)
-+              stac_gpio_set(codec, spec->gpio_mask,
-+                              spec->gpio_dir, spec->gpio_data &
-+                              ~spec->eapd_mask);
-       return 0;
- }
- #endif
-@@ -4173,6 +4274,7 @@
-       .free = stac92xx_free,
-       .unsol_event = stac92xx_unsol_event,
- #ifdef SND_HDA_NEEDS_RESUME
-+      .suspend = stac92xx_suspend,
-       .resume = stac92xx_resume,
- #endif
- };
-@@ -4234,6 +4336,12 @@
-               return err;
-       }
-+      /* CF-74 has no headphone detection, and the driver should *NOT*
-+       * do detection and HP/speaker toggle because the hardware does it.
-+       */
-+      if (spec->board_config == STAC_9200_PANASONIC)
-+              spec->hp_detect = 0;
-+
-       codec->patch_ops = stac92xx_patch_ops;
-       return 0;
-@@ -4340,6 +4448,7 @@
-       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)
-@@ -4368,33 +4477,29 @@
-               stac92xx_set_config_regs(codec);
-       }
--      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->multiout.hp_nid = 0x17;
-               spec->mixer = stac92hd73xx_6ch_mixer;
-               spec->init = stac92hd73xx_6ch_core_init;
-               break;
-       case 0x4: /* 8 Channel */
--              spec->multiout.hp_nid = 0x18;
-               spec->mixer = stac92hd73xx_8ch_mixer;
-               spec->init = stac92hd73xx_8ch_core_init;
-               break;
-       case 0x5: /* 10 Channel */
--              spec->multiout.hp_nid = 0x19;
-               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;
-@@ -4425,9 +4530,8 @@
-               spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
-               spec->eapd_switch = 0;
-               spec->num_amps = 1;
--              spec->multiout.hp_nid = 0; /* dual HPs */
--              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 */
-@@ -4500,7 +4604,9 @@
- static int patch_stac92hd83xxx(struct hda_codec *codec)
- {
-       struct sigmatel_spec *spec;
-+      hda_nid_t conn[STAC92HD83_DAC_COUNT + 1];
-       int err;
-+      int num_dacs;
-       spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-@@ -4514,25 +4620,25 @@
-       spec->dmux_nids = stac92hd83xxx_dmux_nids;
-       spec->adc_nids = stac92hd83xxx_adc_nids;
-       spec->pwr_nids = stac92hd83xxx_pwr_nids;
-+      spec->amp_nids = stac92hd83xxx_amp_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;
--      }
-+      /* set port 0xe to select the last DAC
-+       */
-+      num_dacs = snd_hda_get_connections(codec, 0x0e,
-+              conn, STAC92HD83_DAC_COUNT + 1) - 1;
-+
-+      snd_hda_codec_write_cache(codec, 0xe, 0,
-+              AC_VERB_SET_CONNECT_SEL, num_dacs);
-+      spec->init = stac92hd83xxx_core_init;
-       spec->mixer = stac92hd83xxx_mixer;
-       spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
-       spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
-       spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
-+      spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids);
-       spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
-       spec->dinput_mux = &stac92hd83xxx_dmux;
-       spec->pin_nids = stac92hd83xxx_pin_nids;
-@@ -4555,6 +4661,15 @@
-               stac92xx_set_config_regs(codec);
-       }
-+      switch (codec->vendor_id) {
-+      case 0x111d7604:
-+      case 0x111d7605:
-+              if (spec->board_config == STAC_92HD83XXX_PWR_REF)
-+                      break;
-+              spec->num_pwrs = 0;
-+              break;
-+      }
-+
-       err = stac92xx_parse_auto_config(codec, 0x1d, 0);
-       if (!err) {
-               if (spec->board_config < 0) {
-@@ -4576,54 +4691,6 @@
-       return 0;
- }
--#ifdef SND_HDA_NEEDS_RESUME
--static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
--{
--      struct sigmatel_spec *spec = codec->spec;
--      int i;
--      snd_hda_codec_write_cache(codec, codec->afg, 0,
--              AC_VERB_SET_POWER_STATE, pwr);
--
--      msleep(1);
--      for (i = 0; i < spec->num_adcs; i++) {
--              snd_hda_codec_write_cache(codec,
--                      spec->adc_nids[i], 0,
--                      AC_VERB_SET_POWER_STATE, pwr);
--      }
--};
--
--static int stac92hd71xx_resume(struct hda_codec *codec)
--{
--      stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
--      return stac92xx_resume(codec);
--}
--
--static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
--{
--      struct sigmatel_spec *spec = codec->spec;
--
--      stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
--      if (spec->eapd_mask)
--              stac_gpio_set(codec, spec->gpio_mask,
--                              spec->gpio_dir, spec->gpio_data &
--                              ~spec->eapd_mask);
--      return 0;
--};
--
--#endif
--
--static struct hda_codec_ops stac92hd71bxx_patch_ops = {
--      .build_controls = stac92xx_build_controls,
--      .build_pcms = stac92xx_build_pcms,
--      .init = stac92xx_init,
--      .free = stac92xx_free,
--      .unsol_event = stac92xx_unsol_event,
--#ifdef SND_HDA_NEEDS_RESUME
--      .resume = stac92hd71xx_resume,
--      .suspend = stac92hd71xx_suspend,
--#endif
--};
--
- static struct hda_input_mux stac92hd71bxx_dmux = {
-       .num_items = 4,
-       .items = {
-@@ -4689,21 +4756,21 @@
-               switch (spec->board_config) {
-               case STAC_HP_M4:
-                       /* Enable VREF power saving on GPIO1 detect */
-+                      err = stac_add_event(spec, codec->afg,
-+                                           STAC_VREF_EVENT, 0x02);
-+                      if (err < 0)
-+                              return err;
-                       snd_hda_codec_write_cache(codec, codec->afg, 0,
-                               AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
-                       snd_hda_codec_write_cache(codec, codec->afg, 0,
--                                      AC_VERB_SET_UNSOLICITED_ENABLE,
--                                      (AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
-+                              AC_VERB_SET_UNSOLICITED_ENABLE,
-+                              AC_USRSP_EN | err);
-                       spec->gpio_mask |= 0x02;
-                       break;
-               }
-               if ((codec->revision_id & 0xf) == 0 ||
--                              (codec->revision_id & 0xf) == 1) {
--#ifdef SND_HDA_NEEDS_RESUME
--                      codec->patch_ops = stac92hd71bxx_patch_ops;
--#endif
-+                  (codec->revision_id & 0xf) == 1)
-                       spec->stream_delay = 40; /* 40 milliseconds */
--              }
-               /* no output amps */
-               spec->num_pwrs = 0;
-@@ -4715,12 +4782,8 @@
-               stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
-               break;
-       case 0x111d7603: /* 6 Port with Analog Mixer */
--              if ((codec->revision_id & 0xf) == 1) {
--#ifdef SND_HDA_NEEDS_RESUME
--                      codec->patch_ops = stac92hd71bxx_patch_ops;
--#endif
-+              if ((codec->revision_id & 0xf) == 1)
-                       spec->stream_delay = 40; /* 40 milliseconds */
--              }
-               /* no output amps */
-               spec->num_pwrs = 0;
-@@ -4763,7 +4826,7 @@
-       case STAC_DELL_M4_3:
-               spec->num_dmics = 1;
-               spec->num_smuxes = 0;
--              spec->num_dmuxes = 0;
-+              spec->num_dmuxes = 1;
-               break;
-       default:
-               spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
-@@ -4771,9 +4834,7 @@
-               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 -
-@@ -5097,11 +5158,14 @@
-               stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
-               /* Enable unsol response for GPIO4/Dock HP connection */
-+              err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
-+              if (err < 0)
-+                      return err;
-               snd_hda_codec_write_cache(codec, codec->afg, 0,
-                       AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
-               snd_hda_codec_write_cache(codec, codec->afg, 0,
-                                         AC_VERB_SET_UNSOLICITED_ENABLE,
--                                        (AC_USRSP_EN | STAC_HP_EVENT));
-+                                        AC_USRSP_EN | err);
-               spec->gpio_dir = 0x0b;
-               spec->eapd_mask = 0x01;
-@@ -5275,7 +5339,7 @@
- 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 {