diff --git a/data/device-tests/steelseries-aerox-3-wireless.json b/data/device-tests/steelseries-aerox-3-wireless.json index 876f4ff62..28d286cfb 100644 --- a/data/device-tests/steelseries-aerox-3-wireless.json +++ b/data/device-tests/steelseries-aerox-3-wireless.json @@ -20,6 +20,7 @@ { "version": "1.8.1", "guids": [ + "541b2713-d367-5240-a443-bed07f09ffbf", "4f3fac7c-981b-58cc-bb58-8a3b90f31c9c", "ac7d7cbb-7ef5-5466-ab3d-e70ced97ee61" ] @@ -44,6 +45,7 @@ { "version": "1.9.3", "guids": [ + "541b2713-d367-5240-a443-bed07f09ffbf", "4f3fac7c-981b-58cc-bb58-8a3b90f31c9c", "ac7d7cbb-7ef5-5466-ab3d-e70ced97ee61" ] diff --git a/plugins/steelseries/README.md b/plugins/steelseries/README.md index 27f7df210..347068be4 100644 --- a/plugins/steelseries/README.md +++ b/plugins/steelseries/README.md @@ -59,7 +59,9 @@ Wireless adapter must be connected to host. ### Aerox 3 Wireless -The mouse must be connected to host via the USB-A to USB-C cable. +The mouse switch button underneath must be set to 2.4G, and its 2.4G USB +Wireless adapter must be connected to host; or the mouse must be connected to +host via the USB-A to USB-C cable. ## Vendor ID Security diff --git a/plugins/steelseries/fu-plugin-steelseries.c b/plugins/steelseries/fu-plugin-steelseries.c index 4bb40aab8..008979e22 100644 --- a/plugins/steelseries/fu-plugin-steelseries.c +++ b/plugins/steelseries/fu-plugin-steelseries.c @@ -8,6 +8,7 @@ #include +#include "fu-steelseries-fizz-tunnel.h" #include "fu-steelseries-fizz.h" #include "fu-steelseries-gamepad.h" #include "fu-steelseries-mouse.h" @@ -18,6 +19,7 @@ fu_plugin_steelseries_init(FuPlugin *plugin) { fu_plugin_add_device_gtype(plugin, FU_TYPE_STEELSERIES_MOUSE); fu_plugin_add_device_gtype(plugin, FU_TYPE_STEELSERIES_FIZZ); + fu_plugin_add_device_gtype(plugin, FU_TYPE_STEELSERIES_FIZZ_TUNNEL); fu_plugin_add_device_gtype(plugin, FU_TYPE_STEELSERIES_GAMEPAD); fu_plugin_add_device_gtype(plugin, FU_TYPE_STEELSERIES_SONIC); } diff --git a/plugins/steelseries/fu-steelseries-fizz-tunnel.c b/plugins/steelseries/fu-steelseries-fizz-tunnel.c new file mode 100644 index 000000000..b480aef9f --- /dev/null +++ b/plugins/steelseries/fu-steelseries-fizz-tunnel.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2022 Gaël PORTAY + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-steelseries-firmware.h" +#include "fu-steelseries-fizz-tunnel.h" + +struct _FuSteelseriesFizzTunnel { + FuDevice parent_instance; +}; + +G_DEFINE_TYPE(FuSteelseriesFizzTunnel, fu_steelseries_fizz_tunnel, FU_TYPE_DEVICE) + +static gboolean +fu_steelseries_fizz_tunnel_attach(FuDevice *device, FuProgress *progress, GError **error) +{ + FuDevice *parent = fu_device_get_parent(device); + g_autoptr(GError) error_local = NULL; + + if (!fu_steelseries_fizz_reset(parent, + TRUE, + STEELSERIES_FIZZ_RESET_MODE_NORMAL, + &error_local)) + g_warning("failed to reset: %s", error_local->message); + + fu_progress_sleep(fu_progress_get_child(progress), + fu_device_get_remove_delay(FU_DEVICE(device))); + + /* success */ + return TRUE; +} + +static gboolean +fu_steelseries_fizz_tunnel_probe(FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent(device); + GUsbDevice *usb_device = fu_usb_device_get_dev(FU_USB_DEVICE(parent)); + guint16 release; + + /* set the version if the release has been set */ + release = g_usb_device_get_release(usb_device); + if (release != 0x0 && + fu_device_get_version_format(device) == FWUPD_VERSION_FORMAT_UNKNOWN) { + g_autofree gchar *version = NULL; + version = fu_common_version_from_uint16(release, FWUPD_VERSION_FORMAT_BCD); + fu_device_set_version_format(device, FWUPD_VERSION_FORMAT_BCD); + fu_device_set_version(device, version); + } + + /* add GUIDs in order of priority */ + fu_device_add_instance_str(device, "PROTOCOL", "FIZZ_TUNNEL"); + fu_device_add_instance_u16(device, "VID", g_usb_device_get_vid(usb_device)); + fu_device_add_instance_u16(device, "PID", g_usb_device_get_pid(usb_device)); + fu_device_add_instance_u16(device, "REV", release); + fu_device_build_instance_id_quirk(device, NULL, "STEELSERIES", "VID", "PROTOCOL", NULL); + fu_device_build_instance_id(device, NULL, "STEELSERIES", "VID", "PID", "PROTOCOL", NULL); + fu_device_build_instance_id(device, + NULL, + "STEELSERIES", + "VID", + "PID", + "REV", + "PROTOCOL", + NULL); + + /* success */ + return TRUE; +} + +static gboolean +fu_steelseries_fizz_tunnel_setup(FuDevice *device, GError **error) +{ + FuDevice *parent = fu_device_get_parent(device); + guint32 calculated_crc; + guint32 stored_crc; + guint8 fs = STEELSERIES_FIZZ_FILESYSTEM_MOUSE; + guint8 id = STEELSERIES_FIZZ_MOUSE_FILESYSTEM_BACKUP_APP_ID; + g_autofree gchar *version = NULL; + + version = fu_steelseries_fizz_version(parent, TRUE, error); + if (version == NULL) { + g_prefix_error(error, "failed to get version: "); + return FALSE; + } + fu_device_set_version(device, version); + + if (!fu_steelseries_fizz_file_crc32(parent, + TRUE, + fs, + id, + &calculated_crc, + &stored_crc, + error)) { + g_prefix_error(error, + "failed to get file CRC32 from FS 0x%02x ID 0x%02x: ", + fs, + id); + return FALSE; + } + + if (calculated_crc != stored_crc) { + g_warning("%s: checksum mismatch, got 0x%08x, expected 0x%08x", + fu_device_get_name(device), + calculated_crc, + stored_crc); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_steelseries_fizz_tunnel_write_firmware(FuDevice *device, + FuFirmware *firmware, + FuProgress *progress, + FwupdInstallFlags flags, + GError **error) +{ + FuDevice *parent = fu_device_get_parent(device); + guint8 fs = STEELSERIES_FIZZ_FILESYSTEM_MOUSE; + guint8 id = STEELSERIES_FIZZ_MOUSE_FILESYSTEM_BACKUP_APP_ID; + + fu_progress_set_id(progress, G_STRLOC); + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 100); + + if (!fu_steelseries_fizz_write_file(parent, + TRUE, + fs, + id, + firmware, + fu_progress_get_child(progress), + flags, + error)) + return FALSE; + fu_progress_step_done(progress); + + /* success */ + return TRUE; +} + +static FuFirmware * +fu_steelseries_fizz_tunnel_read_firmware(FuDevice *device, FuProgress *progress, GError **error) +{ + FuDevice *parent = fu_device_get_parent(device); + guint8 fs = STEELSERIES_FIZZ_FILESYSTEM_MOUSE; + guint8 id = STEELSERIES_FIZZ_MOUSE_FILESYSTEM_BACKUP_APP_ID; + g_autoptr(FuFirmware) firmware = NULL; + + fu_progress_set_id(progress, G_STRLOC); + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_READ, 100); + + firmware = fu_steelseries_fizz_read_file(parent, + TRUE, + fs, + id, + fu_device_get_firmware_size_max(device), + fu_progress_get_child(progress), + error); + if (firmware == NULL) + return NULL; + fu_progress_step_done(progress); + + /* success */ + return g_steal_pointer(&firmware); +} + +static void +fu_steelseries_fizz_tunnel_set_progress(FuDevice *self, FuProgress *progress) +{ + fu_progress_set_id(progress, G_STRLOC); + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 0); /* detach */ + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 75); /* write */ + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 25); /* attach */ + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 0); /* reload */ +} + +static void +fu_steelseries_fizz_tunnel_class_init(FuSteelseriesFizzTunnelClass *klass) +{ + FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass); + + klass_device->attach = fu_steelseries_fizz_tunnel_attach; + klass_device->probe = fu_steelseries_fizz_tunnel_probe; + klass_device->setup = fu_steelseries_fizz_tunnel_setup; + klass_device->write_firmware = fu_steelseries_fizz_tunnel_write_firmware; + klass_device->read_firmware = fu_steelseries_fizz_tunnel_read_firmware; + klass_device->set_progress = fu_steelseries_fizz_tunnel_set_progress; +} + +static void +fu_steelseries_fizz_tunnel_init(FuSteelseriesFizzTunnel *self) +{ + fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_TRIPLET); + fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_UPDATABLE); + fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_CAN_VERIFY_IMAGE); + fu_device_add_internal_flag(FU_DEVICE(self), FU_DEVICE_INTERNAL_FLAG_USE_PARENT_FOR_OPEN); + fu_device_add_protocol(FU_DEVICE(self), "com.steelseries.fizz"); + fu_device_set_logical_id(FU_DEVICE(self), "tunnel"); + fu_device_set_install_duration(FU_DEVICE(self), 38); /* 38 s */ + fu_device_set_remove_delay(FU_DEVICE(self), FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); /* 10 s */ + fu_device_set_firmware_gtype(FU_DEVICE(self), FU_TYPE_STEELSERIES_FIRMWARE); +} + +FuSteelseriesFizzTunnel * +fu_steelseries_fizz_tunnel_new(FuSteelseriesFizz *parent) +{ + return g_object_new(FU_TYPE_STEELSERIES_FIZZ_TUNNEL, "parent", FU_DEVICE(parent), NULL); +} diff --git a/plugins/steelseries/fu-steelseries-fizz-tunnel.h b/plugins/steelseries/fu-steelseries-fizz-tunnel.h new file mode 100644 index 000000000..2f9136e12 --- /dev/null +++ b/plugins/steelseries/fu-steelseries-fizz-tunnel.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2022 Gaël PORTAY + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#include "fu-steelseries-fizz.h" + +#define FU_TYPE_STEELSERIES_FIZZ_TUNNEL (fu_steelseries_fizz_tunnel_get_type()) +G_DECLARE_FINAL_TYPE(FuSteelseriesFizzTunnel, + fu_steelseries_fizz_tunnel, + FU, + STEELSERIES_FIZZ_TUNNEL, + FuDevice) + +FuSteelseriesFizzTunnel * +fu_steelseries_fizz_tunnel_new(FuSteelseriesFizz *parent); diff --git a/plugins/steelseries/fu-steelseries-fizz.c b/plugins/steelseries/fu-steelseries-fizz.c index df0040d92..dc8fea74d 100644 --- a/plugins/steelseries/fu-steelseries-fizz.c +++ b/plugins/steelseries/fu-steelseries-fizz.c @@ -7,43 +7,11 @@ #include "config.h" #include "fu-steelseries-firmware.h" +#include "fu-steelseries-fizz-tunnel.h" #include "fu-steelseries-fizz.h" #define STEELSERIES_BUFFER_TRANSFER_SIZE 52 -#define STEELSERIES_FIZZ_FILESYSTEM_RECEIVER 0x01U -#define STEELSERIES_FIZZ_FILESYSTEM_MOUSE 0x02U - -#define STEELSERIES_FIZZ_RESET_MODE_NORMAL 0x00U -#define STEELSERIES_FIZZ_RESET_MODE_BOOTLOADER 0x01U - -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_MAIN_BOOT_ID 0x01U -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_FSDATA_FILE_ID 0x02U -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_FACTORY_SETTINGS_ID 0x03U -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_MAIN_APP_ID 0x04U -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_BACKUP_APP_ID 0x05U -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_PROFILES_MOUSE_ID 0x06U -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_PROFILES_LIGHTING_ID 0x0fU -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_PROFILES_DEVICE_ID 0x10U -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_PROFILES_RESERVED_ID 0x11U -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_RECOVERY_ID 0x0dU -#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_FREE_SPACE_ID 0xf1U - -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_SOFT_DEVICE_ID 0x00U -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_PROFILES_MOUSE_ID 0x06U -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_MAIN_APP_ID 0x07U -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_BACKUP_APP_ID 0x08U -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_MSB_DATA_ID 0x09U -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_FACTORY_SETTINGS_ID 0x0aU -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_FSDATA_FILE_ID 0x0bU -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_MAIN_BOOT_ID 0x0cU -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_RECOVERY_ID 0x0eU -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_PROFILES_LIGHTING_ID 0x0fU -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_PROFILES_DEVICE_ID 0x10U -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_FDS_PAGES_ID 0x12U -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_PROFILES_BLUETOOTH_ID 0x13U -#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_FREE_SPACE_ID 0xf0U - #define STEELSERIES_FIZZ_COMMAND_ERROR_SUCCESS 0 #define STEELSERIES_FIZZ_COMMAND_ERROR_FILE_NOT_FOUND 1 #define STEELSERIES_FIZZ_COMMAND_ERROR_FILE_TOO_SHORT 2 @@ -51,6 +19,8 @@ #define STEELSERIES_FIZZ_COMMAND_ERROR_PERMISSION_DENIED 4 #define STEELSERIES_FIZZ_COMMAND_ERROR_OPERATION_NO_SUPPORTED 5 +#define STEELSERIES_FIZZ_COMMAND_TUNNEL_BIT 1U << 6 + #define STEELSERIES_FIZZ_COMMAND_OFFSET 0x00U #define STEELSERIES_FIZZ_ERROR_OFFSET 0x01U @@ -195,13 +165,16 @@ fu_steelseries_device_command_and_check_error(FuDevice *device, guint8 *data, GE return fu_steelseries_device_command_error_to_error(cmd, err, error); } -static gchar * -fu_steelseries_fizz_version(FuDevice *device, GError **error) +gchar * +fu_steelseries_fizz_version(FuDevice *device, gboolean tunnel, GError **error) { guint8 data[STEELSERIES_BUFFER_CONTROL_SIZE] = {0}; - const guint16 cmd = 0x90U; + guint16 cmd = 0x90U; const guint8 mode = 0U; /* string */ + if (tunnel) + cmd |= STEELSERIES_FIZZ_COMMAND_TUNNEL_BIT; + if (!fu_common_write_uint8_safe(data, sizeof(data), STEELSERIES_FIZZ_VERSION_COMMAND_OFFSET, @@ -227,8 +200,9 @@ fu_steelseries_fizz_version(FuDevice *device, GError **error) return g_strndup((const gchar *)data, sizeof(data)); } -static gboolean +gboolean fu_steelseries_fizz_write_access_file(FuDevice *device, + gboolean tunnel, guint8 fs, guint8 id, const guint8 *buf, @@ -236,10 +210,13 @@ fu_steelseries_fizz_write_access_file(FuDevice *device, FuProgress *progress, GError **error) { - const guint16 cmd = 0x03U; + guint16 cmd = 0x03U; guint8 data[STEELSERIES_BUFFER_CONTROL_SIZE] = {0}; g_autoptr(GPtrArray) chunks = NULL; + if (tunnel) + cmd |= STEELSERIES_FIZZ_COMMAND_TUNNEL_BIT; + chunks = fu_chunk_array_new(buf, bufsz, 0x0, 0x0, STEELSERIES_BUFFER_TRANSFER_SIZE); fu_progress_set_id(progress, G_STRLOC); fu_progress_set_steps(progress, chunks->len); @@ -310,11 +287,18 @@ fu_steelseries_fizz_write_access_file(FuDevice *device, return TRUE; } -static gboolean -fu_steelseries_fizz_erase_file(FuDevice *device, guint8 fs, guint8 id, GError **error) +gboolean +fu_steelseries_fizz_erase_file(FuDevice *device, + gboolean tunnel, + guint8 fs, + guint8 id, + GError **error) { guint8 data[STEELSERIES_BUFFER_CONTROL_SIZE] = {0}; - const guint16 cmd = 0x02U; + guint16 cmd = 0x02U; + + if (tunnel) + cmd |= STEELSERIES_FIZZ_COMMAND_TUNNEL_BIT; if (!fu_common_write_uint8_safe(data, sizeof(data), @@ -348,11 +332,14 @@ fu_steelseries_fizz_erase_file(FuDevice *device, guint8 fs, guint8 id, GError ** return TRUE; } -static gboolean -fu_steelseries_fizz_reset(FuDevice *device, guint8 mode, GError **error) +gboolean +fu_steelseries_fizz_reset(FuDevice *device, gboolean tunnel, guint8 mode, GError **error) { guint8 data[STEELSERIES_BUFFER_CONTROL_SIZE] = {0}; - const guint16 cmd = 0x01U; + guint16 cmd = 0x01U; + + if (tunnel) + cmd |= STEELSERIES_FIZZ_COMMAND_TUNNEL_BIT; if (!fu_common_write_uint8_safe(data, sizeof(data), @@ -377,8 +364,9 @@ fu_steelseries_fizz_reset(FuDevice *device, guint8 mode, GError **error) return TRUE; } -static gboolean +gboolean fu_steelseries_fizz_file_crc32(FuDevice *device, + gboolean tunnel, guint8 fs, guint8 id, guint32 *calculated_crc, @@ -386,7 +374,10 @@ fu_steelseries_fizz_file_crc32(FuDevice *device, GError **error) { guint8 data[STEELSERIES_BUFFER_CONTROL_SIZE] = {0}; - const guint16 cmd = 0x84U; + guint16 cmd = 0x84U; + + if (tunnel) + cmd |= STEELSERIES_FIZZ_COMMAND_TUNNEL_BIT; if (!fu_common_write_uint8_safe(data, sizeof(data), 0x00U, cmd, error)) return FALSE; @@ -424,8 +415,9 @@ fu_steelseries_fizz_file_crc32(FuDevice *device, return TRUE; } -static gboolean +gboolean fu_steelseries_fizz_read_access_file(FuDevice *device, + gboolean tunnel, guint8 fs, guint8 id, guint8 *buf, @@ -433,10 +425,13 @@ fu_steelseries_fizz_read_access_file(FuDevice *device, FuProgress *progress, GError **error) { - const guint16 cmd = 0x83U; + guint16 cmd = 0x83U; guint8 data[STEELSERIES_BUFFER_CONTROL_SIZE] = {0}; g_autoptr(GPtrArray) chunks = NULL; + if (tunnel) + cmd |= STEELSERIES_FIZZ_COMMAND_TUNNEL_BIT; + chunks = fu_chunk_array_mutable_new(buf, bufsz, 0x0, 0x0, STEELSERIES_BUFFER_TRANSFER_SIZE); fu_progress_set_id(progress, G_STRLOC); fu_progress_set_status(progress, FWUPD_STATUS_DEVICE_READ); @@ -512,7 +507,10 @@ fu_steelseries_fizz_attach(FuDevice *device, FuProgress *progress, GError **erro { g_autoptr(GError) error_local = NULL; - if (!fu_steelseries_fizz_reset(device, STEELSERIES_FIZZ_RESET_MODE_NORMAL, &error_local)) + if (!fu_steelseries_fizz_reset(device, + FALSE, + STEELSERIES_FIZZ_RESET_MODE_NORMAL, + &error_local)) g_warning("failed to reset: %s", error_local->message); fu_device_add_flag(device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); @@ -528,8 +526,13 @@ fu_steelseries_fizz_setup(FuDevice *device, GError **error) guint32 stored_crc; guint8 fs = STEELSERIES_FIZZ_FILESYSTEM_MOUSE; guint8 id = STEELSERIES_FIZZ_MOUSE_FILESYSTEM_BACKUP_APP_ID; + g_autoptr(GError) error_local = NULL; g_autofree gchar *version = NULL; + /* in bootloader mode */ + if (fu_device_has_private_flag(device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) + return TRUE; + /* FuUsbDevice->setup */ if (!FU_DEVICE_CLASS(fu_steelseries_fizz_parent_class)->setup(device, error)) return FALSE; @@ -538,7 +541,18 @@ fu_steelseries_fizz_setup(FuDevice *device, GError **error) if (fu_device_has_private_flag(device, FWUPD_DEVICE_FLAG_IS_BOOTLOADER)) return TRUE; - version = fu_steelseries_fizz_version(device, error); + /* it is a USB receiver */ + if (fu_device_has_private_flag(device, FU_STEELSERIES_DEVICE_FLAG_IS_RECEIVER)) { + g_autoptr(FuSteelseriesFizzTunnel) mouse_device = + fu_steelseries_fizz_tunnel_new(FU_STEELSERIES_FIZZ(device)); + + fu_device_add_child(device, FU_DEVICE(mouse_device)); + + fs = STEELSERIES_FIZZ_FILESYSTEM_RECEIVER; + id = STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_BACKUP_APP_ID; + } + + version = fu_steelseries_fizz_version(device, FALSE, error); if (version == NULL) { g_prefix_error(error, "failed to get version: "); return FALSE; @@ -551,7 +565,13 @@ fu_steelseries_fizz_setup(FuDevice *device, GError **error) id = STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_BACKUP_APP_ID; } - if (!fu_steelseries_fizz_file_crc32(device, fs, id, &calculated_crc, &stored_crc, error)) { + if (!fu_steelseries_fizz_file_crc32(device, + FALSE, + fs, + id, + &calculated_crc, + &stored_crc, + error)) { g_prefix_error(error, "failed to get file CRC32 from FS 0x%02x ID 0x%02x: ", fs, @@ -569,8 +589,9 @@ fu_steelseries_fizz_setup(FuDevice *device, GError **error) return TRUE; } -static gboolean +gboolean fu_steelseries_fizz_write_file(FuDevice *device, + gboolean tunnel, guint8 fs, guint8 id, FuFirmware *firmware, @@ -585,9 +606,15 @@ fu_steelseries_fizz_write_file(FuDevice *device, g_autoptr(GBytes) blob = NULL; fu_progress_set_id(progress, G_STRLOC); - fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 38); - fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 60); - fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_VERIFY, 2); + if (tunnel) { + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 13); + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 87); + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_VERIFY, 1); + } else { + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_ERASE, 38); + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 60); + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_VERIFY, 2); + } blob = fu_firmware_get_bytes(firmware, error); if (blob == NULL) @@ -597,12 +624,13 @@ fu_steelseries_fizz_write_file(FuDevice *device, return FALSE; if (g_getenv("FWUPD_STEELSERIES_FIZZ_VERBOSE") != NULL) fu_common_dump_raw(G_LOG_DOMAIN, "File", buf, bufsz); - if (!fu_steelseries_fizz_erase_file(device, fs, id, error)) { + if (!fu_steelseries_fizz_erase_file(device, tunnel, fs, id, error)) { g_prefix_error(error, "failed to erase file 0x%02x:0x%02x: ", fs, id); return FALSE; } fu_progress_step_done(progress); if (!fu_steelseries_fizz_write_access_file(device, + tunnel, fs, id, buf, @@ -614,7 +642,13 @@ fu_steelseries_fizz_write_file(FuDevice *device, } fu_progress_step_done(progress); - if (!fu_steelseries_fizz_file_crc32(device, fs, id, &calculated_crc, &stored_crc, error)) { + if (!fu_steelseries_fizz_file_crc32(device, + tunnel, + fs, + id, + &calculated_crc, + &stored_crc, + error)) { g_prefix_error(error, "failed to get file CRC32 from FS 0x%02x ID 0x%02x: ", fs, @@ -652,6 +686,7 @@ fu_steelseries_fizz_write_firmware(FuDevice *device, fu_progress_set_steps(progress, 1); if (!fu_steelseries_fizz_write_file(device, + FALSE, fs, id, firmware, @@ -665,15 +700,52 @@ fu_steelseries_fizz_write_firmware(FuDevice *device, return TRUE; } +FuFirmware * +fu_steelseries_fizz_read_file(FuDevice *device, + gboolean tunnel, + guint8 fs, + guint8 id, + gsize size, + FuProgress *progress, + GError **error) +{ + g_autoptr(FuFirmware) firmware = fu_steelseries_firmware_new(); + g_autoptr(GBytes) blob = NULL; + g_autofree guint8 *buf = NULL; + + fu_progress_set_id(progress, G_STRLOC); + fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_READ, 100); + + buf = g_malloc0(size); + if (!fu_steelseries_fizz_read_access_file(device, + tunnel, + fs, + id, + buf, + size, + fu_progress_get_child(progress), + error)) { + g_prefix_error(error, "failed to read FS 0x%02x ID 0x%02x: ", fs, id); + return NULL; + } + fu_progress_step_done(progress); + + if (g_getenv("FWUPD_STEELSERIES_FIZZ_VERBOSE") != NULL) + fu_common_dump_raw(G_LOG_DOMAIN, "Firmware", buf, size); + blob = g_bytes_new_take(g_steal_pointer(&buf), size); + if (!fu_firmware_parse(firmware, blob, FWUPD_INSTALL_FLAG_NONE, error)) + return NULL; + + /* success */ + return g_steal_pointer(&firmware); +} + static FuFirmware * fu_steelseries_fizz_read_firmware(FuDevice *device, FuProgress *progress, GError **error) { guint8 fs = STEELSERIES_FIZZ_FILESYSTEM_MOUSE; guint8 id = STEELSERIES_FIZZ_MOUSE_FILESYSTEM_BACKUP_APP_ID; - gsize bufsz = 0x27000; - g_autoptr(FuFirmware) firmware = fu_steelseries_firmware_new(); - g_autoptr(GBytes) blob = NULL; - g_autofree guint8 *buf = NULL; + g_autoptr(FuFirmware) firmware = NULL; fu_progress_set_id(progress, G_STRLOC); fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_READ, 100); @@ -682,26 +754,19 @@ fu_steelseries_fizz_read_firmware(FuDevice *device, FuProgress *progress, GError if (fu_device_has_private_flag(device, FU_STEELSERIES_DEVICE_FLAG_IS_RECEIVER)) { fs = STEELSERIES_FIZZ_FILESYSTEM_RECEIVER; id = STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_BACKUP_APP_ID; - bufsz = 0x23000; } - buf = g_malloc0(bufsz); - if (!fu_steelseries_fizz_read_access_file(device, - fs, - id, - buf, - bufsz, - fu_progress_get_child(progress), - error)) + firmware = fu_steelseries_fizz_read_file(device, + FALSE, + fs, + id, + fu_device_get_firmware_size_max(device), + fu_progress_get_child(progress), + error); + if (firmware == NULL) return NULL; fu_progress_step_done(progress); - if (g_getenv("FWUPD_STEELSERIES_FIZZ_VERBOSE") != NULL) - fu_common_dump_raw(G_LOG_DOMAIN, "Firmware", buf, bufsz); - blob = g_bytes_new_take(g_steal_pointer(&buf), bufsz); - if (!fu_firmware_parse(firmware, blob, FWUPD_INSTALL_FLAG_NONE, error)) - return NULL; - /* success */ return g_steal_pointer(&firmware); } diff --git a/plugins/steelseries/fu-steelseries-fizz.h b/plugins/steelseries/fu-steelseries-fizz.h index 7ba814c92..a259c4c5e 100644 --- a/plugins/steelseries/fu-steelseries-fizz.h +++ b/plugins/steelseries/fu-steelseries-fizz.h @@ -16,3 +16,93 @@ G_DECLARE_FINAL_TYPE(FuSteelseriesFizz, FU, STEELSERIES_FIZZ, FuSteelseriesDevice) + +FuSteelseriesFizz * +fu_steelseries_fizz_new(FuDevice *self); + +#define STEELSERIES_FIZZ_FILESYSTEM_RECEIVER 0x01U +#define STEELSERIES_FIZZ_FILESYSTEM_MOUSE 0x02U + +#define STEELSERIES_FIZZ_RESET_MODE_NORMAL 0x00U +#define STEELSERIES_FIZZ_RESET_MODE_BOOTLOADER 0x01U + +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_MAIN_BOOT_ID 0x01U +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_FSDATA_FILE_ID 0x02U +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_FACTORY_SETTINGS_ID 0x03U +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_MAIN_APP_ID 0x04U +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_BACKUP_APP_ID 0x05U +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_PROFILES_MOUSE_ID 0x06U +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_PROFILES_LIGHTING_ID 0x0fU +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_PROFILES_DEVICE_ID 0x10U +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_PROFILES_RESERVED_ID 0x11U +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_RECOVERY_ID 0x0dU +#define STEELSERIES_FIZZ_RECEIVER_FILESYSTEM_FREE_SPACE_ID 0xf1U + +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_SOFT_DEVICE_ID 0x00U +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_PROFILES_MOUSE_ID 0x06U +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_MAIN_APP_ID 0x07U +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_BACKUP_APP_ID 0x08U +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_MSB_DATA_ID 0x09U +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_FACTORY_SETTINGS_ID 0x0aU +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_FSDATA_FILE_ID 0x0bU +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_MAIN_BOOT_ID 0x0cU +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_RECOVERY_ID 0x0eU +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_PROFILES_LIGHTING_ID 0x0fU +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_PROFILES_DEVICE_ID 0x10U +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_FDS_PAGES_ID 0x12U +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_PROFILES_BLUETOOTH_ID 0x13U +#define STEELSERIES_FIZZ_MOUSE_FILESYSTEM_FREE_SPACE_ID 0xf0U + +gchar * +fu_steelseries_fizz_version(FuDevice *device, gboolean tunnel, GError **error); +gboolean +fu_steelseries_fizz_read_access_file(FuDevice *device, + gboolean tunnel, + guint8 fs, + guint8 id, + guint8 *buf, + gsize bufsz, + FuProgress *progress, + GError **error); +gboolean +fu_steelseries_fizz_write_access_file(FuDevice *device, + gboolean tunnel, + guint8 fs, + guint8 id, + const guint8 *buf, + gsize bufsz, + FuProgress *progress, + GError **error); +gboolean +fu_steelseries_fizz_erase_file(FuDevice *device, + gboolean tunnel, + guint8 fs, + guint8 id, + GError **error); +gboolean +fu_steelseries_fizz_reset(FuDevice *device, gboolean tunnel, guint8 mode, GError **error); +gboolean +fu_steelseries_fizz_file_crc32(FuDevice *device, + gboolean tunnel, + guint8 fs, + guint8 id, + guint32 *calculated_crc, + guint32 *stored_crc, + GError **error); +FuFirmware * +fu_steelseries_fizz_read_file(FuDevice *device, + gboolean tunnel, + guint8 fs, + guint8 id, + gsize size, + FuProgress *progress, + GError **error); +gboolean +fu_steelseries_fizz_write_file(FuDevice *device, + gboolean tunnel, + guint8 fs, + guint8 id, + FuFirmware *firmware, + FuProgress *progress, + FwupdInstallFlags flags, + GError **error); diff --git a/plugins/steelseries/meson.build b/plugins/steelseries/meson.build index fd983c806..6bc8f217f 100644 --- a/plugins/steelseries/meson.build +++ b/plugins/steelseries/meson.build @@ -13,6 +13,7 @@ shared_module('fu_plugin_steelseries', 'fu-steelseries-mouse.c', 'fu-steelseries-firmware.c', 'fu-steelseries-fizz.c', + 'fu-steelseries-fizz-tunnel.c', 'fu-steelseries-gamepad.c', 'fu-steelseries-sonic.c', ], diff --git a/plugins/steelseries/steelseries.quirk b/plugins/steelseries/steelseries.quirk index 084aca76e..b4c781b59 100644 --- a/plugins/steelseries/steelseries.quirk +++ b/plugins/steelseries/steelseries.quirk @@ -29,6 +29,13 @@ Icon = usb-receiver FirmwareSize = 0x23000 Flags = is-bootloader,is-receiver,~usable-during-update +[STEELSERIES\VID_1038&PID_1838&PROTOCOL_FIZZ_TUNNEL] +Plugin = steelseries +GType = FuSteelseriesFizzTunnel +Name = Aerox 3 Wireless Mouse via USB Receiver +Icon = input-mouse +FirmwareSize = 0x27000 + [USB\VID_1038&PID_183A] Plugin = steelseries GType = FuSteelseriesFizz