At Tue, 26 Feb 2008 17:25:35 -0500, Matt Whitlock wrote:
On Tuesday, 26 February 2008 9:01:17 am Takashi Iwai wrote:
There is a clear difference between "default" and "spdif" PCMs. The default uses dmix plugin with the fixed 48kHz rate. The spdif is a direct access and can use all rates the codec chip supports (but no soft-mixing).
Well yes, I knew that. I was trying to show you the inconsistencies of state in ALSA's handling of the S/PDIF output under various sequences of actions.
Can I assume at this point that there is no way to set the idle S/PDIF output sample rate to 44100 Hz? That is my original question.
The driver code resets the format verb of the relevant widgets at closing streams. This verb contains the sample rate, too. Maybe keeping this would prevent the reset.
The below is a test patch. Give it a try.
Takashi
---
diff -r d960c4971891 pci/hda/hda_codec.c --- a/pci/hda/hda_codec.c Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/hda_codec.c Thu Feb 28 12:46:43 2008 +0100 @@ -693,6 +693,19 @@ void snd_hda_codec_setup_stream(struct h (stream_tag << 4) | channel_id); msleep(1); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); +} + +void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) +{ + if (!nid) + return; + + snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); +#if 0 /* keep the format */ + msleep(1); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); +#endif }
/* @@ -2179,7 +2192,7 @@ static int hda_pcm_default_cleanup(struc struct hda_codec *codec, struct snd_pcm_substream *substream) { - snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; }
@@ -2564,7 +2577,7 @@ int snd_hda_multi_out_dig_open(struct hd mutex_lock(&codec->spdif_mutex); if (mout->dig_out_used == HDA_DIG_ANALOG_DUP) /* already opened as analog dup; reset it once */ - snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); mout->dig_out_used = HDA_DIG_EXCLUSIVE; mutex_unlock(&codec->spdif_mutex); return 0; @@ -2659,8 +2672,7 @@ int snd_hda_multi_out_analog_prepare(str stream_tag, format); } else { mout->dig_out_used = 0; - snd_hda_codec_setup_stream(codec, mout->dig_out_nid, - 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); } } mutex_unlock(&codec->spdif_mutex); @@ -2702,17 +2714,16 @@ int snd_hda_multi_out_analog_cleanup(str int i;
for (i = 0; i < mout->num_dacs; i++) - snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, nids[i]); if (mout->hp_nid) - snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, mout->hp_nid); for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) if (mout->extra_out_nid[i]) - snd_hda_codec_setup_stream(codec, - mout->extra_out_nid[i], - 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, + mout->extra_out_nid[i]); mutex_lock(&codec->spdif_mutex); if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { - snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); mout->dig_out_used = 0; } mutex_unlock(&codec->spdif_mutex); diff -r d960c4971891 pci/hda/hda_codec.h --- a/pci/hda/hda_codec.h Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/hda_codec.h Thu Feb 28 12:46:43 2008 +0100 @@ -722,6 +722,7 @@ void snd_hda_codec_setup_stream(struct h void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format); +void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid); unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, unsigned int format, diff -r d960c4971891 pci/hda/hda_generic.c --- a/pci/hda/hda_generic.c Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/hda_generic.c Thu Feb 28 12:46:43 2008 +0100 @@ -1007,8 +1007,8 @@ static int generic_pcm2_cleanup(struct h { struct hda_gspec *spec = codec->spec;
- snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0); - snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, hinfo->nid); + snd_hda_codec_cleanup_stream(codec, spec->dac_node[1]->nid); return 0; }
diff -r d960c4971891 pci/hda/patch_analog.c --- a/pci/hda/patch_analog.c Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/patch_analog.c Thu Feb 28 12:46:43 2008 +0100 @@ -295,8 +295,7 @@ static int ad198x_capture_pcm_cleanup(st struct snd_pcm_substream *substream) { struct ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); return 0; }
@@ -3324,8 +3323,7 @@ static int ad1984_pcm_dmic_cleanup(struc struct hda_codec *codec, struct snd_pcm_substream *substream) { - snd_hda_codec_setup_stream(codec, 0x05 + substream->number, - 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number); return 0; }
diff -r d960c4971891 pci/hda/patch_cmedia.c --- a/pci/hda/patch_cmedia.c Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/patch_cmedia.c Thu Feb 28 12:46:43 2008 +0100 @@ -512,7 +512,7 @@ static int cmi9880_capture_pcm_cleanup(s { struct cmi_spec *spec = codec->spec;
- snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); return 0; }
diff -r d960c4971891 pci/hda/patch_conexant.c --- a/pci/hda/patch_conexant.c Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/patch_conexant.c Thu Feb 28 12:46:43 2008 +0100 @@ -173,8 +173,7 @@ static int conexant_capture_pcm_cleanup( struct snd_pcm_substream *substream) { struct conexant_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); return 0; }
@@ -242,7 +241,7 @@ static int cx5051_capture_pcm_cleanup(st struct snd_pcm_substream *substream) { struct conexant_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); spec->cur_adc = 0; return 0; } @@ -1544,7 +1543,7 @@ static void cxt5051_portc_automic(struct new_adc = spec->adc_nids[spec->cur_adc_idx]; if (spec->cur_adc && spec->cur_adc != new_adc) { /* stream is running, let's swap the current ADC */ - snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); spec->cur_adc = new_adc; snd_hda_codec_setup_stream(codec, new_adc, spec->cur_adc_stream_tag, 0, diff -r d960c4971891 pci/hda/patch_realtek.c --- a/pci/hda/patch_realtek.c Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/patch_realtek.c Thu Feb 28 12:46:43 2008 +0100 @@ -2405,8 +2405,8 @@ static int alc880_alt_capture_pcm_cleanu { struct alc_spec *spec = codec->spec;
- snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], - 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, + spec->adc_nids[substream->number + 1]); return 0; }
diff -r d960c4971891 pci/hda/patch_sigmatel.c --- a/pci/hda/patch_sigmatel.c Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/patch_sigmatel.c Thu Feb 28 12:46:43 2008 +0100 @@ -1891,7 +1891,7 @@ static int stac92xx_capture_pcm_cleanup( { struct sigmatel_spec *spec = codec->spec;
- snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); return 0; }
diff -r d960c4971891 pci/hda/patch_via.c --- a/pci/hda/patch_via.c Thu Feb 28 12:02:56 2008 +0100 +++ b/pci/hda/patch_via.c Thu Feb 28 12:46:43 2008 +0100 @@ -431,8 +431,7 @@ static int via_capture_pcm_cleanup(struc struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - 0, 0, 0); + snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); return 0; }