[alsa-devel] [PATCH] Re: iec958 switch uneffective while playing ac3 stream

Takashi Iwai tiwai at suse.de
Wed Apr 4 16:21:20 CEST 2007


At 04 Apr 2007 16:09:48 +0200,
Dag Lem wrote:
> 
> Dominique Dumont <domi at komarr.grenoble.hp.com> writes:
> 
> > Dominique Dumont <domi.dumont at free.fr> writes:
> > 
> > > I've included the patch which implement the behavior described
> > > above. Although this diff may be more a hack than a patch ...
> > 
> > I forgot to mention that:
> > - my test included Takashi-san patch. I have not yet tested without
> >   it. Dag, did you include Takashi-san's patch in your tests ?
> > - I have not tested (yet) analog output.
> 
> I tested without Takashi's patch - your hack did the trick without any
> further modifications.
> 
> I think Takashi's patch should be included for another reason - it
> adds a check for NID capabilities before muting/unmuting the digital
> converter (and the ALC882M reports no mute/unmute capabilities for the
> digital converter).

Ah, that's one point I forgot in my last patch.  Could you try this
patch alone?


thanks,

Takashi

diff -r 05ecca0fba92 pci/hda/hda_codec.c
--- a/pci/hda/hda_codec.c	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/hda_codec.c	Wed Apr 04 16:12:25 2007 +0200
@@ -1114,10 +1114,14 @@ static int snd_hda_spdif_out_switch_put(
 	change = codec->spdif_ctls != val;
 	if (change || codec->in_resume) {
 		codec->spdif_ctls = val;
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff);
-		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-				    AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT |
-				    AC_AMP_SET_OUTPUT | ((val & 1) ? 0 : 0x80));
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+				    val & 0xff);
+		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_AMP_GAIN_MUTE,
+					    AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT |
+					    AC_AMP_SET_OUTPUT |
+					    ((val & 1) ? 0 : 0x80));
 	}
 	mutex_unlock(&codec->spdif_mutex);
 	return change;
@@ -1886,6 +1890,21 @@ int snd_hda_input_mux_put(struct hda_cod
  * Multi-channel / digital-out PCM helper functions
  */
 
+/* setup SPDIF output stream */
+static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
+				 unsigned int stream_tag, unsigned int format)
+{
+	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+	if (codec->spdif_ctls & 1)
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+				    codec->spdif_ctls & 0xfe);
+	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+	/* turn on again (if needed) */
+	if (codec->spdif_ctls & 1)
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+				    codec->spdif_ctls & 0xff);
+}
+
 /*
  * open the digital out in the exclusive mode
  */
@@ -1897,6 +1916,18 @@ int snd_hda_multi_out_dig_open(struct hd
 		return -EBUSY; /* already being used */
 	}
 	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
+	mutex_unlock(&codec->spdif_mutex);
+	return 0;
+}
+
+int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
+				  struct hda_multi_out *mout,
+				  unsigned int stream_tag,
+				  unsigned int format,
+				  struct snd_pcm_substream *substream)
+{
+	mutex_lock(&codec->spdif_mutex);
+	setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format);
 	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
@@ -1942,9 +1973,8 @@ int snd_hda_multi_out_analog_prepare(str
 		    snd_hda_is_supported_format(codec, mout->dig_out_nid, format) &&
 		    ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) {
 			mout->dig_out_used = HDA_DIG_ANALOG_DUP;
-			/* setup digital receiver */
-			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
-						   stream_tag, 0, format);
+			setup_dig_out_stream(codec, mout->dig_out_nid,
+					     stream_tag, format);
 		} else {
 			mout->dig_out_used = 0;
 			snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
diff -r 05ecca0fba92 pci/hda/hda_local.h
--- a/pci/hda/hda_local.h	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/hda_local.h	Tue Apr 03 15:31:29 2007 +0200
@@ -148,6 +148,11 @@ struct hda_multi_out {
 
 int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout);
 int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout);
+int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
+				  struct hda_multi_out *mout,
+				  unsigned int stream_tag,
+				  unsigned int format,
+				  struct snd_pcm_substream *substream);
 int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout,
 				  struct snd_pcm_substream *substream);
 int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,
diff -r 05ecca0fba92 pci/hda/patch_analog.c
--- a/pci/hda/patch_analog.c	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/patch_analog.c	Tue Apr 03 18:21:06 2007 +0200
@@ -192,6 +192,17 @@ static int ad198x_dig_playback_pcm_close
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					   struct hda_codec *codec,
+					   unsigned int stream_tag,
+					   unsigned int format,
+					   struct snd_pcm_substream *substream)
+{
+	struct ad198x_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					     format, substream);
+}
+
 /*
  * Analog capture
  */
@@ -250,7 +261,8 @@ static struct hda_pcm_stream ad198x_pcm_
 	.nid = 0, /* fill later */
 	.ops = {
 		.open = ad198x_dig_playback_pcm_open,
-		.close = ad198x_dig_playback_pcm_close
+		.close = ad198x_dig_playback_pcm_close,
+		.prepare = ad198x_dig_playback_pcm_prepare
 	},
 };
 
diff -r 05ecca0fba92 pci/hda/patch_atihdmi.c
--- a/pci/hda/patch_atihdmi.c	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/patch_atihdmi.c	Tue Apr 03 18:22:38 2007 +0200
@@ -95,6 +95,17 @@ static int atihdmi_dig_playback_pcm_clos
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					    struct hda_codec *codec,
+					    unsigned int stream_tag,
+					    unsigned int format,
+					    struct snd_pcm_substream *substream)
+{
+	struct atihdmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					     format, substream);
+}
+
 static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
 	.substreams = 1,
 	.channels_min = 2,
