summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_beep.c
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2009-10-21 14:48:23 +0200
committerTakashi Iwai <tiwai@suse.de>2009-11-16 11:34:41 +0100
commit123c07aeddd71fbb295842a8c19866e780b9a100 (patch)
tree8b97495608cad55f9169a826fe4637f9ac2d21c3 /sound/pci/hda/hda_beep.c
parentfe705ab1526bc2c8b7756f3a855f040ab2060af2 (diff)
downloadlinux-123c07aeddd71fbb295842a8c19866e780b9a100.tar.gz
linux-123c07aeddd71fbb295842a8c19866e780b9a100.tar.bz2
linux-123c07aeddd71fbb295842a8c19866e780b9a100.zip
ALSA: hda_intel: Digital PC Beep - change behaviour for input layer
Original implementation was keeping registered input device for SND_BEEP and SND_TONE events all time. This patch changes this behaviour: If digital PC Beep is turned off using universal control switch, the input device is unregistered. Explanation: The kd_mksound() send SND_BEEP and SND_TONE only to last registered device acceping those events. It means that the HDA Intel audio driver blocks also the internal PC Speaker device (pcspkr.c driver) even if the HDA Beep is muted. The user can easy disable all beeps using 'setterm -blength 0' or 'xset b off' command. Signed-off-by: Jaroslav Kysela <perex@perex.cz> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_beep.c')
-rw-r--r--sound/pci/hda/hda_beep.c88
1 files changed, 70 insertions, 18 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,
return 0;
}
-int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
+static void snd_hda_do_detach(struct hda_beep *beep)
+{
+ input_unregister_device(beep->dev);
+ beep->dev = NULL;
+ cancel_work_sync(&beep->beep_work);
+ /* turn off beep for sure */
+ snd_hda_codec_write_cache(beep->codec, beep->nid, 0,
+ AC_VERB_SET_BEEP_CONTROL, 0);
+}
+
+static int snd_hda_do_attach(struct hda_beep *beep)
{
struct input_dev *input_dev;
- struct hda_beep *beep;
+ struct hda_codec *codec = beep->codec;
int err;
- if (!snd_hda_get_bool_hint(codec, "beep"))
- return 0; /* disabled explicitly */
-
- beep = kzalloc(sizeof(*beep), GFP_KERNEL);
- if (beep == NULL)
- return -ENOMEM;
- snprintf(beep->phys, sizeof(beep->phys),
- "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
input_dev = input_allocate_device();
if (!input_dev) {
- kfree(beep);
+ printk(KERN_INFO "hda_beep: unable to allocate input device\n");
return -ENOMEM;
}
@@ -151,21 +153,71 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
err = input_register_device(input_dev);
if (err < 0) {
input_free_device(input_dev);
- kfree(beep);
+ printk(KERN_INFO "hda_beep: unable to register input device\n");
return err;
}
+ beep->dev = input_dev;
+ return 0;
+}
+
+static void snd_hda_do_register(struct work_struct *work)
+{
+ struct hda_beep *beep =
+ container_of(work, struct hda_beep, register_work);
+ int request;
+
+ mutex_lock(&beep->mutex);
+ request = beep->request_enable;
+ if (beep->enabled != request) {
+ if (!request) {
+ snd_hda_do_detach(beep);
+ } else {
+ if (snd_hda_do_attach(beep) < 0)
+ goto __out;
+ }
+ beep->enabled = request;
+ }
+ __out:
+ mutex_unlock(&beep->mutex);
+}
+
+int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
+{
+ struct hda_beep *beep = codec->beep;
+ enable = !!enable;
+ if (beep && beep->enabled != enable) {
+ beep->request_enable = enable;
+ schedule_work(&beep->register_work);
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device);
+
+int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
+{
+ struct hda_beep *beep;
+
+ if (!snd_hda_get_bool_hint(codec, "beep"))
+ return 0; /* disabled explicitly */
+ beep = kzalloc(sizeof(*beep), GFP_KERNEL);
+ if (beep == NULL)
+ return -ENOMEM;
+ snprintf(beep->phys, sizeof(beep->phys),
+ "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
/* enable linear scale */
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_DIGI_CONVERT_2, 0x01);
beep->nid = nid;
- beep->dev = input_dev;
beep->codec = codec;
- beep->enabled = 1;
codec->beep = beep;
+ INIT_WORK(&beep->register_work, &snd_hda_do_register);
INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
+ mutex_init(&beep->mutex);
+
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device);
@@ -174,11 +226,11 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
{
struct hda_beep *beep = codec->beep;
if (beep) {
- cancel_work_sync(&beep->beep_work);
-
- input_unregister_device(beep->dev);
- kfree(beep);
+ cancel_work_sync(&beep->register_work);
+ if (beep->enabled)
+ snd_hda_do_detach(beep);
codec->beep = NULL;
+ kfree(beep);
}
}
EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);