summaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorGeoffrey D. Bennett <g@b4.vu>2021-06-23 02:32:25 +0930
committerTakashi Iwai <tiwai@suse.de>2021-06-22 21:42:24 +0200
commit9e15fae6c51a362418f8b3054f1322c54675df94 (patch)
tree9a3565c4d851a66d725ebaa092e9c46de4afa406 /sound/usb
parent8aea2e32a9e3c3a685dc6f3f7d58fbbd6263a857 (diff)
downloadlinux-9e15fae6c51a362418f8b3054f1322c54675df94.tar.bz2
ALSA: usb-audio: scarlett2: Allow bit-level access to config
Add support for accessing configuration values when multiple values are stored in one byte. Needed by the upcoming Solo and 2i2 Gen 3 support. Signed-off-by: Geoffrey D. Bennett <g@b4.vu> Link: https://lore.kernel.org/r/4e54e9e106ec7029c1a668c51b4fc769a7eb4ed0.1624379707.git.g@b4.vu Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/mixer_scarlett_gen2.c68
1 files changed, 55 insertions, 13 deletions
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 7a5346c68603..08e7b687484e 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -814,7 +814,7 @@ enum {
};
/* Location, size, and activation command number for the configuration
- * parameters
+ * parameters. Size is in bits and may be 1, 8, or 16.
*/
struct scarlett2_config {
u8 offset;
@@ -825,25 +825,25 @@ struct scarlett2_config {
static const struct scarlett2_config
scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = {
[SCARLETT2_CONFIG_DIM_MUTE] = {
- .offset = 0x31, .size = 1, .activate = 2 },
+ .offset = 0x31, .size = 8, .activate = 2 },
[SCARLETT2_CONFIG_LINE_OUT_VOLUME] = {
- .offset = 0x34, .size = 2, .activate = 1 },
+ .offset = 0x34, .size = 16, .activate = 1 },
[SCARLETT2_CONFIG_MUTE_SWITCH] = {
- .offset = 0x5c, .size = 1, .activate = 1 },
+ .offset = 0x5c, .size = 8, .activate = 1 },
[SCARLETT2_CONFIG_SW_HW_SWITCH] = {
- .offset = 0x66, .size = 1, .activate = 3 },
+ .offset = 0x66, .size = 8, .activate = 3 },
[SCARLETT2_CONFIG_LEVEL_SWITCH] = {
- .offset = 0x7c, .size = 1, .activate = 7 },
+ .offset = 0x7c, .size = 8, .activate = 7 },
[SCARLETT2_CONFIG_PAD_SWITCH] = {
- .offset = 0x84, .size = 1, .activate = 8 },
+ .offset = 0x84, .size = 8, .activate = 8 },
[SCARLETT2_CONFIG_MSD_SWITCH] = {
- .offset = 0x9d, .size = 1, .activate = 6 },
+ .offset = 0x9d, .size = 8, .activate = 6 },
};
/* proprietary request/response format */
@@ -1008,9 +1008,25 @@ static int scarlett2_usb_get_config(
{
const struct scarlett2_config *config_item =
&scarlett2_config_items[config_item_num];
- int size = config_item->size * count;
+ int size, err, i;
+ u8 value;
- return scarlett2_usb_get(mixer, config_item->offset, buf, size);
+ /* For byte-sized parameters, retrieve directly into buf */
+ if (config_item->size >= 8) {
+ size = config_item->size / 8 * count;
+ return scarlett2_usb_get(mixer, config_item->offset, buf, size);
+ }
+
+ /* For bit-sized parameters, retrieve into value */
+ err = scarlett2_usb_get(mixer, config_item->offset, &value, 1);
+ if (err < 0)
+ return err;
+
+ /* then unpack from value into buf[] */
+ for (i = 0; i < 8 && i < count; i++, value >>= 1)
+ *(u8 *)buf++ = value & 1;
+
+ return 0;
}
/* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */
@@ -1047,18 +1063,44 @@ static int scarlett2_usb_set_config(
__le32 value;
} __packed req;
__le32 req2;
+ int offset, size;
int err;
struct scarlett2_data *private = mixer->private_data;
/* Cancel any pending NVRAM save */
cancel_delayed_work_sync(&private->work);
+ /* Convert config_item->size in bits to size in bytes and
+ * calculate offset
+ */
+ if (config_item->size >= 8) {
+ size = config_item->size / 8;
+ offset = config_item->offset + index * size;
+
+ /* If updating a bit, retrieve the old value, set/clear the
+ * bit as needed, and update value
+ */
+ } else {
+ u8 tmp;
+
+ size = 1;
+ offset = config_item->offset;
+
+ scarlett2_usb_get(mixer, offset, &tmp, 1);
+ if (value)
+ tmp |= (1 << index);
+ else
+ tmp &= ~(1 << index);
+
+ value = tmp;
+ }
+
/* Send the configuration parameter data */
- req.offset = cpu_to_le32(config_item->offset + index * config_item->size);
- req.bytes = cpu_to_le32(config_item->size);
+ req.offset = cpu_to_le32(offset);
+ req.bytes = cpu_to_le32(size);
req.value = cpu_to_le32(value);
err = scarlett2_usb(mixer, SCARLETT2_USB_SET_DATA,
- &req, sizeof(u32) * 2 + config_item->size,
+ &req, sizeof(u32) * 2 + size,
NULL, 0);
if (err < 0)
return err;