aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/hda_beep.c88
-rw-r--r--sound/pci/hda/hda_beep.h4
-rw-r--r--sound/pci/hda/hda_codec.c12
-rw-r--r--sound/pci/hda/hda_local.h15
-rw-r--r--sound/pci/hda/patch_analog.c2
-rw-r--r--sound/pci/hda/patch_realtek.c2
-rw-r--r--sound/pci/hda/patch_sigmatel.c16
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
116int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) 116static 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
126static 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
163static 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
184int 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}
195EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device);
196
197int 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}
171EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); 223EXPORT_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}
184EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); 236EXPORT_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
43int snd_hda_enable_beep_device(struct hda_codec *codec, int enable);
40int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); 44int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
41void snd_hda_detach_beep_device(struct hda_codec *codec); 45void 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}
1735EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); 1736EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put);
1736 1737
1738int 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}
1747EXPORT_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
70int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, 83int 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);
82int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, 95int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
83 struct snd_ctl_elem_value *ucontrol); 96 struct snd_ctl_elem_value *ucontrol);
97int 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 */
85int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, 100int 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 */
160static struct snd_kcontrol_new ad_beep_mixer[] = { 160static 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 */
2414static struct snd_kcontrol_new alc_beep_mixer[] = { 2414static 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,
2648enum { 2648enum {
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 {
2658static struct snd_kcontrol_new stac92xx_control_templates[] = { 2659static 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
3269static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { 3269static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {