[alsa-devel] [PATCH] hda: slave_dig_outs code block in wrong location

Takashi Iwai tiwai at suse.de
Thu Sep 25 16:42:47 CEST 2008


At Thu, 25 Sep 2008 09:17:11 -0400,
Matthew Ranostay wrote:
> 
> Removed invalid references to slave_dig_outs inside the S/PDIF IN capture switch
> control. Beforehand this was basically a mute switch for the S/PDIF outs as well.
> 
> Signed-off-by: Matthew Ranostay <mranostay at embeddedalley.com>

Thanks, applied now.

Meanwhile, I did some cleanups and fixes regarding dig slave stuff.
The patch is below.


Takashi

===
From 83d114fcaa1399d0485d7bc44cec8b6056caef95 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai at suse.de>
Date: Thu, 25 Sep 2008 16:32:41 +0200
Subject: [PATCH] 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: Takashi Iwai <tiwai at suse.de>

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index b524d0b..cf0932c 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1421,6 +1421,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)
 {
@@ -1439,25 +1462,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;
@@ -1488,17 +1494,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))
@@ -2591,32 +2588,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)
-			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);
-	}
+	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_setup_stream(codec, *d, 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)
-			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);
+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_cleanup_stream(codec, *d);
 	}
-
 }
 
 /*
@@ -2628,7 +2625,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;
@@ -2640,12 +2637,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;
 }
@@ -2712,7 +2705,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;
 
@@ -2726,16 +2718,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);
@@ -2786,7 +2771,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);


More information about the Alsa-devel mailing list