From: Jaroslav Kysela <perex@perex.cz>
Date: Tue, 3 Nov 2009 13:29:50 +0000 (+0100)
Subject: ALSA: hda_intel: Digital PC Beep - delay input device unregistration
X-Git-Tag: firefly_0821_release~9833^2~3540^2~5^2~67
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=13dab0808bb41b18888e1758a060a685deee1f30;p=firefly-linux-kernel-4.4.55.git

ALSA: hda_intel: Digital PC Beep - delay input device unregistration

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>
---

diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 0e986537d570..74db40edb336 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -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);
 
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index 68465f679d8c..53eba8d8414d 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -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;
 };