@@ -102,7 +113,8 @@ static struct hda_pcm_stream atihdmi_pcm
 	.nid = 0x2, /* NID to query formats and rates and setup streams */
 	.ops = {
 		.open = atihdmi_dig_playback_pcm_open,
-		.close = atihdmi_dig_playback_pcm_close
+		.close = atihdmi_dig_playback_pcm_close,
+		.prepare = atihdmi_dig_playback_pcm_prepare
 	},
 };
 
diff -r 05ecca0fba92 pci/hda/patch_cmedia.c
--- a/pci/hda/patch_cmedia.c	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/patch_cmedia.c	Tue Apr 03 18:21:40 2007 +0200
@@ -497,6 +497,17 @@ static int cmi9880_dig_playback_pcm_clos
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+static int cmi9880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					    struct hda_codec *codec,
+					    unsigned int stream_tag,
+					    unsigned int format,
+					    struct snd_pcm_substream *substream)
+{
+	struct cmi_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
+					     format, substream);
+}
+
 /*
  * Analog capture
  */
@@ -556,7 +567,8 @@ static struct hda_pcm_stream cmi9880_pcm
 	/* NID is set in cmi9880_build_pcms */
 	.ops = {
 		.open = cmi9880_dig_playback_pcm_open,
-		.close = cmi9880_dig_playback_pcm_close
+		.close = cmi9880_dig_playback_pcm_close,
+		.prepare = cmi9880_dig_playback_pcm_prepare
 	},
 };
 
diff -r 05ecca0fba92 pci/hda/patch_conexant.c
--- a/pci/hda/patch_conexant.c	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/patch_conexant.c	Tue Apr 03 18:23:15 2007 +0200
@@ -136,6 +136,18 @@ static int conexant_dig_playback_pcm_clo
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+static int conexant_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 unsigned int stream_tag,
+					 unsigned int format,
+					 struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+					     stream_tag,
+					     format, substream);
+}
+
 /*
  * Analog capture
  */
@@ -194,7 +206,8 @@ static struct hda_pcm_stream conexant_pc
 	.nid = 0, /* fill later */
 	.ops = {
 		.open = conexant_dig_playback_pcm_open,
-		.close = conexant_dig_playback_pcm_close
+		.close = conexant_dig_playback_pcm_close,
+		.prepare = conexant_dig_playback_pcm_prepare
 	},
 };
 
diff -r 05ecca0fba92 pci/hda/patch_realtek.c
--- a/pci/hda/patch_realtek.c	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/patch_realtek.c	Tue Apr 03 15:32:23 2007 +0200
@@ -1916,6 +1916,17 @@ static int alc880_dig_playback_pcm_open(
 	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
 }
 
+static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					   struct hda_codec *codec,
+					   unsigned int stream_tag,
+					   unsigned int format,
+					   struct snd_pcm_substream *substream)
+{
+	struct alc_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+					     stream_tag, format, substream);
+}
+
 static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
 					 struct hda_codec *codec,
 					 struct snd_pcm_substream *substream)
@@ -1984,7 +1995,8 @@ static struct hda_pcm_stream alc880_pcm_
 	/* NID is set in alc_build_pcms */
 	.ops = {
 		.open = alc880_dig_playback_pcm_open,
-		.close = alc880_dig_playback_pcm_close
+		.close = alc880_dig_playback_pcm_close,
+		.prepare = alc880_dig_playback_pcm_prepare
 	},
 };
 
diff -r 05ecca0fba92 pci/hda/patch_sigmatel.c
--- a/pci/hda/patch_sigmatel.c	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/patch_sigmatel.c	Tue Apr 03 18:24:01 2007 +0200
@@ -814,6 +814,17 @@ static int stac92xx_dig_playback_pcm_clo
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					 struct hda_codec *codec,
+					 unsigned int stream_tag,
+					 unsigned int format,
+					 struct snd_pcm_substream *substream)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+					     stream_tag, format, substream);
+}
+
 
 /*
  * Analog capture callbacks
@@ -848,7 +859,8 @@ static struct hda_pcm_stream stac92xx_pc
 	/* NID is set in stac92xx_build_pcms */
 	.ops = {
 		.open = stac92xx_dig_playback_pcm_open,
-		.close = stac92xx_dig_playback_pcm_close
+		.close = stac92xx_dig_playback_pcm_close,
+		.prepare = stac92xx_dig_playback_pcm_prepare
 	},
 };
 
diff -r 05ecca0fba92 pci/hda/patch_via.c
--- a/pci/hda/patch_via.c	Tue Apr 03 13:20:49 2007 +0200
+++ b/pci/hda/patch_via.c	Tue Apr 03 18:25:22 2007 +0200
@@ -378,6 +378,17 @@ static int via_dig_playback_pcm_close(st
 	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
+static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+					     stream_tag, format, substream);
+}
+
 /*
  * Analog capture
  */
@@ -434,7 +445,8 @@ static struct hda_pcm_stream vt1708_pcm_
 	/* NID is set in via_build_pcms */
 	.ops = {
 		.open = via_dig_playback_pcm_open,
-		.close = via_dig_playback_pcm_close
+		.close = via_dig_playback_pcm_close,
+		.prepare = via_dig_playback_pcm_prepare
 	},
 };
 


More information about the Alsa-devel mailing list