aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_generic.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-03-16 05:18:08 -0400
committerTakashi Iwai <tiwai@suse.de>2015-03-16 09:44:03 -0400
commitcc261738add93947d138d2fabad9f4dbed4e5c00 (patch)
treedce1925148a516e3a2b015a91b2ce2663206c32e /sound/pci/hda/hda_generic.c
parent06e5801b8cb3fc057d88cb4dc03c0b64b2744cda (diff)
ALSA: hda - Treat stereo-to-mono mix properly
The commit [ef403edb7558: ALSA: hda - Don't access stereo amps for mono channel widgets] fixed the handling of mono widgets in general, but it still misses an exceptional case: namely, a mono mixer widget taking a single stereo input. In this case, it has stereo volumes although it's a mono widget, and thus we have to take care of both left and right input channels, as stated in HD-audio spec ("7.1.3 Widget Interconnection Rules"). This patch covers this missing piece by adding proper checks of stereo amps in both the generic parser and the proc output codes. Reported-by: Raymond Yau <superquad.vortex2@gmail.com> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_generic.c')
-rw-r--r--sound/pci/hda/hda_generic.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index fe18071bf93a..8ec5289f8e05 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -687,13 +687,30 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
687 return val; 687 return val;
688} 688}
689 689
690/* is this a stereo widget or a stereo-to-mono mix? */
691static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
692{
693 unsigned int wcaps = get_wcaps(codec, nid);
694 hda_nid_t conn;
695
696 if (wcaps & AC_WCAP_STEREO)
697 return true;
698 if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
699 return false;
700 if (snd_hda_get_num_conns(codec, nid) != 1)
701 return false;
702 if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
703 return false;
704 return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
705}
706
690/* initialize the amp value (only at the first time) */ 707/* initialize the amp value (only at the first time) */
691static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) 708static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
692{ 709{
693 unsigned int caps = query_amp_caps(codec, nid, dir); 710 unsigned int caps = query_amp_caps(codec, nid, dir);
694 int val = get_amp_val_to_activate(codec, nid, dir, caps, false); 711 int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
695 712
696 if (get_wcaps(codec, nid) & AC_WCAP_STEREO) 713 if (is_stereo_amps(codec, nid, dir))
697 snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); 714 snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
698 else 715 else
699 snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val); 716 snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
@@ -703,7 +720,7 @@ static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
703static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, 720static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
704 unsigned int mask, unsigned int val) 721 unsigned int mask, unsigned int val)
705{ 722{
706 if (get_wcaps(codec, nid) & AC_WCAP_STEREO) 723 if (is_stereo_amps(codec, nid, dir))
707 return snd_hda_codec_amp_stereo(codec, nid, dir, idx, 724 return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
708 mask, val); 725 mask, val);
709 else 726 else