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 > }, > }; > _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel