ALSA: hda - Fix / clean-up slave digital out codes
The recent slave_dig_out addition has some rooms to clean up. Also it doesn't call snd_hda_cleanup_stream() properly for slaves at closing. The patch fixes both issues. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
ddc0f38a62
commit
2f72853ca1
|
@ -1426,6 +1426,29 @@ static unsigned int convert_to_spdif_status(unsigned short val)
|
||||||
return sbits;
|
return sbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set digital convert verbs both for the given NID and its slaves */
|
||||||
|
static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int verb, int val)
|
||||||
|
{
|
||||||
|
hda_nid_t *d;
|
||||||
|
|
||||||
|
snd_hda_codec_write(codec, nid, 0, verb, val);
|
||||||
|
d = codec->slave_dig_outs;
|
||||||
|
if (!d)
|
||||||
|
return;
|
||||||
|
for (; *d; d++)
|
||||||
|
snd_hda_codec_write(codec, *d, 0, verb, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int dig1, int dig2)
|
||||||
|
{
|
||||||
|
if (dig1 != -1)
|
||||||
|
set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1);
|
||||||
|
if (dig2 != -1)
|
||||||
|
set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2);
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
|
static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
|
@ -1444,25 +1467,8 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
|
||||||
change = codec->spdif_ctls != val;
|
change = codec->spdif_ctls != val;
|
||||||
codec->spdif_ctls = val;
|
codec->spdif_ctls = val;
|
||||||
|
|
||||||
if (change) {
|
if (change)
|
||||||
hda_nid_t *d;
|
set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
|
||||||
snd_hda_codec_write_cache(codec, nid, 0,
|
|
||||||
AC_VERB_SET_DIGI_CONVERT_1,
|
|
||||||
val & 0xff);
|
|
||||||
snd_hda_codec_write_cache(codec, nid, 0,
|
|
||||||
AC_VERB_SET_DIGI_CONVERT_2,
|
|
||||||
val >> 8);
|
|
||||||
|
|
||||||
if (codec->slave_dig_outs)
|
|
||||||
for (d = codec->slave_dig_outs; *d; d++) {
|
|
||||||
snd_hda_codec_write_cache(codec, *d, 0,
|
|
||||||
AC_VERB_SET_DIGI_CONVERT_1,
|
|
||||||
val & 0xff);
|
|
||||||
snd_hda_codec_write_cache(codec, *d, 0,
|
|
||||||
AC_VERB_SET_DIGI_CONVERT_2,
|
|
||||||
val >> 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&codec->spdif_mutex);
|
mutex_unlock(&codec->spdif_mutex);
|
||||||
return change;
|
return change;
|
||||||
|
@ -1493,17 +1499,8 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
|
||||||
val |= AC_DIG1_ENABLE;
|
val |= AC_DIG1_ENABLE;
|
||||||
change = codec->spdif_ctls != val;
|
change = codec->spdif_ctls != val;
|
||||||
if (change) {
|
if (change) {
|
||||||
hda_nid_t *d;
|
|
||||||
codec->spdif_ctls = val;
|
codec->spdif_ctls = val;
|
||||||
snd_hda_codec_write_cache(codec, nid, 0,
|
set_dig_out_convert(codec, nid, val & 0xff, -1);
|
||||||
AC_VERB_SET_DIGI_CONVERT_1,
|
|
||||||
val & 0xff);
|
|
||||||
|
|
||||||
if (codec->slave_dig_outs)
|
|
||||||
for (d = codec->slave_dig_outs; *d; d++)
|
|
||||||
snd_hda_codec_write_cache(codec, *d, 0,
|
|
||||||
AC_VERB_SET_DIGI_CONVERT_1,
|
|
||||||
val & 0xff);
|
|
||||||
/* unmute amp switch (if any) */
|
/* unmute amp switch (if any) */
|
||||||
if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
|
if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
|
||||||
(val & AC_DIG1_ENABLE))
|
(val & AC_DIG1_ENABLE))
|
||||||
|
@ -2598,32 +2595,32 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
|
||||||
static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
|
static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
|
||||||
unsigned int stream_tag, unsigned int format)
|
unsigned int stream_tag, unsigned int format)
|
||||||
{
|
{
|
||||||
hda_nid_t *d;
|
|
||||||
|
|
||||||
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
|
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
|
||||||
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
|
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
|
||||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
|
set_dig_out_convert(codec, nid,
|
||||||
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
|
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
|
||||||
|
-1);
|
||||||
if (codec->slave_dig_outs)
|
|
||||||
for (d = codec->slave_dig_outs; *d; d++)
|
|
||||||
snd_hda_codec_write(codec, *d, 0,
|
|
||||||
AC_VERB_SET_DIGI_CONVERT_1,
|
|
||||||
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
|
|
||||||
}
|
|
||||||
snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
|
snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
|
||||||
/* turn on again (if needed) */
|
if (codec->slave_dig_outs) {
|
||||||
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
|
hda_nid_t *d;
|
||||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
|
|
||||||
codec->spdif_ctls & 0xff);
|
|
||||||
|
|
||||||
if (codec->slave_dig_outs)
|
|
||||||
for (d = codec->slave_dig_outs; *d; d++)
|
for (d = codec->slave_dig_outs; *d; d++)
|
||||||
snd_hda_codec_write(codec, *d, 0,
|
snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
|
||||||
AC_VERB_SET_DIGI_CONVERT_1,
|
format);
|
||||||
codec->spdif_ctls & 0xff);
|
}
|
||||||
|
/* turn on again (if needed) */
|
||||||
|
if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
|
||||||
|
set_dig_out_convert(codec, nid,
|
||||||
|
codec->spdif_ctls & 0xff, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
snd_hda_codec_cleanup_stream(codec, nid);
|
||||||
|
if (codec->slave_dig_outs) {
|
||||||
|
hda_nid_t *d;
|
||||||
|
for (d = codec->slave_dig_outs; *d; d++)
|
||||||
|
snd_hda_codec_cleanup_stream(codec, *d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2635,7 +2632,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec,
|
||||||
mutex_lock(&codec->spdif_mutex);
|
mutex_lock(&codec->spdif_mutex);
|
||||||
if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
|
if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
|
||||||
/* already opened as analog dup; reset it once */
|
/* already opened as analog dup; reset it once */
|
||||||
snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
|
cleanup_dig_out_stream(codec, mout->dig_out_nid);
|
||||||
mout->dig_out_used = HDA_DIG_EXCLUSIVE;
|
mout->dig_out_used = HDA_DIG_EXCLUSIVE;
|
||||||
mutex_unlock(&codec->spdif_mutex);
|
mutex_unlock(&codec->spdif_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2647,12 +2644,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
|
||||||
unsigned int format,
|
unsigned int format,
|
||||||
struct snd_pcm_substream *substream)
|
struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
hda_nid_t *nid;
|
|
||||||
mutex_lock(&codec->spdif_mutex);
|
mutex_lock(&codec->spdif_mutex);
|
||||||
setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format);
|
setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format);
|
||||||
if (codec->slave_dig_outs)
|
|
||||||
for (nid = codec->slave_dig_outs; *nid; nid++)
|
|
||||||
setup_dig_out_stream(codec, *nid, stream_tag, format);
|
|
||||||
mutex_unlock(&codec->spdif_mutex);
|
mutex_unlock(&codec->spdif_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2719,7 +2712,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
|
||||||
struct snd_pcm_substream *substream)
|
struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
hda_nid_t *nids = mout->dac_nids;
|
hda_nid_t *nids = mout->dac_nids;
|
||||||
hda_nid_t *d;
|
|
||||||
int chs = substream->runtime->channels;
|
int chs = substream->runtime->channels;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -2733,16 +2725,9 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
|
||||||
mout->dig_out_used = HDA_DIG_ANALOG_DUP;
|
mout->dig_out_used = HDA_DIG_ANALOG_DUP;
|
||||||
setup_dig_out_stream(codec, mout->dig_out_nid,
|
setup_dig_out_stream(codec, mout->dig_out_nid,
|
||||||
stream_tag, format);
|
stream_tag, format);
|
||||||
if (codec->slave_dig_outs)
|
|
||||||
for (d = codec->slave_dig_outs; *d; d++)
|
|
||||||
setup_dig_out_stream(codec, *d,
|
|
||||||
stream_tag, format);
|
|
||||||
} else {
|
} else {
|
||||||
mout->dig_out_used = 0;
|
mout->dig_out_used = 0;
|
||||||
snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
|
cleanup_dig_out_stream(codec, mout->dig_out_nid);
|
||||||
if (codec->slave_dig_outs)
|
|
||||||
for (d = codec->slave_dig_outs; *d; d++)
|
|
||||||
snd_hda_codec_cleanup_stream(codec, *d);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&codec->spdif_mutex);
|
mutex_unlock(&codec->spdif_mutex);
|
||||||
|
@ -2793,7 +2778,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
|
||||||
mout->extra_out_nid[i]);
|
mout->extra_out_nid[i]);
|
||||||
mutex_lock(&codec->spdif_mutex);
|
mutex_lock(&codec->spdif_mutex);
|
||||||
if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
|
if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
|
||||||
snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
|
cleanup_dig_out_stream(codec, mout->dig_out_nid);
|
||||||
mout->dig_out_used = 0;
|
mout->dig_out_used = 0;
|
||||||
}
|
}
|
||||||
mutex_unlock(&codec->spdif_mutex);
|
mutex_unlock(&codec->spdif_mutex);
|
||||||
|
|
Loading…
Reference in New Issue