aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-03-12 11:59:58 -0400
committerTakashi Iwai <tiwai@suse.de>2012-03-13 02:46:50 -0400
commitd2f344b5e0a933b5b1d12f863406ee1d63e5bf8e (patch)
tree3e7354efd8293fa6b1d6e24ddcd3c2356dafb2ba /sound/pci
parent527c73bada6f02a35983ddb34db3a0fd4360c88c (diff)
ALSA: hda - Add "Mute-LED Mode" enum control
Create snd_hda_add_vmaster_hook() and snd_hda_sync_vmaster_hook() helper functions to handle the mute-LED in vmaster hook more commonly. In the former function, a new enum control "Mute-LED Mode" is added. This provides user to choose whether the mute-LED should be turned on/off explicitly or to follow the master-mute status. Reviewed-by: David Henningsson <david.henningsson@canonical.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_codec.c94
-rw-r--r--sound/pci/hda/hda_local.h21
-rw-r--r--sound/pci/hda/patch_conexant.c17
-rw-r--r--sound/pci/hda/patch_realtek.c12
-rw-r--r--sound/pci/hda/patch_sigmatel.c13
5 files changed, 135 insertions, 22 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index b79ee3444654..b981ea9c644c 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2450,6 +2450,100 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
2450} 2450}
2451EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster); 2451EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster);
2452 2452
2453/*
2454 * mute-LED control using vmaster
2455 */
2456static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
2457 struct snd_ctl_elem_info *uinfo)
2458{
2459 static const char * const texts[] = {
2460 "Off", "On", "Follow Master"
2461 };
2462 unsigned int index;
2463
2464 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2465 uinfo->count = 1;
2466 uinfo->value.enumerated.items = 3;
2467 index = uinfo->value.enumerated.item;
2468 if (index >= 3)
2469 index = 2;
2470 strcpy(uinfo->value.enumerated.name, texts[index]);
2471 return 0;
2472}
2473
2474static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol,
2475 struct snd_ctl_elem_value *ucontrol)
2476{
2477 struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
2478 ucontrol->value.enumerated.item[0] = hook->mute_mode;
2479 return 0;
2480}
2481
2482static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol,
2483 struct snd_ctl_elem_value *ucontrol)
2484{
2485 struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol);
2486 unsigned int old_mode = hook->mute_mode;
2487
2488 hook->mute_mode = ucontrol->value.enumerated.item[0];
2489 if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER)
2490 hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
2491 if (old_mode == hook->mute_mode)
2492 return 0;
2493 snd_hda_sync_vmaster_hook(hook);
2494 return 1;
2495}
2496
2497static struct snd_kcontrol_new vmaster_mute_mode = {
2498 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2499 .name = "Mute-LED Mode",
2500 .info = vmaster_mute_mode_info,
2501 .get = vmaster_mute_mode_get,
2502 .put = vmaster_mute_mode_put,
2503};
2504
2505/*
2506 * Add a mute-LED hook with the given vmaster switch kctl
2507 * "Mute-LED Mode" control is automatically created and associated with
2508 * the given hook.
2509 */
2510int snd_hda_add_vmaster_hook(struct hda_codec *codec,
2511 struct hda_vmaster_mute_hook *hook)
2512{
2513 struct snd_kcontrol *kctl;
2514
2515 if (!hook->hook || !hook->sw_kctl)
2516 return 0;
2517 snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec);
2518 hook->codec = codec;
2519 hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
2520 kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
2521 if (!kctl)
2522 return -ENOMEM;
2523 return snd_hda_ctl_add(codec, 0, kctl);
2524}
2525EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook);
2526
2527/*
2528 * Call the hook with the current value for synchronization
2529 * Should be called in init callback
2530 */
2531void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
2532{
2533 if (!hook->hook || !hook->codec)
2534 return;
2535 switch (hook->mute_mode) {
2536 case HDA_VMUTE_FOLLOW_MASTER:
2537 snd_ctl_sync_vmaster_hook(hook->sw_kctl);
2538 break;
2539 default:
2540 hook->hook(hook->codec, hook->mute_mode);
2541 break;
2542 }
2543}
2544EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook);
2545
2546
2453/** 2547/**
2454 * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch 2548 * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
2455 * 2549 *
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index c3ee4ede4482..3f82ab6a0587 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -147,6 +147,27 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
147 __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL) 147 __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL)
148int snd_hda_codec_reset(struct hda_codec *codec); 148int snd_hda_codec_reset(struct hda_codec *codec);
149 149
150enum {
151 HDA_VMUTE_OFF,
152 HDA_VMUTE_ON,
153 HDA_VMUTE_FOLLOW_MASTER,
154};
155
156struct hda_vmaster_mute_hook {
157 /* below two fields must be filled by the caller of
158 * snd_hda_add_vmaster_hook() beforehand
159 */
160 struct snd_kcontrol *sw_kctl;
161 void (*hook)(void *, int);
162 /* below are initialized automatically */
163 unsigned int mute_mode; /* HDA_VMUTE_XXX */
164 struct hda_codec *codec;
165};
166
167int snd_hda_add_vmaster_hook(struct hda_codec *codec,
168 struct hda_vmaster_mute_hook *hook);
169void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook);
170
150/* amp value bits */ 171/* amp value bits */
151#define HDA_AMP_MUTE 0x80 172#define HDA_AMP_MUTE 0x80
152#define HDA_AMP_UNMUTE 0x00 173#define HDA_AMP_UNMUTE 0x00
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index f1c9aed9fa69..a21a485a413c 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -70,8 +70,7 @@ struct conexant_spec {
70 const struct snd_kcontrol_new *mixers[5]; 70 const struct snd_kcontrol_new *mixers[5];
71 int num_mixers; 71 int num_mixers;
72 hda_nid_t vmaster_nid; 72 hda_nid_t vmaster_nid;
73 struct snd_kcontrol *vmaster_sw_kctl; 73 struct hda_vmaster_mute_hook vmaster_mute;
74 void (*vmaster_hook)(struct snd_kcontrol *, int);
75 74
76 const struct hda_verb *init_verbs[5]; /* initialization verbs 75 const struct hda_verb *init_verbs[5]; /* initialization verbs
77 * don't forget NULL 76 * don't forget NULL
@@ -518,7 +517,7 @@ static int conexant_build_controls(struct hda_codec *codec)
518 err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 517 err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
519 NULL, slave_pfxs, 518 NULL, slave_pfxs,
520 "Playback Switch", true, 519 "Playback Switch", true,
521 &spec->vmaster_sw_kctl); 520 &spec->vmaster_mute.sw_kctl);
522 if (err < 0) 521 if (err < 0)
523 return err; 522 return err;
524 } 523 }
@@ -4101,7 +4100,7 @@ static int cx_auto_init(struct hda_codec *codec)
4101 cx_auto_init_input(codec); 4100 cx_auto_init_input(codec);
4102 cx_auto_init_digital(codec); 4101 cx_auto_init_digital(codec);
4103 snd_hda_jack_report_sync(codec); 4102 snd_hda_jack_report_sync(codec);
4104 snd_ctl_sync_vmaster_hook(spec->vmaster_sw_kctl); 4103 snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
4105 return 0; 4104 return 0;
4106} 4105}
4107 4106
@@ -4347,10 +4346,10 @@ static int cx_auto_build_controls(struct hda_codec *codec)
4347 err = snd_hda_jack_add_kctls(codec, &spec->autocfg); 4346 err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
4348 if (err < 0) 4347 if (err < 0)
4349 return err; 4348 return err;
4350 if (spec->vmaster_hook && spec->vmaster_sw_kctl) { 4349 if (spec->vmaster_mute.hook && spec->vmaster_mute.sw_kctl) {
4351 snd_ctl_add_vmaster_hook(spec->vmaster_sw_kctl, 4350 err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
4352 spec->vmaster_hook, codec); 4351 if (err < 0)
4353 snd_ctl_sync_vmaster_hook(spec->vmaster_sw_kctl); 4352 return err;
4354 } 4353 }
4355 return 0; 4354 return 0;
4356} 4355}
@@ -4481,7 +4480,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
4481 /* NOTE: this should be applied via fixup once when the generic 4480 /* NOTE: this should be applied via fixup once when the generic
4482 * fixup code is merged to hda_codec.c 4481 * fixup code is merged to hda_codec.c
4483 */ 4482 */
4484 spec->vmaster_hook = cx_auto_vmaster_hook; 4483 spec->vmaster_mute.hook = cx_auto_vmaster_hook;
4485 4484
4486 err = cx_auto_search_adcs(codec); 4485 err = cx_auto_search_adcs(codec);
4487 if (err < 0) 4486 if (err < 0)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 901547216c4e..b69d2fe40297 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -198,7 +198,7 @@ struct alc_spec {
198 198
199 /* for virtual master */ 199 /* for virtual master */
200 hda_nid_t vmaster_nid; 200 hda_nid_t vmaster_nid;
201 struct snd_kcontrol *vmaster_sw_kctl; 201 struct hda_vmaster_mute_hook vmaster_mute;
202#ifdef CONFIG_SND_HDA_POWER_SAVE 202#ifdef CONFIG_SND_HDA_POWER_SAVE
203 struct hda_loopback_check loopback; 203 struct hda_loopback_check loopback;
204 int num_loopbacks; 204 int num_loopbacks;
@@ -1960,7 +1960,7 @@ static int __alc_build_controls(struct hda_codec *codec)
1960 err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 1960 err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
1961 NULL, alc_slave_pfxs, 1961 NULL, alc_slave_pfxs,
1962 "Playback Switch", 1962 "Playback Switch",
1963 true, &spec->vmaster_sw_kctl); 1963 true, &spec->vmaster_mute.sw_kctl);
1964 if (err < 0) 1964 if (err < 0)
1965 return err; 1965 return err;
1966 } 1966 }
@@ -5894,13 +5894,11 @@ static void alc269_fixup_mic2_mute(struct hda_codec *codec,
5894 struct alc_spec *spec = codec->spec; 5894 struct alc_spec *spec = codec->spec;
5895 switch (action) { 5895 switch (action) {
5896 case ALC_FIXUP_ACT_BUILD: 5896 case ALC_FIXUP_ACT_BUILD:
5897 if (!spec->vmaster_sw_kctl) 5897 spec->vmaster_mute.hook = alc269_fixup_mic2_mute_hook;
5898 return; 5898 snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
5899 snd_ctl_add_vmaster_hook(spec->vmaster_sw_kctl,
5900 alc269_fixup_mic2_mute_hook, codec);
5901 /* fallthru */ 5899 /* fallthru */
5902 case ALC_FIXUP_ACT_INIT: 5900 case ALC_FIXUP_ACT_INIT:
5903 snd_ctl_sync_vmaster_hook(spec->vmaster_sw_kctl); 5901 snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
5904 break; 5902 break;
5905 } 5903 }
5906} 5904}
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 6e926497b230..cd04e29e157b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -311,7 +311,7 @@ struct sigmatel_spec {
311 unsigned auto_dmic_cnt; 311 unsigned auto_dmic_cnt;
312 hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; 312 hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
313 313
314 struct snd_kcontrol *vmaster_sw_kctl; 314 struct hda_vmaster_mute_hook vmaster_mute;
315}; 315};
316 316
317static const hda_nid_t stac9200_adc_nids[1] = { 317static const hda_nid_t stac9200_adc_nids[1] = {
@@ -1160,14 +1160,15 @@ static int stac92xx_build_controls(struct hda_codec *codec)
1160 err = __snd_hda_add_vmaster(codec, "Master Playback Switch", 1160 err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
1161 NULL, slave_pfxs, 1161 NULL, slave_pfxs,
1162 "Playback Switch", true, 1162 "Playback Switch", true,
1163 &spec->vmaster_sw_kctl); 1163 &spec->vmaster_mute.sw_kctl);
1164 if (err < 0) 1164 if (err < 0)
1165 return err; 1165 return err;
1166 1166
1167 if (spec->gpio_led) { 1167 if (spec->gpio_led) {
1168 snd_ctl_add_vmaster_hook(spec->vmaster_sw_kctl, 1168 spec->vmaster_mute.hook = stac92xx_vmaster_hook;
1169 stac92xx_vmaster_hook, codec); 1169 err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
1170 snd_ctl_sync_vmaster_hook(spec->vmaster_sw_kctl); 1170 if (err < 0)
1171 return err;
1171 } 1172 }
1172 1173
1173 if (spec->aloopback_ctl && 1174 if (spec->aloopback_ctl &&
@@ -4432,7 +4433,7 @@ static int stac92xx_init(struct hda_codec *codec)
4432 snd_hda_jack_report_sync(codec); 4433 snd_hda_jack_report_sync(codec);
4433 4434
4434 /* sync mute LED */ 4435 /* sync mute LED */
4435 snd_ctl_sync_vmaster_hook(spec->vmaster_sw_kctl); 4436 snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
4436 if (spec->dac_list) 4437 if (spec->dac_list)
4437 stac92xx_power_down(codec); 4438 stac92xx_power_down(codec);
4438 return 0; 4439 return 0;