aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-11-12 10:45:04 -0500
committerTakashi Iwai <tiwai@suse.de>2008-11-13 08:37:14 -0500
commit4d4e9bb339cfcde7811af10859ba1ce2fe3d46b4 (patch)
treebf9bbfdc9e6c0a9d912013edfba83924d50b6eda /sound/pci/hda
parentd7a8943635485597ae7c6d554a8ccf3ce5a42d2d (diff)
ALSA: hda - Add digital beep playback switch for STAC/IDT codecs
The digital beep widget may have no mute control, and always enabling the beep is ofen pretty annoying, especially on laptops. This patch adds a mixer control "PC Beep Playback Switch" when there is no mixer amp mute is found, and controls it on software. Reference: Novell bnc#444572 https://bugzilla.novell.com/show_bug.cgi?id=444572 Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_beep.c4
-rw-r--r--sound/pci/hda/hda_beep.h1
-rw-r--r--sound/pci/hda/patch_sigmatel.c69
3 files changed, 68 insertions, 6 deletions
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 9b77b3e0fa98..b1796ae1e8fb 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -37,6 +37,9 @@ static void snd_hda_generate_beep(struct work_struct *work)
37 container_of(work, struct hda_beep, beep_work); 37 container_of(work, struct hda_beep, beep_work);
38 struct hda_codec *codec = beep->codec; 38 struct hda_codec *codec = beep->codec;
39 39
40 if (!beep->enabled)
41 return;
42
40 /* generate tone */ 43 /* generate tone */
41 snd_hda_codec_write_cache(codec, beep->nid, 0, 44 snd_hda_codec_write_cache(codec, beep->nid, 0,
42 AC_VERB_SET_BEEP_CONTROL, beep->tone); 45 AC_VERB_SET_BEEP_CONTROL, beep->tone);
@@ -115,6 +118,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
115 beep->nid = nid; 118 beep->nid = nid;
116 beep->dev = input_dev; 119 beep->dev = input_dev;
117 beep->codec = codec; 120 beep->codec = codec;
121 beep->enabled = 1;
118 codec->beep = beep; 122 codec->beep = beep;
119 123
120 INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); 124 INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index de4036e6e710..b9679f081cae 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -31,6 +31,7 @@ struct hda_beep {
31 char phys[32]; 31 char phys[32];
32 int tone; 32 int tone;
33 int nid; 33 int nid;
34 int enabled;
34 struct work_struct beep_work; /* scheduled task for beep event */ 35 struct work_struct beep_work; /* scheduled task for beep event */
35}; 36};
36 37
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 4300a679cd86..1633ef2c654a 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -2587,8 +2587,10 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = {
2587}; 2587};
2588 2588
2589/* add dynamic controls */ 2589/* add dynamic controls */
2590static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type, 2590static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
2591 int idx, const char *name, unsigned long val) 2591 struct snd_kcontrol_new *ktemp,
2592 int idx, const char *name,
2593 unsigned long val)
2592{ 2594{
2593 struct snd_kcontrol_new *knew; 2595 struct snd_kcontrol_new *knew;
2594 2596
@@ -2607,20 +2609,29 @@ static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
2607 } 2609 }
2608 2610
2609 knew = &spec->kctl_alloc[spec->num_kctl_used]; 2611 knew = &spec->kctl_alloc[spec->num_kctl_used];
2610 *knew = stac92xx_control_templates[type]; 2612 *knew = *ktemp;
2611 knew->index = idx; 2613 knew->index = idx;
2612 knew->name = kstrdup(name, GFP_KERNEL); 2614 knew->name = kstrdup(name, GFP_KERNEL);
2613 if (! knew->name) 2615 if (!knew->name)
2614 return -ENOMEM; 2616 return -ENOMEM;
2615 knew->private_value = val; 2617 knew->private_value = val;
2616 spec->num_kctl_used++; 2618 spec->num_kctl_used++;
2617 return 0; 2619 return 0;
2618} 2620}
2619 2621
2622static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
2623 int type, int idx, const char *name,
2624 unsigned long val)
2625{
2626 return stac92xx_add_control_temp(spec,
2627 &stac92xx_control_templates[type],
2628 idx, name, val);
2629}
2630
2620 2631
2621/* add dynamic controls */ 2632/* add dynamic controls */
2622static int stac92xx_add_control(struct sigmatel_spec *spec, int type, 2633static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2623 const char *name, unsigned long val) 2634 const char *name, unsigned long val)
2624{ 2635{
2625 return stac92xx_add_control_idx(spec, type, 0, name, val); 2636 return stac92xx_add_control_idx(spec, type, 0, name, val);
2626} 2637}
@@ -3062,6 +3073,43 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3062 return 0; 3073 return 0;
3063} 3074}
3064 3075
3076#ifdef CONFIG_SND_HDA_INPUT_BEEP
3077#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
3078
3079static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
3080 struct snd_ctl_elem_value *ucontrol)
3081{
3082 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3083 ucontrol->value.integer.value[0] = codec->beep->enabled;
3084 return 0;
3085}
3086
3087static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
3088 struct snd_ctl_elem_value *ucontrol)
3089{
3090 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3091 int enabled = !!ucontrol->value.integer.value[0];
3092 if (codec->beep->enabled != enabled) {
3093 codec->beep->enabled = enabled;
3094 return 1;
3095 }
3096 return 0;
3097}
3098
3099static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
3100 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3101 .info = stac92xx_dig_beep_switch_info,
3102 .get = stac92xx_dig_beep_switch_get,
3103 .put = stac92xx_dig_beep_switch_put,
3104};
3105
3106static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
3107{
3108 return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
3109 0, "PC Beep Playback Switch", 0);
3110}
3111#endif
3112
3065static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) 3113static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
3066{ 3114{
3067 struct sigmatel_spec *spec = codec->spec; 3115 struct sigmatel_spec *spec = codec->spec;
@@ -3368,6 +3416,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
3368#ifdef CONFIG_SND_HDA_INPUT_BEEP 3416#ifdef CONFIG_SND_HDA_INPUT_BEEP
3369 if (spec->digbeep_nid > 0) { 3417 if (spec->digbeep_nid > 0) {
3370 hda_nid_t nid = spec->digbeep_nid; 3418 hda_nid_t nid = spec->digbeep_nid;
3419 unsigned int caps;
3371 3420
3372 err = stac92xx_auto_create_beep_ctls(codec, nid); 3421 err = stac92xx_auto_create_beep_ctls(codec, nid);
3373 if (err < 0) 3422 if (err < 0)
@@ -3375,6 +3424,14 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
3375 err = snd_hda_attach_beep_device(codec, nid); 3424 err = snd_hda_attach_beep_device(codec, nid);
3376 if (err < 0) 3425 if (err < 0)
3377 return err; 3426 return err;
3427 /* if no beep switch is available, make its own one */
3428 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3429 if (codec->beep &&
3430 !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) {
3431 err = stac92xx_beep_switch_ctl(codec);
3432 if (err < 0)
3433 return err;
3434 }
3378 } 3435 }
3379#endif 3436#endif
3380 3437