diff options
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_via.c | 400 |
1 files changed, 260 insertions, 140 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 5232abc341f8..76c688409cd8 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -130,13 +130,28 @@ struct via_spec { | |||
130 | struct hda_multi_out multiout; | 130 | struct hda_multi_out multiout; |
131 | hda_nid_t slave_dig_outs[2]; | 131 | hda_nid_t slave_dig_outs[2]; |
132 | hda_nid_t hp_dac_nid; | 132 | hda_nid_t hp_dac_nid; |
133 | bool hp_indep_shared; /* indep HP-DAC is shared with side ch */ | 133 | hda_nid_t speaker_dac_nid; |
134 | int hp_indep_shared; /* indep HP-DAC is shared with side ch */ | ||
134 | int num_active_streams; | 135 | int num_active_streams; |
135 | 136 | int aamix_mode; /* loopback is enabled for output-path? */ | |
137 | |||
138 | /* Output-paths: | ||
139 | * There are different output-paths depending on the setup. | ||
140 | * out_path, hp_path and speaker_path are primary paths. If both | ||
141 | * direct DAC and aa-loopback routes are available, these contain | ||
142 | * the former paths. Meanwhile *_mix_path contain the paths with | ||
143 | * loopback mixer. (Since the loopback is only for front channel, | ||
144 | * no out_mix_path for surround channels.) | ||
145 | * The HP output has another path, hp_indep_path, which is used in | ||
146 | * the independent-HP mode. | ||
147 | */ | ||
136 | struct nid_path out_path[HDA_SIDE + 1]; | 148 | struct nid_path out_path[HDA_SIDE + 1]; |
149 | struct nid_path out_mix_path; | ||
137 | struct nid_path hp_path; | 150 | struct nid_path hp_path; |
138 | struct nid_path hp_dep_path; | 151 | struct nid_path hp_mix_path; |
152 | struct nid_path hp_indep_path; | ||
139 | struct nid_path speaker_path; | 153 | struct nid_path speaker_path; |
154 | struct nid_path speaker_mix_path; | ||
140 | 155 | ||
141 | /* capture */ | 156 | /* capture */ |
142 | unsigned int num_adc_nids; | 157 | unsigned int num_adc_nids; |
@@ -437,50 +452,20 @@ static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | |||
437 | #define have_mute(codec, nid, dir) \ | 452 | #define have_mute(codec, nid, dir) \ |
438 | check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) | 453 | check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) |
439 | 454 | ||
440 | static bool is_node_in_path(struct nid_path *path, hda_nid_t nid) | ||
441 | { | ||
442 | int i; | ||
443 | if (!nid) | ||
444 | return false; | ||
445 | for (i = 0; i < path->depth; i++) { | ||
446 | if (path->path[i] == nid) | ||
447 | return true; | ||
448 | } | ||
449 | return false; | ||
450 | } | ||
451 | |||
452 | /* enable/disable the output-route mixers */ | 455 | /* enable/disable the output-route mixers */ |
453 | static void activate_output_mix(struct hda_codec *codec, struct nid_path *path, | 456 | static void activate_output_mix(struct hda_codec *codec, struct nid_path *path, |
454 | hda_nid_t mix_nid, int aa_mix_idx, bool enable) | 457 | hda_nid_t mix_nid, int idx, bool enable) |
455 | { | 458 | { |
456 | int i, num, val; | 459 | int i, num, val; |
457 | bool hp_path, front_path; | ||
458 | struct via_spec *spec = codec->spec; | ||
459 | 460 | ||
460 | if (!path) | 461 | if (!path) |
461 | return; | 462 | return; |
462 | num = snd_hda_get_conn_list(codec, mix_nid, NULL); | 463 | num = snd_hda_get_conn_list(codec, mix_nid, NULL); |
463 | hp_path = is_node_in_path(path, spec->hp_dac_nid); | ||
464 | front_path = is_node_in_path(path, spec->multiout.dac_nids[0]); | ||
465 | |||
466 | for (i = 0; i < num; i++) { | 464 | for (i = 0; i < num; i++) { |
467 | if (i == aa_mix_idx) { | 465 | if (i == idx) |
468 | if (hp_path) | 466 | val = AMP_IN_UNMUTE(i); |
469 | val = enable ? AMP_IN_MUTE(i) : | 467 | else |
470 | AMP_IN_UNMUTE(i); | 468 | val = AMP_IN_MUTE(i); |
471 | else if (front_path) | ||
472 | val = AMP_IN_UNMUTE(i); | ||
473 | else | ||
474 | val = AMP_IN_MUTE(i); | ||
475 | } else { | ||
476 | if (hp_path) | ||
477 | val = enable ? AMP_IN_UNMUTE(i) : | ||
478 | AMP_IN_MUTE(i); | ||
479 | else if (front_path) | ||
480 | val = AMP_IN_MUTE(i); | ||
481 | else | ||
482 | val = AMP_IN_UNMUTE(i); | ||
483 | } | ||
484 | snd_hda_codec_write(codec, mix_nid, 0, | 469 | snd_hda_codec_write(codec, mix_nid, 0, |
485 | AC_VERB_SET_AMP_GAIN_MUTE, val); | 470 | AC_VERB_SET_AMP_GAIN_MUTE, val); |
486 | } | 471 | } |
@@ -490,9 +475,8 @@ static void activate_output_mix(struct hda_codec *codec, struct nid_path *path, | |||
490 | static void activate_output_path(struct hda_codec *codec, struct nid_path *path, | 475 | static void activate_output_path(struct hda_codec *codec, struct nid_path *path, |
491 | bool enable, bool force) | 476 | bool enable, bool force) |
492 | { | 477 | { |
493 | int i, val; | ||
494 | struct via_spec *spec = codec->spec; | 478 | struct via_spec *spec = codec->spec; |
495 | hda_nid_t aa_mix_nid = spec->aa_mix_nid; | 479 | int i; |
496 | for (i = 0; i < path->depth; i++) { | 480 | for (i = 0; i < path->depth; i++) { |
497 | hda_nid_t src, dst; | 481 | hda_nid_t src, dst; |
498 | int idx = path->idx[i]; | 482 | int idx = path->idx[i]; |
@@ -504,25 +488,10 @@ static void activate_output_path(struct hda_codec *codec, struct nid_path *path, | |||
504 | if (enable && path->multi[i]) | 488 | if (enable && path->multi[i]) |
505 | snd_hda_codec_write(codec, dst, 0, | 489 | snd_hda_codec_write(codec, dst, 0, |
506 | AC_VERB_SET_CONNECT_SEL, idx); | 490 | AC_VERB_SET_CONNECT_SEL, idx); |
507 | if (!force | 491 | if (!force && (dst == spec->aa_mix_nid)) |
508 | && get_wcaps_type(get_wcaps(codec, src)) == AC_WID_AUD_OUT | ||
509 | && get_wcaps_type(get_wcaps(codec, dst)) == AC_WID_AUD_MIX) | ||
510 | continue; | 492 | continue; |
511 | if (have_mute(codec, dst, HDA_INPUT)) { | 493 | if (have_mute(codec, dst, HDA_INPUT)) |
512 | if (dst == aa_mix_nid) { | 494 | activate_output_mix(codec, path, dst, idx, enable); |
513 | val = enable ? AMP_IN_UNMUTE(idx) : | ||
514 | AMP_IN_MUTE(idx); | ||
515 | snd_hda_codec_write(codec, dst, 0, | ||
516 | AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
517 | } else { | ||
518 | idx = get_connection_index(codec, dst, | ||
519 | aa_mix_nid); | ||
520 | if (idx >= 0) { | ||
521 | activate_output_mix(codec, path, | ||
522 | dst, idx, enable); | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | if (!force && (src == path->vol_ctl || src == path->mute_ctl)) | 495 | if (!force && (src == path->vol_ctl || src == path->mute_ctl)) |
527 | continue; | 496 | continue; |
528 | if (have_mute(codec, src, HDA_OUTPUT)) { | 497 | if (have_mute(codec, src, HDA_OUTPUT)) { |
@@ -548,9 +517,8 @@ static void init_output_pin(struct hda_codec *codec, hda_nid_t pin, | |||
548 | 517 | ||
549 | static void via_auto_init_output(struct hda_codec *codec, | 518 | static void via_auto_init_output(struct hda_codec *codec, |
550 | struct nid_path *path, int pin_type, | 519 | struct nid_path *path, int pin_type, |
551 | bool with_aa_mix, bool force) | 520 | bool force) |
552 | { | 521 | { |
553 | struct via_spec *spec = codec->spec; | ||
554 | unsigned int caps; | 522 | unsigned int caps; |
555 | hda_nid_t pin; | 523 | hda_nid_t pin; |
556 | 524 | ||
@@ -566,41 +534,45 @@ static void via_auto_init_output(struct hda_codec *codec, | |||
566 | snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 534 | snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, |
567 | AMP_OUT_MUTE | val); | 535 | AMP_OUT_MUTE | val); |
568 | } | 536 | } |
569 | |||
570 | /* initialize the AA-path */ | ||
571 | if (!spec->aa_mix_nid) | ||
572 | return; | ||
573 | activate_output_path(codec, path, true, force); | 537 | activate_output_path(codec, path, true, force); |
574 | } | 538 | } |
575 | 539 | ||
576 | static void via_auto_init_multi_out(struct hda_codec *codec) | 540 | static void via_auto_init_multi_out(struct hda_codec *codec) |
577 | { | 541 | { |
578 | struct via_spec *spec = codec->spec; | 542 | struct via_spec *spec = codec->spec; |
543 | struct nid_path *path; | ||
579 | int i; | 544 | int i; |
580 | 545 | ||
581 | for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) | 546 | for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) { |
582 | /* enable aa-mute only for the front channel */ | 547 | path = &spec->out_path[i]; |
583 | via_auto_init_output(codec, &spec->out_path[i], PIN_OUT, | 548 | if (!i && spec->aamix_mode && spec->out_mix_path.depth) |
584 | i == 0, true); | 549 | path = &spec->out_mix_path; |
550 | via_auto_init_output(codec, path, PIN_OUT, true); | ||
551 | } | ||
585 | } | 552 | } |
586 | 553 | ||
587 | static void via_auto_init_hp_out(struct hda_codec *codec) | 554 | static void via_auto_init_hp_out(struct hda_codec *codec) |
588 | { | 555 | { |
589 | struct via_spec *spec = codec->spec; | 556 | struct via_spec *spec = codec->spec; |
557 | int shared = spec->hp_indep_shared; | ||
590 | 558 | ||
591 | if (!spec->hp_dac_nid) { | 559 | if (!spec->hp_path.depth) { |
592 | via_auto_init_output(codec, &spec->hp_dep_path, PIN_HP, | 560 | via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP, true); |
593 | true, true); | ||
594 | return; | 561 | return; |
595 | } | 562 | } |
596 | if (spec->hp_independent_mode) { | 563 | if (spec->hp_independent_mode) { |
597 | activate_output_path(codec, &spec->hp_dep_path, false, false); | ||
598 | via_auto_init_output(codec, &spec->hp_path, PIN_HP, | ||
599 | true, true); | ||
600 | } else { | ||
601 | activate_output_path(codec, &spec->hp_path, false, false); | 564 | activate_output_path(codec, &spec->hp_path, false, false); |
602 | via_auto_init_output(codec, &spec->hp_dep_path, PIN_HP, | 565 | activate_output_path(codec, &spec->hp_mix_path, false, false); |
603 | true, true); | 566 | if (shared) |
567 | activate_output_path(codec, &spec->out_path[shared], | ||
568 | false, false); | ||
569 | via_auto_init_output(codec, &spec->hp_indep_path, PIN_HP, true); | ||
570 | } else if (spec->aamix_mode) { | ||
571 | activate_output_path(codec, &spec->hp_path, false, false); | ||
572 | via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP, true); | ||
573 | } else { | ||
574 | activate_output_path(codec, &spec->hp_mix_path, false, false); | ||
575 | via_auto_init_output(codec, &spec->hp_path, PIN_HP, true); | ||
604 | } | 576 | } |
605 | } | 577 | } |
606 | 578 | ||
@@ -608,9 +580,23 @@ static void via_auto_init_speaker_out(struct hda_codec *codec) | |||
608 | { | 580 | { |
609 | struct via_spec *spec = codec->spec; | 581 | struct via_spec *spec = codec->spec; |
610 | 582 | ||
611 | if (spec->autocfg.speaker_outs) | 583 | if (!spec->autocfg.speaker_outs) |
584 | return; | ||
585 | if (!spec->speaker_path.depth) { | ||
586 | via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT, | ||
587 | true); | ||
588 | return; | ||
589 | } | ||
590 | if (!spec->aamix_mode) { | ||
591 | activate_output_path(codec, &spec->speaker_mix_path, | ||
592 | false, false); | ||
612 | via_auto_init_output(codec, &spec->speaker_path, PIN_OUT, | 593 | via_auto_init_output(codec, &spec->speaker_path, PIN_OUT, |
613 | true, true); | 594 | true); |
595 | } else { | ||
596 | activate_output_path(codec, &spec->speaker_path, false, false); | ||
597 | via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT, | ||
598 | true); | ||
599 | } | ||
614 | } | 600 | } |
615 | 601 | ||
616 | static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin); | 602 | static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin); |
@@ -775,7 +761,7 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
775 | { | 761 | { |
776 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 762 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
777 | struct via_spec *spec = codec->spec; | 763 | struct via_spec *spec = codec->spec; |
778 | int cur; | 764 | int cur, shared; |
779 | 765 | ||
780 | /* no independent-hp status change during PCM playback is running */ | 766 | /* no independent-hp status change during PCM playback is running */ |
781 | if (spec->num_active_streams) | 767 | if (spec->num_active_streams) |
@@ -785,18 +771,19 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
785 | if (spec->hp_independent_mode == cur) | 771 | if (spec->hp_independent_mode == cur) |
786 | return 0; | 772 | return 0; |
787 | spec->hp_independent_mode = cur; | 773 | spec->hp_independent_mode = cur; |
774 | shared = spec->hp_indep_shared; | ||
788 | if (cur) { | 775 | if (cur) { |
789 | activate_output_path(codec, &spec->hp_dep_path, false, false); | 776 | activate_output_path(codec, &spec->hp_mix_path, false, false); |
790 | activate_output_path(codec, &spec->hp_path, true, false); | 777 | if (shared) |
791 | if (spec->hp_indep_shared) | 778 | activate_output_path(codec, &spec->out_path[shared], |
792 | activate_output_path(codec, &spec->out_path[HDA_SIDE], | ||
793 | false, false); | 779 | false, false); |
780 | activate_output_path(codec, &spec->hp_path, true, false); | ||
794 | } else { | 781 | } else { |
795 | activate_output_path(codec, &spec->hp_path, false, false); | 782 | activate_output_path(codec, &spec->hp_path, false, false); |
796 | activate_output_path(codec, &spec->hp_dep_path, true, false); | 783 | if (shared) |
797 | if (spec->hp_indep_shared) | 784 | activate_output_path(codec, &spec->out_path[shared], |
798 | activate_output_path(codec, &spec->out_path[HDA_SIDE], | ||
799 | true, false); | 785 | true, false); |
786 | activate_output_path(codec, &spec->hp_mix_path, true, false); | ||
800 | } | 787 | } |
801 | 788 | ||
802 | /* update jack power state */ | 789 | /* update jack power state */ |
@@ -1671,29 +1658,38 @@ static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac) | |||
1671 | } | 1658 | } |
1672 | 1659 | ||
1673 | static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid, | 1660 | static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid, |
1674 | hda_nid_t target_dac, struct nid_path *path, | 1661 | hda_nid_t target_dac, int with_aa_mix, |
1675 | int depth, int wid_type) | 1662 | struct nid_path *path, int depth) |
1676 | { | 1663 | { |
1664 | struct via_spec *spec = codec->spec; | ||
1677 | hda_nid_t conn[8]; | 1665 | hda_nid_t conn[8]; |
1678 | int i, nums; | 1666 | int i, nums; |
1679 | 1667 | ||
1668 | if (nid == spec->aa_mix_nid) { | ||
1669 | if (!with_aa_mix) | ||
1670 | return false; | ||
1671 | with_aa_mix = 2; /* mark aa-mix is included */ | ||
1672 | } | ||
1673 | |||
1680 | nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn)); | 1674 | nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn)); |
1681 | for (i = 0; i < nums; i++) { | 1675 | for (i = 0; i < nums; i++) { |
1682 | if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT) | 1676 | if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT) |
1683 | continue; | 1677 | continue; |
1684 | if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) | 1678 | if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) { |
1685 | goto found; | 1679 | /* aa-mix is requested but not included? */ |
1680 | if (!(spec->aa_mix_nid && with_aa_mix == 1)) | ||
1681 | goto found; | ||
1682 | } | ||
1686 | } | 1683 | } |
1687 | if (depth >= MAX_NID_PATH_DEPTH) | 1684 | if (depth >= MAX_NID_PATH_DEPTH) |
1688 | return false; | 1685 | return false; |
1689 | for (i = 0; i < nums; i++) { | 1686 | for (i = 0; i < nums; i++) { |
1690 | unsigned int type; | 1687 | unsigned int type; |
1691 | type = get_wcaps_type(get_wcaps(codec, conn[i])); | 1688 | type = get_wcaps_type(get_wcaps(codec, conn[i])); |
1692 | if (type == AC_WID_AUD_OUT || | 1689 | if (type == AC_WID_AUD_OUT) |
1693 | (wid_type != -1 && type != wid_type)) | ||
1694 | continue; | 1690 | continue; |
1695 | if (__parse_output_path(codec, conn[i], target_dac, | 1691 | if (__parse_output_path(codec, conn[i], target_dac, |
1696 | path, depth + 1, AC_WID_AUD_SEL)) | 1692 | with_aa_mix, path, depth + 1)) |
1697 | goto found; | 1693 | goto found; |
1698 | } | 1694 | } |
1699 | return false; | 1695 | return false; |
@@ -1708,11 +1704,15 @@ static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid, | |||
1708 | } | 1704 | } |
1709 | 1705 | ||
1710 | static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid, | 1706 | static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid, |
1711 | hda_nid_t target_dac, struct nid_path *path) | 1707 | hda_nid_t target_dac, int with_aa_mix, |
1708 | struct nid_path *path) | ||
1712 | { | 1709 | { |
1713 | if (__parse_output_path(codec, nid, target_dac, path, 1, -1)) { | 1710 | if (__parse_output_path(codec, nid, target_dac, with_aa_mix, path, 1)) { |
1714 | path->path[path->depth] = nid; | 1711 | path->path[path->depth] = nid; |
1715 | path->depth++; | 1712 | path->depth++; |
1713 | snd_printdd("output-path: depth=%d, %02x/%02x/%02x/%02x/%02x\n", | ||
1714 | path->depth, path->path[0], path->path[1], | ||
1715 | path->path[2], path->path[3], path->path[4]); | ||
1716 | return true; | 1716 | return true; |
1717 | } | 1717 | } |
1718 | return false; | 1718 | return false; |
@@ -1728,14 +1728,24 @@ static int via_auto_fill_dac_nids(struct hda_codec *codec) | |||
1728 | spec->multiout.dac_nids = spec->private_dac_nids; | 1728 | spec->multiout.dac_nids = spec->private_dac_nids; |
1729 | dac_num = 0; | 1729 | dac_num = 0; |
1730 | for (i = 0; i < cfg->line_outs; i++) { | 1730 | for (i = 0; i < cfg->line_outs; i++) { |
1731 | hda_nid_t dac = 0; | ||
1731 | nid = cfg->line_out_pins[i]; | 1732 | nid = cfg->line_out_pins[i]; |
1732 | if (!nid) | 1733 | if (!nid) |
1733 | continue; | 1734 | continue; |
1734 | if (parse_output_path(codec, nid, 0, &spec->out_path[i])) { | 1735 | if (parse_output_path(codec, nid, 0, 0, &spec->out_path[i])) |
1735 | spec->private_dac_nids[i] = spec->out_path[i].path[0]; | 1736 | dac = spec->out_path[i].path[0]; |
1737 | if (!i && parse_output_path(codec, nid, dac, 1, | ||
1738 | &spec->out_mix_path)) | ||
1739 | dac = spec->out_mix_path.path[0]; | ||
1740 | if (dac) { | ||
1741 | spec->private_dac_nids[i] = dac; | ||
1736 | dac_num++; | 1742 | dac_num++; |
1737 | } | 1743 | } |
1738 | } | 1744 | } |
1745 | if (!spec->out_path[0].depth && spec->out_mix_path.depth) { | ||
1746 | spec->out_path[0] = spec->out_mix_path; | ||
1747 | spec->out_mix_path.depth = 0; | ||
1748 | } | ||
1739 | spec->multiout.num_dacs = dac_num; | 1749 | spec->multiout.num_dacs = dac_num; |
1740 | return 0; | 1750 | return 0; |
1741 | } | 1751 | } |
@@ -1832,6 +1842,7 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec) | |||
1832 | { | 1842 | { |
1833 | struct via_spec *spec = codec->spec; | 1843 | struct via_spec *spec = codec->spec; |
1834 | struct auto_pin_cfg *cfg = &spec->autocfg; | 1844 | struct auto_pin_cfg *cfg = &spec->autocfg; |
1845 | struct nid_path *path; | ||
1835 | static const char * const chname[4] = { | 1846 | static const char * const chname[4] = { |
1836 | "Front", "Surround", "C/LFE", "Side" | 1847 | "Front", "Surround", "C/LFE", "Side" |
1837 | }; | 1848 | }; |
@@ -1857,13 +1868,12 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec) | |||
1857 | dac = spec->multiout.dac_nids[i]; | 1868 | dac = spec->multiout.dac_nids[i]; |
1858 | if (!pin || !dac) | 1869 | if (!pin || !dac) |
1859 | continue; | 1870 | continue; |
1871 | path = spec->out_path + i; | ||
1860 | if (i == HDA_CLFE) { | 1872 | if (i == HDA_CLFE) { |
1861 | err = create_ch_ctls(codec, "Center", 1, true, | 1873 | err = create_ch_ctls(codec, "Center", 1, true, path); |
1862 | &spec->out_path[i]); | ||
1863 | if (err < 0) | 1874 | if (err < 0) |
1864 | return err; | 1875 | return err; |
1865 | err = create_ch_ctls(codec, "LFE", 2, true, | 1876 | err = create_ch_ctls(codec, "LFE", 2, true, path); |
1866 | &spec->out_path[i]); | ||
1867 | if (err < 0) | 1877 | if (err < 0) |
1868 | return err; | 1878 | return err; |
1869 | } else { | 1879 | } else { |
@@ -1871,25 +1881,35 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec) | |||
1871 | if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && | 1881 | if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && |
1872 | cfg->line_outs == 1) | 1882 | cfg->line_outs == 1) |
1873 | pfx = "Speaker"; | 1883 | pfx = "Speaker"; |
1874 | err = create_ch_ctls(codec, pfx, 3, true, | 1884 | err = create_ch_ctls(codec, pfx, 3, true, path); |
1875 | &spec->out_path[i]); | ||
1876 | if (err < 0) | 1885 | if (err < 0) |
1877 | return err; | 1886 | return err; |
1878 | } | 1887 | } |
1888 | if (path != spec->out_path + i) { | ||
1889 | spec->out_path[i].vol_ctl = path->vol_ctl; | ||
1890 | spec->out_path[i].mute_ctl = path->mute_ctl; | ||
1891 | } | ||
1892 | if (path == spec->out_path && spec->out_mix_path.depth) { | ||
1893 | spec->out_mix_path.vol_ctl = path->vol_ctl; | ||
1894 | spec->out_mix_path.mute_ctl = path->mute_ctl; | ||
1895 | } | ||
1879 | } | 1896 | } |
1880 | 1897 | ||
1881 | idx = get_connection_index(codec, spec->aa_mix_nid, | 1898 | idx = get_connection_index(codec, spec->aa_mix_nid, |
1882 | spec->multiout.dac_nids[0]); | 1899 | spec->multiout.dac_nids[0]); |
1883 | if (idx >= 0) { | 1900 | if (idx >= 0) { |
1884 | /* add control to mixer */ | 1901 | /* add control to mixer */ |
1885 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 1902 | const char *name; |
1886 | "PCM Playback Volume", | 1903 | name = spec->out_mix_path.depth ? |
1904 | "PCM Loopback Playback Volume" : "PCM Playback Volume"; | ||
1905 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
1887 | HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, | 1906 | HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, |
1888 | idx, HDA_INPUT)); | 1907 | idx, HDA_INPUT)); |
1889 | if (err < 0) | 1908 | if (err < 0) |
1890 | return err; | 1909 | return err; |
1891 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 1910 | name = spec->out_mix_path.depth ? |
1892 | "PCM Playback Switch", | 1911 | "PCM Loopback Playback Switch" : "PCM Playback Switch"; |
1912 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
1893 | HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, | 1913 | HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, |
1894 | idx, HDA_INPUT)); | 1914 | idx, HDA_INPUT)); |
1895 | if (err < 0) | 1915 | if (err < 0) |
@@ -1906,70 +1926,167 @@ static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) | |||
1906 | struct via_spec *spec = codec->spec; | 1926 | struct via_spec *spec = codec->spec; |
1907 | struct nid_path *path; | 1927 | struct nid_path *path; |
1908 | bool check_dac; | 1928 | bool check_dac; |
1909 | int err; | 1929 | int i, err; |
1910 | 1930 | ||
1911 | if (!pin) | 1931 | if (!pin) |
1912 | return 0; | 1932 | return 0; |
1913 | 1933 | ||
1914 | if (parse_output_path(codec, pin, 0, &spec->hp_path)) | 1934 | if (!parse_output_path(codec, pin, 0, 0, &spec->hp_indep_path)) { |
1915 | spec->hp_dac_nid = spec->hp_path.path[0]; | 1935 | for (i = HDA_SIDE; i >= HDA_CLFE; i--) { |
1916 | else if (spec->multiout.dac_nids[HDA_SIDE] && | 1936 | if (i < spec->multiout.num_dacs && |
1917 | parse_output_path(codec, pin, | 1937 | parse_output_path(codec, pin, |
1918 | spec->multiout.dac_nids[HDA_SIDE], | 1938 | spec->multiout.dac_nids[i], 0, |
1919 | &spec->hp_path)) { | 1939 | &spec->hp_indep_path)) { |
1920 | spec->hp_dac_nid = spec->hp_path.path[0]; | 1940 | spec->hp_indep_shared = i; |
1921 | spec->hp_indep_shared = true; | 1941 | break; |
1922 | } else if (spec->multiout.dac_nids[HDA_CLFE] && | 1942 | } |
1923 | parse_output_path(codec, pin, | 1943 | } |
1924 | spec->multiout.dac_nids[HDA_CLFE], | ||
1925 | &spec->hp_path)) { | ||
1926 | spec->hp_dac_nid = spec->hp_path.path[0]; | ||
1927 | spec->hp_indep_shared = true; | ||
1928 | } | 1944 | } |
1945 | if (spec->hp_indep_path.depth) { | ||
1946 | spec->hp_dac_nid = spec->hp_indep_path.path[0]; | ||
1947 | if (!spec->hp_indep_shared) | ||
1948 | spec->hp_path = spec->hp_indep_path; | ||
1949 | } | ||
1950 | /* optionally check front-path w/o AA-mix */ | ||
1951 | if (!spec->hp_path.depth) | ||
1952 | parse_output_path(codec, pin, | ||
1953 | spec->multiout.dac_nids[HDA_FRONT], 0, | ||
1954 | &spec->hp_path); | ||
1929 | 1955 | ||
1930 | if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], | 1956 | if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], |
1931 | &spec->hp_dep_path) && | 1957 | 1, &spec->hp_mix_path) && !spec->hp_path.depth) |
1932 | !spec->hp_dac_nid) | ||
1933 | return 0; | 1958 | return 0; |
1934 | 1959 | ||
1935 | if (spec->hp_dac_nid && !spec->hp_indep_shared) { | 1960 | if (spec->hp_path.depth) { |
1936 | path = &spec->hp_path; | 1961 | path = &spec->hp_path; |
1937 | check_dac = true; | 1962 | check_dac = true; |
1938 | } else { | 1963 | } else { |
1939 | path = &spec->hp_dep_path; | 1964 | path = &spec->hp_mix_path; |
1940 | check_dac = false; | 1965 | check_dac = false; |
1941 | } | 1966 | } |
1942 | err = create_ch_ctls(codec, "Headphone", 3, check_dac, path); | 1967 | err = create_ch_ctls(codec, "Headphone", 3, check_dac, path); |
1943 | if (err < 0) | 1968 | if (err < 0) |
1944 | return err; | 1969 | return err; |
1945 | if (spec->hp_dac_nid) { | 1970 | if (check_dac) { |
1946 | spec->hp_dep_path.vol_ctl = spec->hp_path.vol_ctl; | 1971 | spec->hp_mix_path.vol_ctl = path->vol_ctl; |
1947 | spec->hp_dep_path.mute_ctl = spec->hp_path.mute_ctl; | 1972 | spec->hp_mix_path.mute_ctl = path->mute_ctl; |
1973 | } else { | ||
1974 | spec->hp_path.vol_ctl = path->vol_ctl; | ||
1975 | spec->hp_path.mute_ctl = path->mute_ctl; | ||
1948 | } | 1976 | } |
1949 | |||
1950 | return 0; | 1977 | return 0; |
1951 | } | 1978 | } |
1952 | 1979 | ||
1953 | static int via_auto_create_speaker_ctls(struct hda_codec *codec) | 1980 | static int via_auto_create_speaker_ctls(struct hda_codec *codec) |
1954 | { | 1981 | { |
1955 | struct via_spec *spec = codec->spec; | 1982 | struct via_spec *spec = codec->spec; |
1983 | struct nid_path *path; | ||
1984 | bool check_dac; | ||
1956 | hda_nid_t pin, dac; | 1985 | hda_nid_t pin, dac; |
1986 | int err; | ||
1957 | 1987 | ||
1958 | pin = spec->autocfg.speaker_pins[0]; | 1988 | pin = spec->autocfg.speaker_pins[0]; |
1959 | if (!spec->autocfg.speaker_outs || !pin) | 1989 | if (!spec->autocfg.speaker_outs || !pin) |
1960 | return 0; | 1990 | return 0; |
1961 | 1991 | ||
1962 | if (parse_output_path(codec, pin, 0, &spec->speaker_path)) { | 1992 | if (parse_output_path(codec, pin, 0, 0, &spec->speaker_path)) |
1963 | dac = spec->speaker_path.path[0]; | 1993 | dac = spec->speaker_path.path[0]; |
1964 | spec->multiout.extra_out_nid[0] = dac; | 1994 | if (!dac) |
1965 | return create_ch_ctls(codec, "Speaker", 3, true, | 1995 | parse_output_path(codec, pin, |
1966 | &spec->speaker_path); | 1996 | spec->multiout.dac_nids[HDA_FRONT], 0, |
1997 | &spec->speaker_path); | ||
1998 | if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], | ||
1999 | 1, &spec->speaker_mix_path) && !dac) | ||
2000 | return 0; | ||
2001 | |||
2002 | /* no AA-path for front? */ | ||
2003 | if (!spec->out_mix_path.depth && spec->speaker_mix_path.depth) | ||
2004 | dac = 0; | ||
2005 | |||
2006 | spec->speaker_dac_nid = dac; | ||
2007 | spec->multiout.extra_out_nid[0] = dac; | ||
2008 | if (dac) { | ||
2009 | path = &spec->speaker_path; | ||
2010 | check_dac = true; | ||
2011 | } else { | ||
2012 | path = &spec->speaker_mix_path; | ||
2013 | check_dac = false; | ||
2014 | } | ||
2015 | err = create_ch_ctls(codec, "Speaker", 3, check_dac, path); | ||
2016 | if (err < 0) | ||
2017 | return err; | ||
2018 | if (check_dac) { | ||
2019 | spec->speaker_mix_path.vol_ctl = path->vol_ctl; | ||
2020 | spec->speaker_mix_path.mute_ctl = path->mute_ctl; | ||
2021 | } else { | ||
2022 | spec->speaker_path.vol_ctl = path->vol_ctl; | ||
2023 | spec->speaker_path.mute_ctl = path->mute_ctl; | ||
1967 | } | 2024 | } |
1968 | if (parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], | 2025 | return 0; |
1969 | &spec->speaker_path)) | 2026 | } |
1970 | return create_ch_ctls(codec, "Speaker", 3, false, | 2027 | |
1971 | &spec->speaker_path); | 2028 | #define via_aamix_ctl_info via_pin_power_ctl_info |
1972 | 2029 | ||
2030 | static int via_aamix_ctl_get(struct snd_kcontrol *kcontrol, | ||
2031 | struct snd_ctl_elem_value *ucontrol) | ||
2032 | { | ||
2033 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2034 | struct via_spec *spec = codec->spec; | ||
2035 | ucontrol->value.enumerated.item[0] = spec->aamix_mode; | ||
2036 | return 0; | ||
2037 | } | ||
2038 | |||
2039 | static void update_aamix_paths(struct hda_codec *codec, int do_mix, | ||
2040 | struct nid_path *nomix, struct nid_path *mix) | ||
2041 | { | ||
2042 | if (do_mix) { | ||
2043 | activate_output_path(codec, nomix, false, false); | ||
2044 | activate_output_path(codec, mix, true, false); | ||
2045 | } else { | ||
2046 | activate_output_path(codec, mix, false, false); | ||
2047 | activate_output_path(codec, nomix, true, false); | ||
2048 | } | ||
2049 | } | ||
2050 | |||
2051 | static int via_aamix_ctl_put(struct snd_kcontrol *kcontrol, | ||
2052 | struct snd_ctl_elem_value *ucontrol) | ||
2053 | { | ||
2054 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2055 | struct via_spec *spec = codec->spec; | ||
2056 | unsigned int val = ucontrol->value.enumerated.item[0]; | ||
2057 | |||
2058 | if (val == spec->aamix_mode) | ||
2059 | return 0; | ||
2060 | spec->aamix_mode = val; | ||
2061 | /* update front path */ | ||
2062 | update_aamix_paths(codec, val, &spec->out_path[0], &spec->out_mix_path); | ||
2063 | /* update HP path */ | ||
2064 | if (!spec->hp_independent_mode) { | ||
2065 | update_aamix_paths(codec, val, &spec->hp_path, | ||
2066 | &spec->hp_mix_path); | ||
2067 | } | ||
2068 | /* update speaker path */ | ||
2069 | update_aamix_paths(codec, val, &spec->speaker_path, | ||
2070 | &spec->speaker_mix_path); | ||
2071 | return 1; | ||
2072 | } | ||
2073 | |||
2074 | static const struct snd_kcontrol_new via_aamix_ctl_enum = { | ||
2075 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2076 | .name = "Loopback Mixing", | ||
2077 | .info = via_aamix_ctl_info, | ||
2078 | .get = via_aamix_ctl_get, | ||
2079 | .put = via_aamix_ctl_put, | ||
2080 | }; | ||
2081 | |||
2082 | static int via_auto_create_loopback_switch(struct hda_codec *codec) | ||
2083 | { | ||
2084 | struct via_spec *spec = codec->spec; | ||
2085 | |||
2086 | if (!spec->aa_mix_nid || !spec->out_mix_path.depth) | ||
2087 | return 0; /* no loopback switching available */ | ||
2088 | if (!via_clone_control(spec, &via_aamix_ctl_enum)) | ||
2089 | return -ENOMEM; | ||
1973 | return 0; | 2090 | return 0; |
1974 | } | 2091 | } |
1975 | 2092 | ||
@@ -2440,6 +2557,9 @@ static int via_parse_auto_config(struct hda_codec *codec) | |||
2440 | err = via_auto_create_speaker_ctls(codec); | 2557 | err = via_auto_create_speaker_ctls(codec); |
2441 | if (err < 0) | 2558 | if (err < 0) |
2442 | return err; | 2559 | return err; |
2560 | err = via_auto_create_loopback_switch(codec); | ||
2561 | if (err < 0) | ||
2562 | return err; | ||
2443 | err = via_auto_create_analog_input_ctls(codec); | 2563 | err = via_auto_create_analog_input_ctls(codec); |
2444 | if (err < 0) | 2564 | if (err < 0) |
2445 | return err; | 2565 | return err; |
@@ -2453,7 +2573,7 @@ static int via_parse_auto_config(struct hda_codec *codec) | |||
2453 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | 2573 | spec->mixers[spec->num_mixers++] = spec->kctls.list; |
2454 | 2574 | ||
2455 | 2575 | ||
2456 | if (spec->hp_dac_nid && spec->hp_dep_path.depth) { | 2576 | if (spec->hp_dac_nid && spec->hp_mix_path.depth) { |
2457 | err = via_hp_build(codec); | 2577 | err = via_hp_build(codec); |
2458 | if (err < 0) | 2578 | if (err < 0) |
2459 | return err; | 2579 | return err; |