Commit 05ee7964 authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarDylan Reid <dgreid@chromium.org>
Cc: <stable@kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 25d7d59d
...@@ -237,6 +237,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, ...@@ -237,6 +237,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
} }
static void cs_update_input_select(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
if (spec->cur_adc)
snd_hda_codec_write(codec, spec->cur_adc, 0,
AC_VERB_SET_CONNECT_SEL,
spec->adc_idx[spec->cur_input]);
}
/* /*
* Analog capture * Analog capture
*/ */
...@@ -250,6 +259,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -250,6 +259,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
spec->cur_adc = spec->adc_nid[spec->cur_input]; spec->cur_adc = spec->adc_nid[spec->cur_input];
spec->cur_adc_stream_tag = stream_tag; spec->cur_adc_stream_tag = stream_tag;
spec->cur_adc_format = format; spec->cur_adc_format = format;
cs_update_input_select(codec);
snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
return 0; return 0;
} }
...@@ -689,10 +699,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx, ...@@ -689,10 +699,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx,
spec->cur_adc_stream_tag, 0, spec->cur_adc_stream_tag, 0,
spec->cur_adc_format); spec->cur_adc_format);
} }
snd_hda_codec_write(codec, spec->cur_adc, 0,
AC_VERB_SET_CONNECT_SEL,
spec->adc_idx[idx]);
spec->cur_input = idx; spec->cur_input = idx;
cs_update_input_select(codec);
return 1; return 1;
} }
...@@ -973,10 +981,7 @@ static void cs_automic(struct hda_codec *codec) ...@@ -973,10 +981,7 @@ static void cs_automic(struct hda_codec *codec)
} else { } else {
spec->cur_input = spec->last_input; spec->cur_input = spec->last_input;
} }
cs_update_input_select(codec);
snd_hda_codec_write_cache(codec, spec->cur_adc, 0,
AC_VERB_SET_CONNECT_SEL,
spec->adc_idx[spec->cur_input]);
} else { } else {
if (present) if (present)
change_cur_input(codec, spec->automic_idx, 0); change_cur_input(codec, spec->automic_idx, 0);
...@@ -1073,9 +1078,7 @@ static void init_input(struct hda_codec *codec) ...@@ -1073,9 +1078,7 @@ static void init_input(struct hda_codec *codec)
cs_automic(codec); cs_automic(codec);
else { else {
spec->cur_adc = spec->adc_nid[spec->cur_input]; spec->cur_adc = spec->adc_nid[spec->cur_input];
snd_hda_codec_write(codec, spec->cur_adc, 0, cs_update_input_select(codec);
AC_VERB_SET_CONNECT_SEL,
spec->adc_idx[spec->cur_input]);
} }
} else { } else {
change_cur_input(codec, spec->cur_input, 1); change_cur_input(codec, spec->cur_input, 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment