diff options
author | Stephen Warren <swarren@nvidia.com> | 2011-06-01 11:14:18 -0600 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-06-06 12:51:59 +0200 |
commit | 74b654c957e901e7596ebc7b9f5a1bea62b20509 (patch) | |
tree | 2ae316f1b481c0ad4a84c1caff9b99ca57fe63ba | |
parent | 7c9359762797ba7a70bbaa6364aaecc16786ac83 (diff) |
ALSA: hda: Virtualize SPDIF out controls
The SPDIF output controls apply to converter widgets. A future change
will create a PCM device per pin widget, and hence a set of SPDIF output
controls per pin widget, for certain HDMI codecs. To support this, we
need the ability to virtualize the SPDIF output controls. Specifically:
* Controls can be "unassigned" from real hardware when a converter is
not used for the PCM the control was created for.
* Control puts only write to hardware when they are assigned.
* Controls can be "assigned" to real hardware when a converter is picked
to support output for a particular PCM.
* When a converter is assigned, the hardware is updated to the cached
configuration.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/hda_codec.c | 62 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 4 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 4 | ||||
-rw-r--r-- | sound/pci/hda/patch_ca0110.c | 3 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 3 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 4 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 3 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 4 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 1 |
12 files changed, 69 insertions, 23 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e17e2998d33..c63a06703de 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -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 */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1d21c0624e0..96c35cab57b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -954,6 +954,8 @@ struct hda_spdif_out { }; struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, hda_nid_t nid); +void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx); +void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid); /* * Mixer diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 08ec073444e..8b88c92826a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -212,7 +212,9 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, /* * SPDIF I/O */ -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 snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); /* diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index d694e9d4921..0f7b8951440 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -213,7 +213,9 @@ static int ad198x_build_controls(struct hda_codec *codec) return err; } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 61b92634b16..6b406840846 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -240,7 +240,8 @@ static int ca0110_build_controls(struct hda_codec *codec) } if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out); + err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, + spec->dig_out); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 26a1521045b..c7b5ca28fa7 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -821,7 +821,8 @@ static int build_digital_output(struct hda_codec *codec) if (!spec->multiout.dig_out_nid) return 0; - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index ab3308daa96..9eaf99b01ae 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -327,7 +327,9 @@ static int cmi9880_build_controls(struct hda_codec *codec) return err; } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 3e6b9a8539c..217ca9e1342 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -510,6 +510,7 @@ static int conexant_build_controls(struct hda_codec *codec) } if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid, spec->multiout.dig_out_nid); if (err < 0) return err; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 86b35a071a8..13ee4449718 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1095,7 +1095,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) int i; for (i = 0; i < codec->num_pcms; i++) { - err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); + err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i], + spec->cvt[i]); if (err < 0) return err; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7a4e10002f5..5c8a4ea75cd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3217,6 +3217,7 @@ static int alc_build_controls(struct hda_codec *codec) } if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid, spec->multiout.dig_out_nid); if (err < 0) return err; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7f81cc2274f..7407095cbc7 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1112,7 +1112,9 @@ static int stac92xx_build_controls(struct hda_codec *codec) } if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid); if (err < 0) return err; err = snd_hda_create_spdif_share_sw(codec, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 8304c748dfb..89a0f2a3d26 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1497,6 +1497,7 @@ static int via_build_controls(struct hda_codec *codec) if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid, spec->multiout.dig_out_nid); if (err < 0) return err; |