summaryrefslogtreecommitdiff
path: root/sound/usb
diff options
context:
space:
mode:
authorGeoffrey D. Bennett <g@b4.vu>2023-12-20 04:08:58 +1030
committerTakashi Iwai <tiwai@suse.de>2023-12-29 15:39:27 +0100
commit34101a0fb1d47d8def145e50b4221201f5348cd0 (patch)
tree0cebfee84b576c61c6cc7c2e022017f7b3cdcb23 /sound/usb
parent103c23ccacaab14e5f8a63d60bdc4e5c81e166fc (diff)
ALSA: scarlett2: Retrieve useful flash segment numbers
Call SCARLETT2_USB_INFO_FLASH and SCARLETT2_USB_INFO_SEGMENT to find the App_Settings and App_Upgrade flash segment numbers, and store them in the scarlett2_data struct. These will be used later to implement reset to factory defaults and firmware upgrade functions. Signed-off-by: Geoffrey D. Bennett <g@b4.vu> Link: https://lore.kernel.org/r/70f0108a9cf99b69f7aa920c4bcdb0cf4bf3da98.1703001053.git.g@b4.vu Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/mixer_scarlett2.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
index a2d6d99bc13d..b62fc0038671 100644
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -190,6 +190,11 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = {
16345
};
+/* Flash segments that we may manipulate */
+#define SCARLETT2_SEGMENT_ID_SETTINGS 0
+#define SCARLETT2_SEGMENT_ID_FIRMWARE 1
+#define SCARLETT2_SEGMENT_ID_COUNT 2
+
/* Maximum number of analogue outputs */
#define SCARLETT2_ANALOGUE_MAX 10
@@ -429,6 +434,8 @@ struct scarlett2_data {
int num_mux_srcs;
int num_mux_dsts;
u32 firmware_version;
+ u8 flash_segment_nums[SCARLETT2_SEGMENT_ID_COUNT];
+ u8 flash_segment_blocks[SCARLETT2_SEGMENT_ID_COUNT];
u16 scarlett2_seq;
u8 sync_updated;
u8 vol_updated;
@@ -1160,6 +1167,13 @@ static int scarlett2_get_port_start_num(
#define SCARLETT2_USB_VOLUME_STATUS_OFFSET 0x31
#define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1
+#define SCARLETT2_FLASH_BLOCK_SIZE 4096
+#define SCARLETT2_SEGMENT_NUM_MIN 1
+#define SCARLETT2_SEGMENT_NUM_MAX 4
+
+#define SCARLETT2_SEGMENT_SETTINGS_NAME "App_Settings"
+#define SCARLETT2_SEGMENT_FIRMWARE_NAME "App_Upgrade"
+
/* volume status is read together (matches scarlett2_config_items[1]) */
struct scarlett2_usb_volume_status {
/* dim/mute buttons */
@@ -4202,6 +4216,90 @@ static int scarlett2_usb_init(struct usb_mixer_interface *mixer)
return 0;
}
+/* Get the flash segment numbers for the App_Settings and App_Upgrade
+ * segments and put them in the private data
+ */
+static int scarlett2_get_flash_segment_nums(struct usb_mixer_interface *mixer)
+{
+ struct scarlett2_data *private = mixer->private_data;
+ int err, count, i;
+
+ struct {
+ __le32 size;
+ __le32 count;
+ u8 unknown[8];
+ } __packed flash_info;
+
+ struct {
+ __le32 size;
+ __le32 flags;
+ char name[16];
+ } __packed segment_info;
+
+ err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_FLASH,
+ NULL, 0,
+ &flash_info, sizeof(flash_info));
+ if (err < 0)
+ return err;
+
+ count = le32_to_cpu(flash_info.count);
+
+ /* sanity check count */
+ if (count < SCARLETT2_SEGMENT_NUM_MIN ||
+ count > SCARLETT2_SEGMENT_NUM_MAX + 1) {
+ usb_audio_err(mixer->chip,
+ "invalid flash segment count: %d\n", count);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < count; i++) {
+ __le32 segment_num_req = cpu_to_le32(i);
+ int flash_segment_id;
+
+ err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_SEGMENT,
+ &segment_num_req, sizeof(segment_num_req),
+ &segment_info, sizeof(segment_info));
+ if (err < 0) {
+ usb_audio_err(mixer->chip,
+ "failed to get flash segment info %d: %d\n",
+ i, err);
+ return err;
+ }
+
+ if (!strncmp(segment_info.name,
+ SCARLETT2_SEGMENT_SETTINGS_NAME, 16))
+ flash_segment_id = SCARLETT2_SEGMENT_ID_SETTINGS;
+ else if (!strncmp(segment_info.name,
+ SCARLETT2_SEGMENT_FIRMWARE_NAME, 16))
+ flash_segment_id = SCARLETT2_SEGMENT_ID_FIRMWARE;
+ else
+ continue;
+
+ private->flash_segment_nums[flash_segment_id] = i;
+ private->flash_segment_blocks[flash_segment_id] =
+ le32_to_cpu(segment_info.size) /
+ SCARLETT2_FLASH_BLOCK_SIZE;
+ }
+
+ /* segment 0 is App_Gold and we never want to touch that, so
+ * use 0 as the "not-found" value
+ */
+ if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_SETTINGS]) {
+ usb_audio_err(mixer->chip,
+ "failed to find flash segment %s\n",
+ SCARLETT2_SEGMENT_SETTINGS_NAME);
+ return -EINVAL;
+ }
+ if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_FIRMWARE]) {
+ usb_audio_err(mixer->chip,
+ "failed to find flash segment %s\n",
+ SCARLETT2_SEGMENT_FIRMWARE_NAME);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* Read configuration from the interface on start */
static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
{
@@ -4517,6 +4615,11 @@ static int snd_scarlett2_controls_create(
if (err < 0)
return err;
+ /* Get the upgrade & settings flash segment numbers */
+ err = scarlett2_get_flash_segment_nums(mixer);
+ if (err < 0)
+ return err;
+
/* Add firmware version control */
err = scarlett2_add_firmware_version_ctl(mixer);
if (err < 0)