diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-01-10 10:53:55 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:29:54 -0500 |
commit | 2134ea4f37d36addbe86d4901f6c67a22a5db006 (patch) | |
tree | 804d187d5c46d71246db2d8919a59e2e7feef956 /sound/pci/hda | |
parent | 3b0a5f22d4649433a5842ffc7313803292e95718 (diff) |
[ALSA] hda-codec - Add virtual master controls
Add master controls using vmaster to codecs that have no real hardware
master volume registers.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 60 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 7 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 69 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 111 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 48 |
5 files changed, 276 insertions, 19 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a2b40dc372c9..caacc58c0813 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1012,6 +1012,66 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
1012 | return 0; | 1012 | return 0; |
1013 | } | 1013 | } |
1014 | 1014 | ||
1015 | /* | ||
1016 | * set (static) TLV for virtual master volume; recalculated as max 0dB | ||
1017 | */ | ||
1018 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
1019 | unsigned int *tlv) | ||
1020 | { | ||
1021 | u32 caps; | ||
1022 | int nums, step; | ||
1023 | |||
1024 | caps = query_amp_caps(codec, nid, dir); | ||
1025 | nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
1026 | step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; | ||
1027 | step = (step + 1) * 25; | ||
1028 | tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; | ||
1029 | tlv[1] = 2 * sizeof(unsigned int); | ||
1030 | tlv[2] = -nums * step; | ||
1031 | tlv[3] = step; | ||
1032 | } | ||
1033 | |||
1034 | /* find a mixer control element with the given name */ | ||
1035 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | ||
1036 | const char *name) | ||
1037 | { | ||
1038 | struct snd_ctl_elem_id id; | ||
1039 | memset(&id, 0, sizeof(id)); | ||
1040 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1041 | strcpy(id.name, name); | ||
1042 | return snd_ctl_find_id(codec->bus->card, &id); | ||
1043 | } | ||
1044 | |||
1045 | /* create a virtual master control and add slaves */ | ||
1046 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||
1047 | unsigned int *tlv, const char **slaves) | ||
1048 | { | ||
1049 | struct snd_kcontrol *kctl; | ||
1050 | const char **s; | ||
1051 | int err; | ||
1052 | |||
1053 | kctl = snd_ctl_make_virtual_master(name, tlv); | ||
1054 | if (!kctl) | ||
1055 | return -ENOMEM; | ||
1056 | err = snd_ctl_add(codec->bus->card, kctl); | ||
1057 | if (err < 0) | ||
1058 | return err; | ||
1059 | |||
1060 | for (s = slaves; *s; s++) { | ||
1061 | struct snd_kcontrol *sctl; | ||
1062 | |||
1063 | sctl = snd_hda_find_mixer_ctl(codec, *s); | ||
1064 | if (!sctl) { | ||
1065 | snd_printdd("Cannot find slave %s, skipped\n", *s); | ||
1066 | continue; | ||
1067 | } | ||
1068 | err = snd_ctl_add_slave(kctl, sctl); | ||
1069 | if (err < 0) | ||
1070 | return err; | ||
1071 | } | ||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1015 | /* switch */ | 1075 | /* switch */ |
1016 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, | 1076 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, |
1017 | struct snd_ctl_elem_info *uinfo) | 1077 | struct snd_ctl_elem_info *uinfo) |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index e09f41bd6b2a..ddc61a1d1153 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -90,6 +90,13 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | |||
90 | void snd_hda_codec_resume_amp(struct hda_codec *codec); | 90 | void snd_hda_codec_resume_amp(struct hda_codec *codec); |
91 | #endif | 91 | #endif |
92 | 92 | ||
93 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
94 | unsigned int *tlv); | ||
95 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | ||
96 | const char *name); | ||
97 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||
98 | unsigned int *tlv, const char **slaves); | ||
99 | |||
93 | /* amp value bits */ | 100 | /* amp value bits */ |
94 | #define HDA_AMP_MUTE 0x80 | 101 | #define HDA_AMP_MUTE 0x80 |
95 | #define HDA_AMP_UNMUTE 0x00 | 102 | #define HDA_AMP_UNMUTE 0x00 |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 6664a0688ef5..b0755407be9d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -78,6 +78,11 @@ struct ad198x_spec { | |||
78 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 78 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
79 | struct hda_loopback_check loopback; | 79 | struct hda_loopback_check loopback; |
80 | #endif | 80 | #endif |
81 | /* for virtual master */ | ||
82 | hda_nid_t vmaster_nid; | ||
83 | u32 vmaster_tlv[4]; | ||
84 | const char **slave_vols; | ||
85 | const char **slave_sws; | ||
81 | }; | 86 | }; |
82 | 87 | ||
83 | /* | 88 | /* |
@@ -125,6 +130,28 @@ static int ad198x_init(struct hda_codec *codec) | |||
125 | return 0; | 130 | return 0; |
126 | } | 131 | } |
127 | 132 | ||
133 | static const char *ad_slave_vols[] = { | ||
134 | "Front Playback Volume", | ||
135 | "Surround Playback Volume", | ||
136 | "Center Playback Volume", | ||
137 | "LFE Playback Volume", | ||
138 | "Side Playback Volume", | ||
139 | "Headphone Playback Volume", | ||
140 | "Mono Playback Volume", | ||
141 | NULL | ||
142 | }; | ||
143 | |||
144 | static const char *ad_slave_sws[] = { | ||
145 | "Front Playback Switch", | ||
146 | "Surround Playback Switch", | ||
147 | "Center Playback Switch", | ||
148 | "LFE Playback Switch", | ||
149 | "Side Playback Switch", | ||
150 | "Headphone Playback Switch", | ||
151 | "Mono Playback Switch", | ||
152 | NULL | ||
153 | }; | ||
154 | |||
128 | static int ad198x_build_controls(struct hda_codec *codec) | 155 | static int ad198x_build_controls(struct hda_codec *codec) |
129 | { | 156 | { |
130 | struct ad198x_spec *spec = codec->spec; | 157 | struct ad198x_spec *spec = codec->spec; |
@@ -146,6 +173,27 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
146 | if (err < 0) | 173 | if (err < 0) |
147 | return err; | 174 | return err; |
148 | } | 175 | } |
176 | |||
177 | /* if we have no master control, let's create it */ | ||
178 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
179 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
180 | HDA_OUTPUT, spec->vmaster_tlv); | ||
181 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
182 | spec->vmaster_tlv, | ||
183 | (spec->slave_vols ? | ||
184 | spec->slave_vols : ad_slave_vols)); | ||
185 | if (err < 0) | ||
186 | return err; | ||
187 | } | ||
188 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
189 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
190 | NULL, | ||
191 | (spec->slave_sws ? | ||
192 | spec->slave_sws : ad_slave_sws)); | ||
193 | if (err < 0) | ||
194 | return err; | ||
195 | } | ||
196 | |||
149 | return 0; | 197 | return 0; |
150 | } | 198 | } |
151 | 199 | ||
@@ -899,6 +947,7 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
899 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 947 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
900 | spec->loopback.amplist = ad1986a_loopbacks; | 948 | spec->loopback.amplist = ad1986a_loopbacks; |
901 | #endif | 949 | #endif |
950 | spec->vmaster_nid = 0x1b; | ||
902 | 951 | ||
903 | codec->patch_ops = ad198x_patch_ops; | 952 | codec->patch_ops = ad198x_patch_ops; |
904 | 953 | ||
@@ -1141,6 +1190,7 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1141 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1190 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1142 | spec->loopback.amplist = ad1983_loopbacks; | 1191 | spec->loopback.amplist = ad1983_loopbacks; |
1143 | #endif | 1192 | #endif |
1193 | spec->vmaster_nid = 0x05; | ||
1144 | 1194 | ||
1145 | codec->patch_ops = ad198x_patch_ops; | 1195 | codec->patch_ops = ad198x_patch_ops; |
1146 | 1196 | ||
@@ -1537,6 +1587,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1537 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1587 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1538 | spec->loopback.amplist = ad1981_loopbacks; | 1588 | spec->loopback.amplist = ad1981_loopbacks; |
1539 | #endif | 1589 | #endif |
1590 | spec->vmaster_nid = 0x05; | ||
1540 | 1591 | ||
1541 | codec->patch_ops = ad198x_patch_ops; | 1592 | codec->patch_ops = ad198x_patch_ops; |
1542 | 1593 | ||
@@ -2850,6 +2901,7 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2850 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2901 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2851 | spec->loopback.amplist = ad1988_loopbacks; | 2902 | spec->loopback.amplist = ad1988_loopbacks; |
2852 | #endif | 2903 | #endif |
2904 | spec->vmaster_nid = 0x04; | ||
2853 | 2905 | ||
2854 | return 0; | 2906 | return 0; |
2855 | } | 2907 | } |
@@ -3016,6 +3068,19 @@ static struct hda_amp_list ad1884_loopbacks[] = { | |||
3016 | }; | 3068 | }; |
3017 | #endif | 3069 | #endif |
3018 | 3070 | ||
3071 | static const char *ad1884_slave_vols[] = { | ||
3072 | "PCM Playback Volume", | ||
3073 | "Mic Playback Volume", | ||
3074 | "Mono Playback Volume", | ||
3075 | "Front Mic Playback Volume", | ||
3076 | "Mic Playback Volume", | ||
3077 | "CD Playback Volume", | ||
3078 | "Internal Mic Playback Volume", | ||
3079 | "Docking Mic Playback Volume" | ||
3080 | "Beep Playback Volume", | ||
3081 | NULL | ||
3082 | }; | ||
3083 | |||
3019 | static int patch_ad1884(struct hda_codec *codec) | 3084 | static int patch_ad1884(struct hda_codec *codec) |
3020 | { | 3085 | { |
3021 | struct ad198x_spec *spec; | 3086 | struct ad198x_spec *spec; |
@@ -3043,6 +3108,9 @@ static int patch_ad1884(struct hda_codec *codec) | |||
3043 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3108 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3044 | spec->loopback.amplist = ad1884_loopbacks; | 3109 | spec->loopback.amplist = ad1884_loopbacks; |
3045 | #endif | 3110 | #endif |
3111 | spec->vmaster_nid = 0x04; | ||
3112 | /* we need to cover all playback volumes */ | ||
3113 | spec->slave_vols = ad1884_slave_vols; | ||
3046 | 3114 | ||
3047 | codec->patch_ops = ad198x_patch_ops; | 3115 | codec->patch_ops = ad198x_patch_ops; |
3048 | 3116 | ||
@@ -3485,6 +3553,7 @@ static int patch_ad1882(struct hda_codec *codec) | |||
3485 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3553 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3486 | spec->loopback.amplist = ad1882_loopbacks; | 3554 | spec->loopback.amplist = ad1882_loopbacks; |
3487 | #endif | 3555 | #endif |
3556 | spec->vmaster_nid = 0x04; | ||
3488 | 3557 | ||
3489 | codec->patch_ops = ad198x_patch_ops; | 3558 | codec->patch_ops = ad198x_patch_ops; |
3490 | 3559 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9184586c9721..4bc7f3daeab0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -262,6 +262,9 @@ struct alc_spec { | |||
262 | unsigned int sense_updated: 1; | 262 | unsigned int sense_updated: 1; |
263 | unsigned int jack_present: 1; | 263 | unsigned int jack_present: 1; |
264 | 264 | ||
265 | /* for virtual master */ | ||
266 | hda_nid_t vmaster_nid; | ||
267 | u32 vmaster_tlv[4]; | ||
265 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 268 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
266 | struct hda_loopback_check loopback; | 269 | struct hda_loopback_check loopback; |
267 | #endif | 270 | #endif |
@@ -1309,8 +1312,8 @@ static hda_nid_t alc880_f1734_dac_nids[1] = { | |||
1309 | static struct snd_kcontrol_new alc880_f1734_mixer[] = { | 1312 | static struct snd_kcontrol_new alc880_f1734_mixer[] = { |
1310 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1313 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1311 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), | 1314 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1312 | HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1315 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1313 | HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1316 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1314 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 1317 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
1315 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 1318 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
1316 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 1319 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
@@ -1408,10 +1411,10 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { | |||
1408 | 1411 | ||
1409 | /* Uniwill */ | 1412 | /* Uniwill */ |
1410 | static struct snd_kcontrol_new alc880_uniwill_mixer[] = { | 1413 | static struct snd_kcontrol_new alc880_uniwill_mixer[] = { |
1411 | HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1414 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1412 | HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), | 1415 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1413 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1416 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1414 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1417 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1415 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 1418 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
1416 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 1419 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
1417 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | 1420 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
@@ -1451,16 +1454,50 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { | |||
1451 | }; | 1454 | }; |
1452 | 1455 | ||
1453 | static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { | 1456 | static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { |
1454 | HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1457 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1455 | HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), | 1458 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1456 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1459 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1457 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1460 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1458 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 1461 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
1459 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 1462 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
1460 | { } /* end */ | 1463 | { } /* end */ |
1461 | }; | 1464 | }; |
1462 | 1465 | ||
1463 | /* | 1466 | /* |
1467 | * virtual master controls | ||
1468 | */ | ||
1469 | |||
1470 | /* | ||
1471 | * slave controls for virtual master | ||
1472 | */ | ||
1473 | static const char *alc_slave_vols[] = { | ||
1474 | "Front Playback Volume", | ||
1475 | "Surround Playback Volume", | ||
1476 | "Center Playback Volume", | ||
1477 | "LFE Playback Volume", | ||
1478 | "Side Playback Volume", | ||
1479 | "Headphone Playback Volume", | ||
1480 | "Speaker Playback Volume", | ||
1481 | "Mono Playback Volume", | ||
1482 | "iSpeaker Playback Volume", | ||
1483 | "Line-Out Playback Volume", | ||
1484 | NULL, | ||
1485 | }; | ||
1486 | |||
1487 | static const char *alc_slave_sws[] = { | ||
1488 | "Front Playback Switch", | ||
1489 | "Surround Playback Switch", | ||
1490 | "Center Playback Switch", | ||
1491 | "LFE Playback Switch", | ||
1492 | "Side Playback Switch", | ||
1493 | "Headphone Playback Switch", | ||
1494 | "Speaker Playback Switch", | ||
1495 | "Mono Playback Switch", | ||
1496 | "iSpeaker Playback Switch", | ||
1497 | NULL, | ||
1498 | }; | ||
1499 | |||
1500 | /* | ||
1464 | * build control elements | 1501 | * build control elements |
1465 | */ | 1502 | */ |
1466 | static int alc_build_controls(struct hda_codec *codec) | 1503 | static int alc_build_controls(struct hda_codec *codec) |
@@ -1486,6 +1523,23 @@ static int alc_build_controls(struct hda_codec *codec) | |||
1486 | if (err < 0) | 1523 | if (err < 0) |
1487 | return err; | 1524 | return err; |
1488 | } | 1525 | } |
1526 | |||
1527 | /* if we have no master control, let's create it */ | ||
1528 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
1529 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
1530 | HDA_OUTPUT, spec->vmaster_tlv); | ||
1531 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
1532 | spec->vmaster_tlv, alc_slave_vols); | ||
1533 | if (err < 0) | ||
1534 | return err; | ||
1535 | } | ||
1536 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
1537 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
1538 | NULL, alc_slave_sws); | ||
1539 | if (err < 0) | ||
1540 | return err; | ||
1541 | } | ||
1542 | |||
1489 | return 0; | 1543 | return 0; |
1490 | } | 1544 | } |
1491 | 1545 | ||
@@ -2034,8 +2088,8 @@ static struct hda_channel_mode alc880_lg_ch_modes[3] = { | |||
2034 | 2088 | ||
2035 | static struct snd_kcontrol_new alc880_lg_mixer[] = { | 2089 | static struct snd_kcontrol_new alc880_lg_mixer[] = { |
2036 | /* FIXME: it's not really "master" but front channels */ | 2090 | /* FIXME: it's not really "master" but front channels */ |
2037 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | 2091 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), |
2038 | HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT), | 2092 | HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), |
2039 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 2093 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
2040 | HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), | 2094 | HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), |
2041 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), | 2095 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), |
@@ -3592,6 +3646,8 @@ static int patch_alc880(struct hda_codec *codec) | |||
3592 | } | 3646 | } |
3593 | } | 3647 | } |
3594 | 3648 | ||
3649 | spec->vmaster_nid = 0x0c; | ||
3650 | |||
3595 | codec->patch_ops = alc_patch_ops; | 3651 | codec->patch_ops = alc_patch_ops; |
3596 | if (board_config == ALC880_AUTO) | 3652 | if (board_config == ALC880_AUTO) |
3597 | spec->init_hook = alc880_auto_init; | 3653 | spec->init_hook = alc880_auto_init; |
@@ -4969,6 +5025,8 @@ static int patch_alc260(struct hda_codec *codec) | |||
4969 | spec->stream_digital_playback = &alc260_pcm_digital_playback; | 5025 | spec->stream_digital_playback = &alc260_pcm_digital_playback; |
4970 | spec->stream_digital_capture = &alc260_pcm_digital_capture; | 5026 | spec->stream_digital_capture = &alc260_pcm_digital_capture; |
4971 | 5027 | ||
5028 | spec->vmaster_nid = 0x08; | ||
5029 | |||
4972 | codec->patch_ops = alc_patch_ops; | 5030 | codec->patch_ops = alc_patch_ops; |
4973 | if (board_config == ALC260_AUTO) | 5031 | if (board_config == ALC260_AUTO) |
4974 | spec->init_hook = alc260_auto_init; | 5032 | spec->init_hook = alc260_auto_init; |
@@ -5169,15 +5227,15 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { | |||
5169 | }; | 5227 | }; |
5170 | 5228 | ||
5171 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { | 5229 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { |
5172 | HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT), | 5230 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), |
5173 | HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT), | 5231 | HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), |
5174 | HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT), | 5232 | HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT), |
5175 | HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT), | 5233 | HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT), |
5176 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT), | 5234 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
5177 | HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT), | 5235 | HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
5178 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), | 5236 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), |
5179 | HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), | 5237 | HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), |
5180 | HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT), | 5238 | HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT), |
5181 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), | 5239 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), |
5182 | { } /* end */ | 5240 | { } /* end */ |
5183 | }; | 5241 | }; |
@@ -6181,6 +6239,8 @@ static int patch_alc882(struct hda_codec *codec) | |||
6181 | } | 6239 | } |
6182 | } | 6240 | } |
6183 | 6241 | ||
6242 | spec->vmaster_nid = 0x0c; | ||
6243 | |||
6184 | codec->patch_ops = alc_patch_ops; | 6244 | codec->patch_ops = alc_patch_ops; |
6185 | if (board_config == ALC882_AUTO) | 6245 | if (board_config == ALC882_AUTO) |
6186 | spec->init_hook = alc882_auto_init; | 6246 | spec->init_hook = alc882_auto_init; |
@@ -7763,6 +7823,8 @@ static int patch_alc883(struct hda_codec *codec) | |||
7763 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | 7823 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); |
7764 | } | 7824 | } |
7765 | 7825 | ||
7826 | spec->vmaster_nid = 0x0c; | ||
7827 | |||
7766 | codec->patch_ops = alc_patch_ops; | 7828 | codec->patch_ops = alc_patch_ops; |
7767 | if (board_config == ALC883_AUTO) | 7829 | if (board_config == ALC883_AUTO) |
7768 | spec->init_hook = alc883_auto_init; | 7830 | spec->init_hook = alc883_auto_init; |
@@ -9123,6 +9185,8 @@ static int patch_alc262(struct hda_codec *codec) | |||
9123 | } | 9185 | } |
9124 | } | 9186 | } |
9125 | 9187 | ||
9188 | spec->vmaster_nid = 0x0c; | ||
9189 | |||
9126 | codec->patch_ops = alc_patch_ops; | 9190 | codec->patch_ops = alc_patch_ops; |
9127 | if (board_config == ALC262_AUTO) | 9191 | if (board_config == ALC262_AUTO) |
9128 | spec->init_hook = alc262_auto_init; | 9192 | spec->init_hook = alc262_auto_init; |
@@ -9848,6 +9912,9 @@ static int patch_alc268(struct hda_codec *codec) | |||
9848 | } | 9912 | } |
9849 | } | 9913 | } |
9850 | } | 9914 | } |
9915 | |||
9916 | spec->vmaster_nid = 0x02; | ||
9917 | |||
9851 | codec->patch_ops = alc_patch_ops; | 9918 | codec->patch_ops = alc_patch_ops; |
9852 | if (board_config == ALC268_AUTO) | 9919 | if (board_config == ALC268_AUTO) |
9853 | spec->init_hook = alc268_auto_init; | 9920 | spec->init_hook = alc268_auto_init; |
@@ -11358,6 +11425,8 @@ static int patch_alc861(struct hda_codec *codec) | |||
11358 | spec->stream_digital_playback = &alc861_pcm_digital_playback; | 11425 | spec->stream_digital_playback = &alc861_pcm_digital_playback; |
11359 | spec->stream_digital_capture = &alc861_pcm_digital_capture; | 11426 | spec->stream_digital_capture = &alc861_pcm_digital_capture; |
11360 | 11427 | ||
11428 | spec->vmaster_nid = 0x03; | ||
11429 | |||
11361 | codec->patch_ops = alc_patch_ops; | 11430 | codec->patch_ops = alc_patch_ops; |
11362 | if (board_config == ALC861_AUTO) | 11431 | if (board_config == ALC861_AUTO) |
11363 | spec->init_hook = alc861_auto_init; | 11432 | spec->init_hook = alc861_auto_init; |
@@ -12334,6 +12403,8 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
12334 | spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; | 12403 | spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; |
12335 | spec->num_mixers++; | 12404 | spec->num_mixers++; |
12336 | 12405 | ||
12406 | spec->vmaster_nid = 0x02; | ||
12407 | |||
12337 | codec->patch_ops = alc_patch_ops; | 12408 | codec->patch_ops = alc_patch_ops; |
12338 | 12409 | ||
12339 | if (board_config == ALC861VD_AUTO) | 12410 | if (board_config == ALC861VD_AUTO) |
@@ -13305,6 +13376,8 @@ static int patch_alc662(struct hda_codec *codec) | |||
13305 | spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); | 13376 | spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); |
13306 | } | 13377 | } |
13307 | 13378 | ||
13379 | spec->vmaster_nid = 0x02; | ||
13380 | |||
13308 | codec->patch_ops = alc_patch_ops; | 13381 | codec->patch_ops = alc_patch_ops; |
13309 | if (board_config == ALC662_AUTO) | 13382 | if (board_config == ALC662_AUTO) |
13310 | spec->init_hook = alc662_auto_init; | 13383 | spec->init_hook = alc662_auto_init; |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a0af8680dd0d..190e112f2f8e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -170,6 +170,9 @@ struct sigmatel_spec { | |||
170 | struct snd_kcontrol_new *kctl_alloc; | 170 | struct snd_kcontrol_new *kctl_alloc; |
171 | struct hda_input_mux private_dimux; | 171 | struct hda_input_mux private_dimux; |
172 | struct hda_input_mux private_imux; | 172 | struct hda_input_mux private_imux; |
173 | |||
174 | /* virtual master */ | ||
175 | unsigned int vmaster_tlv[4]; | ||
173 | }; | 176 | }; |
174 | 177 | ||
175 | static hda_nid_t stac9200_adc_nids[1] = { | 178 | static hda_nid_t stac9200_adc_nids[1] = { |
@@ -794,6 +797,34 @@ static struct snd_kcontrol_new stac_dmux_mixer = { | |||
794 | .put = stac92xx_dmux_enum_put, | 797 | .put = stac92xx_dmux_enum_put, |
795 | }; | 798 | }; |
796 | 799 | ||
800 | static const char *slave_vols[] = { | ||
801 | "Front Playback Volume", | ||
802 | "Surround Playback Volume", | ||
803 | "Center Playback Volume", | ||
804 | "LFE Playback Volume", | ||
805 | "Side Playback Volume", | ||
806 | "Headphone Playback Volume", | ||
807 | "Headphone Playback Volume", | ||
808 | "Speaker Playback Volume", | ||
809 | "External Speaker Playback Volume", | ||
810 | "Speaker2 Playback Volume", | ||
811 | NULL | ||
812 | }; | ||
813 | |||
814 | static const char *slave_sws[] = { | ||
815 | "Front Playback Switch", | ||
816 | "Surround Playback Switch", | ||
817 | "Center Playback Switch", | ||
818 | "LFE Playback Switch", | ||
819 | "Side Playback Switch", | ||
820 | "Headphone Playback Switch", | ||
821 | "Headphone Playback Switch", | ||
822 | "Speaker Playback Switch", | ||
823 | "External Speaker Playback Switch", | ||
824 | "Speaker2 Playback Switch", | ||
825 | NULL | ||
826 | }; | ||
827 | |||
797 | static int stac92xx_build_controls(struct hda_codec *codec) | 828 | static int stac92xx_build_controls(struct hda_codec *codec) |
798 | { | 829 | { |
799 | struct sigmatel_spec *spec = codec->spec; | 830 | struct sigmatel_spec *spec = codec->spec; |
@@ -827,6 +858,23 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
827 | if (err < 0) | 858 | if (err < 0) |
828 | return err; | 859 | return err; |
829 | } | 860 | } |
861 | |||
862 | /* if we have no master control, let's create it */ | ||
863 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
864 | snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], | ||
865 | HDA_OUTPUT, spec->vmaster_tlv); | ||
866 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
867 | spec->vmaster_tlv, slave_vols); | ||
868 | if (err < 0) | ||
869 | return err; | ||
870 | } | ||
871 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
872 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
873 | NULL, slave_sws); | ||
874 | if (err < 0) | ||
875 | return err; | ||
876 | } | ||
877 | |||
830 | return 0; | 878 | return 0; |
831 | } | 879 | } |
832 | 880 | ||