diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index 5845c3ae..66049b1f 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -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; diff --git a/src/hidpp20.c b/src/hidpp20.c index a026f77f..24f5b56f 100644 --- a/src/hidpp20.c +++ b/src/hidpp20.c @@ -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 diff --git a/src/hidpp20.h b/src/hidpp20.h index ac8d8097..86f528b2 100644 --- a/src/hidpp20.h +++ b/src/hidpp20.h @@ -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; }; diff --git a/src/libratbag-data.c b/src/libratbag-data.c index 2387155d..38ba119a 100644 --- a/src/libratbag-data.c +++ b/src/libratbag-data.c @@ -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 */ diff --git a/src/libratbag-data.h b/src/libratbag-data.h index c51a7bf5..fd82cf9b 100644 --- a/src/libratbag-data.h +++ b/src/libratbag-data.h @@ -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 */