diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-11-16 12:05:11 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-11-16 12:05:11 -0500 |
commit | 05ee7964a470d29889ac48cc8274c1b5a1904a11 (patch) | |
tree | 3d07f56df01f5766ddda417e752647eb74e7bcb6 /sound/pci | |
parent | 25d7d59d1f7321be85bda175c9a1bb85ca1b5881 (diff) |
ALSA: hda - Fix the connection selection of ADCs on Cirrus codecs
spec->cur_adc isn't set until cs_capture_pcm_prepare() is called although
the driver tries to select the connection at init time and at auto-mic
switch. This results in the access to the widget NID 0, which is
obviously invalid, also a wrong capture source.
This patch fixes the issue by issuing the connect-select verb conditionally
at appropriate places.
Reported-and-tested-by: Dylan Reid <dgreid@chromium.org>
Cc: <stable@kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 2a2d8645ba09..2fbab8e29576 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -237,6 +237,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
237 | return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); | 237 | return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); |
238 | } | 238 | } |
239 | 239 | ||
240 | static void cs_update_input_select(struct hda_codec *codec) | ||
241 | { | ||
242 | struct cs_spec *spec = codec->spec; | ||
243 | if (spec->cur_adc) | ||
244 | snd_hda_codec_write(codec, spec->cur_adc, 0, | ||
245 | AC_VERB_SET_CONNECT_SEL, | ||
246 | spec->adc_idx[spec->cur_input]); | ||
247 | } | ||
248 | |||
240 | /* | 249 | /* |
241 | * Analog capture | 250 | * Analog capture |
242 | */ | 251 | */ |
@@ -250,6 +259,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
250 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | 259 | spec->cur_adc = spec->adc_nid[spec->cur_input]; |
251 | spec->cur_adc_stream_tag = stream_tag; | 260 | spec->cur_adc_stream_tag = stream_tag; |
252 | spec->cur_adc_format = format; | 261 | spec->cur_adc_format = format; |
262 | cs_update_input_select(codec); | ||
253 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); | 263 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); |
254 | return 0; | 264 | return 0; |
255 | } | 265 | } |
@@ -689,10 +699,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx, | |||
689 | spec->cur_adc_stream_tag, 0, | 699 | spec->cur_adc_stream_tag, 0, |
690 | spec->cur_adc_format); | 700 | spec->cur_adc_format); |
691 | } | 701 | } |
692 | snd_hda_codec_write(codec, spec->cur_adc, 0, | ||
693 | AC_VERB_SET_CONNECT_SEL, | ||
694 | spec->adc_idx[idx]); | ||
695 | spec->cur_input = idx; | 702 | spec->cur_input = idx; |
703 | cs_update_input_select(codec); | ||
696 | return 1; | 704 | return 1; |
697 | } | 705 | } |
698 | 706 | ||
@@ -973,10 +981,7 @@ static void cs_automic(struct hda_codec *codec) | |||
973 | } else { | 981 | } else { |
974 | spec->cur_input = spec->last_input; | 982 | spec->cur_input = spec->last_input; |
975 | } | 983 | } |
976 | 984 | cs_update_input_select(codec); | |
977 | snd_hda_codec_write_cache(codec, spec->cur_adc, 0, | ||
978 | AC_VERB_SET_CONNECT_SEL, | ||
979 | spec->adc_idx[spec->cur_input]); | ||
980 | } else { | 985 | } else { |
981 | if (present) | 986 | if (present) |
982 | change_cur_input(codec, spec->automic_idx, 0); | 987 | change_cur_input(codec, spec->automic_idx, 0); |
@@ -1073,9 +1078,7 @@ static void init_input(struct hda_codec *codec) | |||
1073 | cs_automic(codec); | 1078 | cs_automic(codec); |
1074 | else { | 1079 | else { |
1075 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | 1080 | spec->cur_adc = spec->adc_nid[spec->cur_input]; |
1076 | snd_hda_codec_write(codec, spec->cur_adc, 0, | 1081 | cs_update_input_select(codec); |
1077 | AC_VERB_SET_CONNECT_SEL, | ||
1078 | spec->adc_idx[spec->cur_input]); | ||
1079 | } | 1082 | } |
1080 | } else { | 1083 | } else { |
1081 | change_cur_input(codec, spec->cur_input, 1); | 1084 | change_cur_input(codec, spec->cur_input, 1); |