aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-06-21 05:48:29 -0400
committerTakashi Iwai <tiwai@suse.de>2011-06-21 06:20:13 -0400
commit8df2a3129d946dc91f9824958567a990329822b3 (patch)
treeb2c6b7002bffa7c0cc9361bf8c7ed8babcd5919a /sound
parenta00a5fad9ddbabc7cd03d143520b9a4730edc75d (diff)
ALSA: hda - Fix re-routing of HP-independent mode in patch_via.c
Re-route the whole output path when HP-independent mode is changed. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_via.c101
1 files changed, 60 insertions, 41 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 853d24411d53..7b353405e068 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -138,9 +138,7 @@ struct via_spec {
138 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; 138 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
139 139
140 /* HP mode source */ 140 /* HP mode source */
141 const struct hda_input_mux *hp_mux;
142 unsigned int hp_independent_mode; 141 unsigned int hp_independent_mode;
143 unsigned int hp_independent_mode_index;
144 unsigned int dmic_enabled; 142 unsigned int dmic_enabled;
145 unsigned int no_pin_power_ctl; 143 unsigned int no_pin_power_ctl;
146 enum VIA_HDA_CODEC codec_type; 144 enum VIA_HDA_CODEC codec_type;
@@ -406,6 +404,24 @@ static int __get_connection_index(struct hda_codec *codec, hda_nid_t mux,
406#define get_connection_index(codec, mux, nid) \ 404#define get_connection_index(codec, mux, nid) \
407 __get_connection_index(codec, mux, nid, NULL) 405 __get_connection_index(codec, mux, nid, NULL)
408 406
407static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
408 unsigned int mask)
409{
410 unsigned int caps = get_wcaps(codec, nid);
411 if (dir == HDA_INPUT)
412 caps &= AC_WCAP_IN_AMP;
413 else
414 caps &= AC_WCAP_OUT_AMP;
415 if (!caps)
416 return false;
417 if (query_amp_caps(codec, nid, dir) & mask)
418 return true;
419 return false;
420}
421
422#define have_vol_or_mute(codec, nid, dir) \
423 check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS | AC_AMPCAP_MUTE)
424
409/* unmute input amp and select the specificed source */ 425/* unmute input amp and select the specificed source */
410static void unmute_and_select(struct hda_codec *codec, hda_nid_t nid, 426static void unmute_and_select(struct hda_codec *codec, hda_nid_t nid,
411 hda_nid_t src, hda_nid_t mix) 427 hda_nid_t src, hda_nid_t mix)
@@ -423,22 +439,20 @@ static void unmute_and_select(struct hda_codec *codec, hda_nid_t nid,
423 AC_VERB_SET_CONNECT_SEL, idx); 439 AC_VERB_SET_CONNECT_SEL, idx);
424 440
425 /* unmute if the input amp is present */ 441 /* unmute if the input amp is present */
426 if (query_amp_caps(codec, nid, HDA_INPUT) & 442 if (have_vol_or_mute(codec, nid, HDA_INPUT))
427 (AC_AMPCAP_NUM_STEPS | AC_AMPCAP_MUTE))
428 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 443 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
429 AMP_IN_UNMUTE(idx)); 444 AMP_IN_UNMUTE(idx));
430 445
431 /* unmute the src output */ 446 /* unmute the src output */
432 if (query_amp_caps(codec, src, HDA_OUTPUT) & 447 if (have_vol_or_mute(codec, src, HDA_OUTPUT))
433 (AC_AMPCAP_NUM_STEPS | AC_AMPCAP_MUTE))
434 snd_hda_codec_write(codec, src, 0, AC_VERB_SET_AMP_GAIN_MUTE, 448 snd_hda_codec_write(codec, src, 0, AC_VERB_SET_AMP_GAIN_MUTE,
435 AMP_OUT_UNMUTE); 449 AMP_OUT_UNMUTE);
436 450
437 /* unmute AA-path if present */ 451 /* unmute AA-path if present */
438 if (!mix) 452 if (!mix || mix == src)
439 return; 453 return;
440 idx = __get_connection_index(codec, nid, mix, NULL); 454 idx = __get_connection_index(codec, nid, mix, NULL);
441 if (idx >= 0) 455 if (idx >= 0 && have_vol_or_mute(codec, nid, HDA_INPUT))
442 snd_hda_codec_write(codec, nid, 0, 456 snd_hda_codec_write(codec, nid, 0,
443 AC_VERB_SET_AMP_GAIN_MUTE, 457 AC_VERB_SET_AMP_GAIN_MUTE,
444 AMP_IN_UNMUTE(idx)); 458 AMP_IN_UNMUTE(idx));
@@ -694,9 +708,16 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
694static int via_independent_hp_info(struct snd_kcontrol *kcontrol, 708static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
695 struct snd_ctl_elem_info *uinfo) 709 struct snd_ctl_elem_info *uinfo)
696{ 710{
697 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 711 static const char * const texts[] = { "OFF", "ON" };
698 struct via_spec *spec = codec->spec; 712
699 return snd_hda_input_mux_info(spec->hp_mux, uinfo); 713 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
714 uinfo->count = 1;
715 uinfo->value.enumerated.items = 2;
716 if (uinfo->value.enumerated.item >= 2)
717 uinfo->value.enumerated.item = 1;
718 strcpy(uinfo->value.enumerated.name,
719 texts[uinfo->value.enumerated.item]);
720 return 0;
700} 721}
701 722
702static int via_independent_hp_get(struct snd_kcontrol *kcontrol, 723static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
@@ -714,12 +735,28 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
714{ 735{
715 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 736 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
716 struct via_spec *spec = codec->spec; 737 struct via_spec *spec = codec->spec;
717 hda_nid_t nid = kcontrol->private_value; 738 hda_nid_t nid, src;
718 unsigned int pinsel = ucontrol->value.enumerated.item[0]; 739 int i, idx, num_conns;
719 /* Get Independent Mode index of headphone pin widget */ 740 struct nid_path *path;
720 spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel 741
721 ? 1 : 0; 742 spec->hp_independent_mode = !!ucontrol->value.enumerated.item[0];
722 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); 743 if (spec->hp_independent_mode)
744 path = &spec->hp_path;
745 else
746 path = &spec->hp_dep_path;
747
748 /* re-route the output path */
749 for (i = path->depth - 1; i > 0; i--) {
750 nid = path->path[i];
751 src = path->path[i - 1];
752 idx = __get_connection_index(codec, nid, src, &num_conns);
753 if (idx < 0)
754 continue;
755 if (num_conns > 1 &&
756 get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX)
757 snd_hda_codec_write(codec, nid, 0,
758 AC_VERB_SET_CONNECT_SEL, idx);
759 }
723 760
724 /* update jack power state */ 761 /* update jack power state */
725 set_widgets_power_state(codec); 762 set_widgets_power_state(codec);
@@ -746,7 +783,6 @@ static int via_hp_build(struct hda_codec *codec)
746 return -ENOMEM; 783 return -ENOMEM;
747 784
748 knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; 785 knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
749 knew->private_value = nid;
750 786
751 return 0; 787 return 0;
752} 788}
@@ -1622,9 +1658,9 @@ static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
1622 hda_nid_t nid; 1658 hda_nid_t nid;
1623 int err; 1659 int err;
1624 1660
1625 if (dac && query_amp_caps(codec, dac, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS) 1661 if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
1626 nid = dac; 1662 nid = dac;
1627 else if (query_amp_caps(codec, pin, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS) 1663 else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
1628 nid = pin; 1664 nid = pin;
1629 else 1665 else
1630 nid = 0; 1666 nid = 0;
@@ -1636,9 +1672,9 @@ static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
1636 return err; 1672 return err;
1637 } 1673 }
1638 1674
1639 if (dac && query_amp_caps(codec, dac, HDA_OUTPUT) & AC_AMPCAP_MUTE) 1675 if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE))
1640 nid = dac; 1676 nid = dac;
1641 else if (query_amp_caps(codec, pin, HDA_OUTPUT) & AC_AMPCAP_MUTE) 1677 else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE))
1642 nid = pin; 1678 nid = pin;
1643 else 1679 else
1644 nid = 0; 1680 nid = 0;
@@ -1741,19 +1777,6 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec)
1741 return 0; 1777 return 0;
1742} 1778}
1743 1779
1744static void create_hp_imux(struct via_spec *spec)
1745{
1746 int i;
1747 struct hda_input_mux *imux = &spec->private_imux[1];
1748 static const char * const texts[] = { "OFF", "ON", NULL};
1749
1750 /* for hp mode select */
1751 for (i = 0; texts[i]; i++)
1752 snd_hda_add_imux_item(imux, texts[i], i, NULL);
1753
1754 spec->hp_mux = &spec->private_imux[1];
1755}
1756
1757static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) 1780static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
1758{ 1781{
1759 struct via_spec *spec = codec->spec; 1782 struct via_spec *spec = codec->spec;
@@ -1762,18 +1785,14 @@ static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
1762 if (!pin) 1785 if (!pin)
1763 return 0; 1786 return 0;
1764 1787
1765 if (parse_output_path(codec, pin, 0, &spec->hp_path)) { 1788 if (parse_output_path(codec, pin, 0, &spec->hp_path))
1766 spec->hp_dac_nid = spec->hp_path.path[0]; 1789 spec->hp_dac_nid = spec->hp_path.path[0];
1767 spec->hp_independent_mode_index = spec->hp_path.idx[0];
1768 create_hp_imux(spec);
1769 }
1770 1790
1771 if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], 1791 if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
1772 &spec->hp_dep_path) && 1792 &spec->hp_dep_path) &&
1773 !spec->hp_dac_nid) 1793 !spec->hp_dac_nid)
1774 return 0; 1794 return 0;
1775 1795
1776
1777 err = create_ch_ctls(codec, "Headphone", pin, spec->hp_dac_nid, 3); 1796 err = create_ch_ctls(codec, "Headphone", pin, spec->hp_dac_nid, 3);
1778 if (err < 0) 1797 if (err < 0)
1779 return err; 1798 return err;
@@ -2068,7 +2087,7 @@ static int via_parse_auto_config(struct hda_codec *codec)
2068 2087
2069 spec->input_mux = &spec->private_imux[0]; 2088 spec->input_mux = &spec->private_imux[0];
2070 2089
2071 if (spec->hp_mux) { 2090 if (spec->hp_dac_nid && spec->hp_dep_path.depth) {
2072 err = via_hp_build(codec); 2091 err = via_hp_build(codec);
2073 if (err < 0) 2092 if (err < 0)
2074 return err; 2093 return err;