diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-03-12 11:59:58 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-03-13 02:46:50 -0400 |
commit | d2f344b5e0a933b5b1d12f863406ee1d63e5bf8e (patch) | |
tree | 3e7354efd8293fa6b1d6e24ddcd3c2356dafb2ba /sound/pci | |
parent | 527c73bada6f02a35983ddb34db3a0fd4360c88c (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.c | 94 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 21 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 17 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 12 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 13 |
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 | } |
2451 | EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster); | 2451 | EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster); |
2452 | 2452 | ||
2453 | /* | ||
2454 | * mute-LED control using vmaster | ||
2455 | */ | ||
2456 | static 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 | |||
2474 | static 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 | |||
2482 | static 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 | |||
2497 | static 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 | */ | ||
2510 | int 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 | } | ||
2525 | EXPORT_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 | */ | ||
2531 | void 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 | } | ||
2544 | EXPORT_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) |
148 | int snd_hda_codec_reset(struct hda_codec *codec); | 148 | int snd_hda_codec_reset(struct hda_codec *codec); |
149 | 149 | ||
150 | enum { | ||
151 | HDA_VMUTE_OFF, | ||
152 | HDA_VMUTE_ON, | ||
153 | HDA_VMUTE_FOLLOW_MASTER, | ||
154 | }; | ||
155 | |||
156 | struct 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 | |||
167 | int snd_hda_add_vmaster_hook(struct hda_codec *codec, | ||
168 | struct hda_vmaster_mute_hook *hook); | ||
169 | void 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 | ||
317 | static const hda_nid_t stac9200_adc_nids[1] = { | 317 | static 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; |