forked from drath/libratbag
hidpp20: support multiple quirks per device
The hidpp20 quirk was a single enum value, so a device could carry only one quirk. Some devices need several at once. For example the G502 X PLUS needs G502X_PLUS (LED in the 2nd slot) and INDEX_OFFSET (1-indexed active profile) together, which a single field cannot express. #1799 noted this was worth adding. Make the quirk enum combinable bit flags stored as a bitmask. The "Quirk" key now takes a ;-separated list (like the asus driver's "Quirks"); existing single-value device files parse the same as before.
This commit is contained in:
committed by
staticssleever668
parent
43f76eee67
commit
b0f2779270
@@ -411,7 +411,7 @@ hidpp20drv_read_led_8071(struct ratbag_led *led, struct hidpp20drv_data* drv_dat
|
||||
hidpp20_rgb_effects_get_device_info(drv_data->dev, &device_info);
|
||||
cluster_info = drv_data->led_infos.color_leds_8071[led->index];
|
||||
profile = &drv_data->profiles->profiles[led->profile->index];
|
||||
if (drv_data->dev->quirk == HIDPP20_QUIRK_G502X_PLUS) {
|
||||
if (drv_data->dev->quirks & HIDPP20_QUIRK_G502X_PLUS) {
|
||||
// On G502X+ the second slot controls the user configurable LED.
|
||||
// (Note: There is only 1 reported LED, it just happens to use 2nd index though)
|
||||
h_led = &profile->leds[1];
|
||||
@@ -697,7 +697,7 @@ hidpp20drv_update_led_8070_8071(struct ratbag_led *led, struct ratbag_profile* p
|
||||
|
||||
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
|
||||
h_profile = &drv_data->profiles->profiles[profile->index];
|
||||
if (drv_data->dev->quirk == HIDPP20_QUIRK_G502X_PLUS) {
|
||||
if (drv_data->dev->quirks & HIDPP20_QUIRK_G502X_PLUS) {
|
||||
// On G502X+ the second slot controls the user configurable LED.
|
||||
// (Note: There is only 1 reported LED, it just happens to use 2nd index though)
|
||||
h_led = &(h_profile->leds[1]);
|
||||
@@ -1434,7 +1434,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
|
||||
case HIDPP_PAGE_COLOR_LED_EFFECTS: {
|
||||
/* The 8070 feature implemented in the G602 doesn't follow the spec,
|
||||
* so we ignore it */
|
||||
if (ratbag_device_data_hidpp20_get_quirk(device->data) == HIDPP20_QUIRK_G602)
|
||||
if (ratbag_device_data_hidpp20_get_quirks(device->data) & HIDPP20_QUIRK_G602)
|
||||
break;
|
||||
|
||||
log_debug(ratbag, "device has color effects\n");
|
||||
@@ -1708,14 +1708,15 @@ hidpp20drv_probe(struct ratbag_device *device)
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev->quirk = ratbag_device_data_hidpp20_get_quirk(device->data);
|
||||
dev->quirks = ratbag_device_data_hidpp20_get_quirks(device->data);
|
||||
|
||||
drv_data->dev = dev;
|
||||
|
||||
log_debug(device->ratbag, "'%s' is using protocol v%d.%d\n", ratbag_device_get_name(device), dev->proto_major, dev->proto_minor);
|
||||
|
||||
if(dev->quirk != HIDPP20_QUIRK_NONE)
|
||||
log_debug(device->ratbag, "'%s' is quirked (%s)\n", ratbag_device_get_name(device), hidpp20_get_quirk_string(dev->quirk));
|
||||
/* quirks is a bitmask; log each flag that is set */
|
||||
for (uint32_t q = dev->quirks; q != 0; q &= q - 1)
|
||||
log_debug(device->ratbag, "'%s' is quirked (%s)\n", ratbag_device_get_name(device), hidpp20_get_quirk_string(q & ~(q - 1)));
|
||||
|
||||
/* add some defaults that will be overwritten by the device */
|
||||
drv_data->num_profiles = 1;
|
||||
|
||||
@@ -1532,7 +1532,7 @@ hidpp20_adjustable_dpi_get_dpi_list(struct hidpp20_device *device,
|
||||
.msg.parameters[0] = sensor->index,
|
||||
};
|
||||
|
||||
if (device->quirk == HIDPP20_QUIRK_G602) {
|
||||
if (device->quirks & HIDPP20_QUIRK_G602) {
|
||||
msg.msg.parameters[0] = 1;
|
||||
i = 0;
|
||||
}
|
||||
@@ -1548,7 +1548,7 @@ hidpp20_adjustable_dpi_get_dpi_list(struct hidpp20_device *device,
|
||||
get_unaligned_be_u16(&msg.msg.parameters[i]) != 0) {
|
||||
uint16_t value = get_unaligned_be_u16(&msg.msg.parameters[i]);
|
||||
|
||||
if (device->quirk == HIDPP20_QUIRK_G602 && i == 2)
|
||||
if ((device->quirks & HIDPP20_QUIRK_G602) && i == 2)
|
||||
value += 0xe000;
|
||||
|
||||
if (value > 0xe000) {
|
||||
@@ -1580,7 +1580,7 @@ hidpp20_adjustable_dpi_get_dpi(struct hidpp20_device *device,
|
||||
.msg.parameters[0] = sensor->index,
|
||||
};
|
||||
|
||||
if (device->quirk == HIDPP20_QUIRK_G602)
|
||||
if (device->quirks & HIDPP20_QUIRK_G602)
|
||||
msg.msg.parameters[0] = 1;
|
||||
|
||||
rc = hidpp20_request_command(device, &msg);
|
||||
@@ -1662,7 +1662,7 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
|
||||
.msg.parameters[0] = sensor->index,
|
||||
};
|
||||
|
||||
if (device->quirk == HIDPP20_QUIRK_G602)
|
||||
if (device->quirks & HIDPP20_QUIRK_G602)
|
||||
msg.msg.parameters[0] = 1;
|
||||
|
||||
set_unaligned_be_u16(&msg.msg.parameters[1], dpi);
|
||||
@@ -2279,7 +2279,7 @@ hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
|
||||
active_profile_index = rc;
|
||||
|
||||
/* Apply quirk for devices that return 1-indexed profile */
|
||||
if (device->quirk == HIDPP20_QUIRK_INDEX_OFFSET && active_profile_index > 0)
|
||||
if ((device->quirks & HIDPP20_QUIRK_INDEX_OFFSET) && active_profile_index > 0)
|
||||
active_profile_index--;
|
||||
|
||||
profiles = zalloc(sizeof(struct hidpp20_profiles));
|
||||
@@ -2802,7 +2802,7 @@ hidpp20_onboard_profiles_initialize(struct hidpp20_device *device,
|
||||
profiles->sector_size,
|
||||
data);
|
||||
|
||||
if (rc && device->quirk == HIDPP20_QUIRK_G305) {
|
||||
if (rc && (device->quirks & HIDPP20_QUIRK_G305)) {
|
||||
/* The G305 has a bug where it throws an ERR_INVALID_ARGUMENT
|
||||
if the sector has not been written to yet. If this happens
|
||||
we will read the ROM profiles.*/
|
||||
@@ -2971,7 +2971,7 @@ hidpp20_onboard_profiles_write_profile(struct hidpp20_device *device,
|
||||
// Mice like G502X can store custom animations onboard.
|
||||
// ratbag does not support this, so we set it to disable it to ensure
|
||||
// that the actual lighting matches the user's settings.
|
||||
if (device->quirk == HIDPP20_QUIRK_G502X_PLUS)
|
||||
if (device->quirks & HIDPP20_QUIRK_G502X_PLUS)
|
||||
{
|
||||
// Note(sewer56): There are two known mice which use this field;
|
||||
// G502X PLUS and G705. [And I only own one of these.] But it's not known how
|
||||
|
||||
@@ -51,12 +51,13 @@ struct hidpp20_feature {
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
/* Combinable flags so a device can have several at once (stored as a bitmask). */
|
||||
enum hidpp20_quirk {
|
||||
HIDPP20_QUIRK_NONE,
|
||||
HIDPP20_QUIRK_G305,
|
||||
HIDPP20_QUIRK_G602,
|
||||
HIDPP20_QUIRK_G502X_PLUS, // G502X+ uses 2nd LED slot instead of 1st.
|
||||
HIDPP20_QUIRK_INDEX_OFFSET, // Device returns 1-indexed profile, decrement by 1.
|
||||
HIDPP20_QUIRK_NONE = 0,
|
||||
HIDPP20_QUIRK_G305 = (1 << 0),
|
||||
HIDPP20_QUIRK_G602 = (1 << 1),
|
||||
HIDPP20_QUIRK_G502X_PLUS = (1 << 2), // G502X+ uses 2nd LED slot instead of 1st.
|
||||
HIDPP20_QUIRK_INDEX_OFFSET = (1 << 3), // Device returns 1-indexed profile, decrement by 1.
|
||||
};
|
||||
|
||||
struct hidpp20_device {
|
||||
@@ -66,7 +67,7 @@ struct hidpp20_device {
|
||||
unsigned proto_minor;
|
||||
unsigned feature_count;
|
||||
struct hidpp20_feature *feature_list;
|
||||
enum hidpp20_quirk quirk;
|
||||
uint32_t quirks; /* bitmask of enum hidpp20_quirk */
|
||||
unsigned int led_ext_caps;
|
||||
};
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ enum driver {
|
||||
|
||||
struct data_hidpp20 {
|
||||
int index;
|
||||
enum hidpp20_quirk quirk;
|
||||
uint32_t quirks; /* bitmask of enum hidpp20_quirk */
|
||||
int led_count;
|
||||
int report_rate;
|
||||
int button_count;
|
||||
@@ -176,6 +176,20 @@ init_data_hidpp10(struct ratbag *ratbag,
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
hidpp20_quirk_from_string(const char *str)
|
||||
{
|
||||
if (streq(str, "G305"))
|
||||
return HIDPP20_QUIRK_G305;
|
||||
if (streq(str, "G602"))
|
||||
return HIDPP20_QUIRK_G602;
|
||||
if (streq(str, "G502X_PLUS"))
|
||||
return HIDPP20_QUIRK_G502X_PLUS;
|
||||
if (streq(str, "INDEX_OFFSET"))
|
||||
return HIDPP20_QUIRK_INDEX_OFFSET;
|
||||
return HIDPP20_QUIRK_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
init_data_hidpp20(struct ratbag *ratbag,
|
||||
GKeyFile *keyfile,
|
||||
@@ -184,7 +198,6 @@ init_data_hidpp20(struct ratbag *ratbag,
|
||||
const char *group = "Driver/hidpp20";
|
||||
GError *error = NULL;
|
||||
int num;
|
||||
char *str;
|
||||
|
||||
data->hidpp20.button_count = -1;
|
||||
data->hidpp20.index = -1;
|
||||
@@ -218,18 +231,13 @@ init_data_hidpp20(struct ratbag *ratbag,
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
|
||||
str = g_key_file_get_string(keyfile, group, "Quirk", NULL);
|
||||
data->hidpp20.quirk = HIDPP20_QUIRK_NONE;
|
||||
if (str) {
|
||||
if (streq(str, "G305"))
|
||||
data->hidpp20.quirk = HIDPP20_QUIRK_G305;
|
||||
else if(streq(str, "G602"))
|
||||
data->hidpp20.quirk = HIDPP20_QUIRK_G602;
|
||||
else if(streq(str, "G502X_PLUS"))
|
||||
data->hidpp20.quirk = HIDPP20_QUIRK_G502X_PLUS;
|
||||
else if(streq(str, "INDEX_OFFSET"))
|
||||
data->hidpp20.quirk = HIDPP20_QUIRK_INDEX_OFFSET;
|
||||
}
|
||||
/* Quirks are a bitmask: "Quirk" takes a ;-separated list. */
|
||||
data->hidpp20.quirks = HIDPP20_QUIRK_NONE;
|
||||
|
||||
gsize quirks_count = 0;
|
||||
_cleanup_(g_strfreevp) char **quirks = g_key_file_get_string_list(keyfile, group, "Quirk", &quirks_count, NULL);
|
||||
for (gsize i = 0; quirks && i < quirks_count; i++)
|
||||
data->hidpp20.quirks |= hidpp20_quirk_from_string(quirks[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -830,12 +838,12 @@ ratbag_device_data_hidpp20_get_report_rate(const struct ratbag_device_data *data
|
||||
return data->hidpp20.report_rate;
|
||||
}
|
||||
|
||||
enum hidpp20_quirk
|
||||
ratbag_device_data_hidpp20_get_quirk(const struct ratbag_device_data *data)
|
||||
uint32_t
|
||||
ratbag_device_data_hidpp20_get_quirks(const struct ratbag_device_data *data)
|
||||
{
|
||||
assert(data->drivertype == HIDPP20);
|
||||
|
||||
return data->hidpp20.quirk;
|
||||
return data->hidpp20.quirks;
|
||||
}
|
||||
|
||||
/* SinoWealth */
|
||||
|
||||
@@ -90,8 +90,8 @@ ratbag_device_data_hidpp20_get_led_count(const struct ratbag_device_data *data);
|
||||
int
|
||||
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);
|
||||
uint32_t
|
||||
ratbag_device_data_hidpp20_get_quirks(const struct ratbag_device_data *data);
|
||||
|
||||
/* SinoWealth */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user