ALSA: hda_intel: Digital PC Beep - delay input device unregistration
authorJaroslav Kysela <perex@perex.cz>
Tue, 3 Nov 2009 13:29:50 +0000 (14:29 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 16 Nov 2009 10:35:00 +0000 (11:35 +0100)
The massive register/unregister calls for input device layer might be
overkill. Delay unregister call by one HZ as workaround.

Also, as benefit, beep->enabled variable is changed immediately now
(not from workqueue).

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_beep.h

index 0e986537d570340408bba4ec79453f347618927a..74db40edb336e4163f4157d06c42e6e22fdee855 100644 (file)
@@ -164,20 +164,21 @@ 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:
+       if (beep->enabled && !beep->dev)
+               snd_hda_do_attach(beep);
+       mutex_unlock(&beep->mutex);
+}
+
+static void snd_hda_do_unregister(struct work_struct *work)
+{
+       struct hda_beep *beep =
+               container_of(work, struct hda_beep, unregister_work.work);
+
+       mutex_lock(&beep->mutex);
+       if (!beep->enabled && beep->dev)
+               snd_hda_do_detach(beep);
        mutex_unlock(&beep->mutex);
 }
 
@@ -185,9 +186,19 @@ 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);
+       if (beep == NULL)
+               return 0;
+       if (beep->enabled != enable) {
+               beep->enabled = enable;
+               if (enable) {
+                       cancel_delayed_work(&beep->unregister_work);
+                       schedule_work(&beep->register_work);
+               } else {
+                       /* turn off beep */
+                       snd_hda_codec_write_cache(beep->codec, beep->nid, 0,
+                                                 AC_VERB_SET_BEEP_CONTROL, 0);
+                       schedule_delayed_work(&beep->unregister_work, HZ);
+               }
                return 1;
        }
        return 0;
@@ -215,6 +226,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
        codec->beep = beep;
 
        INIT_WORK(&beep->register_work, &snd_hda_do_register);
+       INIT_DELAYED_WORK(&beep->unregister_work, &snd_hda_do_unregister);
        INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
        mutex_init(&beep->mutex);
 
index 68465f679d8c688c889dc743213c3a8482c76730..53eba8d8414d6385de7a3f8cb72b95cea374821b 100644 (file)
@@ -34,7 +34,8 @@ struct hda_beep {
        unsigned int enabled:1;
        unsigned int request_enable:1;
        unsigned int linear_tone:1;     /* linear tone for IDT/STAC codec */
-       struct work_struct register_work; /* scheduled task for beep event */
+       struct work_struct register_work; /* registration work */
+       struct delayed_work unregister_work; /* unregistration work */
        struct work_struct beep_work; /* scheduled task for beep event */
        struct mutex mutex;
 };