diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-06-13 08:16:38 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-06-22 06:28:59 -0400 |
commit | e9edcee061a80181f0d6e7cada07e1898c14718e (patch) | |
tree | b8ce3f0430ef436cbfbe98736f1ef6bc86fd8c94 /sound/pci/hda/patch_cmedia.c | |
parent | b636a71d9b9525ee51ca872d461817a5bd5c39fd (diff) |
[ALSA] hda-codec - More fix of ALC880 codec support
Documentation,HDA Codec driver,HDA generic driver,HDA Intel driver
- Fix some invalid configurations, typos in the last patch
- Make init_verbs chainable, so that different configs can share the same
init_verbs
- Reorder and clean up the source codes in patch_realtek.c
- Add the pin default configuration parser, used commonly in cmedia
and realtek patch codes.
- Add 'auto' model to ALC880 for auto-configuration from BIOS
Use this model as default, and 3-stack as fallback
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_cmedia.c')
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 236 |
1 files changed, 79 insertions, 157 deletions
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 087230ca20a5..2d6e3e3d0a38 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -51,6 +51,7 @@ struct cmi_spec { | |||
51 | /* playback */ | 51 | /* playback */ |
52 | struct hda_multi_out multiout; | 52 | struct hda_multi_out multiout; |
53 | hda_nid_t dac_nids[4]; /* NID for each DAC */ | 53 | hda_nid_t dac_nids[4]; /* NID for each DAC */ |
54 | int num_dacs; | ||
54 | 55 | ||
55 | /* capture */ | 56 | /* capture */ |
56 | hda_nid_t *adc_nids; | 57 | hda_nid_t *adc_nids; |
@@ -77,6 +78,19 @@ struct cmi_spec { | |||
77 | struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ | 78 | struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ |
78 | }; | 79 | }; |
79 | 80 | ||
81 | /* amp values */ | ||
82 | #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) | ||
83 | #define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) | ||
84 | #define AMP_OUT_MUTE 0xb080 | ||
85 | #define AMP_OUT_UNMUTE 0xb000 | ||
86 | #define AMP_OUT_ZERO 0xb000 | ||
87 | /* pinctl values */ | ||
88 | #define PIN_IN 0x20 | ||
89 | #define PIN_VREF80 0x24 | ||
90 | #define PIN_VREF50 0x21 | ||
91 | #define PIN_OUT 0x40 | ||
92 | #define PIN_HP 0xc0 | ||
93 | |||
80 | /* | 94 | /* |
81 | * input MUX | 95 | * input MUX |
82 | */ | 96 | */ |
@@ -114,9 +128,9 @@ static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon | |||
114 | /* 3-stack / 2 channel */ | 128 | /* 3-stack / 2 channel */ |
115 | static struct hda_verb cmi9880_ch2_init[] = { | 129 | static struct hda_verb cmi9880_ch2_init[] = { |
116 | /* set line-in PIN for input */ | 130 | /* set line-in PIN for input */ |
117 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | 131 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
118 | /* set mic PIN for input, also enable vref */ | 132 | /* set mic PIN for input, also enable vref */ |
119 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 133 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
120 | /* route front PCM (DAC1) to HP */ | 134 | /* route front PCM (DAC1) to HP */ |
121 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | 135 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
122 | {} | 136 | {} |
@@ -125,9 +139,9 @@ static struct hda_verb cmi9880_ch2_init[] = { | |||
125 | /* 3-stack / 6 channel */ | 139 | /* 3-stack / 6 channel */ |
126 | static struct hda_verb cmi9880_ch6_init[] = { | 140 | static struct hda_verb cmi9880_ch6_init[] = { |
127 | /* set line-in PIN for output */ | 141 | /* set line-in PIN for output */ |
128 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | 142 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
129 | /* set mic PIN for output */ | 143 | /* set mic PIN for output */ |
130 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | 144 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
131 | /* route front PCM (DAC1) to HP */ | 145 | /* route front PCM (DAC1) to HP */ |
132 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | 146 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
133 | {} | 147 | {} |
@@ -136,9 +150,9 @@ static struct hda_verb cmi9880_ch6_init[] = { | |||
136 | /* 3-stack+front / 8 channel */ | 150 | /* 3-stack+front / 8 channel */ |
137 | static struct hda_verb cmi9880_ch8_init[] = { | 151 | static struct hda_verb cmi9880_ch8_init[] = { |
138 | /* set line-in PIN for output */ | 152 | /* set line-in PIN for output */ |
139 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | 153 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
140 | /* set mic PIN for output */ | 154 | /* set mic PIN for output */ |
141 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | 155 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
142 | /* route rear-surround PCM (DAC4) to HP */ | 156 | /* route rear-surround PCM (DAC4) to HP */ |
143 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, | 157 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, |
144 | {} | 158 | {} |
@@ -281,27 +295,27 @@ static hda_nid_t cmi9880_adc_nids[2] = { | |||
281 | */ | 295 | */ |
282 | static struct hda_verb cmi9880_basic_init[] = { | 296 | static struct hda_verb cmi9880_basic_init[] = { |
283 | /* port-D for line out (rear panel) */ | 297 | /* port-D for line out (rear panel) */ |
284 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 298 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
285 | /* port-E for HP out (front panel) */ | 299 | /* port-E for HP out (front panel) */ |
286 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 300 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
287 | /* route front PCM to HP */ | 301 | /* route front PCM to HP */ |
288 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | 302 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
289 | /* port-A for surround (rear panel) */ | 303 | /* port-A for surround (rear panel) */ |
290 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 304 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
291 | /* port-G for CLFE (rear panel) */ | 305 | /* port-G for CLFE (rear panel) */ |
292 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 306 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
293 | { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, | 307 | { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, |
294 | /* port-H for side (rear panel) */ | 308 | /* port-H for side (rear panel) */ |
295 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 309 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
296 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, | 310 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, |
297 | /* port-C for line-in (rear panel) */ | 311 | /* port-C for line-in (rear panel) */ |
298 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | 312 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
299 | /* port-B for mic-in (rear panel) with vref */ | 313 | /* port-B for mic-in (rear panel) with vref */ |
300 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 314 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
301 | /* port-F for mic-in (front panel) with vref */ | 315 | /* port-F for mic-in (front panel) with vref */ |
302 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 316 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
303 | /* CD-in */ | 317 | /* CD-in */ |
304 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | 318 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
305 | /* route front mic to ADC1/2 */ | 319 | /* route front mic to ADC1/2 */ |
306 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, | 320 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, |
307 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, | 321 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, |
@@ -310,27 +324,27 @@ static struct hda_verb cmi9880_basic_init[] = { | |||
310 | 324 | ||
311 | static struct hda_verb cmi9880_allout_init[] = { | 325 | static struct hda_verb cmi9880_allout_init[] = { |
312 | /* port-D for line out (rear panel) */ | 326 | /* port-D for line out (rear panel) */ |
313 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 327 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
314 | /* port-E for HP out (front panel) */ | 328 | /* port-E for HP out (front panel) */ |
315 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 329 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
316 | /* route front PCM to HP */ | 330 | /* route front PCM to HP */ |
317 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | 331 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, |
318 | /* port-A for side (rear panel) */ | 332 | /* port-A for side (rear panel) */ |
319 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 333 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
320 | /* port-G for CLFE (rear panel) */ | 334 | /* port-G for CLFE (rear panel) */ |
321 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 335 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
322 | { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, | 336 | { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x02 }, |
323 | /* port-H for side (rear panel) */ | 337 | /* port-H for side (rear panel) */ |
324 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 338 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
325 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, | 339 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x01 }, |
326 | /* port-C for surround (rear panel) */ | 340 | /* port-C for surround (rear panel) */ |
327 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | 341 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, |
328 | /* port-B for mic-in (rear panel) with vref */ | 342 | /* port-B for mic-in (rear panel) with vref */ |
329 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 343 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
330 | /* port-F for mic-in (front panel) with vref */ | 344 | /* port-F for mic-in (front panel) with vref */ |
331 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | 345 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
332 | /* CD-in */ | 346 | /* CD-in */ |
333 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | 347 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
334 | /* route front mic to ADC1/2 */ | 348 | /* route front mic to ADC1/2 */ |
335 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, | 349 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, |
336 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, | 350 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, |
@@ -365,101 +379,9 @@ static int cmi9880_build_controls(struct hda_codec *codec) | |||
365 | return 0; | 379 | return 0; |
366 | } | 380 | } |
367 | 381 | ||
368 | #define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) | ||
369 | #define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) | ||
370 | #define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) | ||
371 | |||
372 | /* get all pin default configuration in def_conf */ | ||
373 | static int cmi9880_get_pin_def_config(struct hda_codec *codec) | ||
374 | { | ||
375 | struct cmi_spec *spec = codec->spec; | ||
376 | hda_nid_t nid, nid_start; | ||
377 | int i = 0, nodes; | ||
378 | |||
379 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); | ||
380 | for (nid = nid_start; nid < nodes + nid_start; nid++) { | ||
381 | unsigned int wid_caps = snd_hda_param_read(codec, nid, | ||
382 | AC_PAR_AUDIO_WIDGET_CAP); | ||
383 | unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
384 | /* read all default configuration for pin complex */ | ||
385 | if (wid_type == AC_WID_PIN) { | ||
386 | spec->pin_nid[i] = nid; | ||
387 | spec->def_conf[i] = | ||
388 | snd_hda_codec_read(codec, nid, 0, | ||
389 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
390 | i++; | ||
391 | } | ||
392 | } | ||
393 | spec->pin_def_confs = i; | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | /* get a pin default configuration of nid in def_conf */ | ||
398 | static unsigned int cmi9880_get_def_config(struct hda_codec *codec, hda_nid_t nid) | ||
399 | { | ||
400 | struct cmi_spec *spec = codec->spec; | ||
401 | int i = 0; | ||
402 | |||
403 | while (spec->pin_nid[i] != nid && i < spec->pin_def_confs) | ||
404 | i++; | ||
405 | if (i == spec->pin_def_confs) | ||
406 | return (unsigned int) -1; | ||
407 | else | ||
408 | return spec->def_conf[i]; | ||
409 | } | ||
410 | |||
411 | /* decide what pins to use for multichannel playback */ | ||
412 | static int cmi9880_get_multich_pins(struct hda_codec *codec) | ||
413 | { | ||
414 | struct cmi_spec *spec = codec->spec; | ||
415 | int i, j, pins, seq[4]; | ||
416 | int max_channel = 0; | ||
417 | unsigned int def_conf, sequence; | ||
418 | hda_nid_t nid; | ||
419 | |||
420 | memset(spec->multich_pin, 0, sizeof(spec->multich_pin)); | ||
421 | for (pins = 0, i = 0; i < spec->pin_def_confs && pins < 4; i++) { | ||
422 | def_conf = spec->def_conf[i]; | ||
423 | /* skip pin not connected */ | ||
424 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) | ||
425 | continue; | ||
426 | /* get the sequence if association == 1 */ | ||
427 | /* the other pins have association = 0, incorrect in spec 1.0 */ | ||
428 | if (get_defcfg_association(def_conf) == 1) { | ||
429 | sequence = get_defcfg_sequence(def_conf); | ||
430 | seq[pins] = sequence; | ||
431 | spec->multich_pin[pins] = spec->pin_nid[i]; | ||
432 | pins++; // ready for next slot | ||
433 | max_channel += 2; | ||
434 | } | ||
435 | } | ||
436 | /* sort by sequence, data collected here will be for Windows */ | ||
437 | for (i = 0; i < pins; i++) { | ||
438 | for (j = i + 1; j < pins; j++) { | ||
439 | if (seq[j] < seq[i]) { | ||
440 | sequence = seq[j]; | ||
441 | nid = spec->multich_pin[j]; | ||
442 | seq[j] = seq[i]; | ||
443 | spec->multich_pin[j] = spec->multich_pin[i]; | ||
444 | seq[i] = sequence; | ||
445 | spec->multich_pin[i] = nid; | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | /* the pin assignment is for front, C/LFE, surround and back */ | ||
450 | if (max_channel >= 6) { | ||
451 | hda_nid_t temp; | ||
452 | /* exchange pin of C/LFE and surround */ | ||
453 | temp = spec->multich_pin[1]; | ||
454 | spec->multich_pin[1] = spec->multich_pin[2]; | ||
455 | spec->multich_pin[2] = temp; | ||
456 | } | ||
457 | return max_channel; | ||
458 | } | ||
459 | |||
460 | /* fill in the multi_dac_nids table, which will decide | 382 | /* fill in the multi_dac_nids table, which will decide |
461 | which audio widget to use for each channel */ | 383 | which audio widget to use for each channel */ |
462 | static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) | 384 | static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) |
463 | { | 385 | { |
464 | struct cmi_spec *spec = codec->spec; | 386 | struct cmi_spec *spec = codec->spec; |
465 | hda_nid_t nid; | 387 | hda_nid_t nid; |
@@ -470,32 +392,34 @@ static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) | |||
470 | memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); | 392 | memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); |
471 | memset(assigned, 0, sizeof(assigned)); | 393 | memset(assigned, 0, sizeof(assigned)); |
472 | /* check the pins we found */ | 394 | /* check the pins we found */ |
473 | for (i = 0; i < spec->multiout.max_channels / 2; i++) { | 395 | for (i = 0; i < cfg->line_outs; i++) { |
474 | nid = spec->multich_pin[i]; | 396 | nid = cfg->line_out_pins[i]; |
475 | /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ | 397 | /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ |
476 | if (nid <= 0x0e && nid >= 0x0b) { | 398 | if (nid >= 0x0b && nid <= 0x0e) { |
477 | spec->dac_nids[i] = nid - 0x08; | 399 | spec->dac_nids[i] = (nid - 0x0b) + 0x03; |
478 | assigned[nid - 0x0b] = 1; | 400 | assigned[nid - 0x0b] = 1; |
479 | } | 401 | } |
480 | } | 402 | } |
481 | /* left pin can be connect to any audio widget */ | 403 | /* left pin can be connect to any audio widget */ |
482 | for (i = 0; i < spec->multiout.max_channels / 2; i++) { | 404 | for (i = 0; i < cfg->line_outs; i++) { |
483 | if (!assigned[i]) { | 405 | nid = cfg->line_out_pins[i]; |
484 | /* search for an empty channel */ | 406 | if (nid <= 0x0e) |
485 | /* I should also check the pin type */ | 407 | continue; |
486 | for (j = 0; j < ARRAY_SIZE(spec->dac_nids); j++) | 408 | /* search for an empty channel */ |
487 | if (! spec->dac_nids[j]) { | 409 | for (j = 0; j < cfg->line_outs; j++) { |
488 | spec->dac_nids[j] = i + 3; | 410 | if (! assigned[j]) { |
489 | assigned[i] = 1; | 411 | spec->dac_nids[i] = i + 0x03; |
490 | break; | 412 | assigned[j] = 1; |
491 | } | 413 | break; |
414 | } | ||
492 | } | 415 | } |
493 | } | 416 | } |
417 | spec->num_dacs = cfg->line_outs; | ||
494 | return 0; | 418 | return 0; |
495 | } | 419 | } |
496 | 420 | ||
497 | /* create multi_init table, which is used for multichannel initialization */ | 421 | /* create multi_init table, which is used for multichannel initialization */ |
498 | static int cmi9880_fill_multi_init(struct hda_codec *codec) | 422 | static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg) |
499 | { | 423 | { |
500 | struct cmi_spec *spec = codec->spec; | 424 | struct cmi_spec *spec = codec->spec; |
501 | hda_nid_t nid; | 425 | hda_nid_t nid; |
@@ -503,29 +427,26 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec) | |||
503 | 427 | ||
504 | /* clear the table, only one c-media dac assumed here */ | 428 | /* clear the table, only one c-media dac assumed here */ |
505 | memset(spec->multi_init, 0, sizeof(spec->multi_init)); | 429 | memset(spec->multi_init, 0, sizeof(spec->multi_init)); |
506 | for (j = 0, i = 0; i < spec->multiout.max_channels / 2; i++) { | 430 | for (j = 0, i = 0; i < cfg->line_outs; i++) { |
507 | hda_nid_t conn[4]; | 431 | hda_nid_t conn[4]; |
508 | nid = spec->multich_pin[i]; | 432 | nid = cfg->line_out_pins[i]; |
509 | /* set as output */ | 433 | /* set as output */ |
510 | spec->multi_init[j].nid = nid; | 434 | spec->multi_init[j].nid = nid; |
511 | spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; | 435 | spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; |
512 | spec->multi_init[j].param = 0xc0; | 436 | spec->multi_init[j].param = PIN_OUT; |
513 | j++; | 437 | j++; |
514 | /* nid 0x0f,0x10,0x1f,0x20 are needed to set connection */ | 438 | if (nid > 0x0e) { |
515 | switch (nid) { | ||
516 | case 0x0f: | ||
517 | case 0x10: | ||
518 | case 0x1f: | ||
519 | case 0x20: | ||
520 | /* set connection */ | 439 | /* set connection */ |
521 | spec->multi_init[j].nid = nid; | 440 | spec->multi_init[j].nid = nid; |
522 | spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; | 441 | spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; |
442 | spec->multi_init[j].param = 0; | ||
523 | /* find the index in connect list */ | 443 | /* find the index in connect list */ |
524 | len = snd_hda_get_connections(codec, nid, conn, 4); | 444 | len = snd_hda_get_connections(codec, nid, conn, 4); |
525 | for (k = 0; k < len; k++) | 445 | for (k = 0; k < len; k++) |
526 | if (conn[k] == spec->dac_nids[i]) | 446 | if (conn[k] == spec->dac_nids[i]) { |
447 | spec->multi_init[j].param = j; | ||
527 | break; | 448 | break; |
528 | spec->multi_init[j].param = k < len ? k : 0; | 449 | } |
529 | j++; | 450 | j++; |
530 | break; | 451 | break; |
531 | } | 452 | } |
@@ -759,6 +680,7 @@ static int patch_cmi9880(struct hda_codec *codec) | |||
759 | 680 | ||
760 | /* copy default DAC NIDs */ | 681 | /* copy default DAC NIDs */ |
761 | memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); | 682 | memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); |
683 | spec->num_dacs = 4; | ||
762 | 684 | ||
763 | switch (spec->board_config) { | 685 | switch (spec->board_config) { |
764 | case CMI_MINIMAL: | 686 | case CMI_MINIMAL: |
@@ -795,18 +717,16 @@ static int patch_cmi9880(struct hda_codec *codec) | |||
795 | { | 717 | { |
796 | unsigned int port_e, port_f, port_g, port_h; | 718 | unsigned int port_e, port_f, port_g, port_h; |
797 | unsigned int port_spdifi, port_spdifo; | 719 | unsigned int port_spdifi, port_spdifo; |
798 | int max_channels; | 720 | struct auto_pin_cfg cfg; |
721 | |||
799 | /* collect pin default configuration */ | 722 | /* collect pin default configuration */ |
800 | cmi9880_get_pin_def_config(codec); | 723 | port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); |
801 | port_e = cmi9880_get_def_config(codec, 0x0f); | 724 | port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); |
802 | port_f = cmi9880_get_def_config(codec, 0x10); | ||
803 | port_g = cmi9880_get_def_config(codec, 0x1f); | ||
804 | port_h = cmi9880_get_def_config(codec, 0x20); | ||
805 | port_spdifi = cmi9880_get_def_config(codec, 0x13); | ||
806 | port_spdifo = cmi9880_get_def_config(codec, 0x12); | ||
807 | spec->front_panel = 1; | 725 | spec->front_panel = 1; |
808 | if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || | 726 | if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || |
809 | get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { | 727 | get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { |
728 | port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
729 | port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
810 | spec->surr_switch = 1; | 730 | spec->surr_switch = 1; |
811 | /* no front panel */ | 731 | /* no front panel */ |
812 | if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || | 732 | if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || |
@@ -824,24 +744,26 @@ static int patch_cmi9880(struct hda_codec *codec) | |||
824 | spec->multiout.max_channels = cmi9880_channel_modes[0].channels; | 744 | spec->multiout.max_channels = cmi9880_channel_modes[0].channels; |
825 | } else { | 745 | } else { |
826 | spec->input_mux = &cmi9880_basic_mux; | 746 | spec->input_mux = &cmi9880_basic_mux; |
747 | port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
748 | port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
827 | if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) | 749 | if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) |
828 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; | 750 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; |
829 | if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) | 751 | if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) |
830 | spec->dig_in_nid = CMI_DIG_IN_NID; | 752 | spec->dig_in_nid = CMI_DIG_IN_NID; |
831 | spec->multiout.max_channels = 8; | 753 | spec->multiout.max_channels = 8; |
832 | } | 754 | } |
833 | max_channels = cmi9880_get_multich_pins(codec); | 755 | snd_hda_parse_pin_def_config(codec, &cfg); |
834 | if (max_channels > 0) { | 756 | if (cfg.line_outs) { |
835 | spec->multiout.max_channels = max_channels; | 757 | spec->multiout.max_channels = cfg.line_outs * 2; |
836 | cmi9880_fill_multi_dac_nids(codec); | 758 | cmi9880_fill_multi_dac_nids(codec, &cfg); |
837 | cmi9880_fill_multi_init(codec); | 759 | cmi9880_fill_multi_init(codec, &cfg); |
838 | } else | 760 | } else |
839 | snd_printd("patch_cmedia: cannot detect association in defcfg\n"); | 761 | snd_printd("patch_cmedia: cannot detect association in defcfg\n"); |
840 | break; | 762 | break; |
841 | } | 763 | } |
842 | } | 764 | } |
843 | 765 | ||
844 | spec->multiout.num_dacs = 4; | 766 | spec->multiout.num_dacs = spec->num_dacs; |
845 | spec->multiout.dac_nids = spec->dac_nids; | 767 | spec->multiout.dac_nids = spec->dac_nids; |
846 | 768 | ||
847 | spec->adc_nids = cmi9880_adc_nids; | 769 | spec->adc_nids = cmi9880_adc_nids; |