|
@@ -2663,10 +2663,8 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
|
|
|
val |= spdif->ctls & 1;
|
|
|
change = spdif->ctls != val;
|
|
|
spdif->ctls = val;
|
|
|
-
|
|
|
- if (change)
|
|
|
+ if (change && nid != (u16)-1)
|
|
|
set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
|
|
|
-
|
|
|
mutex_unlock(&codec->spdif_mutex);
|
|
|
return change;
|
|
|
}
|
|
@@ -2684,6 +2682,17 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid,
|
|
|
+ int dig1, int dig2)
|
|
|
+{
|
|
|
+ set_dig_out_convert(codec, nid, dig1, dig2);
|
|
|
+ /* unmute amp switch (if any) */
|
|
|
+ if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
|
|
|
+ (dig1 & AC_DIG1_ENABLE))
|
|
|
+ snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
|
|
+ HDA_AMP_MUTE, 0);
|
|
|
+}
|
|
|
+
|
|
|
static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
@@ -2699,15 +2708,9 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
|
|
|
if (ucontrol->value.integer.value[0])
|
|
|
val |= AC_DIG1_ENABLE;
|
|
|
change = spdif->ctls != val;
|
|
|
- if (change) {
|
|
|
- spdif->ctls = val;
|
|
|
- set_dig_out_convert(codec, nid, val & 0xff, -1);
|
|
|
- /* unmute amp switch (if any) */
|
|
|
- if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
|
|
|
- (val & AC_DIG1_ENABLE))
|
|
|
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
|
|
|
- HDA_AMP_MUTE, 0);
|
|
|
- }
|
|
|
+ spdif->ctls = val;
|
|
|
+ if (change && nid != (u16)-1)
|
|
|
+ set_spdif_ctls(codec, nid, val & 0xff, -1);
|
|
|
mutex_unlock(&codec->spdif_mutex);
|
|
|
return change;
|
|
|
}
|
|
@@ -2754,7 +2757,9 @@ static struct snd_kcontrol_new dig_mixes[] = {
|
|
|
*
|
|
|
* Returns 0 if successful, or a negative error code.
|
|
|
*/
|
|
|
-int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
|
|
|
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
|
|
|
+ hda_nid_t associated_nid,
|
|
|
+ hda_nid_t cvt_nid)
|
|
|
{
|
|
|
int err;
|
|
|
struct snd_kcontrol *kctl;
|
|
@@ -2774,12 +2779,12 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
|
|
|
return -ENOMEM;
|
|
|
kctl->id.index = idx;
|
|
|
kctl->private_value = codec->spdif_out.used - 1;
|
|
|
- err = snd_hda_ctl_add(codec, nid, kctl);
|
|
|
+ err = snd_hda_ctl_add(codec, associated_nid, kctl);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
}
|
|
|
- spdif->nid = nid;
|
|
|
- spdif->ctls = snd_hda_codec_read(codec, nid, 0,
|
|
|
+ spdif->nid = cvt_nid;
|
|
|
+ spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0,
|
|
|
AC_VERB_GET_DIGI_CONVERT_1, 0);
|
|
|
spdif->status = convert_to_spdif_status(spdif->ctls);
|
|
|
return 0;
|
|
@@ -2800,6 +2805,31 @@ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
|
|
|
}
|
|
|
EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
|
|
|
|
|
|
+void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
|
|
|
+{
|
|
|
+ struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
|
|
|
+
|
|
|
+ mutex_lock(&codec->spdif_mutex);
|
|
|
+ spdif->nid = (u16)-1;
|
|
|
+ mutex_unlock(&codec->spdif_mutex);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
|
|
|
+
|
|
|
+void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
|
|
|
+{
|
|
|
+ struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
|
|
|
+ unsigned short val;
|
|
|
+
|
|
|
+ mutex_lock(&codec->spdif_mutex);
|
|
|
+ if (spdif->nid != nid) {
|
|
|
+ spdif->nid = nid;
|
|
|
+ val = spdif->ctls;
|
|
|
+ set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff);
|
|
|
+ }
|
|
|
+ mutex_unlock(&codec->spdif_mutex);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign);
|
|
|
+
|
|
|
/*
|
|
|
* SPDIF sharing with analog output
|
|
|
*/
|