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

Commit 2f72853c authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

ALSA: hda - Fix / clean-up slave digital out codes



The recent slave_dig_out addition has some rooms to clean up.
Also it doesn't call snd_hda_cleanup_stream() properly for slaves
at closing.  The patch fixes both issues.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
parent ddc0f38a
Loading
Loading
Loading
Loading
+50 −65
Original line number Diff line number Diff line
@@ -1426,6 +1426,29 @@ static unsigned int convert_to_spdif_status(unsigned short val)
	return sbits;
}

/* set digital convert verbs both for the given NID and its slaves */
static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
			int verb, int val)
{
	hda_nid_t *d;

	snd_hda_codec_write(codec, nid, 0, verb, val);
	d = codec->slave_dig_outs;
	if (!d)
		return;
	for (; *d; d++)
		snd_hda_codec_write(codec, *d, 0, verb, val);
}

static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
				       int dig1, int dig2)
{
	if (dig1 != -1)
		set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1);
	if (dig2 != -1)
		set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2);
}

static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
				     struct snd_ctl_elem_value *ucontrol)
{
@@ -1444,25 +1467,8 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
	change = codec->spdif_ctls != val;
	codec->spdif_ctls = val;

	if (change) {
		hda_nid_t *d;
		snd_hda_codec_write_cache(codec, nid, 0,
					  AC_VERB_SET_DIGI_CONVERT_1,
					  val & 0xff);
		snd_hda_codec_write_cache(codec, nid, 0,
					  AC_VERB_SET_DIGI_CONVERT_2,
					  val >> 8);

		if (codec->slave_dig_outs)
			for (d = codec->slave_dig_outs; *d; d++) {
				snd_hda_codec_write_cache(codec, *d, 0,
					  AC_VERB_SET_DIGI_CONVERT_1,
					  val & 0xff);
				snd_hda_codec_write_cache(codec, *d, 0,
					  AC_VERB_SET_DIGI_CONVERT_2,
					  val >> 8);
			}
	}
	if (change)
		set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);

	mutex_unlock(&codec->spdif_mutex);
	return change;
@@ -1493,17 +1499,8 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
		val |= AC_DIG1_ENABLE;
	change = codec->spdif_ctls != val;
	if (change) {
		hda_nid_t *d;
		codec->spdif_ctls = val;
		snd_hda_codec_write_cache(codec, nid, 0,
					  AC_VERB_SET_DIGI_CONVERT_1,
					  val & 0xff);

		if (codec->slave_dig_outs)
			for (d = codec->slave_dig_outs; *d; d++)
				snd_hda_codec_write_cache(codec, *d, 0,
					  AC_VERB_SET_DIGI_CONVERT_1,
					  val & 0xff);
		set_dig_out_convert(codec, nid, val & 0xff, -1);
		/* unmute amp switch (if any) */
		if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
		    (val & AC_DIG1_ENABLE))
@@ -2598,32 +2595,32 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
				 unsigned int stream_tag, unsigned int format)
{
	hda_nid_t *d;

	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
			    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);

		if (codec->slave_dig_outs)
	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
		set_dig_out_convert(codec, nid, 
				    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
				    -1);
	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
	if (codec->slave_dig_outs) {
		hda_nid_t *d;
		for (d = codec->slave_dig_outs; *d; d++)
				snd_hda_codec_write(codec, *d, 0,
				    AC_VERB_SET_DIGI_CONVERT_1,
				    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
			snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
						   format);
	}
	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
	/* turn on again (if needed) */
	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
				    codec->spdif_ctls & 0xff);
	if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
		set_dig_out_convert(codec, nid,
				    codec->spdif_ctls & 0xff, -1);
}

		if (codec->slave_dig_outs)
static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
{
	snd_hda_codec_cleanup_stream(codec, nid);
	if (codec->slave_dig_outs) {
		hda_nid_t *d;
		for (d = codec->slave_dig_outs; *d; d++)
				snd_hda_codec_write(codec, *d, 0,
				    AC_VERB_SET_DIGI_CONVERT_1,
				    codec->spdif_ctls & 0xff);
			snd_hda_codec_cleanup_stream(codec, *d);
	}

}

/*
@@ -2635,7 +2632,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec,
	mutex_lock(&codec->spdif_mutex);
	if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
		/* already opened as analog dup; reset it once */
		snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
		cleanup_dig_out_stream(codec, mout->dig_out_nid);
	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
	mutex_unlock(&codec->spdif_mutex);
	return 0;
@@ -2647,12 +2644,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
				  unsigned int format,
				  struct snd_pcm_substream *substream)
{
	hda_nid_t *nid;
	mutex_lock(&codec->spdif_mutex);
	setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format);
	if (codec->slave_dig_outs)
		for (nid = codec->slave_dig_outs; *nid; nid++)
			setup_dig_out_stream(codec, *nid, stream_tag, format);
	mutex_unlock(&codec->spdif_mutex);
	return 0;
}
@@ -2719,7 +2712,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
				     struct snd_pcm_substream *substream)
{
	hda_nid_t *nids = mout->dac_nids;
	hda_nid_t *d;
	int chs = substream->runtime->channels;
	int i;

@@ -2733,16 +2725,9 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
			mout->dig_out_used = HDA_DIG_ANALOG_DUP;
			setup_dig_out_stream(codec, mout->dig_out_nid,
					     stream_tag, format);
			if (codec->slave_dig_outs)
				for (d = codec->slave_dig_outs; *d; d++)
					setup_dig_out_stream(codec, *d,
						stream_tag, format);
		} else {
			mout->dig_out_used = 0;
			snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
			if (codec->slave_dig_outs)
				for (d = codec->slave_dig_outs; *d; d++)
					snd_hda_codec_cleanup_stream(codec, *d);
			cleanup_dig_out_stream(codec, mout->dig_out_nid);
		}
	}
	mutex_unlock(&codec->spdif_mutex);
@@ -2793,7 +2778,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
						     mout->extra_out_nid[i]);
	mutex_lock(&codec->spdif_mutex);
	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
		snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
		cleanup_dig_out_stream(codec, mout->dig_out_nid);
		mout->dig_out_used = 0;
	}
	mutex_unlock(&codec->spdif_mutex);