aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-11-16 12:05:11 -0500
committerTakashi Iwai <tiwai@suse.de>2011-11-16 12:05:11 -0500
commit05ee7964a470d29889ac48cc8274c1b5a1904a11 (patch)
tree3d07f56df01f5766ddda417e752647eb74e7bcb6 /sound/pci
parent25d7d59d1f7321be85bda175c9a1bb85ca1b5881 (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.c23
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
240static 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);