[alsa-devel] iec958 switch uneffective while playing ac3 stream
Takashi Iwai
tiwai at suse.de
Tue Apr 3 15:37:53 CEST 2007
[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.
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