public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures
@ 2026-04-29 13:20 Cássio Gabriel
  2026-04-29 13:20 ` [PATCH 1/2] ALSA: usb-audio: Roll back quirk control caches on write errors Cássio Gabriel
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Cássio Gabriel @ 2026-04-29 13:20 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Thomas Ebeling, Ian Douglas Scott, Jaroslav Kysela, linux-sound,
	linux-kernel, Cássio Gabriel, stable

This series fixes stale software cache handling in several usb-audio
mixer quirks.

A number of quirk callbacks update kcontrol->private_value before
issuing vendor or class writes. When such a write fails, the driver can
keep reporting and later replaying a value the device never accepted,
because the corresponding get and resume paths consume the cached state.

- Patch 1 fixes the simple single-write quirk callbacks by restoring the
  previous cache on error.
- Patch 2 fixes the RME Babyface Pro packed-state callbacks by updating
  the cache only after a successful write, since those helpers already
  take explicit arguments and do not need private_value to be updated
  before the USB request.

The split keeps the generic quirk fixes separate from the Babyface Pro
packed-state logic and keeps each patch tied to its own introducing bug.

Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
---
Cássio Gabriel (2):
      ALSA: usb-audio: Roll back quirk control caches on write errors
      ALSA: usb-audio: Update Babyface Pro control caches only after successful writes

 sound/usb/mixer_quirks.c | 61 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 47 insertions(+), 14 deletions(-)
---
base-commit: 7b04e87c2a10db9c65b3133949bbe1b738b6ed7e
change-id: 20260418-alsa-usb-quirks-cache-rollback-43a07052f22c

Best regards,
--  
Cássio Gabriel <cassiogabrielcontato@gmail.com>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] ALSA: usb-audio: Roll back quirk control caches on write errors
  2026-04-29 13:20 [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures Cássio Gabriel
@ 2026-04-29 13:20 ` Cássio Gabriel
  2026-04-29 13:20 ` [PATCH 2/2] ALSA: usb-audio: Update Babyface Pro control caches only after successful writes Cássio Gabriel
  2026-04-29 15:16 ` [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures Takashi Iwai
  2 siblings, 0 replies; 4+ messages in thread
From: Cássio Gabriel @ 2026-04-29 13:20 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Thomas Ebeling, Ian Douglas Scott, Jaroslav Kysela, linux-sound,
	linux-kernel, Cássio Gabriel, stable

Several mixer quirk callbacks cache the requested
control value in kcontrol->private_value before
issuing a single vendor or class write.

Their paired get and resume paths consume that cache
directly, so a failed write currently leaves software
state changed even though the update did not succeed.
That can make later reads report a value the device
never accepted and can replay the stale cache on resume.

Restore the previous cached value on failure in
the Audigy2NX LED, Emu0204 channel switch,
Xonar U1 output switch, Native Instruments controls,
FTU effect program switch, and Sound Blaster E1 input source switch.

Fixes: 9cf3689bfe07 ("ALSA: usb-audio: Add audigy2nx resume support")
Fixes: 5f503ee9e270 ("ALSA: usb-audio: Add Emu0204 channel switch resume support")
Fixes: 2bfb14c3b8fb ("ALSA: usb-audio: Add Xonar U1 resume support")
Fixes: da6d276957ea ("ALSA: usb-audio: Add resume support for Native Instruments controls")
Fixes: 0b4e9cfcef05 ("ALSA: usb-audio: Add resume support for FTU controls")
Fixes: 388fdb8f882a ("ALSA: usb-audio: Support changing input on Sound Blaster E1")
Cc: stable@vger.kernel.org
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
---
 sound/usb/mixer_quirks.c | 45 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 1bdaa46d4fe1..229be55e9158 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -333,6 +333,7 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol,
 	int index = kcontrol->private_value & 0xff;
 	unsigned int value = ucontrol->value.integer.value[0];
 	int old_value = kcontrol->private_value >> 8;
+	unsigned long old_pval = kcontrol->private_value;
 	int err;
 
 	if (value > 1)
@@ -341,7 +342,11 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol,
 		return 0;
 	kcontrol->private_value = (value << 8) | index;
 	err = snd_audigy2nx_led_update(mixer, value, index);
-	return err < 0 ? err : 1;
+	if (err < 0) {
+		kcontrol->private_value = old_pval;
+		return err;
+	}
+	return 1;
 }
 
 static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list)
@@ -487,6 +492,7 @@ static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
 	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
 	struct usb_mixer_interface *mixer = list->mixer;
 	unsigned int value = ucontrol->value.enumerated.item[0];
+	unsigned long old_pval = kcontrol->private_value;
 	int err;
 
 	if (value > 1)
@@ -497,7 +503,11 @@ static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
 
 	kcontrol->private_value = value;
 	err = snd_emu0204_ch_switch_update(mixer, value);
-	return err < 0 ? err : 1;
+	if (err < 0) {
+		kcontrol->private_value = old_pval;
+		return err;
+	}
+	return 1;
 }
 
 static int snd_emu0204_ch_switch_resume(struct usb_mixer_elem_list *list)
@@ -821,7 +831,11 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
 
 	kcontrol->private_value = new_status;
 	err = snd_xonar_u1_switch_update(list->mixer, new_status);
-	return err < 0 ? err : 1;
+	if (err < 0) {
+		kcontrol->private_value = old_status;
+		return err;
+	}
+	return 1;
 }
 
 static int snd_xonar_u1_switch_resume(struct usb_mixer_elem_list *list)
@@ -1159,7 +1173,8 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
 					     struct snd_ctl_elem_value *ucontrol)
 {
 	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
-	u8 oldval = (kcontrol->private_value >> 24) & 0xff;
+	unsigned long old_pval = kcontrol->private_value;
+	u8 oldval = (old_pval >> 24) & 0xff;
 	u8 newval = ucontrol->value.integer.value[0];
 	int err;
 
@@ -1169,7 +1184,11 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
 	kcontrol->private_value &= ~(0xff << 24);
 	kcontrol->private_value |= (unsigned int)newval << 24;
 	err = snd_ni_update_cur_val(list);
-	return err < 0 ? err : 1;
+	if (err < 0) {
+		kcontrol->private_value = old_pval;
+		return err;
+	}
+	return 1;
 }
 
 static const struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
@@ -1324,7 +1343,8 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
 				  struct snd_ctl_elem_value *ucontrol)
 {
 	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
-	unsigned int pval = list->kctl->private_value;
+	unsigned long old_pval = list->kctl->private_value;
+	unsigned int pval = old_pval;
 	int cur_val, err, new_val;
 
 	cur_val = pval >> 24;
@@ -1335,7 +1355,11 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
 	kctl->private_value &= ~(0xff << 24);
 	kctl->private_value |= new_val << 24;
 	err = snd_ftu_eff_switch_update(list);
-	return err < 0 ? err : 1;
+	if (err < 0) {
+		kctl->private_value = old_pval;
+		return err;
+	}
+	return 1;
 }
 
 static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer,
