mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
ALSA: caiaq: Fix control_put() result and cache rollback
commita3542d1b30upstream. control_put() always returns 1 and updates cdev->control_state[] before sending the USB command. It also ignores transport errors from usb_bulk_msg(), snd_usb_caiaq_send_command(), and snd_usb_caiaq_send_command_bank(). That breaks the ALSA .put() contract and can leave control_get() reporting a cached value the device never accepted. Return 0 for unchanged values, propagate transport failures, and restore the cached byte when the write fails. Fixes:8e3cd08ed8("[ALSA] caiaq - add control API and more input features") Cc: stable@vger.kernel.org Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com> Link: https://patch.msgid.link/20260417-caiaq-control-put-v1-1-c37826e92447@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
e794e1763e
commit
f4dfbdc1be
+36
-16
@@ -87,6 +87,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card);
|
||||
int pos = kcontrol->private_value;
|
||||
int v = ucontrol->value.integer.value[0];
|
||||
int ret;
|
||||
unsigned char cmd;
|
||||
|
||||
switch (cdev->chip.usb_id) {
|
||||
@@ -103,6 +104,10 @@ static int control_put(struct snd_kcontrol *kcontrol,
|
||||
|
||||
if (pos & CNT_INTVAL) {
|
||||
int i = pos & ~CNT_INTVAL;
|
||||
unsigned char old = cdev->control_state[i];
|
||||
|
||||
if (old == v)
|
||||
return 0;
|
||||
|
||||
cdev->control_state[i] = v;
|
||||
|
||||
@@ -113,10 +118,11 @@ static int control_put(struct snd_kcontrol *kcontrol,
|
||||
cdev->ep8_out_buf[0] = i;
|
||||
cdev->ep8_out_buf[1] = v;
|
||||
|
||||
usb_bulk_msg(cdev->chip.dev,
|
||||
usb_sndbulkpipe(cdev->chip.dev, 8),
|
||||
cdev->ep8_out_buf, sizeof(cdev->ep8_out_buf),
|
||||
&actual_len, 200);
|
||||
ret = usb_bulk_msg(cdev->chip.dev,
|
||||
usb_sndbulkpipe(cdev->chip.dev, 8),
|
||||
cdev->ep8_out_buf,
|
||||
sizeof(cdev->ep8_out_buf),
|
||||
&actual_len, 200);
|
||||
} else if (cdev->chip.usb_id ==
|
||||
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) {
|
||||
|
||||
@@ -128,21 +134,36 @@ static int control_put(struct snd_kcontrol *kcontrol,
|
||||
offset = MASCHINE_BANK_SIZE;
|
||||
}
|
||||
|
||||
snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
|
||||
cdev->control_state + offset,
|
||||
MASCHINE_BANK_SIZE);
|
||||
ret = snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
|
||||
cdev->control_state + offset,
|
||||
MASCHINE_BANK_SIZE);
|
||||
} else {
|
||||
snd_usb_caiaq_send_command(cdev, cmd,
|
||||
cdev->control_state, sizeof(cdev->control_state));
|
||||
ret = snd_usb_caiaq_send_command(cdev, cmd,
|
||||
cdev->control_state,
|
||||
sizeof(cdev->control_state));
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
cdev->control_state[i] = old;
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
if (v)
|
||||
cdev->control_state[pos / 8] |= 1 << (pos % 8);
|
||||
else
|
||||
cdev->control_state[pos / 8] &= ~(1 << (pos % 8));
|
||||
int idx = pos / 8;
|
||||
unsigned char mask = 1 << (pos % 8);
|
||||
unsigned char old = cdev->control_state[idx];
|
||||
unsigned char val = v ? (old | mask) : (old & ~mask);
|
||||
|
||||
snd_usb_caiaq_send_command(cdev, cmd,
|
||||
cdev->control_state, sizeof(cdev->control_state));
|
||||
if (old == val)
|
||||
return 0;
|
||||
|
||||
cdev->control_state[idx] = val;
|
||||
ret = snd_usb_caiaq_send_command(cdev, cmd,
|
||||
cdev->control_state,
|
||||
sizeof(cdev->control_state));
|
||||
if (ret < 0) {
|
||||
cdev->control_state[idx] = old;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -640,4 +661,3 @@ int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user