diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/pci/hda/hda_generic.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/pci/hda/hda_generic.c')
-rw-r--r-- | sound/pci/hda/hda_generic.c | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c new file mode 100644 index 000000000000..69f7b6c4cf83 --- /dev/null +++ b/sound/pci/hda/hda_generic.c | |||
@@ -0,0 +1,906 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * Generic widget tree parser | ||
5 | * | ||
6 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
7 | * | ||
8 | * This driver is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This driver is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <sound/core.h> | ||
28 | #include "hda_codec.h" | ||
29 | #include "hda_local.h" | ||
30 | |||
31 | /* widget node for parsing */ | ||
32 | struct hda_gnode { | ||
33 | hda_nid_t nid; /* NID of this widget */ | ||
34 | unsigned short nconns; /* number of input connections */ | ||
35 | hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; /* input connections */ | ||
36 | unsigned int wid_caps; /* widget capabilities */ | ||
37 | unsigned char type; /* widget type */ | ||
38 | unsigned char pin_ctl; /* pin controls */ | ||
39 | unsigned char checked; /* the flag indicates that the node is already parsed */ | ||
40 | unsigned int pin_caps; /* pin widget capabilities */ | ||
41 | unsigned int def_cfg; /* default configuration */ | ||
42 | unsigned int amp_out_caps; /* AMP out capabilities */ | ||
43 | unsigned int amp_in_caps; /* AMP in capabilities */ | ||
44 | struct list_head list; | ||
45 | }; | ||
46 | |||
47 | /* pathc-specific record */ | ||
48 | struct hda_gspec { | ||
49 | struct hda_gnode *dac_node; /* DAC node */ | ||
50 | struct hda_gnode *out_pin_node; /* Output pin (Line-Out) node */ | ||
51 | struct hda_gnode *pcm_vol_node; /* Node for PCM volume */ | ||
52 | unsigned int pcm_vol_index; /* connection of PCM volume */ | ||
53 | |||
54 | struct hda_gnode *adc_node; /* ADC node */ | ||
55 | struct hda_gnode *cap_vol_node; /* Node for capture volume */ | ||
56 | unsigned int cur_cap_src; /* current capture source */ | ||
57 | struct hda_input_mux input_mux; | ||
58 | char cap_labels[HDA_MAX_NUM_INPUTS][16]; | ||
59 | |||
60 | unsigned int def_amp_in_caps; | ||
61 | unsigned int def_amp_out_caps; | ||
62 | |||
63 | struct hda_pcm pcm_rec; /* PCM information */ | ||
64 | |||
65 | struct list_head nid_list; /* list of widgets */ | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * retrieve the default device type from the default config value | ||
70 | */ | ||
71 | #define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) | ||
72 | #define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) | ||
73 | |||
74 | /* | ||
75 | * destructor | ||
76 | */ | ||
77 | static void snd_hda_generic_free(struct hda_codec *codec) | ||
78 | { | ||
79 | struct hda_gspec *spec = codec->spec; | ||
80 | struct list_head *p, *n; | ||
81 | |||
82 | if (! spec) | ||
83 | return; | ||
84 | /* free all widgets */ | ||
85 | list_for_each_safe(p, n, &spec->nid_list) { | ||
86 | struct hda_gnode *node = list_entry(p, struct hda_gnode, list); | ||
87 | kfree(node); | ||
88 | } | ||
89 | kfree(spec); | ||
90 | } | ||
91 | |||
92 | |||
93 | /* | ||
94 | * add a new widget node and read its attributes | ||
95 | */ | ||
96 | static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid) | ||
97 | { | ||
98 | struct hda_gnode *node; | ||
99 | int nconns; | ||
100 | |||
101 | node = kcalloc(1, sizeof(*node), GFP_KERNEL); | ||
102 | if (node == NULL) | ||
103 | return -ENOMEM; | ||
104 | node->nid = nid; | ||
105 | nconns = snd_hda_get_connections(codec, nid, node->conn_list, HDA_MAX_CONNECTIONS); | ||
106 | if (nconns < 0) { | ||
107 | kfree(node); | ||
108 | return nconns; | ||
109 | } | ||
110 | node->nconns = nconns; | ||
111 | node->wid_caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); | ||
112 | node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
113 | |||
114 | if (node->type == AC_WID_PIN) { | ||
115 | node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP); | ||
116 | node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
117 | node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
118 | } | ||
119 | |||
120 | if (node->wid_caps & AC_WCAP_OUT_AMP) { | ||
121 | if (node->wid_caps & AC_WCAP_AMP_OVRD) | ||
122 | node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP); | ||
123 | if (! node->amp_out_caps) | ||
124 | node->amp_out_caps = spec->def_amp_out_caps; | ||
125 | } | ||
126 | if (node->wid_caps & AC_WCAP_IN_AMP) { | ||
127 | if (node->wid_caps & AC_WCAP_AMP_OVRD) | ||
128 | node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP); | ||
129 | if (! node->amp_in_caps) | ||
130 | node->amp_in_caps = spec->def_amp_in_caps; | ||
131 | } | ||
132 | list_add_tail(&node->list, &spec->nid_list); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * build the AFG subtree | ||
138 | */ | ||
139 | static int build_afg_tree(struct hda_codec *codec) | ||
140 | { | ||
141 | struct hda_gspec *spec = codec->spec; | ||
142 | int i, nodes, err; | ||
143 | hda_nid_t nid; | ||
144 | |||
145 | snd_assert(spec, return -EINVAL); | ||
146 | |||
147 | spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP); | ||
148 | spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP); | ||
149 | |||
150 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); | ||
151 | if (! nid || nodes < 0) { | ||
152 | printk(KERN_ERR "Invalid AFG subtree\n"); | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | /* parse all nodes belonging to the AFG */ | ||
157 | for (i = 0; i < nodes; i++, nid++) { | ||
158 | if ((err = add_new_node(codec, spec, nid)) < 0) | ||
159 | return err; | ||
160 | } | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | |||
166 | /* | ||
167 | * look for the node record for the given NID | ||
168 | */ | ||
169 | /* FIXME: should avoid the braindead linear search */ | ||
170 | static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) | ||
171 | { | ||
172 | struct list_head *p; | ||
173 | struct hda_gnode *node; | ||
174 | |||
175 | list_for_each(p, &spec->nid_list) { | ||
176 | node = list_entry(p, struct hda_gnode, list); | ||
177 | if (node->nid == nid) | ||
178 | return node; | ||
179 | } | ||
180 | return NULL; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * unmute (and set max vol) the output amplifier | ||
185 | */ | ||
186 | static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) | ||
187 | { | ||
188 | unsigned int val, ofs; | ||
189 | snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid); | ||
190 | val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
191 | ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; | ||
192 | if (val >= ofs) | ||
193 | val -= ofs; | ||
194 | val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; | ||
195 | val |= AC_AMP_SET_OUTPUT; | ||
196 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * unmute (and set max vol) the input amplifier | ||
201 | */ | ||
202 | static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index) | ||
203 | { | ||
204 | unsigned int val, ofs; | ||
205 | snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index); | ||
206 | val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
207 | ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; | ||
208 | if (val >= ofs) | ||
209 | val -= ofs; | ||
210 | val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; | ||
211 | val |= AC_AMP_SET_INPUT; | ||
212 | // awk added - fixed to allow unmuting of indexed amps | ||
213 | val |= index << AC_AMP_SET_INDEX_SHIFT; | ||
214 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * select the input connection of the given node. | ||
219 | */ | ||
220 | static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node, | ||
221 | unsigned int index) | ||
222 | { | ||
223 | snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); | ||
224 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index); | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * clear checked flag of each node in the node list | ||
229 | */ | ||
230 | static void clear_check_flags(struct hda_gspec *spec) | ||
231 | { | ||
232 | struct list_head *p; | ||
233 | struct hda_gnode *node; | ||
234 | |||
235 | list_for_each(p, &spec->nid_list) { | ||
236 | node = list_entry(p, struct hda_gnode, list); | ||
237 | node->checked = 0; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * parse the output path recursively until reach to an audio output widget | ||
243 | * | ||
244 | * returns 0 if not found, 1 if found, or a negative error code. | ||
245 | */ | ||
246 | static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, | ||
247 | struct hda_gnode *node) | ||
248 | { | ||
249 | int i, err; | ||
250 | struct hda_gnode *child; | ||
251 | |||
252 | if (node->checked) | ||
253 | return 0; | ||
254 | |||
255 | node->checked = 1; | ||
256 | if (node->type == AC_WID_AUD_OUT) { | ||
257 | if (node->wid_caps & AC_WCAP_DIGITAL) { | ||
258 | snd_printdd("Skip Digital OUT node %x\n", node->nid); | ||
259 | return 0; | ||
260 | } | ||
261 | snd_printdd("AUD_OUT found %x\n", node->nid); | ||
262 | if (spec->dac_node) { | ||
263 | /* already DAC node is assigned, just unmute & connect */ | ||
264 | return node == spec->dac_node; | ||
265 | } | ||
266 | spec->dac_node = node; | ||
267 | if (node->wid_caps & AC_WCAP_OUT_AMP) { | ||
268 | spec->pcm_vol_node = node; | ||
269 | spec->pcm_vol_index = 0; | ||
270 | } | ||
271 | return 1; /* found */ | ||
272 | } | ||
273 | |||
274 | for (i = 0; i < node->nconns; i++) { | ||
275 | child = hda_get_node(spec, node->conn_list[i]); | ||
276 | if (! child) | ||
277 | continue; | ||
278 | err = parse_output_path(codec, spec, child); | ||
279 | if (err < 0) | ||
280 | return err; | ||
281 | else if (err > 0) { | ||
282 | /* found one, | ||
283 | * select the path, unmute both input and output | ||
284 | */ | ||
285 | if (node->nconns > 1) | ||
286 | select_input_connection(codec, node, i); | ||
287 | unmute_input(codec, node, i); | ||
288 | unmute_output(codec, node); | ||
289 | if (! spec->pcm_vol_node) { | ||
290 | if (node->wid_caps & AC_WCAP_IN_AMP) { | ||
291 | spec->pcm_vol_node = node; | ||
292 | spec->pcm_vol_index = i; | ||
293 | } else if (node->wid_caps & AC_WCAP_OUT_AMP) { | ||
294 | spec->pcm_vol_node = node; | ||
295 | spec->pcm_vol_index = 0; | ||
296 | } | ||
297 | } | ||
298 | return 1; | ||
299 | } | ||
300 | } | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Look for the output PIN widget with the given jack type | ||
306 | * and parse the output path to that PIN. | ||
307 | * | ||
308 | * Returns the PIN node when the path to DAC is established. | ||
309 | */ | ||
310 | static struct hda_gnode *parse_output_jack(struct hda_codec *codec, | ||
311 | struct hda_gspec *spec, | ||
312 | int jack_type) | ||
313 | { | ||
314 | struct list_head *p; | ||
315 | struct hda_gnode *node; | ||
316 | int err; | ||
317 | |||
318 | list_for_each(p, &spec->nid_list) { | ||
319 | node = list_entry(p, struct hda_gnode, list); | ||
320 | if (node->type != AC_WID_PIN) | ||
321 | continue; | ||
322 | /* output capable? */ | ||
323 | if (! (node->pin_caps & AC_PINCAP_OUT)) | ||
324 | continue; | ||
325 | if (jack_type >= 0) { | ||
326 | if (jack_type != get_defcfg_type(node)) | ||
327 | continue; | ||
328 | if (node->wid_caps & AC_WCAP_DIGITAL) | ||
329 | continue; /* skip SPDIF */ | ||
330 | } else { | ||
331 | /* output as default? */ | ||
332 | if (! (node->pin_ctl & AC_PINCTL_OUT_EN)) | ||
333 | continue; | ||
334 | } | ||
335 | clear_check_flags(spec); | ||
336 | err = parse_output_path(codec, spec, node); | ||
337 | if (err < 0) | ||
338 | return NULL; | ||
339 | else if (err > 0) { | ||
340 | /* unmute the PIN output */ | ||
341 | unmute_output(codec, node); | ||
342 | /* set PIN-Out enable */ | ||
343 | snd_hda_codec_write(codec, node->nid, 0, | ||
344 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
345 | AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | ||
346 | return node; | ||
347 | } | ||
348 | } | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | |||
353 | /* | ||
354 | * parse outputs | ||
355 | */ | ||
356 | static int parse_output(struct hda_codec *codec) | ||
357 | { | ||
358 | struct hda_gspec *spec = codec->spec; | ||
359 | struct hda_gnode *node; | ||
360 | |||
361 | /* | ||
362 | * Look for the output PIN widget | ||
363 | */ | ||
364 | /* first, look for the line-out pin */ | ||
365 | node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT); | ||
366 | if (node) /* found, remember the PIN node */ | ||
367 | spec->out_pin_node = node; | ||
368 | /* look for the HP-out pin */ | ||
369 | node = parse_output_jack(codec, spec, AC_JACK_HP_OUT); | ||
370 | if (node) { | ||
371 | if (! spec->out_pin_node) | ||
372 | spec->out_pin_node = node; | ||
373 | } | ||
374 | |||
375 | if (! spec->out_pin_node) { | ||
376 | /* no line-out or HP pins found, | ||
377 | * then choose for the first output pin | ||
378 | */ | ||
379 | spec->out_pin_node = parse_output_jack(codec, spec, -1); | ||
380 | if (! spec->out_pin_node) | ||
381 | snd_printd("hda_generic: no proper output path found\n"); | ||
382 | } | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | * input MUX | ||
389 | */ | ||
390 | |||
391 | /* control callbacks */ | ||
392 | static int capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
393 | { | ||
394 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
395 | struct hda_gspec *spec = codec->spec; | ||
396 | return snd_hda_input_mux_info(&spec->input_mux, uinfo); | ||
397 | } | ||
398 | |||
399 | static int capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
400 | { | ||
401 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
402 | struct hda_gspec *spec = codec->spec; | ||
403 | |||
404 | ucontrol->value.enumerated.item[0] = spec->cur_cap_src; | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
409 | { | ||
410 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
411 | struct hda_gspec *spec = codec->spec; | ||
412 | return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, | ||
413 | spec->adc_node->nid, &spec->cur_cap_src); | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * return the string name of the given input PIN widget | ||
418 | */ | ||
419 | static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) | ||
420 | { | ||
421 | unsigned int location = get_defcfg_location(node); | ||
422 | switch (get_defcfg_type(node)) { | ||
423 | case AC_JACK_LINE_IN: | ||
424 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
425 | return "Front Line"; | ||
426 | return "Line"; | ||
427 | case AC_JACK_CD: | ||
428 | if (pinctl) | ||
429 | *pinctl |= AC_PIN_VREF_GRD; | ||
430 | return "CD"; | ||
431 | case AC_JACK_AUX: | ||
432 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
433 | return "Front Aux"; | ||
434 | return "Aux"; | ||
435 | case AC_JACK_MIC_IN: | ||
436 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
437 | return "Front Mic"; | ||
438 | return "Mic"; | ||
439 | case AC_JACK_SPDIF_IN: | ||
440 | return "SPDIF"; | ||
441 | case AC_JACK_DIG_OTHER_IN: | ||
442 | return "Digital"; | ||
443 | } | ||
444 | return NULL; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * parse the nodes recursively until reach to the input PIN | ||
449 | * | ||
450 | * returns 0 if not found, 1 if found, or a negative error code. | ||
451 | */ | ||
452 | static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, | ||
453 | struct hda_gnode *node) | ||
454 | { | ||
455 | int i, err; | ||
456 | unsigned int pinctl; | ||
457 | char *label; | ||
458 | const char *type; | ||
459 | |||
460 | if (node->checked) | ||
461 | return 0; | ||
462 | |||
463 | node->checked = 1; | ||
464 | if (node->type != AC_WID_PIN) { | ||
465 | for (i = 0; i < node->nconns; i++) { | ||
466 | struct hda_gnode *child; | ||
467 | child = hda_get_node(spec, node->conn_list[i]); | ||
468 | if (! child) | ||
469 | continue; | ||
470 | err = parse_adc_sub_nodes(codec, spec, child); | ||
471 | if (err < 0) | ||
472 | return err; | ||
473 | if (err > 0) { | ||
474 | /* found one, | ||
475 | * select the path, unmute both input and output | ||
476 | */ | ||
477 | if (node->nconns > 1) | ||
478 | select_input_connection(codec, node, i); | ||
479 | unmute_input(codec, node, i); | ||
480 | unmute_output(codec, node); | ||
481 | return err; | ||
482 | } | ||
483 | } | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | /* input capable? */ | ||
488 | if (! (node->pin_caps & AC_PINCAP_IN)) | ||
489 | return 0; | ||
490 | |||
491 | if (node->wid_caps & AC_WCAP_DIGITAL) | ||
492 | return 0; /* skip SPDIF */ | ||
493 | |||
494 | if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) { | ||
495 | snd_printk(KERN_ERR "hda_generic: Too many items for capture\n"); | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | |||
499 | pinctl = AC_PINCTL_IN_EN; | ||
500 | /* create a proper capture source label */ | ||
501 | type = get_input_type(node, &pinctl); | ||
502 | if (! type) { | ||
503 | /* input as default? */ | ||
504 | if (! (node->pin_ctl & AC_PINCTL_IN_EN)) | ||
505 | return 0; | ||
506 | type = "Input"; | ||
507 | } | ||
508 | label = spec->cap_labels[spec->input_mux.num_items]; | ||
509 | strcpy(label, type); | ||
510 | spec->input_mux.items[spec->input_mux.num_items].label = label; | ||
511 | |||
512 | /* unmute the PIN external input */ | ||
513 | unmute_input(codec, node, 0); /* index = 0? */ | ||
514 | /* set PIN-In enable */ | ||
515 | snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); | ||
516 | |||
517 | return 1; /* found */ | ||
518 | } | ||
519 | |||
520 | /* | ||
521 | * parse input | ||
522 | */ | ||
523 | static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) | ||
524 | { | ||
525 | struct hda_gspec *spec = codec->spec; | ||
526 | struct hda_gnode *node; | ||
527 | int i, err; | ||
528 | |||
529 | snd_printdd("AUD_IN = %x\n", adc_node->nid); | ||
530 | clear_check_flags(spec); | ||
531 | |||
532 | // awk added - fixed no recording due to muted widget | ||
533 | unmute_input(codec, adc_node, 0); | ||
534 | |||
535 | /* | ||
536 | * check each connection of the ADC | ||
537 | * if it reaches to a proper input PIN, add the path as the | ||
538 | * input path. | ||
539 | */ | ||
540 | for (i = 0; i < adc_node->nconns; i++) { | ||
541 | node = hda_get_node(spec, adc_node->conn_list[i]); | ||
542 | if (! node) | ||
543 | continue; | ||
544 | err = parse_adc_sub_nodes(codec, spec, node); | ||
545 | if (err < 0) | ||
546 | return err; | ||
547 | else if (err > 0) { | ||
548 | struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items]; | ||
549 | char *buf = spec->cap_labels[spec->input_mux.num_items]; | ||
550 | int ocap; | ||
551 | for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) { | ||
552 | if (! strcmp(buf, spec->cap_labels[ocap])) { | ||
553 | /* same label already exists, | ||
554 | * put the index number to be unique | ||
555 | */ | ||
556 | sprintf(buf, "%s %d", spec->cap_labels[ocap], | ||
557 | spec->input_mux.num_items); | ||
558 | } | ||
559 | } | ||
560 | csrc->index = i; | ||
561 | spec->input_mux.num_items++; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (! spec->input_mux.num_items) | ||
566 | return 0; /* no input path found... */ | ||
567 | |||
568 | snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items); | ||
569 | for (i = 0; i < spec->input_mux.num_items; i++) | ||
570 | snd_printdd(" [%s] IDX=0x%x\n", spec->input_mux.items[i].label, | ||
571 | spec->input_mux.items[i].index); | ||
572 | |||
573 | spec->adc_node = adc_node; | ||
574 | return 1; | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * parse input | ||
579 | */ | ||
580 | static int parse_input(struct hda_codec *codec) | ||
581 | { | ||
582 | struct hda_gspec *spec = codec->spec; | ||
583 | struct list_head *p; | ||
584 | struct hda_gnode *node; | ||
585 | int err; | ||
586 | |||
587 | /* | ||
588 | * At first we look for an audio input widget. | ||
589 | * If it reaches to certain input PINs, we take it as the | ||
590 | * input path. | ||
591 | */ | ||
592 | list_for_each(p, &spec->nid_list) { | ||
593 | node = list_entry(p, struct hda_gnode, list); | ||
594 | if (node->wid_caps & AC_WCAP_DIGITAL) | ||
595 | continue; /* skip SPDIF */ | ||
596 | if (node->type == AC_WID_AUD_IN) { | ||
597 | err = parse_input_path(codec, node); | ||
598 | if (err < 0) | ||
599 | return err; | ||
600 | else if (err > 0) | ||
601 | return 0; | ||
602 | } | ||
603 | } | ||
604 | snd_printd("hda_generic: no proper input path found\n"); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | /* | ||
609 | * create mixer controls if possible | ||
610 | */ | ||
611 | #define DIR_OUT 0x1 | ||
612 | #define DIR_IN 0x2 | ||
613 | |||
614 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, | ||
615 | unsigned int index, const char *type, const char *dir_sfx) | ||
616 | { | ||
617 | char name[32]; | ||
618 | int err; | ||
619 | int created = 0; | ||
620 | snd_kcontrol_new_t knew; | ||
621 | |||
622 | if (type) | ||
623 | sprintf(name, "%s %s Switch", type, dir_sfx); | ||
624 | else | ||
625 | sprintf(name, "%s Switch", dir_sfx); | ||
626 | if ((node->wid_caps & AC_WCAP_IN_AMP) && | ||
627 | (node->amp_in_caps & AC_AMPCAP_MUTE)) { | ||
628 | knew = (snd_kcontrol_new_t)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); | ||
629 | snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); | ||
630 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | ||
631 | return err; | ||
632 | created = 1; | ||
633 | } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && | ||
634 | (node->amp_out_caps & AC_AMPCAP_MUTE)) { | ||
635 | knew = (snd_kcontrol_new_t)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); | ||
636 | snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); | ||
637 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | ||
638 | return err; | ||
639 | created = 1; | ||
640 | } | ||
641 | |||
642 | if (type) | ||
643 | sprintf(name, "%s %s Volume", type, dir_sfx); | ||
644 | else | ||
645 | sprintf(name, "%s Volume", dir_sfx); | ||
646 | if ((node->wid_caps & AC_WCAP_IN_AMP) && | ||
647 | (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { | ||
648 | knew = (snd_kcontrol_new_t)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); | ||
649 | snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); | ||
650 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | ||
651 | return err; | ||
652 | created = 1; | ||
653 | } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && | ||
654 | (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { | ||
655 | knew = (snd_kcontrol_new_t)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); | ||
656 | snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); | ||
657 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | ||
658 | return err; | ||
659 | created = 1; | ||
660 | } | ||
661 | |||
662 | return created; | ||
663 | } | ||
664 | |||
665 | /* | ||
666 | * check whether the controls with the given name and direction suffix already exist | ||
667 | */ | ||
668 | static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir) | ||
669 | { | ||
670 | snd_ctl_elem_id_t id; | ||
671 | memset(&id, 0, sizeof(id)); | ||
672 | sprintf(id.name, "%s %s Volume", type, dir); | ||
673 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
674 | if (snd_ctl_find_id(codec->bus->card, &id)) | ||
675 | return 1; | ||
676 | sprintf(id.name, "%s %s Switch", type, dir); | ||
677 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
678 | if (snd_ctl_find_id(codec->bus->card, &id)) | ||
679 | return 1; | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * build output mixer controls | ||
685 | */ | ||
686 | static int build_output_controls(struct hda_codec *codec) | ||
687 | { | ||
688 | struct hda_gspec *spec = codec->spec; | ||
689 | int err; | ||
690 | |||
691 | err = create_mixer(codec, spec->pcm_vol_node, spec->pcm_vol_index, | ||
692 | "PCM", "Playback"); | ||
693 | if (err < 0) | ||
694 | return err; | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | /* create capture volume/switch */ | ||
699 | static int build_input_controls(struct hda_codec *codec) | ||
700 | { | ||
701 | struct hda_gspec *spec = codec->spec; | ||
702 | struct hda_gnode *adc_node = spec->adc_node; | ||
703 | int err; | ||
704 | |||
705 | if (! adc_node) | ||
706 | return 0; /* not found */ | ||
707 | |||
708 | /* create capture volume and switch controls if the ADC has an amp */ | ||
709 | err = create_mixer(codec, adc_node, 0, NULL, "Capture"); | ||
710 | |||
711 | /* create input MUX if multiple sources are available */ | ||
712 | if (spec->input_mux.num_items > 1) { | ||
713 | static snd_kcontrol_new_t cap_sel = { | ||
714 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
715 | .name = "Capture Source", | ||
716 | .info = capture_source_info, | ||
717 | .get = capture_source_get, | ||
718 | .put = capture_source_put, | ||
719 | }; | ||
720 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0) | ||
721 | return err; | ||
722 | spec->cur_cap_src = 0; | ||
723 | select_input_connection(codec, adc_node, spec->input_mux.items[0].index); | ||
724 | } | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | |||
729 | /* | ||
730 | * parse the nodes recursively until reach to the output PIN. | ||
731 | * | ||
732 | * returns 0 - if not found, | ||
733 | * 1 - if found, but no mixer is created | ||
734 | * 2 - if found and mixer was already created, (just skip) | ||
735 | * a negative error code | ||
736 | */ | ||
737 | static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, | ||
738 | struct hda_gnode *node, struct hda_gnode *dest_node, | ||
739 | const char *type) | ||
740 | { | ||
741 | int i, err; | ||
742 | |||
743 | if (node->checked) | ||
744 | return 0; | ||
745 | |||
746 | node->checked = 1; | ||
747 | if (node == dest_node) { | ||
748 | /* loopback connection found */ | ||
749 | return 1; | ||
750 | } | ||
751 | |||
752 | for (i = 0; i < node->nconns; i++) { | ||
753 | struct hda_gnode *child = hda_get_node(spec, node->conn_list[i]); | ||
754 | if (! child) | ||
755 | continue; | ||
756 | err = parse_loopback_path(codec, spec, child, dest_node, type); | ||
757 | if (err < 0) | ||
758 | return err; | ||
759 | else if (err >= 1) { | ||
760 | if (err == 1) { | ||
761 | err = create_mixer(codec, node, i, type, "Playback"); | ||
762 | if (err < 0) | ||
763 | return err; | ||
764 | if (err > 0) | ||
765 | return 2; /* ok, created */ | ||
766 | /* not created, maybe in the lower path */ | ||
767 | err = 1; | ||
768 | } | ||
769 | /* connect and unmute */ | ||
770 | if (node->nconns > 1) | ||
771 | select_input_connection(codec, node, i); | ||
772 | unmute_input(codec, node, i); | ||
773 | unmute_output(codec, node); | ||
774 | return err; | ||
775 | } | ||
776 | } | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | /* | ||
781 | * parse the tree and build the loopback controls | ||
782 | */ | ||
783 | static int build_loopback_controls(struct hda_codec *codec) | ||
784 | { | ||
785 | struct hda_gspec *spec = codec->spec; | ||
786 | struct list_head *p; | ||
787 | struct hda_gnode *node; | ||
788 | int err; | ||
789 | const char *type; | ||
790 | |||
791 | if (! spec->out_pin_node) | ||
792 | return 0; | ||
793 | |||
794 | list_for_each(p, &spec->nid_list) { | ||
795 | node = list_entry(p, struct hda_gnode, list); | ||
796 | if (node->type != AC_WID_PIN) | ||
797 | continue; | ||
798 | /* input capable? */ | ||
799 | if (! (node->pin_caps & AC_PINCAP_IN)) | ||
800 | return 0; | ||
801 | type = get_input_type(node, NULL); | ||
802 | if (type) { | ||
803 | if (check_existing_control(codec, type, "Playback")) | ||
804 | continue; | ||
805 | clear_check_flags(spec); | ||
806 | err = parse_loopback_path(codec, spec, spec->out_pin_node, | ||
807 | node, type); | ||
808 | if (err < 0) | ||
809 | return err; | ||
810 | if (! err) | ||
811 | continue; | ||
812 | } | ||
813 | } | ||
814 | return 0; | ||
815 | } | ||
816 | |||
817 | /* | ||
818 | * build mixer controls | ||
819 | */ | ||
820 | static int build_generic_controls(struct hda_codec *codec) | ||
821 | { | ||
822 | int err; | ||
823 | |||
824 | if ((err = build_input_controls(codec)) < 0 || | ||
825 | (err = build_output_controls(codec)) < 0 || | ||
826 | (err = build_loopback_controls(codec)) < 0) | ||
827 | return err; | ||
828 | |||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | /* | ||
833 | * PCM | ||
834 | */ | ||
835 | static struct hda_pcm_stream generic_pcm_playback = { | ||
836 | .substreams = 1, | ||
837 | .channels_min = 2, | ||
838 | .channels_max = 2, | ||
839 | }; | ||
840 | |||
841 | static int build_generic_pcms(struct hda_codec *codec) | ||
842 | { | ||
843 | struct hda_gspec *spec = codec->spec; | ||
844 | struct hda_pcm *info = &spec->pcm_rec; | ||
845 | |||
846 | if (! spec->dac_node && ! spec->adc_node) { | ||
847 | snd_printd("hda_generic: no PCM found\n"); | ||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | codec->num_pcms = 1; | ||
852 | codec->pcm_info = info; | ||
853 | |||
854 | info->name = "HDA Generic"; | ||
855 | if (spec->dac_node) { | ||
856 | info->stream[0] = generic_pcm_playback; | ||
857 | info->stream[0].nid = spec->dac_node->nid; | ||
858 | } | ||
859 | if (spec->adc_node) { | ||
860 | info->stream[1] = generic_pcm_playback; | ||
861 | info->stream[1].nid = spec->adc_node->nid; | ||
862 | } | ||
863 | |||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | |||
868 | /* | ||
869 | */ | ||
870 | static struct hda_codec_ops generic_patch_ops = { | ||
871 | .build_controls = build_generic_controls, | ||
872 | .build_pcms = build_generic_pcms, | ||
873 | .free = snd_hda_generic_free, | ||
874 | }; | ||
875 | |||
876 | /* | ||
877 | * the generic parser | ||
878 | */ | ||
879 | int snd_hda_parse_generic_codec(struct hda_codec *codec) | ||
880 | { | ||
881 | struct hda_gspec *spec; | ||
882 | int err; | ||
883 | |||
884 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
885 | if (spec == NULL) { | ||
886 | printk(KERN_ERR "hda_generic: can't allocate spec\n"); | ||
887 | return -ENOMEM; | ||
888 | } | ||
889 | codec->spec = spec; | ||
890 | INIT_LIST_HEAD(&spec->nid_list); | ||
891 | |||
892 | if ((err = build_afg_tree(codec)) < 0) | ||
893 | goto error; | ||
894 | |||
895 | if ((err = parse_input(codec)) < 0 || | ||
896 | (err = parse_output(codec)) < 0) | ||
897 | goto error; | ||
898 | |||
899 | codec->patch_ops = generic_patch_ops; | ||
900 | |||
901 | return 0; | ||
902 | |||
903 | error: | ||
904 | snd_hda_generic_free(codec); | ||
905 | return err; | ||
906 | } | ||