]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ALSA: scarlett2: Fix 2i2 Gen 4 direct monitor gain on firmware 2417
authorGeoffrey D. Bennett <g@b4.vu>
Sat, 23 May 2026 21:04:14 +0000 (06:34 +0930)
committerTakashi Iwai <tiwai@suse.de>
Mon, 25 May 2026 07:24:56 +0000 (09:24 +0200)
Firmware 2417 for the Scarlett 4th Gen 2i2 moved the direct monitor
gain parameter by 4 bytes, from offset 0x2a0 to 0x2a4, breaking the
"Direct Monitor X Mix Y" controls.

Special-case the offset in the get/set config helpers when the
running firmware is 2417 or later.

Fixes: 4e809a299677 ("ALSA: scarlett2: Add support for Solo, 2i2, and 4i4 Gen 4")
Cc: <stable@vger.kernel.org>
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://patch.msgid.link/ahIWTueUlWA5xiV+@m.b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/mixer_scarlett2.c

index 8e80a7165faf22c025d9928664c2f829dfa48cca..a4fac46522013940e1e09358d6a2831fda49d69a 100644 (file)
@@ -2504,6 +2504,27 @@ static int scarlett2_has_config_item(
        return !!private->config_set->items[config_item_num].offset;
 }
 
+/* Return the configuration item's offset, applying any per-firmware
+ * overrides.
+ *
+ * Firmware 2417 for the 2i2 Gen 4 moved DIRECT_MONITOR_GAIN by 4
+ * bytes. Apply that shift here so that the rest of the driver can
+ * keep using the single config set. This override can be removed
+ * once the multi-config-set framework lands.
+ */
+static int scarlett2_config_item_offset(
+       struct scarlett2_data *private, int config_item_num)
+{
+       int offset = private->config_set->items[config_item_num].offset;
+
+       if (config_item_num == SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN &&
+           private->info == &s2i2_gen4_info &&
+           private->firmware_version >= 2417)
+               offset = 0x2a4;
+
+       return offset;
+}
+
 /* Send a USB message to get configuration parameters; result placed in *buf */
 static int scarlett2_usb_get_config(
        struct usb_mixer_interface *mixer,
@@ -2513,6 +2534,7 @@ static int scarlett2_usb_get_config(
        const struct scarlett2_config *config_item =
                &private->config_set->items[config_item_num];
        int size, err, i;
+       int item_offset;
        u8 *buf_8;
        u8 value;
 
@@ -2522,13 +2544,15 @@ static int scarlett2_usb_get_config(
        if (!config_item->offset)
                return -EFAULT;
 
+       item_offset = scarlett2_config_item_offset(private, config_item_num);
+
        /* Writes to the parameter buffer are always 1 byte */
        size = config_item->size ? config_item->size : 8;
 
        /* For byte-sized parameters, retrieve directly into buf */
        if (size >= 8) {
                size = size / 8 * count;
-               err = scarlett2_usb_get(mixer, config_item->offset, buf, size);
+               err = scarlett2_usb_get(mixer, item_offset, buf, size);
                if (err < 0)
                        return err;
                if (config_item->size == 16) {
@@ -2546,7 +2570,7 @@ static int scarlett2_usb_get_config(
        }
 
        /* For bit-sized parameters, retrieve into value */
-       err = scarlett2_usb_get(mixer, config_item->offset, &value, 1);
+       err = scarlett2_usb_get(mixer, item_offset, &value, 1);
        if (err < 0)
                return err;
 
@@ -2696,7 +2720,8 @@ static int scarlett2_usb_set_config(
         */
        if (config_item->size >= 8) {
                size = config_item->size / 8;
-               offset = config_item->offset + index * size;
+               offset = scarlett2_config_item_offset(private, config_item_num) +
+                        index * size;
 
        /* If updating a bit, retrieve the old value, set/clear the
         * bit as needed, and update value
@@ -2705,7 +2730,7 @@ static int scarlett2_usb_set_config(
                u8 tmp;
 
                size = 1;
-               offset = config_item->offset;
+               offset = scarlett2_config_item_offset(private, config_item_num);
 
                err = scarlett2_usb_get(mixer, offset, &tmp, 1);
                if (err < 0)