@@ -2114,13 +2138,18 @@ static int snd_soundblaster_e1_switch_put(struct snd_kcontrol *kcontrol,
 {
 	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
 	unsigned char value = !!ucontrol->value.integer.value[0];
+	unsigned long old_pval = kcontrol->private_value;
 	int err;
 
 	if (kcontrol->private_value == value)
 		return 0;
 	kcontrol->private_value = value;
 	err = snd_soundblaster_e1_switch_update(list->mixer, value);
-	return err < 0 ? err : 1;
+	if (err < 0) {
+		kcontrol->private_value = old_pval;
+		return err;
+	}
+	return 1;
 }
 
 static int snd_soundblaster_e1_switch_resume(struct usb_mixer_elem_list *list)

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] ALSA: usb-audio: Update Babyface Pro control caches only after successful writes
  2026-04-29 13:20 [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures Cássio Gabriel
  2026-04-29 13:20 ` [PATCH 1/2] ALSA: usb-audio: Roll back quirk control caches on write errors Cássio Gabriel
@ 2026-04-29 13:20 ` Cássio Gabriel
  2026-04-29 15:16 ` [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures Takashi Iwai
  2 siblings, 0 replies; 4+ messages in thread
From: Cássio Gabriel @ 2026-04-29 13:20 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Thomas Ebeling, Ian Douglas Scott, Jaroslav Kysela, linux-sound,
	linux-kernel, Cássio Gabriel, stable

snd_bbfpro_ctl_put() and snd_bbfpro_vol_put()
cache the requested packed control state in
kcontrol->private_value before issuing the USB write.

Their get and resume paths use that cached value directly,
so a failed write can leave the driver reporting and later
replaying a setting the hardware never accepted.

Update the cached state only after a successful USB write.

Fixes: 3e8f3bd04716 ("ALSA: usb-audio: RME Babyface Pro mixer patch")
Cc: stable@vger.kernel.org
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
---
 sound/usb/mixer_quirks.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 229be55e9158..99975c3240a5 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -3027,12 +3027,14 @@ static int snd_bbfpro_ctl_put(struct snd_kcontrol *kcontrol,
 	if (val == old_value)
 		return 0;
 
+	err = snd_bbfpro_ctl_update(mixer, reg, idx, val);
+	if (err < 0)
+		return err;
+
 	kcontrol->private_value = reg
 		| ((idx & SND_BBFPRO_CTL_IDX_MASK) << SND_BBFPRO_CTL_IDX_SHIFT)
 		| ((val & SND_BBFPRO_CTL_VAL_MASK) << SND_BBFPRO_CTL_VAL_SHIFT);
-
-	err = snd_bbfpro_ctl_update(mixer, reg, idx, val);
-	return err < 0 ? err : 1;
+	return 1;
 }
 
 static int snd_bbfpro_ctl_resume(struct usb_mixer_elem_list *list)
@@ -3217,11 +3219,13 @@ static int snd_bbfpro_vol_put(struct snd_kcontrol *kcontrol,
 
 	new_val = uvalue & SND_BBFPRO_MIXER_VAL_MASK;
 
+	err = snd_bbfpro_vol_update(mixer, idx, new_val);
+	if (err < 0)
+		return err;
+
 	kcontrol->private_value = idx
 		| (new_val << SND_BBFPRO_MIXER_VAL_SHIFT);
-
-	err = snd_bbfpro_vol_update(mixer, idx, new_val);
-	return err < 0 ? err : 1;
+	return 1;
 }
 
 static int snd_bbfpro_vol_resume(struct usb_mixer_elem_list *list)

-- 
2.54.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures
  2026-04-29 13:20 [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures Cássio Gabriel
  2026-04-29 13:20 ` [PATCH 1/2] ALSA: usb-audio: Roll back quirk control caches on write errors Cássio Gabriel
  2026-04-29 13:20 ` [PATCH 2/2] ALSA: usb-audio: Update Babyface Pro control caches only after successful writes Cássio Gabriel
@ 2026-04-29 15:16 ` Takashi Iwai
  2 siblings, 0 replies; 4+ messages in thread
From: Takashi Iwai @ 2026-04-29 15:16 UTC (permalink / raw)
  To: Cássio Gabriel
  Cc: Takashi Iwai, Thomas Ebeling, Ian Douglas Scott, Jaroslav Kysela,
	linux-sound, linux-kernel, stable

On Wed, 29 Apr 2026 15:20:00 +0200,
Cássio Gabriel wrote:
> 
> This series fixes stale software cache handling in several usb-audio
> mixer quirks.
> 
> A number of quirk callbacks update kcontrol->private_value before
> issuing vendor or class writes. When such a write fails, the driver can
> keep reporting and later replaying a value the device never accepted,
> because the corresponding get and resume paths consume the cached state.
> 
> - Patch 1 fixes the simple single-write quirk callbacks by restoring the
>   previous cache on error.
> - Patch 2 fixes the RME Babyface Pro packed-state callbacks by updating
>   the cache only after a successful write, since those helpers already
>   take explicit arguments and do not need private_value to be updated
>   before the USB request.
> 
> The split keeps the generic quirk fixes separate from the Babyface Pro
> packed-state logic and keeps each patch tied to its own introducing bug.
> 
> Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
> ---
> Cássio Gabriel (2):
>       ALSA: usb-audio: Roll back quirk control caches on write errors
>       ALSA: usb-audio: Update Babyface Pro control caches only after successful writes

Applied both to for-next branch.  Thanks.


Takashi

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-04-29 15:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-29 13:20 [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures Cássio Gabriel
2026-04-29 13:20 ` [PATCH 1/2] ALSA: usb-audio: Roll back quirk control caches on write errors Cássio Gabriel
2026-04-29 13:20 ` [PATCH 2/2] ALSA: usb-audio: Update Babyface Pro control caches only after successful writes Cássio Gabriel
2026-04-29 15:16 ` [PATCH 0/2] ALSA: usb-audio: Fix stale quirk control caches after write failures Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox