]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Takashi Iwai <tiwai@suse.de> |
2 | Subject: ALSA: hda - Add digital beep playback switch for STAC/IDT codecs | |
3 | Patch-mainline: | |
4 | References: #444572 | |
5 | ||
6 | The digital beep widget may have no mute control, and always enabling | |
7 | the beep is ofen pretty annoying, especially on laptops. | |
8 | ||
9 | This patch adds a mixer control "PC Beep Playback Switch" when there | |
10 | is no mixer amp mute is found, and controls it on software. | |
11 | ||
12 | Reference: Novell bnc#444572 | |
13 | https://bugzilla.novell.com/show_bug.cgi?id=444572 | |
14 | ||
15 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
16 | ||
17 | --- | |
18 | sound/pci/hda/hda_beep.c | 4 ++ | |
19 | sound/pci/hda/hda_beep.h | 1 | |
20 | sound/pci/hda/patch_sigmatel.c | 69 +++++++++++++++++++++++++++++++++++++---- | |
21 | 3 files changed, 68 insertions(+), 6 deletions(-) | |
22 | ||
23 | --- a/sound/pci/hda/hda_beep.c | |
24 | +++ b/sound/pci/hda/hda_beep.c | |
25 | @@ -37,6 +37,9 @@ static void snd_hda_generate_beep(struct | |
26 | container_of(work, struct hda_beep, beep_work); | |
27 | struct hda_codec *codec = beep->codec; | |
28 | ||
29 | + if (!beep->enabled) | |
30 | + return; | |
31 | + | |
32 | /* generate tone */ | |
33 | snd_hda_codec_write_cache(codec, beep->nid, 0, | |
34 | AC_VERB_SET_BEEP_CONTROL, beep->tone); | |
35 | @@ -115,6 +118,7 @@ int snd_hda_attach_beep_device(struct hd | |
36 | beep->nid = nid; | |
37 | beep->dev = input_dev; | |
38 | beep->codec = codec; | |
39 | + beep->enabled = 1; | |
40 | codec->beep = beep; | |
41 | ||
42 | INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); | |
43 | --- a/sound/pci/hda/hda_beep.h | |
44 | +++ b/sound/pci/hda/hda_beep.h | |
45 | @@ -31,6 +31,7 @@ struct hda_beep { | |
46 | char phys[32]; | |
47 | int tone; | |
48 | int nid; | |
49 | + int enabled; | |
50 | struct work_struct beep_work; /* scheduled task for beep event */ | |
51 | }; | |
52 | ||
53 | --- a/sound/pci/hda/patch_sigmatel.c | |
54 | +++ b/sound/pci/hda/patch_sigmatel.c | |
55 | @@ -2592,8 +2592,10 @@ static struct snd_kcontrol_new stac92xx_ | |
56 | }; | |
57 | ||
58 | /* add dynamic controls */ | |
59 | -static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type, | |
60 | - int idx, const char *name, unsigned long val) | |
61 | +static int stac92xx_add_control_temp(struct sigmatel_spec *spec, | |
62 | + struct snd_kcontrol_new *ktemp, | |
63 | + int idx, const char *name, | |
64 | + unsigned long val) | |
65 | { | |
66 | struct snd_kcontrol_new *knew; | |
67 | ||
68 | @@ -2612,20 +2614,29 @@ static int stac92xx_add_control_idx(stru | |
69 | } | |
70 | ||
71 | knew = &spec->kctl_alloc[spec->num_kctl_used]; | |
72 | - *knew = stac92xx_control_templates[type]; | |
73 | + *knew = *ktemp; | |
74 | knew->index = idx; | |
75 | knew->name = kstrdup(name, GFP_KERNEL); | |
76 | - if (! knew->name) | |
77 | + if (!knew->name) | |
78 | return -ENOMEM; | |
79 | knew->private_value = val; | |
80 | spec->num_kctl_used++; | |
81 | return 0; | |
82 | } | |
83 | ||
84 | +static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, | |
85 | + int type, int idx, const char *name, | |
86 | + unsigned long val) | |
87 | +{ | |
88 | + return stac92xx_add_control_temp(spec, | |
89 | + &stac92xx_control_templates[type], | |
90 | + idx, name, val); | |
91 | +} | |
92 | + | |
93 | ||
94 | /* add dynamic controls */ | |
95 | -static int stac92xx_add_control(struct sigmatel_spec *spec, int type, | |
96 | - const char *name, unsigned long val) | |
97 | +static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type, | |
98 | + const char *name, unsigned long val) | |
99 | { | |
100 | return stac92xx_add_control_idx(spec, type, 0, name, val); | |
101 | } | |
102 | @@ -3067,6 +3078,43 @@ static int stac92xx_auto_create_beep_ctl | |
103 | return 0; | |
104 | } | |
105 | ||
106 | +#ifdef CONFIG_SND_HDA_INPUT_BEEP | |
107 | +#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info | |
108 | + | |
109 | +static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol, | |
110 | + struct snd_ctl_elem_value *ucontrol) | |
111 | +{ | |
112 | + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | |
113 | + ucontrol->value.integer.value[0] = codec->beep->enabled; | |
114 | + return 0; | |
115 | +} | |
116 | + | |
117 | +static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol, | |
118 | + struct snd_ctl_elem_value *ucontrol) | |
119 | +{ | |
120 | + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | |
121 | + int enabled = !!ucontrol->value.integer.value[0]; | |
122 | + if (codec->beep->enabled != enabled) { | |
123 | + codec->beep->enabled = enabled; | |
124 | + return 1; | |
125 | + } | |
126 | + return 0; | |
127 | +} | |
128 | + | |
129 | +static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { | |
130 | + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
131 | + .info = stac92xx_dig_beep_switch_info, | |
132 | + .get = stac92xx_dig_beep_switch_get, | |
133 | + .put = stac92xx_dig_beep_switch_put, | |
134 | +}; | |
135 | + | |
136 | +static int stac92xx_beep_switch_ctl(struct hda_codec *codec) | |
137 | +{ | |
138 | + return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl, | |
139 | + 0, "PC Beep Playback Switch", 0); | |
140 | +} | |
141 | +#endif | |
142 | + | |
143 | static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) | |
144 | { | |
145 | struct sigmatel_spec *spec = codec->spec; | |
146 | @@ -3373,6 +3421,7 @@ static int stac92xx_parse_auto_config(st | |
147 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | |
148 | if (spec->digbeep_nid > 0) { | |
149 | hda_nid_t nid = spec->digbeep_nid; | |
150 | + unsigned int caps; | |
151 | ||
152 | err = stac92xx_auto_create_beep_ctls(codec, nid); | |
153 | if (err < 0) | |
154 | @@ -3380,6 +3429,14 @@ static int stac92xx_parse_auto_config(st | |
155 | err = snd_hda_attach_beep_device(codec, nid); | |
156 | if (err < 0) | |
157 | return err; | |
158 | + /* if no beep switch is available, make its own one */ | |
159 | + caps = query_amp_caps(codec, nid, HDA_OUTPUT); | |
160 | + if (codec->beep && | |
161 | + !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) { | |
162 | + err = stac92xx_beep_switch_ctl(codec); | |
163 | + if (err < 0) | |
164 | + return err; | |
165 | + } | |
166 | } | |
167 | #endif | |
168 |