Index | Thread | Search

From:
Alexandre Ratchov <alex@caoua.org>
Subject:
audio(4): postpone volume changes to the end of DVACT_WAKEUP
To:
tech@openbsd.org
Date:
Tue, 13 Aug 2024 15:11:26 +0200

Download raw body.

Thread
During DVACT_WAKEUP, acpithinkpad(4) restores the speaker mute control
using the wskbd interface with a value obtained from the acpi
controller. As the audio(4) driver saves and restores the full mixer
state, the mute control is overwritten with the value saved during
suspend, which is not acpithinkpad(4)'s intent.

As both saved and acpithinkpad states are the same most (all?) of the
time the problems stays unnoticed, but let's fix it.

So, postpone changes with the wskbd interface until the end of the
mixer's DVACT_WAKEUP section of audio(4).

OK?

Index: audio.c
===================================================================
RCS file: /cvs/src/sys/dev/audio.c,v
diff -u -p -r1.207 audio.c
--- audio.c	7 Jun 2024 08:48:10 -0000	1.207
+++ audio.c	13 Aug 2024 12:48:16 -0000
@@ -1323,6 +1323,12 @@ audio_activate(struct device *self, int 
 			audio_stop_do(sc);
 
 		/*
+		 * prevent keyboard keys from touching the controls
+		 */
+		if (task_del(systq, &sc->wskbd_task))
+			device_unref(&sc->dev);
+
+		/*
 		 * save mixer state
 		 */
 		for (i = 0; i != sc->mix_nent; i++)
@@ -1349,6 +1355,13 @@ audio_activate(struct device *self, int 
 		sc->quiesce = 0;
 		wakeup(&sc->quiesce);
 
+		/*
+		 * run the wskbd task (changes can be scheduled during sleep)
+		 */
+		device_ref(&sc->dev);
+		if (!task_add(systq, &sc->wskbd_task))
+			device_unref(&sc->dev);
+
 		if (sc->mode != 0) {
 			if (audio_setpar(sc) != 0)
 				break;
@@ -2440,7 +2453,7 @@ wskbd_set_mixermute(long mute, long out)
 		return ENODEV;
 	vol = out ? &sc->spkr : &sc->mic;
 	vol->mute_pending = mute ? WSKBD_MUTE_ENABLE : WSKBD_MUTE_DISABLE;
-	if (!task_add(systq, &sc->wskbd_task))
+	if (sc->quiesce || !task_add(systq, &sc->wskbd_task))
 		device_unref(&sc->dev);
 	return 0;
 }
@@ -2494,7 +2507,7 @@ wskbd_set_mixervolume_unit(int unit, lon
 		vol->mute_pending ^= WSKBD_MUTE_TOGGLE;
 	else
 		vol->val_pending += dir;
-	if (!task_add(systq, &sc->wskbd_task))
+	if (sc->quiesce || !task_add(systq, &sc->wskbd_task))
 		device_unref(&sc->dev);
 	return 0;
 }