Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+13 −10
Original line number Diff line number Diff line
@@ -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);
}

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
 */
@@ -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_stream_tag = stream_tag;
	spec->cur_adc_format = format;
	cs_update_input_select(codec);
	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
	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_format);
	}
	snd_hda_codec_write(codec, spec->cur_adc, 0,
			    AC_VERB_SET_CONNECT_SEL,
			    spec->adc_idx[idx]);
	spec->cur_input = idx;
	cs_update_input_select(codec);
	return 1;
}

@@ -973,10 +981,7 @@ static void cs_automic(struct hda_codec *codec)
		} else  {
			spec->cur_input = spec->last_input;
		}

		snd_hda_codec_write_cache(codec, spec->cur_adc, 0,
					AC_VERB_SET_CONNECT_SEL,
					spec->adc_idx[spec->cur_input]);
		cs_update_input_select(codec);
	} else {
		if (present)
			change_cur_input(codec, spec->automic_idx, 0);
@@ -1073,9 +1078,7 @@ static void init_input(struct hda_codec *codec)
			cs_automic(codec);
		else  {
			spec->cur_adc = spec->adc_nid[spec->cur_input];
			snd_hda_codec_write(codec, spec->cur_adc, 0,
					AC_VERB_SET_CONNECT_SEL,
					spec->adc_idx[spec->cur_input]);
			cs_update_input_select(codec);
		}
	} else {
		change_cur_input(codec, spec->cur_input, 1);