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>
This commit is contained in:
@@ -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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
} 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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user