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

Takashi Iwai tiwai at suse.de
Tue Apr 3 15:41:41 CEST 2007


At Tue, 03 Apr 2007 15:37:53 +0200,
I wrote:
> 
> [Nice analysis cut out..]
> 
> At Tue, 03 Apr 2007 10:17:16 +0200,
> Dominique Dumont wrote:
> > 
> > If the stream format is not valid when the digi converter is set up,
> > there's a chance that the digi converter goes belly up.
> > 
> > I reckon that setting the stream *then* the digi converter would be safer.
> 
> OK, now question is whether we need to turn off DIGI_CONV* once before
> setting it up again.
> 
> Anyway, a test patch is below.  It forces to set DIGI_CONV* verbs in
> prepare.  Give it a try.

BTW, it might be better first to remove the check of AC_WCAP_OUT_AMP
in setup_digi_convert().  I vaguely remember that this amp setup was
required for some codecs and it might be somehow broken that doesn't
report the amp capability correctly.


Takashi

> 
> 
> 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	Tue Apr 03 15:28:47 2007 +0200
> @@ -1083,6 +1083,19 @@ static int snd_hda_spdif_default_put(str
>  	return change;
>  }
>  
> +static void setup_digi_convert(struct hda_codec *codec, hda_nid_t nid)
> +{
> +	unsigned short val = codec->spdif_ctls;
> +
> +	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));
> +}
> +
>  static int snd_hda_spdif_out_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
>  {
>  	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
> @@ -1114,10 +1127,7 @@ 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));
> +		setup_digi_convert(codec, nid);
>  	}
>  	mutex_unlock(&codec->spdif_mutex);
>  	return change;
> @@ -1901,6 +1911,21 @@ int snd_hda_multi_out_dig_open(struct hd
>  	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);
> +	snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
> +				   stream_tag, 0, format);
> +	/* set up DIGI_* verbs again */
> +	setup_digi_convert(codec, mout->dig_out_nid);
> +	mutex_unlock(&codec->spdif_mutex);
> +	return 0;
> +}
> +
>  /*
>   * release the digital out
>   */
> @@ -1949,6 +1974,8 @@ int snd_hda_multi_out_analog_prepare(str
>  			mout->dig_out_used = 0;
>  			snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
>  		}
> +		/* set up DIGI_* verbs again */
> +		setup_digi_convert(codec, mout->dig_out_nid);
>  	}
>  	mutex_unlock(&codec->spdif_mutex);
>  
> 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_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
>  	},
>  };
>  


More information about the Alsa-devel mailing list