aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2011-06-01 13:14:18 -0400
committerTakashi Iwai <tiwai@suse.de>2011-06-06 06:51:59 -0400
commit74b654c957e901e7596ebc7b9f5a1bea62b20509 (patch)
tree2ae316f1b481c0ad4a84c1caff9b99ca57fe63ba /sound
parent7c9359762797ba7a70bbaa6364aaecc16786ac83 (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>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/hda_codec.c62
-rw-r--r--sound/pci/hda/hda_codec.h2
-rw-r--r--sound/pci/hda/hda_local.h4
-rw-r--r--sound/pci/hda/patch_analog.c4
-rw-r--r--sound/pci/hda/patch_ca0110.c3
-rw-r--r--sound/pci/hda/patch_cirrus.c3
-rw-r--r--sound/pci/hda/patch_cmedia.c4
-rw-r--r--sound/pci/hda/patch_conexant.c1
-rw-r--r--sound/pci/hda/patch_hdmi.c3
-rw-r--r--sound/pci/hda/patch_realtek.c1
-rw-r--r--sound/pci/hda/patch_sigmatel.c4
-rw-r--r--sound/pci/hda/patch_via.c1
12 files changed, 69 insertions, 23 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e17e2998d333..c63a06703de3 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,
2663 val |= spdif->ctls & 1; 2663 val |= spdif->ctls & 1;
2664 change = spdif->ctls != val; 2664 change = spdif->ctls != val;
2665 spdif->ctls = val; 2665 spdif->ctls = val;
2666 2666 if (change && nid != (u16)-1)
2667 if (change)
2668 set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff); 2667 set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
2669
2670 mutex_unlock(&codec->spdif_mutex); 2668 mutex_unlock(&codec->spdif_mutex);
2671 return change; 2669 return change;
2672} 2670}
@@ -2684,6 +2682,17 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
2684 return 0; 2682 return 0;
2685} 2683}
2686 2684
2685static inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid,
2686 int dig1, int dig2)
2687{
2688 set_dig_out_convert(codec, nid, dig1, dig2);
2689 /* unmute amp switch (if any) */
2690 if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
2691 (dig1 & AC_DIG1_ENABLE))
2692 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2693 HDA_AMP_MUTE, 0);
2694}
2695
2687static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, 2696static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
2688 struct snd_ctl_elem_value *ucontrol) 2697 struct snd_ctl_elem_value *ucontrol)
2689{ 2698{
@@ -2699,15 +2708,9 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
2699 if (ucontrol->value.integer.value[0]) 2708 if (ucontrol->value.integer.value[0])
2700 val |= AC_DIG1_ENABLE; 2709 val |= AC_DIG1_ENABLE;
2701 change = spdif->ctls != val; 2710 change = spdif->ctls != val;
2702 if (change) { 2711 spdif->ctls = val;
2703 spdif->ctls = val; 2712 if (change && nid != (u16)-1)
2704 set_dig_out_convert(codec, nid, val & 0xff, -1); 2713 set_spdif_ctls(codec, nid, val & 0xff, -1);
2705 /* unmute amp switch (if any) */
2706 if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
2707 (val & AC_DIG1_ENABLE))
2708 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2709 HDA_AMP_MUTE, 0);
2710 }
2711 mutex_unlock(&codec->spdif_mutex); 2714 mutex_unlock(&codec->spdif_mutex);
2712 return change; 2715 return change;
2713} 2716}
@@ -2754,7 +2757,9 @@ static struct snd_kcontrol_new dig_mixes[] = {
2754 * 2757 *
2755 * Returns 0 if successful, or a negative error code. 2758 * Returns 0 if successful, or a negative error code.
2756 */ 2759 */
2757int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) 2760int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
2761 hda_nid_t associated_nid,
2762 hda_nid_t cvt_nid)
2758{ 2763{
2759 int err; 2764 int err;
2760 struct snd_kcontrol *kctl; 2765 struct snd_kcontrol *kctl;
@@ -2774,12 +2779,12 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
2774 return -ENOMEM; 2779 return -ENOMEM;
2775 kctl->id.index = idx; 2780 kctl->id.index = idx;
2776 kctl->private_value = codec->spdif_out.used - 1; 2781 kctl->private_value = codec->spdif_out.used - 1;
2777 err = snd_hda_ctl_add(codec, nid, kctl); 2782 err = snd_hda_ctl_add(codec, associated_nid, kctl);
2778 if (err < 0) 2783 if (err < 0)
2779 return err; 2784 return err;
2780 } 2785 }
2781 spdif->nid = nid; 2786 spdif->nid = cvt_nid;
2782 spdif->ctls = snd_hda_codec_read(codec, nid, 0, 2787 spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0,
2783 AC_VERB_GET_DIGI_CONVERT_1, 0); 2788 AC_VERB_GET_DIGI_CONVERT_1, 0);
2784 spdif->status = convert_to_spdif_status(spdif->ctls); 2789 spdif->status = convert_to_spdif_status(spdif->ctls);
2785 return 0; 2790 return 0;
@@ -2800,6 +2805,31 @@ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
2800} 2805}
2801EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid); 2806EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
2802 2807
2808void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
2809{
2810 struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
2811
2812 mutex_lock(&codec->spdif_mutex);
2813 spdif->nid = (u16)-1;
2814 mutex_unlock(&codec->spdif_mutex);
2815}
2816EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
2817
2818void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
2819{
2820 struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
2821 unsigned short val;
2822
2823 mutex_lock(&codec->spdif_mutex);
2824 if (spdif->nid != nid) {
2825 spdif->nid = nid;
2826 val = spdif->ctls;
2827 set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff);
2828 }
2829 mutex_unlock(&codec->spdif_mutex);
2830}
2831EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign);
2832
2803/* 2833/*
2804 * SPDIF sharing with analog output 2834 * SPDIF sharing with analog output
2805 */ 2835 */
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 1d21c0624e03..96c35cab57bf 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -954,6 +954,8 @@ struct hda_spdif_out {
954}; 954};
955struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, 955struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
956 hda_nid_t nid); 956 hda_nid_t nid);
957void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx);
958void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid);
957 959
958/* 960/*
959 * Mixer 961 * Mixer
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 08ec073444e2..8b88c92826a1 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,
212/* 212/*
213 * SPDIF I/O 213 * SPDIF I/O
214 */ 214 */
215int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); 215int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
216 hda_nid_t associated_nid,
217 hda_nid_t cvt_nid);
216int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); 218int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
217 219
218/* 220/*
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index d694e9d4921d..0f7b8951440f 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)
213 return err; 213 return err;
214 } 214 }
215 if (spec->multiout.dig_out_nid) { 215 if (spec->multiout.dig_out_nid) {
216 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 216 err = snd_hda_create_spdif_out_ctls(codec,
217 spec->multiout.dig_out_nid,
218 spec->multiout.dig_out_nid);
217 if (err < 0) 219 if (err < 0)
218 return err; 220 return err;
219 err = snd_hda_create_spdif_share_sw(codec, 221 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 61b92634b161..6b406840846e 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)
240 } 240 }
241 241
242 if (spec->dig_out) { 242 if (spec->dig_out) {
243 err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out); 243 err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
244 spec->dig_out);
244 if (err < 0) 245 if (err < 0)
245 return err; 246 return err;
246 err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); 247 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 26a1521045bb..c7b5ca28fa77 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)
821 if (!spec->multiout.dig_out_nid) 821 if (!spec->multiout.dig_out_nid)
822 return 0; 822 return 0;
823 823
824 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 824 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid,
825 spec->multiout.dig_out_nid);
825 if (err < 0) 826 if (err < 0)
826 return err; 827 return err;
827 err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); 828 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 ab3308daa960..9eaf99b01aec 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)
327 return err; 327 return err;
328 } 328 }
329 if (spec->multiout.dig_out_nid) { 329 if (spec->multiout.dig_out_nid) {
330 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 330 err = snd_hda_create_spdif_out_ctls(codec,
331 spec->multiout.dig_out_nid,
332 spec->multiout.dig_out_nid);
331 if (err < 0) 333 if (err < 0)
332 return err; 334 return err;
333 err = snd_hda_create_spdif_share_sw(codec, 335 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 3e6b9a8539c2..217ca9e13425 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)
510 } 510 }
511 if (spec->multiout.dig_out_nid) { 511 if (spec->multiout.dig_out_nid) {
512 err = snd_hda_create_spdif_out_ctls(codec, 512 err = snd_hda_create_spdif_out_ctls(codec,
513 spec->multiout.dig_out_nid,
513 spec->multiout.dig_out_nid); 514 spec->multiout.dig_out_nid);
514 if (err < 0) 515 if (err < 0)
515 return err; 516 return err;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 86b35a071a83..13ee4449718f 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)
1095 int i; 1095 int i;
1096 1096
1097 for (i = 0; i < codec->num_pcms; i++) { 1097 for (i = 0; i < codec->num_pcms; i++) {
1098 err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); 1098 err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i],
1099 spec->cvt[i]);
1099 if (err < 0) 1100 if (err < 0)
1100 return err; 1101 return err;
1101 } 1102 }
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7a4e10002f56..5c8a4ea75cd7 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)
3217 } 3217 }
3218 if (spec->multiout.dig_out_nid) { 3218 if (spec->multiout.dig_out_nid) {
3219 err = snd_hda_create_spdif_out_ctls(codec, 3219 err = snd_hda_create_spdif_out_ctls(codec,
3220 spec->multiout.dig_out_nid,
3220 spec->multiout.dig_out_nid); 3221 spec->multiout.dig_out_nid);
3221 if (err < 0) 3222 if (err < 0)
3222 return err; 3223 return err;
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 7f81cc2274f3..7407095cbc78 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)
1112 } 1112 }
1113 1113
1114 if (spec->multiout.dig_out_nid) { 1114 if (spec->multiout.dig_out_nid) {
1115 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 1115 err = snd_hda_create_spdif_out_ctls(codec,
1116 spec->multiout.dig_out_nid,
1117 spec->multiout.dig_out_nid);
1116 if (err < 0) 1118 if (err < 0)
1117 return err; 1119 return err;
1118 err = snd_hda_create_spdif_share_sw(codec, 1120 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 8304c748dfb7..89a0f2a3d269 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)
1497 1497
1498 if (spec->multiout.dig_out_nid) { 1498 if (spec->multiout.dig_out_nid) {
1499 err = snd_hda_create_spdif_out_ctls(codec, 1499 err = snd_hda_create_spdif_out_ctls(codec,
1500 spec->multiout.dig_out_nid,
1500 spec->multiout.dig_out_nid); 1501 spec->multiout.dig_out_nid);
1501 if (err < 0) 1502 if (err < 0)
1502 return err; 1503 return err;