At 04 Apr 2007 16:09:48 +0200, Dag Lem wrote:
Dominique Dumont domi@komarr.grenoble.hp.com writes:
Dominique Dumont domi.dumont@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 }, };