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.
This commit is contained in:
Yaroslav Chvanov
2022-06-06 10:15:19 +03:00
parent ea7b4b6821
commit a4da425298
9 changed files with 226 additions and 142 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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',

View File

@@ -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.

41
src/driver-sinowealth.h Normal file
View File

@@ -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;
};

View File

@@ -30,11 +30,13 @@
#include <glib.h>
#include <limits.h>
#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

View File

@@ -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 */
/**