aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-11-28 05:05:28 -0500
committerTakashi Iwai <tiwai@suse.de>2013-11-28 05:32:00 -0500
commit2ded3e5b61d61d0bc90bebb8004db6184c7db6eb (patch)
tree16ab06590f0d03e6fe66cd811226a6c18de0a636
parent16c0cefe8951b2c4b824fd06011ac1b359b1ab3b (diff)
ALSA: hda - Check leaf nodes to find aamix amps
The current generic parser assumes blindly that the volume and mute amps are found in the aamix node itself. But on some codecs, typically Analog Devices ones, the aamix amps are separately implemented in each leaf node of the aamix node, and the current driver can't establish the correct amp controls. This is a regression compared with the previous static quirks. This patch extends the search for the amps to the leaf nodes for allowing the aamix controls again on such codecs. In this implementation, I didn't code to loop through the whole paths, since usually one depth should suffice, and we can't search too deeply, as it may result in the conflicting control assignments. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=65641 Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/hda_generic.c57
1 files changed, 45 insertions, 12 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index faefff1d3e81..c4671d00babd 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -2808,6 +2808,42 @@ static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
2808 return 0; 2808 return 0;
2809} 2809}
2810 2810
2811/* return true if either a volume or a mute amp is found for the given
2812 * aamix path; the amp has to be either in the mixer node or its direct leaf
2813 */
2814static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid,
2815 hda_nid_t pin, unsigned int *mix_val,
2816 unsigned int *mute_val)
2817{
2818 int idx, num_conns;
2819 const hda_nid_t *list;
2820 hda_nid_t nid;
2821
2822 idx = snd_hda_get_conn_index(codec, mix_nid, pin, true);
2823 if (idx < 0)
2824 return false;
2825
2826 *mix_val = *mute_val = 0;
2827 if (nid_has_volume(codec, mix_nid, HDA_INPUT))
2828 *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
2829 if (nid_has_mute(codec, mix_nid, HDA_INPUT))
2830 *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
2831 if (*mix_val && *mute_val)
2832 return true;
2833
2834 /* check leaf node */
2835 num_conns = snd_hda_get_conn_list(codec, mix_nid, &list);
2836 if (num_conns < idx)
2837 return false;
2838 nid = list[idx];
2839 if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT))
2840 *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2841 if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT))
2842 *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2843
2844 return *mix_val || *mute_val;
2845}
2846
2811/* create input playback/capture controls for the given pin */ 2847/* create input playback/capture controls for the given pin */
2812static int new_analog_input(struct hda_codec *codec, int input_idx, 2848static int new_analog_input(struct hda_codec *codec, int input_idx,
2813 hda_nid_t pin, const char *ctlname, int ctlidx, 2849 hda_nid_t pin, const char *ctlname, int ctlidx,
@@ -2815,12 +2851,11 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
2815{ 2851{
2816 struct hda_gen_spec *spec = codec->spec; 2852 struct hda_gen_spec *spec = codec->spec;
2817 struct nid_path *path; 2853 struct nid_path *path;
2818 unsigned int val; 2854 unsigned int mix_val, mute_val;
2819 int err, idx; 2855 int err, idx;
2820 2856
2821 if (!nid_has_volume(codec, mix_nid, HDA_INPUT) && 2857 if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val))
2822 !nid_has_mute(codec, mix_nid, HDA_INPUT)) 2858 return 0;
2823 return 0; /* no need for analog loopback */
2824 2859
2825 path = snd_hda_add_new_path(codec, pin, mix_nid, 0); 2860 path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
2826 if (!path) 2861 if (!path)
@@ -2829,20 +2864,18 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
2829 spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); 2864 spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
2830 2865
2831 idx = path->idx[path->depth - 1]; 2866 idx = path->idx[path->depth - 1];
2832 if (nid_has_volume(codec, mix_nid, HDA_INPUT)) { 2867 if (mix_val) {
2833 val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2868 err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val);
2834 err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val);
2835 if (err < 0) 2869 if (err < 0)
2836 return err; 2870 return err;
2837 path->ctls[NID_PATH_VOL_CTL] = val; 2871 path->ctls[NID_PATH_VOL_CTL] = mix_val;
2838 } 2872 }
2839 2873
2840 if (nid_has_mute(codec, mix_nid, HDA_INPUT)) { 2874 if (mute_val) {
2841 val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); 2875 err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val);
2842 err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val);
2843 if (err < 0) 2876 if (err < 0)
2844 return err; 2877 return err;
2845 path->ctls[NID_PATH_MUTE_CTL] = val; 2878 path->ctls[NID_PATH_MUTE_CTL] = mute_val;
2846 } 2879 }
2847 2880
2848 path->active = true; 2881 path->active = true;