From a4da42529815f6ef1c6c3c5cf5ab4a96711fa0f3 Mon Sep 17 00:00:00 2001 From: Yaroslav Chvanov Date: Mon, 6 Jun 2022 10:15:19 +0300 Subject: [PATCH] sinowealth: move device-specific data out of the driver This moves device data out of the driver into device files. However, a _single_ device file contains data for _several mice_ at the same time. The reason for this is that different mice by SinoWealth may use the same VID:PID pair. This is unfortunate, as we only allow a single device file a given VID:PID pair. Also move `sinowealth_led_format` enum into a header file and rename its constants to fit in outside of the driver. --- data/devices/glorious-model-d.device | 6 + data/devices/glorious-model-o.device | 6 + data/devices/sinowealth-0027.device | 40 ++++++- data/devices/sinowealth-1007.device | 20 ++++ meson.build | 1 + src/driver-sinowealth.c | 163 +++++---------------------- src/driver-sinowealth.h | 41 +++++++ src/libratbag-data.c | 81 ++++++++++++- src/libratbag-data.h | 10 ++ 9 files changed, 226 insertions(+), 142 deletions(-) create mode 100644 data/devices/sinowealth-1007.device create mode 100644 src/driver-sinowealth.h diff --git a/data/devices/glorious-model-d.device b/data/devices/glorious-model-d.device index 7b8a0b8b..11eadc5f 100644 --- a/data/devices/glorious-model-d.device +++ b/data/devices/glorious-model-d.device @@ -3,3 +3,9 @@ Name=Glorious Model D DeviceMatch=usb:258a:0033 Driver=sinowealth +[Driver/sinowealth/devices/GloriousModelD] +ButtonCount=6 +DeviceName=Glorious Model D +FwVersion=V102 +LedType=RBG +SensorType=PMW3360 diff --git a/data/devices/glorious-model-o.device b/data/devices/glorious-model-o.device index 31094586..0f903fe4 100644 --- a/data/devices/glorious-model-o.device +++ b/data/devices/glorious-model-o.device @@ -3,3 +3,9 @@ Name=Glorious Model O/O- DeviceMatch=usb:258a:0036 Driver=sinowealth +[Driver/sinowealth/devices/GloriousModelO] +ButtonCount=6 +DeviceName=Glorious Model O/O- (updated firmware) +FwVersion=V103 +LedType=RBG +SensorType=PMW3360 diff --git a/data/devices/sinowealth-0027.device b/data/devices/sinowealth-0027.device index c2b9cfd2..ce61b22b 100644 --- a/data/devices/sinowealth-0027.device +++ b/data/devices/sinowealth-0027.device @@ -1,10 +1,38 @@ [Device] -# Several mice match this ID: -# - Dream Machines DM5 Blink -# - G-Wolves Hati HT-M Wired Ace -# - G-Wolves Hati HT-M Wired Classic -# - Genesys Xenon 770 -# - Glorious Model O (old firmware) DeviceMatch=usb:258a:0027 Driver=sinowealth Name=SinoWealth Generic Mouse (0027) + +[Driver/sinowealth/devices/DreamMachinesDM5Blink] +ButtonCount=8 +DeviceName=DreamMachines DM5 Blink +FwVersion=3106 +LedType=RGB +SensorType=PMW3389 + +[Driver/sinowealth/devices/GWolvesHatiHTM] +ButtonCount=6 +# Can be both `Ace` and `Classic` version. +DeviceName=G-Wolves Hati HT-M Wired +FwVersion=V161 +LedType=None +# Can also be PMW3389 +SensorType=PMW3360 + +[Driver/sinowealth/devices/GenesysXenon770] +# There are 5 main buttons. +# Side buttons are detachable. +# There can be either 3 or 9 buttons on the side. +# Going for the maximum count: 5 + 9 = 14. +ButtonCount=14 +DeviceName=Genesys Xenon 770 +FwVersion=3110 +LedType=RGB +SensorType=PMW3327 + +[Driver/sinowealth/devices/GloriousModelOOld] +ButtonCount=6 +DeviceName=Glorious Model O (old firmware) +FwVersion=V102 +LedType=RBG +SensorType=PMW3360 diff --git a/data/devices/sinowealth-1007.device b/data/devices/sinowealth-1007.device new file mode 100644 index 00000000..648a2160 --- /dev/null +++ b/data/devices/sinowealth-1007.device @@ -0,0 +1,20 @@ +[Device] +DeviceMatch=usb:258a:1007 +Driver=sinowealth +Name=SinoWealth Generic Mouse (1007) + +# This does NOT work. See libratbag/libratbag#1296. +# For future: ID of A3050 sensor is 0x2, and maximum DPI is 4000. +#[Driver/sinowealth/devices/AntEsportsGM500] +#ButtonCount=7 +#DeviceName=Ant Esports GM500 +#FwVersion=0910 +#LedType=RBG +#SensorType=A3050 + +[Driver/sinowealth/devices/MarvoScorpionG961] +ButtonCount=6 +DeviceName=Marvo Scorpion G961 +FwVersion=9677 +LedType=RGB +SensorType=PMW3327 diff --git a/meson.build b/meson.build index 5d91bea8..4a7e711f 100644 --- a/meson.build +++ b/meson.build @@ -179,6 +179,7 @@ src_libratbag = [ 'src/driver-steelseries.c', 'src/driver-steelseries.h', 'src/driver-sinowealth.c', + 'src/driver-sinowealth.h', 'src/driver-sinowealth-nubwo.c', 'src/driver-test.c', 'src/libratbag.c', diff --git a/src/driver-sinowealth.c b/src/driver-sinowealth.c index d1aee7f2..5b4fba74 100644 --- a/src/driver-sinowealth.c +++ b/src/driver-sinowealth.c @@ -21,6 +21,9 @@ * DEALINGS IN THE SOFTWARE. */ +#include "driver-sinowealth.h" + +#include "libratbag-data.h" #include "libratbag-private.h" #include "libratbag-hidraw.h" #include "shared-macro.h" @@ -188,12 +191,6 @@ union sinowealth_dpis { }; _Static_assert(sizeof(union sinowealth_dpis) == sizeof(uint8_t[16]), "Invalid size"); -enum sinowealth_led_format { - LED_NONE, - LED_RBG, - LED_RGB, -}; - /* Configuration data the way it's stored in mouse memory. * When we want to change a setting, we basically copy the entire mouse * configuration, modify it and send it back. @@ -651,12 +648,12 @@ sinowealth_raw_to_color(struct ratbag_device *device, struct sinowealth_color ra switch (drv_data->led_type) { /* Fall back to RBG if the LED type is incorrect. */ default: - case LED_RBG: + case SINOWEALTH_LED_TYPE_RBG: color.red = raw_color.data[0]; color.green = raw_color.data[2]; color.blue = raw_color.data[1]; break; - case LED_RGB: + case SINOWEALTH_LED_TYPE_RGB: color.red = raw_color.data[0]; color.green = raw_color.data[1]; color.blue = raw_color.data[2]; @@ -679,12 +676,12 @@ sinowealth_color_to_raw(struct ratbag_device *device, struct ratbag_color color) switch (drv_data->led_type) { /* Fall back to RBG if the LED type is incorrect. */ default: - case LED_RBG: + case SINOWEALTH_LED_TYPE_RBG: raw_color.data[0] = color.red; raw_color.data[1] = color.blue; raw_color.data[2] = color.green; break; - case LED_RGB: + case SINOWEALTH_LED_TYPE_RGB: raw_color.data[0] = color.red; raw_color.data[1] = color.green; raw_color.data[2] = color.blue; @@ -1373,140 +1370,31 @@ sinowealth_update_macro_from_action(struct ratbag_profile *profile, struct ratba macro->event_count = raw_event_count; } -struct sinowealth_device_data { - const char fw_version[4]; - const char *device_name; - enum sinowealth_led_format led_type; - /* Not necessarily the sensor used on the mouse, some mice may have - * different sensers per the same model. - * We may fall back to this value in the future if we ever find mice - * with broken sensor type field. - */ - enum sinowealth_sensor sensor_type; - uint16_t pid; - uint16_t vid; - unsigned int button_count; -}; - -static const struct sinowealth_device_data sinowealth_supported_devices[] = { - /* 258a:0027 devices. */ - { - .fw_version = "V102", - .device_name = "Glorious Model O (old firmware)", - .led_type = LED_RBG, - .sensor_type = SINOWEALTH_SENSOR_PMW3360, - .vid = 0x258a, - .pid = 0x27, - .button_count = 6, - }, - { - .fw_version = "V161", - .device_name = "G-Wolves Hati HT-M Wired", - .led_type = LED_NONE, - /* Can also be PMW3389. */ - .sensor_type = SINOWEALTH_SENSOR_PMW3360, - .vid = 0x258a, - .pid = 0x27, - .button_count = 6, - }, - { - .fw_version = "3106", - .device_name = "DreamMachines DM5 Blink", - .led_type = LED_RGB, - .sensor_type = SINOWEALTH_SENSOR_PMW3389, - .vid = 0x258a, - .pid = 0x27, - .button_count = 8, - }, - { - .fw_version = "3110", - .device_name = "Genesis Xenon 770", - .led_type = LED_RGB, - .sensor_type = SINOWEALTH_SENSOR_PMW3327, - .vid = 0x258a, - .pid = 0x27, - /* Side buttons are detachable. - * There can be either 3 or 9 buttons on the side. - */ - .button_count = 5 + 9, - }, - - /* 258a:0033 devices. */ - { - .fw_version = "V102", - .device_name = "Glorious Model D", - .led_type = LED_RBG, - .sensor_type = SINOWEALTH_SENSOR_PMW3360, - .vid = 0x258a, - .pid = 0x33, - .button_count = 6, - }, - - /* 258a:0036 devices. */ - { - .fw_version = "V103", - .device_name = "Glorious Model O/O- (updated firmware)", - .led_type = LED_RBG, - .sensor_type = SINOWEALTH_SENSOR_PMW3360, - .vid = 0x258a, - .pid = 0x36, - .button_count = 6, - }, - - /* 258a:003E devices. */ - { - /* Untested. */ - /* This matches both Classic and Ace versions. */ - .fw_version = "3105", - .device_name = "G-Wolves Hati HT-S Wired", - .led_type = LED_NONE, - .sensor_type = SINOWEALTH_SENSOR_PMW3360, - .vid = 0x258a, - .pid = 0x3e, - .button_count = 6, - }, - - /* 2581:1007 devices. */ - { - .fw_version = "9677", - .device_name = "Marvo Scorpion G961", - .led_type = LED_RGB, - /* Official software allows up to 12000 DPI instead of 10200. */ - .sensor_type = SINOWEALTH_SENSOR_PMW3327, - .vid = 0x258a, - .pid = 0x1007, - .button_count = 6, - }, - - /* Dummy device. Make sure it's the last entry. */ - { - .fw_version = "0000", - .device_name = "Generic SinoWealth Mouse", - .led_type = LED_RBG, - .sensor_type = SINOWEALTH_SENSOR_PMW3360, - .vid = 0xffff, - .pid = 0xffff, - .button_count = 6, - }, -}; +/* + * @return Supported device data for the device or `NULL`. + */ static const struct sinowealth_device_data * -sinowealth_find_device_data(struct input_id ids, const char *fw_version) +sinowealth_find_device_data(struct ratbag_device *device, const char *fw_version) { - const struct sinowealth_device_data *device_data = NULL; + const struct ratbag_device_data *data = device->data; - ARRAY_FOR_EACH(sinowealth_supported_devices, device_data) { - if (device_data->vid != ids.vendor || device_data->pid != ids.product) + const struct list *supported_devices = ratbag_device_data_sinowealth_get_supported_devices(data); + + struct sinowealth_device_data *device_data = NULL; + list_for_each(device_data, supported_devices, link) { + if (device_data->fw_version == NULL || device_data->device_name == NULL) { + log_error(device->ratbag, "Skipping invalid device data\n"); continue; + } - if (!strneq(fw_version, device_data->fw_version, sizeof(device_data->fw_version))) + if (!strneq(fw_version, device_data->fw_version, SINOWEALTH_FW_VERSION_LEN)) continue; return device_data; } - /* Return the last entry in `sinowealth_device_data` - a dummy. */ - return device_data; + return NULL; } /* Initialize profiles for device `device`. @@ -1543,7 +1431,12 @@ sinowealth_init_profile(struct ratbag_device *device) if (rc) return rc; - const struct sinowealth_device_data *device_data = sinowealth_find_device_data(device->ids, fw_version); + const struct sinowealth_device_data *device_data = sinowealth_find_device_data(device, fw_version); + + if (device_data == NULL) { + log_error(device->ratbag, "Device with firmware version %s is not supported\n", fw_version); + return -1; + } drv_data->button_count = device_data->button_count; drv_data->led_type = device_data->led_type; @@ -1552,7 +1445,7 @@ sinowealth_init_profile(struct ratbag_device *device) /* LED count. */ drv_data->led_count = 0; - if (config->rgb_effect != RGB_NOT_SUPPORTED && drv_data->led_type != LED_NONE) { + if (config->rgb_effect != RGB_NOT_SUPPORTED && drv_data->led_type != SINOWEALTH_LED_TYPE_NONE) { drv_data->led_count += 1; } /* We may want to account for the DPI LEDs in the future. diff --git a/src/driver-sinowealth.h b/src/driver-sinowealth.h new file mode 100644 index 00000000..bdc2018c --- /dev/null +++ b/src/driver-sinowealth.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2022 Yaroslav Chvanov + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "libratbag-util.h" + +enum sinowealth_led_format { + SINOWEALTH_LED_TYPE_NONE, + SINOWEALTH_LED_TYPE_RBG, + SINOWEALTH_LED_TYPE_RGB, +}; + +struct sinowealth_device_data { + char *fw_version; + char *device_name; + enum sinowealth_led_format led_type; + unsigned int button_count; + + struct list link; +}; diff --git a/src/libratbag-data.c b/src/libratbag-data.c index 04378d9f..c390060c 100644 --- a/src/libratbag-data.c +++ b/src/libratbag-data.c @@ -30,11 +30,13 @@ #include #include +#include "driver-sinowealth.h" #include "driver-steelseries.h" #include "libratbag.h" #include "libratbag-private.h" #include "libratbag-data.h" #include "hidpp20.h" +#include "shared-macro.h" #include "usb-ids.h" #define GROUP_DEVICE "Device" @@ -78,6 +80,10 @@ struct data_hidpp10 { int led_count; }; +struct data_sinowealth { + struct list supported_devices; +}; + struct data_steelseries { int device_version; int button_count; @@ -98,6 +104,7 @@ struct ratbag_device_data { union { struct data_hidpp20 hidpp20; struct data_hidpp10 hidpp10; + struct data_sinowealth sinowealth; struct data_steelseries steelseries; }; @@ -207,6 +214,56 @@ init_data_hidpp20(struct ratbag *ratbag, } } +static void +init_data_sinowealth(struct ratbag *ratbag, + GKeyFile *keyfile, + struct ratbag_device_data *data) +{ + const char *devices_group = "Driver/sinowealth/devices/"; + + GError *error = NULL; + + size_t group_count = 0; + _cleanup_(g_strfreevp) char **groups = g_key_file_get_groups(keyfile, &group_count); + + list_init(&data->sinowealth.supported_devices); + + for (size_t i = 0; i < group_count; ++i) { + const char *device_group = groups[i]; + if (startswith(device_group, devices_group) == NULL) + continue; + + struct sinowealth_device_data *device = zalloc(sizeof(struct sinowealth_device_data)); + + device->button_count = g_key_file_get_integer(keyfile, device_group, "ButtonCount", &error); + g_clear_error(&error); + + device->device_name = g_key_file_get_string(keyfile, device_group, "DeviceName", &error); + g_clear_error(&error); + + device->fw_version = g_key_file_get_string(keyfile, device_group, "FwVersion", &error); + g_clear_error(&error); + + _cleanup_free_ char *led_type_str = g_key_file_get_string(keyfile, device_group, "LedType", &error); + if (led_type_str) { + if (streq(led_type_str, "RGB")) { + device->led_type = SINOWEALTH_LED_TYPE_RGB; + } else if (streq(led_type_str, "RBG")) { + device->led_type = SINOWEALTH_LED_TYPE_RBG; + } else if (streq(led_type_str, "None")) { + device->led_type = SINOWEALTH_LED_TYPE_NONE; + } else { + log_error(ratbag, "Unknown LED type '%s' in group '%s'\n", led_type_str, device_group); + + device->led_type = SINOWEALTH_LED_TYPE_NONE; + } + } + g_clear_error(&error); + + list_insert(&data->sinowealth.supported_devices, &device->link); + } +} + static void init_data_steelseries(struct ratbag *ratbag, GKeyFile *keyfile, @@ -287,7 +344,7 @@ static const struct driver_map { { LOGITECH_G300, "logitech_g300", NULL}, { LOGITECH_G600, "logitech_g600", NULL}, { STEELSERIES, "steelseries", init_data_steelseries }, - { SINOWEALTH, "sinowealth", NULL }, + { SINOWEALTH, "sinowealth", init_data_sinowealth }, { SINOWEALTH_NUBWO, "sinowealth_nubwo", NULL}, { OPENINPUT, "openinput", NULL }, }; @@ -333,6 +390,18 @@ ratbag_device_data_destroy(struct ratbag_device_data *data) free(data->hidpp10.dpi_range); free(data->hidpp10.profile_type); break; + case SINOWEALTH: { + struct sinowealth_device_data *device_data = NULL; + struct sinowealth_device_data *device_data_next = NULL; + + list_for_each_safe(device_data, device_data_next, &data->sinowealth.supported_devices, link) { + free(device_data->device_name); + free(device_data->fw_version); + free(device_data); + } + + break; + } case STEELSERIES: if (data->steelseries.dpi_list) { free(data->steelseries.dpi_list->entries); @@ -656,6 +725,16 @@ ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data) return data->hidpp20.quirk; } +/* SinoWealth */ + +const struct list * +ratbag_device_data_sinowealth_get_supported_devices(const struct ratbag_device_data *data) +{ + assert(data->drivertype == SINOWEALTH); + + return &data->sinowealth.supported_devices; +} + /* SteelSeries */ int diff --git a/src/libratbag-data.h b/src/libratbag-data.h index ee7c80e3..9341c2c6 100644 --- a/src/libratbag-data.h +++ b/src/libratbag-data.h @@ -92,6 +92,16 @@ ratbag_device_data_hidpp20_get_report_rate(const struct ratbag_device_data *data enum hidpp20_quirk ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data); +/* SinoWealth */ + +/* + * NOTE: Don't forget to check for NULL in fields of each device data entry. + * + * @return List of data for supported devices. + */ +const struct list * +ratbag_device_data_sinowealth_get_supported_devices(const struct ratbag_device_data *data); + /* SteelSeries */ /**