From: Alexandre Ratchov 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 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; }