diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_beep.c | 88 | ||||
-rw-r--r-- | sound/pci/hda/hda_beep.h | 4 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 12 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 15 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 16 |
7 files changed, 111 insertions, 28 deletions
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 3f51a981e604..0e986537d570 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c | |||
@@ -113,23 +113,25 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, | |||
113 | return 0; | 113 | return 0; |
114 | } | 114 | } |
115 | 115 | ||
116 | int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) | 116 | static void snd_hda_do_detach(struct hda_beep *beep) |
117 | { | ||
118 | input_unregister_device(beep->dev); | ||
119 | beep->dev = NULL; | ||
120 | cancel_work_sync(&beep->beep_work); | ||
121 | /* turn off beep for sure */ | ||
122 | snd_hda_codec_write_cache(beep->codec, beep->nid, 0, | ||
123 | AC_VERB_SET_BEEP_CONTROL, 0); | ||
124 | } | ||
125 | |||
126 | static int snd_hda_do_attach(struct hda_beep *beep) | ||
117 | { | 127 | { |
118 | struct input_dev *input_dev; | 128 | struct input_dev *input_dev; |
119 | struct hda_beep *beep; | 129 | struct hda_codec *codec = beep->codec; |
120 | int err; | 130 | int err; |
121 | 131 | ||
122 | if (!snd_hda_get_bool_hint(codec, "beep")) | ||
123 | return 0; /* disabled explicitly */ | ||
124 | |||
125 | beep = kzalloc(sizeof(*beep), GFP_KERNEL); | ||
126 | if (beep == NULL) | ||
127 | return -ENOMEM; | ||
128 | snprintf(beep->phys, sizeof(beep->phys), | ||
129 | "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); | ||
130 | input_dev = input_allocate_device(); | 132 | input_dev = input_allocate_device(); |
131 | if (!input_dev) { | 133 | if (!input_dev) { |
132 | kfree(beep); | 134 | printk(KERN_INFO "hda_beep: unable to allocate input device\n"); |
133 | return -ENOMEM; | 135 | return -ENOMEM; |
134 | } | 136 | } |
135 | 137 | ||
@@ -151,21 +153,71 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) | |||
151 | err = input_register_device(input_dev); | 153 | err = input_register_device(input_dev); |
152 | if (err < 0) { | 154 | if (err < 0) { |
153 | input_free_device(input_dev); | 155 | input_free_device(input_dev); |
154 | kfree(beep); | 156 | printk(KERN_INFO "hda_beep: unable to register input device\n"); |
155 | return err; | 157 | return err; |
156 | } | 158 | } |
159 | beep->dev = input_dev; | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static void snd_hda_do_register(struct work_struct *work) | ||
164 | { | ||
165 | struct hda_beep *beep = | ||
166 | container_of(work, struct hda_beep, register_work); | ||
167 | int request; | ||
168 | |||
169 | mutex_lock(&beep->mutex); | ||
170 | request = beep->request_enable; | ||
171 | if (beep->enabled != request) { | ||
172 | if (!request) { | ||
173 | snd_hda_do_detach(beep); | ||
174 | } else { | ||
175 | if (snd_hda_do_attach(beep) < 0) | ||
176 | goto __out; | ||
177 | } | ||
178 | beep->enabled = request; | ||
179 | } | ||
180 | __out: | ||
181 | mutex_unlock(&beep->mutex); | ||
182 | } | ||
183 | |||
184 | int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) | ||
185 | { | ||
186 | struct hda_beep *beep = codec->beep; | ||
187 | enable = !!enable; | ||
188 | if (beep && beep->enabled != enable) { | ||
189 | beep->request_enable = enable; | ||
190 | schedule_work(&beep->register_work); | ||
191 | return 1; | ||
192 | } | ||
193 | return 0; | ||
194 | } | ||
195 | EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device); | ||
196 | |||
197 | int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) | ||
198 | { | ||
199 | struct hda_beep *beep; | ||
200 | |||
201 | if (!snd_hda_get_bool_hint(codec, "beep")) | ||
202 | return 0; /* disabled explicitly */ | ||
157 | 203 | ||
204 | beep = kzalloc(sizeof(*beep), GFP_KERNEL); | ||
205 | if (beep == NULL) | ||
206 | return -ENOMEM; | ||
207 | snprintf(beep->phys, sizeof(beep->phys), | ||
208 | "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); | ||
158 | /* enable linear scale */ | 209 | /* enable linear scale */ |
159 | snd_hda_codec_write(codec, nid, 0, | 210 | snd_hda_codec_write(codec, nid, 0, |
160 | AC_VERB_SET_DIGI_CONVERT_2, 0x01); | 211 | AC_VERB_SET_DIGI_CONVERT_2, 0x01); |
161 | 212 | ||
162 | beep->nid = nid; | 213 | beep->nid = nid; |
163 | beep->dev = input_dev; | ||
164 | beep->codec = codec; | 214 | beep->codec = codec; |
165 | beep->enabled = 1; | ||
166 | codec->beep = beep; | 215 | codec->beep = beep; |
167 | 216 | ||
217 | INIT_WORK(&beep->register_work, &snd_hda_do_register); | ||
168 | INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); | 218 | INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); |
219 | mutex_init(&beep->mutex); | ||
220 | |||
169 | return 0; | 221 | return 0; |
170 | } | 222 | } |
171 | EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); | 223 | EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); |
@@ -174,11 +226,11 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) | |||
174 | { | 226 | { |
175 | struct hda_beep *beep = codec->beep; | 227 | struct hda_beep *beep = codec->beep; |
176 | if (beep) { | 228 | if (beep) { |
177 | cancel_work_sync(&beep->beep_work); | 229 | cancel_work_sync(&beep->register_work); |
178 | 230 | if (beep->enabled) | |
179 | input_unregister_device(beep->dev); | 231 | snd_hda_do_detach(beep); |
180 | kfree(beep); | ||
181 | codec->beep = NULL; | 232 | codec->beep = NULL; |
233 | kfree(beep); | ||
182 | } | 234 | } |
183 | } | 235 | } |
184 | EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); | 236 | EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); |
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index 0c3de787c717..68465f679d8c 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h | |||
@@ -32,11 +32,15 @@ struct hda_beep { | |||
32 | int tone; | 32 | int tone; |
33 | hda_nid_t nid; | 33 | hda_nid_t nid; |
34 | unsigned int enabled:1; | 34 | unsigned int enabled:1; |
35 | unsigned int request_enable:1; | ||
35 | unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ | 36 | unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ |
37 | struct work_struct register_work; /* scheduled task for beep event */ | ||
36 | struct work_struct beep_work; /* scheduled task for beep event */ | 38 | struct work_struct beep_work; /* scheduled task for beep event */ |
39 | struct mutex mutex; | ||
37 | }; | 40 | }; |
38 | 41 | ||
39 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 42 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
43 | int snd_hda_enable_beep_device(struct hda_codec *codec, int enable); | ||
40 | int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); | 44 | int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); |
41 | void snd_hda_detach_beep_device(struct hda_codec *codec); | 45 | void snd_hda_detach_beep_device(struct hda_codec *codec); |
42 | #else | 46 | #else |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 444d9039c1ac..7fd2abe1129d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <sound/tlv.h> | 30 | #include <sound/tlv.h> |
31 | #include <sound/initval.h> | 31 | #include <sound/initval.h> |
32 | #include "hda_local.h" | 32 | #include "hda_local.h" |
33 | #include "hda_beep.h" | ||
33 | #include <sound/hda_hwdep.h> | 34 | #include <sound/hda_hwdep.h> |
34 | 35 | ||
35 | /* | 36 | /* |
@@ -1734,6 +1735,17 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, | |||
1734 | } | 1735 | } |
1735 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); | 1736 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); |
1736 | 1737 | ||
1738 | int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, | ||
1739 | struct snd_ctl_elem_value *ucontrol) | ||
1740 | { | ||
1741 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1742 | long *valp = ucontrol->value.integer.value; | ||
1743 | |||
1744 | snd_hda_enable_beep_device(codec, *valp); | ||
1745 | return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
1746 | } | ||
1747 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep); | ||
1748 | |||
1737 | /* | 1749 | /* |
1738 | * bound volume controls | 1750 | * bound volume controls |
1739 | * | 1751 | * |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index c1ca3182e6a4..3001794ad291 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -66,6 +66,19 @@ | |||
66 | /* stereo mute switch */ | 66 | /* stereo mute switch */ |
67 | #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ | 67 | #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ |
68 | HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) | 68 | HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) |
69 | /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ | ||
70 | #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | ||
71 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | ||
72 | .info = snd_hda_mixer_amp_switch_info, \ | ||
73 | .get = snd_hda_mixer_amp_switch_get, \ | ||
74 | .put = snd_hda_mixer_amp_switch_put_beep, \ | ||
75 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } | ||
76 | /* special beep mono mute switch */ | ||
77 | #define HDA_CODEC_MUTE_BEEP_MONO(xname, nid, channel, xindex, direction) \ | ||
78 | HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, 0, nid, channel, xindex, direction) | ||
79 | /* special beep stereo mute switch */ | ||
80 | #define HDA_CODEC_MUTE_BEEP(xname, nid, xindex, direction) \ | ||
81 | HDA_CODEC_MUTE_BEEP_MONO(xname, nid, 3, xindex, direction) | ||
69 | 82 | ||
70 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | 83 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, |
71 | struct snd_ctl_elem_info *uinfo); | 84 | struct snd_ctl_elem_info *uinfo); |
@@ -81,6 +94,8 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, | |||
81 | struct snd_ctl_elem_value *ucontrol); | 94 | struct snd_ctl_elem_value *ucontrol); |
82 | int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, | 95 | int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, |
83 | struct snd_ctl_elem_value *ucontrol); | 96 | struct snd_ctl_elem_value *ucontrol); |
97 | int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, | ||
98 | struct snd_ctl_elem_value *ucontrol); | ||
84 | /* lowlevel accessor with caching; use carefully */ | 99 | /* lowlevel accessor with caching; use carefully */ |
85 | int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, | 100 | int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, |
86 | int direction, int index); | 101 | int direction, int index); |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2d603f6aba63..a0293614a0b9 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -159,7 +159,7 @@ static void ad198x_free_kctls(struct hda_codec *codec); | |||
159 | /* additional beep mixers; the actual parameters are overwritten at build */ | 159 | /* additional beep mixers; the actual parameters are overwritten at build */ |
160 | static struct snd_kcontrol_new ad_beep_mixer[] = { | 160 | static struct snd_kcontrol_new ad_beep_mixer[] = { |
161 | HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), | 161 | HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), |
162 | HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_OUTPUT), | 162 | HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT), |
163 | { } /* end */ | 163 | { } /* end */ |
164 | }; | 164 | }; |
165 | 165 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 49de107db16b..8c04e0e0f655 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -2413,7 +2413,7 @@ static void alc_free_kctls(struct hda_codec *codec); | |||
2413 | /* additional beep mixers; the actual parameters are overwritten at build */ | 2413 | /* additional beep mixers; the actual parameters are overwritten at build */ |
2414 | static struct snd_kcontrol_new alc_beep_mixer[] = { | 2414 | static struct snd_kcontrol_new alc_beep_mixer[] = { |
2415 | HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), | 2415 | HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), |
2416 | HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT), | 2416 | HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), |
2417 | { } /* end */ | 2417 | { } /* end */ |
2418 | }; | 2418 | }; |
2419 | 2419 | ||
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8d65d2b25234..87ba239ff1c9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -2648,6 +2648,7 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, | |||
2648 | enum { | 2648 | enum { |
2649 | STAC_CTL_WIDGET_VOL, | 2649 | STAC_CTL_WIDGET_VOL, |
2650 | STAC_CTL_WIDGET_MUTE, | 2650 | STAC_CTL_WIDGET_MUTE, |
2651 | STAC_CTL_WIDGET_MUTE_BEEP, | ||
2651 | STAC_CTL_WIDGET_MONO_MUX, | 2652 | STAC_CTL_WIDGET_MONO_MUX, |
2652 | STAC_CTL_WIDGET_HP_SWITCH, | 2653 | STAC_CTL_WIDGET_HP_SWITCH, |
2653 | STAC_CTL_WIDGET_IO_SWITCH, | 2654 | STAC_CTL_WIDGET_IO_SWITCH, |
@@ -2658,6 +2659,7 @@ enum { | |||
2658 | static struct snd_kcontrol_new stac92xx_control_templates[] = { | 2659 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
2659 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 2660 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
2660 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 2661 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
2662 | HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0), | ||
2661 | STAC_MONO_MUX, | 2663 | STAC_MONO_MUX, |
2662 | STAC_CODEC_HP_SWITCH(NULL), | 2664 | STAC_CODEC_HP_SWITCH(NULL), |
2663 | STAC_CODEC_IO_SWITCH(NULL, 0), | 2665 | STAC_CODEC_IO_SWITCH(NULL, 0), |
@@ -3221,11 +3223,14 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, | |||
3221 | { | 3223 | { |
3222 | struct sigmatel_spec *spec = codec->spec; | 3224 | struct sigmatel_spec *spec = codec->spec; |
3223 | u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); | 3225 | u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); |
3224 | int err; | 3226 | int err, type = STAC_CTL_WIDGET_MUTE_BEEP; |
3227 | |||
3228 | if (spec->anabeep_nid == nid) | ||
3229 | type = STAC_CTL_WIDGET_MUTE; | ||
3225 | 3230 | ||
3226 | /* check for mute support for the the amp */ | 3231 | /* check for mute support for the the amp */ |
3227 | if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { | 3232 | if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { |
3228 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, | 3233 | err = stac92xx_add_control(spec, type, |
3229 | "Beep Playback Switch", | 3234 | "Beep Playback Switch", |
3230 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); | 3235 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); |
3231 | if (err < 0) | 3236 | if (err < 0) |
@@ -3258,12 +3263,7 @@ static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol, | |||
3258 | struct snd_ctl_elem_value *ucontrol) | 3263 | struct snd_ctl_elem_value *ucontrol) |
3259 | { | 3264 | { |
3260 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 3265 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
3261 | int enabled = !!ucontrol->value.integer.value[0]; | 3266 | return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); |
3262 | if (codec->beep->enabled != enabled) { | ||
3263 | codec->beep->enabled = enabled; | ||
3264 | return 1; | ||
3265 | } | ||
3266 | return 0; | ||
3267 | } | 3267 | } |
3268 | 3268 | ||
3269 | static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { | 3269 | static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { |