]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.drivers/alsa-hda-stac-hp-detect-fix
Updated xen patches taken from suse.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.drivers / alsa-hda-stac-hp-detect-fix
1 From: Takashi Iwai <tiwai@suse.de>
2 Subject: ALSA: hda - Fix IDT/STAC multiple HP detection
3 Patch-mainline:
4 References: bnc#443267
5
6 Due to the recent change for multiple HP as line-out switch, only
7 one of the multiple headphons (usually a wrong one) is toggled
8 and the other pins are still disabled. This causes the silent output
9 problem on some Dell laptops.
10
11 Also, the hp_switch check is screwed up when a line-in or a mic-in
12 jack exists. This is added as an additional output, but hp_switch
13 check doesn't take it into account.
14
15 This patch fixes these issues: simplify hp_switch check by using
16 the NID instead of bool, and clean up / fix the toggle of HP pins
17 in unsol event handler code.
18
19 Reference: Novell bnc#443267
20 https://bugzilla.novell.com/show_bug.cgi?id=443267
21
22 Signed-off-by: Takashi Iwai <tiwai@suse.de>
23
24 ---
25 sound/pci/hda/patch_sigmatel.c | 57 +++++++++++++++++++++++++++++++----------
26 1 file changed, 44 insertions(+), 13 deletions(-)
27
28 --- a/sound/pci/hda/patch_sigmatel.c
29 +++ b/sound/pci/hda/patch_sigmatel.c
30 @@ -212,7 +212,7 @@ struct sigmatel_spec {
31 /* i/o switches */
32 unsigned int io_switch[2];
33 unsigned int clfe_swap;
34 - unsigned int hp_switch;
35 + unsigned int hp_switch; /* NID of HP as line-out */
36 unsigned int aloopback;
37
38 struct hda_pcm pcm_rec[2]; /* PCM information */
39 @@ -2448,7 +2448,7 @@ static int stac92xx_hp_switch_get(struct
40 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
41 struct sigmatel_spec *spec = codec->spec;
42
43 - ucontrol->value.integer.value[0] = spec->hp_switch;
44 + ucontrol->value.integer.value[0] = !!spec->hp_switch;
45 return 0;
46 }
47
48 @@ -2457,8 +2457,9 @@ static int stac92xx_hp_switch_put(struct
49 {
50 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
51 struct sigmatel_spec *spec = codec->spec;
52 + int nid = kcontrol->private_value;
53
54 - spec->hp_switch = ucontrol->value.integer.value[0];
55 + spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
56
57 /* check to be sure that the ports are upto date with
58 * switch changes
59 @@ -2867,7 +2868,8 @@ static int stac92xx_auto_create_multi_ou
60 if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
61 err = stac92xx_add_control(spec,
62 STAC_CTL_WIDGET_HP_SWITCH,
63 - "Headphone as Line Out Switch", 0);
64 + "Headphone as Line Out Switch",
65 + cfg->hp_pins[cfg->hp_outs - 1]);
66 if (err < 0)
67 return err;
68 }
69 @@ -3791,11 +3793,30 @@ static int get_hp_pin_presence(struct hd
70 return 0;
71 }
72
73 +/* return non-zero if the hp-pin of the given array index isn't
74 + * a jack-detection target
75 + */
76 +static int no_hp_sensing(struct sigmatel_spec *spec, int i)
77 +{
78 + struct auto_pin_cfg *cfg = &spec->autocfg;
79 +
80 + /* ignore sensing of shared line and mic jacks */
81 + if (spec->line_switch &&
82 + cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
83 + return 1;
84 + if (spec->mic_switch &&
85 + cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
86 + return 1;
87 + /* ignore if the pin is set as line-out */
88 + if (cfg->hp_pins[i] == spec->hp_switch)
89 + return 1;
90 + return 0;
91 +}
92 +
93 static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
94 {
95 struct sigmatel_spec *spec = codec->spec;
96 struct auto_pin_cfg *cfg = &spec->autocfg;
97 - int nid = cfg->hp_pins[cfg->hp_outs - 1];
98 int i, presence;
99
100 presence = 0;
101 @@ -3806,15 +3827,16 @@ static void stac92xx_hp_detect(struct hd
102 for (i = 0; i < cfg->hp_outs; i++) {
103 if (presence)
104 break;
105 - if (spec->hp_switch && cfg->hp_pins[i] == nid)
106 - break;
107 + if (no_hp_sensing(spec, i))
108 + continue;
109 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
110 }
111
112 if (presence) {
113 - /* disable lineouts, enable hp */
114 + /* disable lineouts */
115 if (spec->hp_switch)
116 - stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
117 + stac92xx_reset_pinctl(codec, spec->hp_switch,
118 + AC_PINCTL_OUT_EN);
119 for (i = 0; i < cfg->line_outs; i++)
120 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
121 AC_PINCTL_OUT_EN);
122 @@ -3826,9 +3848,10 @@ static void stac92xx_hp_detect(struct hd
123 spec->gpio_dir, spec->gpio_data &
124 ~spec->eapd_mask);
125 } else {
126 - /* enable lineouts, disable hp */
127 + /* enable lineouts */
128 if (spec->hp_switch)
129 - stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
130 + stac92xx_set_pinctl(codec, spec->hp_switch,
131 + AC_PINCTL_OUT_EN);
132 for (i = 0; i < cfg->line_outs; i++)
133 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
134 AC_PINCTL_OUT_EN);
135 @@ -3840,8 +3863,16 @@ static void stac92xx_hp_detect(struct hd
136 spec->gpio_dir, spec->gpio_data |
137 spec->eapd_mask);
138 }
139 - if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
140 - stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
141 + /* toggle hp outs */
142 + for (i = 0; i < cfg->hp_outs; i++) {
143 + unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
144 + if (no_hp_sensing(spec, i))
145 + continue;
146 + if (presence)
147 + stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
148 + else
149 + stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
150 + }
151 }
152
153 static void stac92xx_pin_sense(struct hda_codec *codec, int idx)