Commit de51ca12 authored by Matthew Ranostay's avatar Matthew Ranostay Committed by Jaroslav Kysela

ALSA: hda: slave digital out support

Added support for playing a stream on multiple digital outs. This is done
by defining codec->slave_dig_outs as array of hda_nid_t with a null-terminated entry to set the
slave SPDIF outs, in which the slave outs have cloned settings of the master out (e.g. dig_out_nid).
Signed-off-by: default avatarMatthew Ranostay <mranostay@embeddedalley.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
parent de30d36b
...@@ -1454,12 +1454,22 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, ...@@ -1454,12 +1454,22 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
codec->spdif_ctls = val; codec->spdif_ctls = val;
if (change) { if (change) {
hda_nid_t *d;
snd_hda_codec_write_cache(codec, nid, 0, snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_1, AC_VERB_SET_DIGI_CONVERT_1,
val & 0xff); val & 0xff);
snd_hda_codec_write_cache(codec, nid, 0, snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_2, AC_VERB_SET_DIGI_CONVERT_2,
val >> 8); val >> 8);
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);
...@@ -1491,10 +1501,16 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, ...@@ -1491,10 +1501,16 @@ 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, snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_1, AC_VERB_SET_DIGI_CONVERT_1,
val & 0xff); val & 0xff);
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))
...@@ -1643,9 +1659,14 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, ...@@ -1643,9 +1659,14 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol,
mutex_lock(&codec->spdif_mutex); mutex_lock(&codec->spdif_mutex);
change = codec->spdif_in_enable != val; change = codec->spdif_in_enable != val;
if (change) { if (change) {
hda_nid_t *d;
codec->spdif_in_enable = val; codec->spdif_in_enable = val;
snd_hda_codec_write_cache(codec, nid, 0, snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_1, val); AC_VERB_SET_DIGI_CONVERT_1, val);
for (d = codec->slave_dig_outs; *d; d++)
snd_hda_codec_write_cache(codec, *d, 0,
AC_VERB_SET_DIGI_CONVERT_1, val);
} }
mutex_unlock(&codec->spdif_mutex); mutex_unlock(&codec->spdif_mutex);
return change; return change;
...@@ -2589,15 +2610,30 @@ int snd_hda_input_mux_put(struct hda_codec *codec, ...@@ -2589,15 +2610,30 @@ 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, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
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) */ /* turn on again (if needed) */
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, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
codec->spdif_ctls & 0xff); codec->spdif_ctls & 0xff);
for (d = codec->slave_dig_outs; *d; d++)
snd_hda_codec_write(codec, *d, 0,
AC_VERB_SET_DIGI_CONVERT_1,
codec->spdif_ctls & 0xff);
}
} }
/* /*
...@@ -2621,8 +2657,12 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, ...@@ -2621,8 +2657,12 @@ 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;
} }
...@@ -2689,6 +2729,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, ...@@ -2689,6 +2729,7 @@ 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;
...@@ -2702,9 +2743,16 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, ...@@ -2702,9 +2743,16 @@ 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); snd_hda_codec_cleanup_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);
......
...@@ -725,6 +725,7 @@ struct hda_codec { ...@@ -725,6 +725,7 @@ struct hda_codec {
unsigned int spdif_status; /* IEC958 status bits */ unsigned int spdif_status; /* IEC958 status bits */
unsigned short spdif_ctls; /* SPDIF control bits */ unsigned short spdif_ctls; /* SPDIF control bits */
unsigned int spdif_in_enable; /* SPDIF input enable? */ unsigned int spdif_in_enable; /* SPDIF input enable? */
hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
struct snd_hwdep *hwdep; /* assigned hwdep device */ struct snd_hwdep *hwdep; /* assigned hwdep device */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment