]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From dc04d1b4d2043e2fca2d94d6d5542b930f2bc5b3 Mon Sep 17 00:00:00 2001 |
2 | From: Takashi Iwai <tiwai@suse.de> | |
3 | Date: Fri, 6 Mar 2009 10:00:05 +0100 | |
4 | Subject: ALSA: hda - Create output controls according to pin types for IDT/STAC | |
5 | Patch-mainline: | |
6 | References: bnc#479558, bnc#482052 | |
7 | ||
8 | Improve the parser to pick up more intuitive control names for the | |
9 | outputs judging from the pin type, instead of fixed names assigned | |
10 | to channels. | |
11 | ||
12 | Also, revive the multi-HP workaround since this change fixes the | |
13 | problem with the multi-HP detection. | |
14 | ||
15 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
16 | ||
17 | --- | |
18 | sound/pci/hda/patch_sigmatel.c | 141 ++++++++++++++++++++--------------------- | |
19 | 1 file changed, 72 insertions(+), 69 deletions(-) | |
20 | ||
21 | --- a/sound/pci/hda/patch_sigmatel.c | |
22 | +++ b/sound/pci/hda/patch_sigmatel.c | |
23 | @@ -2998,35 +2998,33 @@ static int add_spec_extra_dacs(struct si | |
24 | return 1; | |
25 | } | |
26 | ||
27 | -static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid) | |
28 | -{ | |
29 | - int i; | |
30 | - | |
31 | - if (spec->autocfg.line_outs != 1) | |
32 | - return 0; | |
33 | - if (spec->multiout.hp_nid == nid) | |
34 | - return 0; | |
35 | - for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) | |
36 | - if (spec->multiout.extra_out_nid[i] == nid) | |
37 | - return 0; | |
38 | - return 1; | |
39 | -} | |
40 | - | |
41 | -/* add playback controls from the parsed DAC table */ | |
42 | -static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |
43 | - const struct auto_pin_cfg *cfg) | |
44 | +/* Create output controls | |
45 | + * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT) | |
46 | + */ | |
47 | +static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, | |
48 | + const hda_nid_t *pins, | |
49 | + const hda_nid_t *dac_nids, | |
50 | + int type) | |
51 | { | |
52 | struct sigmatel_spec *spec = codec->spec; | |
53 | static const char *chname[4] = { | |
54 | "Front", "Surround", NULL /*CLFE*/, "Side" | |
55 | }; | |
56 | - hda_nid_t nid = 0; | |
57 | + static const char *hp_pfxs[] = { | |
58 | + "Headphone", "Headphone2", "Headphone3", "Headphone4" | |
59 | + }; | |
60 | + static const char *speaker_pfxs[] = { | |
61 | + "Speaker", "External Speaker", "Speaker2", "Speaker3" | |
62 | + }; | |
63 | + hda_nid_t nid; | |
64 | int i, err; | |
65 | unsigned int wid_caps; | |
66 | ||
67 | - for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { | |
68 | - nid = spec->multiout.dac_nids[i]; | |
69 | - if (i == 2) { | |
70 | + for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) { | |
71 | + nid = dac_nids[i]; | |
72 | + if (!nid) | |
73 | + continue; | |
74 | + if (type != AUTO_PIN_HP_OUT && i == 2) { | |
75 | /* Center/LFE */ | |
76 | err = create_controls(codec, "Center", nid, 1); | |
77 | if (err < 0) | |
78 | @@ -3047,23 +3045,43 @@ static int stac92xx_auto_create_multi_ou | |
79 | } | |
80 | ||
81 | } else { | |
82 | - const char *name = chname[i]; | |
83 | - /* if it's a single DAC, assign a better name */ | |
84 | - if (!i && is_unique_dac(spec, nid)) { | |
85 | - switch (cfg->line_out_type) { | |
86 | - case AUTO_PIN_HP_OUT: | |
87 | - name = "Headphone"; | |
88 | - break; | |
89 | - case AUTO_PIN_SPEAKER_OUT: | |
90 | - name = "Speaker"; | |
91 | - break; | |
92 | - } | |
93 | + const char *name; | |
94 | + switch (type) { | |
95 | + case AUTO_PIN_HP_OUT: | |
96 | + name = hp_pfxs[i]; | |
97 | + break; | |
98 | + case AUTO_PIN_SPEAKER_OUT: | |
99 | + name = speaker_pfxs[i]; | |
100 | + break; | |
101 | + default: | |
102 | + name = chname[i]; | |
103 | + break; | |
104 | } | |
105 | err = create_controls(codec, name, nid, 3); | |
106 | if (err < 0) | |
107 | return err; | |
108 | + if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) { | |
109 | + wid_caps = get_wcaps(codec, pins[i]); | |
110 | + if (wid_caps & AC_WCAP_UNSOL_CAP) | |
111 | + spec->hp_detect = 1; | |
112 | + } | |
113 | } | |
114 | } | |
115 | + return 0; | |
116 | +} | |
117 | + | |
118 | +/* add playback controls from the parsed DAC table */ | |
119 | +static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |
120 | + const struct auto_pin_cfg *cfg) | |
121 | +{ | |
122 | + struct sigmatel_spec *spec = codec->spec; | |
123 | + int err; | |
124 | + | |
125 | + err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, | |
126 | + spec->multiout.dac_nids, | |
127 | + cfg->line_out_type); | |
128 | + if (err < 0) | |
129 | + return err; | |
130 | ||
131 | if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { | |
132 | err = stac92xx_add_control(spec, | |
133 | @@ -3098,40 +3116,18 @@ static int stac92xx_auto_create_hp_ctls( | |
134 | struct auto_pin_cfg *cfg) | |
135 | { | |
136 | struct sigmatel_spec *spec = codec->spec; | |
137 | - hda_nid_t nid; | |
138 | - int i, err, nums; | |
139 | + int err; | |
140 | + | |
141 | + err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins, | |
142 | + spec->hp_dacs, AUTO_PIN_HP_OUT); | |
143 | + if (err < 0) | |
144 | + return err; | |
145 | + | |
146 | + err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, | |
147 | + spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT); | |
148 | + if (err < 0) | |
149 | + return err; | |
150 | ||
151 | - nums = 0; | |
152 | - for (i = 0; i < cfg->hp_outs; i++) { | |
153 | - static const char *pfxs[] = { | |
154 | - "Headphone", "Headphone2", "Headphone3", | |
155 | - }; | |
156 | - unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); | |
157 | - if (wid_caps & AC_WCAP_UNSOL_CAP) | |
158 | - spec->hp_detect = 1; | |
159 | - if (nums >= ARRAY_SIZE(pfxs)) | |
160 | - continue; | |
161 | - nid = spec->hp_dacs[i]; | |
162 | - if (!nid) | |
163 | - continue; | |
164 | - err = create_controls(codec, pfxs[nums++], nid, 3); | |
165 | - if (err < 0) | |
166 | - return err; | |
167 | - } | |
168 | - nums = 0; | |
169 | - for (i = 0; i < cfg->speaker_outs; i++) { | |
170 | - static const char *pfxs[] = { | |
171 | - "Speaker", "External Speaker", "Speaker2", | |
172 | - }; | |
173 | - if (nums >= ARRAY_SIZE(pfxs)) | |
174 | - continue; | |
175 | - nid = spec->speaker_dacs[i]; | |
176 | - if (!nid) | |
177 | - continue; | |
178 | - err = create_controls(codec, pfxs[nums++], nid, 3); | |
179 | - if (err < 0) | |
180 | - return err; | |
181 | - } | |
182 | return 0; | |
183 | } | |
184 | ||
185 | @@ -3468,6 +3464,7 @@ static void stac92xx_auto_init_hp_out(st | |
186 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) | |
187 | { | |
188 | struct sigmatel_spec *spec = codec->spec; | |
189 | + int hp_swap = 0; | |
190 | int err; | |
191 | ||
192 | if ((err = snd_hda_parse_pin_def_config(codec, | |
193 | @@ -3477,7 +3474,6 @@ static int stac92xx_parse_auto_config(st | |
194 | if (! spec->autocfg.line_outs) | |
195 | return 0; /* can't find valid pin config */ | |
196 | ||
197 | -#if 0 /* FIXME: temporarily disabled */ | |
198 | /* If we have no real line-out pin and multiple hp-outs, HPs should | |
199 | * be set up as multi-channel outputs. | |
200 | */ | |
201 | @@ -3496,8 +3492,8 @@ static int stac92xx_parse_auto_config(st | |
202 | spec->autocfg.line_outs = spec->autocfg.hp_outs; | |
203 | spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; | |
204 | spec->autocfg.hp_outs = 0; | |
205 | + hp_swap = 1; | |
206 | } | |
207 | -#endif /* FIXME: temporarily disabled */ | |
208 | if (spec->autocfg.mono_out_pin) { | |
209 | int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & | |
210 | (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); | |
211 | @@ -3590,12 +3586,19 @@ static int stac92xx_parse_auto_config(st | |
212 | #endif | |
213 | ||
214 | err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); | |
215 | - | |
216 | if (err < 0) | |
217 | return err; | |
218 | ||
219 | - err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); | |
220 | + /* All output parsing done, now restore the swapped hp pins */ | |
221 | + if (hp_swap) { | |
222 | + memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, | |
223 | + sizeof(spec->autocfg.hp_pins)); | |
224 | + spec->autocfg.hp_outs = spec->autocfg.line_outs; | |
225 | + spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; | |
226 | + spec->autocfg.line_outs = 0; | |
227 | + } | |
228 | ||
229 | + err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); | |
230 | if (err < 0) | |
231 | return err; | |
232 |