aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_cmedia.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2005-04-08 09:05:13 -0400
committerJaroslav Kysela <perex@suse.cz>2005-05-29 03:58:43 -0400
commitf953eff29c1ea4c744afe3d50ff5ca33b44efcd2 (patch)
tree1755bab90bfeae4ec27953808b1c512d94110682 /sound/pci/hda/patch_cmedia.c
parent22e0732e59b3482bb2f068bfe911c532767e5974 (diff)
[ALSA] choose multi-channel jacks automatically
HDA Codec driver Patch by C.L. Tien <cltien@cmedia.com.tw>: The patch makes cm9880 to choose multi-channel jacks automatically. 1. I found the current code has basic_init, which already includes necessary controls for 6-stack initialization, so I don't need another model. 2. I add a new model 'auto' to let the driver find a. if there are option real panel/front panel, b. the jacks to be used for multichannel. Because the jack color are based on MS's channel sequence, so the 'auto' model will pick the same jacks for multichannel MS uses. I did this to hope to minimize users questions. These code can also be applied to other codecs but I don't have any to test. 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.c233
1 files changed, 230 insertions, 3 deletions
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index a44d64e828d5..e64e29dac824 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -29,6 +29,7 @@
29#include <sound/core.h> 29#include <sound/core.h>
30#include "hda_codec.h" 30#include "hda_codec.h"
31#include "hda_local.h" 31#include "hda_local.h"
32#define NUM_PINS 11
32 33
33 34
34/* board config type */ 35/* board config type */
@@ -38,6 +39,7 @@ enum {
38 CMI_FULL, /* back 6-jack + front-panel 2-jack */ 39 CMI_FULL, /* back 6-jack + front-panel 2-jack */
39 CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ 40 CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */
40 CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ 41 CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */
42 CMI_AUTO, /* let driver guess it */
41}; 43};
42 44
43struct cmi_spec { 45struct cmi_spec {
@@ -48,6 +50,7 @@ struct cmi_spec {
48 50
49 /* playback */ 51 /* playback */
50 struct hda_multi_out multiout; 52 struct hda_multi_out multiout;
53 hda_nid_t dac_nids[4]; /* NID for each DAC */
51 54
52 /* capture */ 55 /* capture */
53 hda_nid_t *adc_nids; 56 hda_nid_t *adc_nids;
@@ -63,6 +66,15 @@ struct cmi_spec {
63 const struct cmi_channel_mode *channel_modes; 66 const struct cmi_channel_mode *channel_modes;
64 67
65 struct hda_pcm pcm_rec[2]; /* PCM information */ 68 struct hda_pcm pcm_rec[2]; /* PCM information */
69
70 /* pin deafault configuration */
71 hda_nid_t pin_nid[NUM_PINS];
72 unsigned int def_conf[NUM_PINS];
73 unsigned int pin_def_confs;
74
75 /* multichannel pins */
76 hda_nid_t multich_pin[4]; /* max 8-channel */
77 struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */
66}; 78};
67 79
68/* 80/*
@@ -353,6 +365,175 @@ static int cmi9880_build_controls(struct hda_codec *codec)
353 return 0; 365 return 0;
354} 366}
355 367
368#define AC_DEFCFG_ASSOC_SHIFT 4
369#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
370#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT)
371#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE)
372
373/* get all pin default configuration in def_conf */
374static int cmi9880_get_pin_def_config(struct hda_codec *codec)
375{
376 struct cmi_spec *spec = codec->spec;
377 hda_nid_t nid, nid_start;
378 int i = 0, nodes;
379
380 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
381 for (nid = nid_start; nid < nodes + nid_start; nid++) {
382 unsigned int wid_caps = snd_hda_param_read(codec, nid,
383 AC_PAR_AUDIO_WIDGET_CAP);
384 unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
385 /* read all default configuration for pin complex */
386 if (wid_type == AC_WID_PIN) {
387 spec->pin_nid[i] = nid;
388 spec->def_conf[i] =
389 snd_hda_codec_read(codec, nid, 0,
390 AC_VERB_GET_CONFIG_DEFAULT, 0);
391 i++;
392 }
393 }
394 spec->pin_def_confs = i;
395 return 0;
396}
397
398/* get a pin default configuration of nid in def_conf */
399static unsigned int cmi9880_get_def_config(struct hda_codec *codec, hda_nid_t nid)
400{
401 struct cmi_spec *spec = codec->spec;
402 int i = 0;
403
404 while (spec->pin_nid[i] != nid && i < spec->pin_def_confs)
405 i++;
406 if (i == spec->pin_def_confs)
407 return (unsigned int) -1;
408 else
409 return spec->def_conf[i];
410}
411
412/* decide what pins to use for multichannel playback */
413static int cmi9880_get_multich_pins(struct hda_codec *codec)
414{
415 struct cmi_spec *spec = codec->spec;
416 int i, j, pins, seq[4];
417 int max_channel = 0;
418 unsigned int def_conf, sequence;
419 hda_nid_t nid;
420
421 memset(spec->multich_pin, 0, sizeof(spec->multich_pin));
422 for (pins = 0, i = 0; i < spec->pin_def_confs && pins < 4; i++) {
423 def_conf = spec->def_conf[i];
424 /* skip pin not connected */
425 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
426 continue;
427 /* get the sequence if association == 1 */
428 /* the other pins have association = 0, incorrect in spec 1.0 */
429 if (get_defcfg_association(def_conf) == 1) {
430 sequence = get_defcfg_sequence(def_conf);
431 seq[pins] = sequence;
432 spec->multich_pin[pins] = spec->pin_nid[i];
433 pins++; // ready for next slot
434 max_channel += 2;
435 }
436 }
437 /* sort by sequence, data collected here will be for Windows */
438 for (i = 0; i < pins; i++) {
439 for (j = i + 1; j < pins; j++) {
440 if (seq[j] < seq[i]) {
441 sequence = seq[j];
442 nid = spec->multich_pin[j];
443 seq[j] = seq[i];
444 spec->multich_pin[j] = spec->multich_pin[i];
445 seq[i] = sequence;
446 spec->multich_pin[i] = nid;
447 }
448 }
449 }
450 /* the pin assignment is for front, C/LFE, surround and back */
451 if (max_channel >= 6) {
452 hda_nid_t temp;
453 /* exchange pin of C/LFE and surround */
454 temp = spec->multich_pin[1];
455 spec->multich_pin[1] = spec->multich_pin[2];
456 spec->multich_pin[2] = temp;
457 }
458 return max_channel;
459}
460
461/* fill in the multi_dac_nids table, which will decide
462 which audio widget to use for each channel */
463static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec)
464{
465 struct cmi_spec *spec = codec->spec;
466 hda_nid_t nid;
467 int assigned[4];
468 int i, j;
469
470 /* clear the table, only one c-media dac assumed here */
471 memset(spec->dac_nids, 0, sizeof(spec->dac_nids));
472 memset(assigned, 0, sizeof(assigned));
473 /* check the pins we found */
474 for (i = 0; i < spec->multiout.max_channels / 2; i++) {
475 nid = spec->multich_pin[i];
476 /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */
477 if (nid <= 0x0e && nid >= 0x0b) {
478 spec->dac_nids[i] = nid - 0x08;
479 assigned[nid - 0x0b] = 1;
480 }
481 }
482 /* left pin can be connect to any audio widget */
483 for (i = 0; i < spec->multiout.max_channels / 2; i++) {
484 if (!assigned[i]) {
485 /* search for an empty channel */
486 /* I should also check the pin type */
487 for (j = 0; j < ARRAY_SIZE(spec->dac_nids); j++)
488 if (! spec->dac_nids[j]) {
489 spec->dac_nids[j] = i + 3;
490 assigned[i] = 1;
491 break;
492 }
493 }
494 }
495 return 0;
496}
497
498/* create multi_init table, which is used for multichannel initialization */
499static int cmi9880_fill_multi_init(struct hda_codec *codec)
500{
501 struct cmi_spec *spec = codec->spec;
502 hda_nid_t nid;
503 int i, j, k, len;
504
505 /* clear the table, only one c-media dac assumed here */
506 memset(spec->multi_init, 0, sizeof(spec->multi_init));
507 for (j = 0, i = 0; i < spec->multiout.max_channels / 2; i++) {
508 hda_nid_t conn[4];
509 nid = spec->multich_pin[i];
510 /* set as output */
511 spec->multi_init[j].nid = nid;
512 spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL;
513 spec->multi_init[j].param = 0xc0;
514 j++;
515 /* nid 0x0f,0x10,0x1f,0x20 are needed to set connection */
516 switch (nid) {
517 case 0x0f:
518 case 0x10:
519 case 0x1f:
520 case 0x20:
521 /* set connection */
522 spec->multi_init[j].nid = nid;
523 spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL;
524 /* find the index in connect list */
525 len = snd_hda_get_connections(codec, nid, conn, 4);
526 for (k = 0; k < len; k++)
527 if (conn[k] == spec->dac_nids[i])
528 break;
529 spec->multi_init[j].param = k < len ? k : 0;
530 j++;
531 break;
532 }
533 }
534 return 0;
535}
536
356static int cmi9880_init(struct hda_codec *codec) 537static int cmi9880_init(struct hda_codec *codec)
357{ 538{
358 struct cmi_spec *spec = codec->spec; 539 struct cmi_spec *spec = codec->spec;
@@ -360,6 +541,8 @@ static int cmi9880_init(struct hda_codec *codec)
360 snd_hda_sequence_write(codec, cmi9880_allout_init); 541 snd_hda_sequence_write(codec, cmi9880_allout_init);
361 else 542 else
362 snd_hda_sequence_write(codec, cmi9880_basic_init); 543 snd_hda_sequence_write(codec, cmi9880_basic_init);
544 if (spec->board_config == CMI_AUTO)
545 snd_hda_sequence_write(codec, spec->multi_init);
363 return 0; 546 return 0;
364} 547}
365 548
@@ -546,6 +729,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = {
546 { .modelname = "full", .config = CMI_FULL }, 729 { .modelname = "full", .config = CMI_FULL },
547 { .modelname = "full_dig", .config = CMI_FULL_DIG }, 730 { .modelname = "full_dig", .config = CMI_FULL_DIG },
548 { .modelname = "allout", .config = CMI_ALLOUT }, 731 { .modelname = "allout", .config = CMI_ALLOUT },
732 { .modelname = "auto", .config = CMI_AUTO },
549 {} /* terminator */ 733 {} /* terminator */
550}; 734};
551 735
@@ -570,10 +754,13 @@ static int patch_cmi9880(struct hda_codec *codec)
570 codec->spec = spec; 754 codec->spec = spec;
571 spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); 755 spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl);
572 if (spec->board_config < 0) { 756 if (spec->board_config < 0) {
573 snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); 757 snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n");
574 spec->board_config = CMI_FULL_DIG; /* try everything */ 758 spec->board_config = CMI_AUTO; /* try everything */
575 } 759 }
576 760
761 /* copy default DAC NIDs */
762 memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids));
763
577 switch (spec->board_config) { 764 switch (spec->board_config) {
578 case CMI_MINIMAL: 765 case CMI_MINIMAL:
579 case CMI_MIN_FP: 766 case CMI_MIN_FP:
@@ -605,10 +792,50 @@ static int patch_cmi9880(struct hda_codec *codec)
605 spec->input_mux = &cmi9880_no_line_mux; 792 spec->input_mux = &cmi9880_no_line_mux;
606 spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; 793 spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
607 break; 794 break;
795 case CMI_AUTO:
796 {
797 unsigned int port_e, port_f, port_g, port_h;
798 unsigned int port_spdifi, port_spdifo;
799 /* collect pin default configuration */
800 cmi9880_get_pin_def_config(codec);
801 port_e = cmi9880_get_def_config(codec, 0x0f);
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;
808 if ((get_defcfg_connect(port_e) == AC_JACK_PORT_NONE)
809 || (get_defcfg_connect(port_f) == AC_JACK_PORT_NONE)) {
810 spec->surr_switch = 1;
811 /* no front panel */
812 if ((get_defcfg_connect(port_g) == AC_JACK_PORT_NONE)
813 || (get_defcfg_connect(port_h) == AC_JACK_PORT_NONE)) {
814 /* no optional rear panel */
815 spec->board_config = CMI_MINIMAL;
816 spec->front_panel = 0;
817 spec->num_ch_modes = 2;
818 } else
819 spec->board_config = CMI_MIN_FP;
820 spec->num_ch_modes = 3;
821 spec->channel_modes = cmi9880_channel_modes;
822 spec->input_mux = &cmi9880_basic_mux;
823 } else {
824 spec->input_mux = &cmi9880_basic_mux;
825 if (get_defcfg_connect(port_spdifo) != 1)
826 spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
827 if (get_defcfg_connect(port_spdifi) != 1)
828 spec->dig_in_nid = CMI_DIG_IN_NID;
829 }
830 spec->multiout.max_channels = cmi9880_get_multich_pins(codec);
831 cmi9880_fill_multi_dac_nids(codec);
832 cmi9880_fill_multi_init(codec);
833 }
834 break;
608 } 835 }
609 836
610 spec->multiout.num_dacs = 4; 837 spec->multiout.num_dacs = 4;
611 spec->multiout.dac_nids = cmi9880_dac_nids; 838 spec->multiout.dac_nids = spec->dac_nids;
612 839
613 spec->adc_nids = cmi9880_adc_nids; 840 spec->adc_nids = cmi9880_adc_nids;
614 841