+++ /dev/null
-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 {