Commit 9e15fae6 authored by Geoffrey D. Bennett's avatar Geoffrey D. Bennett Committed by Takashi Iwai

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: default avatarGeoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/4e54e9e106ec7029c1a668c51b4fc769a7eb4ed0.1624379707.git.g@b4.vuSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 8aea2e32
...@@ -814,7 +814,7 @@ enum { ...@@ -814,7 +814,7 @@ enum {
}; };
/* Location, size, and activation command number for the configuration /* 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 { struct scarlett2_config {
u8 offset; u8 offset;
...@@ -825,25 +825,25 @@ struct scarlett2_config { ...@@ -825,25 +825,25 @@ struct scarlett2_config {
static const struct scarlett2_config static const struct scarlett2_config
scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = { scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = {
[SCARLETT2_CONFIG_DIM_MUTE] = { [SCARLETT2_CONFIG_DIM_MUTE] = {
.offset = 0x31, .size = 1, .activate = 2 }, .offset = 0x31, .size = 8, .activate = 2 },
[SCARLETT2_CONFIG_LINE_OUT_VOLUME] = { [SCARLETT2_CONFIG_LINE_OUT_VOLUME] = {
.offset = 0x34, .size = 2, .activate = 1 }, .offset = 0x34, .size = 16, .activate = 1 },
[SCARLETT2_CONFIG_MUTE_SWITCH] = { [SCARLETT2_CONFIG_MUTE_SWITCH] = {
.offset = 0x5c, .size = 1, .activate = 1 }, .offset = 0x5c, .size = 8, .activate = 1 },
[SCARLETT2_CONFIG_SW_HW_SWITCH] = { [SCARLETT2_CONFIG_SW_HW_SWITCH] = {
.offset = 0x66, .size = 1, .activate = 3 }, .offset = 0x66, .size = 8, .activate = 3 },
[SCARLETT2_CONFIG_LEVEL_SWITCH] = { [SCARLETT2_CONFIG_LEVEL_SWITCH] = {
.offset = 0x7c, .size = 1, .activate = 7 }, .offset = 0x7c, .size = 8, .activate = 7 },
[SCARLETT2_CONFIG_PAD_SWITCH] = { [SCARLETT2_CONFIG_PAD_SWITCH] = {
.offset = 0x84, .size = 1, .activate = 8 }, .offset = 0x84, .size = 8, .activate = 8 },
[SCARLETT2_CONFIG_MSD_SWITCH] = { [SCARLETT2_CONFIG_MSD_SWITCH] = {
.offset = 0x9d, .size = 1, .activate = 6 }, .offset = 0x9d, .size = 8, .activate = 6 },
}; };
/* proprietary request/response format */ /* proprietary request/response format */
...@@ -1008,9 +1008,25 @@ static int scarlett2_usb_get_config( ...@@ -1008,9 +1008,25 @@ static int scarlett2_usb_get_config(
{ {
const struct scarlett2_config *config_item = const struct scarlett2_config *config_item =
&scarlett2_config_items[config_item_num]; &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 */ /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */
...@@ -1047,18 +1063,44 @@ static int scarlett2_usb_set_config( ...@@ -1047,18 +1063,44 @@ static int scarlett2_usb_set_config(
__le32 value; __le32 value;
} __packed req; } __packed req;
__le32 req2; __le32 req2;
int offset, size;
int err; int err;
struct scarlett2_data *private = mixer->private_data; struct scarlett2_data *private = mixer->private_data;
/* Cancel any pending NVRAM save */ /* Cancel any pending NVRAM save */
cancel_delayed_work_sync(&private->work); 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 */ /* Send the configuration parameter data */
req.offset = cpu_to_le32(config_item->offset + index * config_item->size); req.offset = cpu_to_le32(offset);
req.bytes = cpu_to_le32(config_item->size); req.bytes = cpu_to_le32(size);
req.value = cpu_to_le32(value); req.value = cpu_to_le32(value);
err = scarlett2_usb(mixer, SCARLETT2_USB_SET_DATA, err = scarlett2_usb(mixer, SCARLETT2_USB_SET_DATA,
&req, sizeof(u32) * 2 + config_item->size, &req, sizeof(u32) * 2 + size,
NULL, 0); NULL, 0);
if (err < 0) if (err < 0)
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment