From 1c85d77d567b7263725b8484ae94fe91d1a8fd08 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 9 Oct 2017 08:39:26 +1000 Subject: [PATCH] data: add LedTypes keyword argument to the device files At least on HID++ 2.0, the LED types appear to be random and don't match the protocol specs. Other protocols don't even have those bits, so let's make this a generic entry. This is pre-filled for all LEDs but drivers can override it where required. Fixes #377 Signed-off-by: Peter Hutterer --- data/devices/data-parse-test.py | 18 ++++++++- data/devices/device.example | 5 +++ data/devices/logitech-g303.device | 1 + src/driver-hidpp20.c | 5 ++- src/libratbag-data.c | 61 +++++++++++++++++++++++++++++-- src/libratbag-data.h | 3 ++ src/libratbag.c | 2 + 7 files changed, 89 insertions(+), 6 deletions(-) diff --git a/data/devices/data-parse-test.py b/data/devices/data-parse-test.py index fd1108ea..2adcfa2a 100755 --- a/data/devices/data-parse-test.py +++ b/data/devices/data-parse-test.py @@ -62,9 +62,20 @@ def check_match_str(string): assert(pid == '{:04x}'.format(int(pid, 16))) +def check_ledtypes_str(string): + permitted_types = ['logo', 'side', 'battery', 'dpi'] + + types = string.split(';') + for t in types: + if not t: # emtpy string if trailing ; + continue + + assert(t in permitted_types) + + def check_section_device(section): required_keys = ['Name', 'Driver', 'DeviceMatch'] - permitted_keys = required_keys + ['Svg'] + permitted_keys = required_keys + ['Svg', 'LedTypes'] for key in section.keys(): assert(key in permitted_keys) @@ -77,6 +88,11 @@ def check_section_device(section): except KeyError: pass + try: + check_ledtypes_str(section['LedTypes']) + except KeyError: + pass + check_match_str(section['DeviceMatch']) diff --git a/data/devices/device.example b/data/devices/device.example index ddda1667..d9ed1e51 100644 --- a/data/devices/device.example +++ b/data/devices/device.example @@ -18,6 +18,11 @@ Svg=logitech-example.svg # The libratbag driver backend Driver=hidpp10 +# The types of the LEDs, in the indexed order they appear in, separated by a +# semicolon. +# Allowed values: logo, side, battery, dpi +LedTypes=logo;side + # Only one group of driver-specific properties is permitted and it must be # [Driver/]. It is a bug do have any other [Driver/foo] group in # a device file, but this example file lists all. diff --git a/data/devices/logitech-g303.device b/data/devices/logitech-g303.device index 7ecac489..9b03fa01 100644 --- a/data/devices/logitech-g303.device +++ b/data/devices/logitech-g303.device @@ -4,3 +4,4 @@ Name=Logitech Gaming Mouse G303 DeviceMatch=usb:046d:c080 Svg=logitech-g303.svg Driver=hidpp20 +LedTypes=logo;side; diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index bc85ab1a..d7a7af96 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -322,7 +322,10 @@ hidpp20drv_read_led_8070(struct ratbag_led *led, struct hidpp20drv_data* drv_dat led->mode = RATBAG_LED_OFF; break; } - led->type = hidpp20_8070_get_location_mapping(led_info->location); + + /* pre-filled, only override if unknown */ + if (led->type == RATBAG_LED_TYPE_UNKNOWN) + led->type = hidpp20_8070_get_location_mapping(led_info->location); led->color.red = h_led->color.red; led->color.green = h_led->color.green; led->color.blue = h_led->color.blue; diff --git a/src/libratbag-data.c b/src/libratbag-data.c index 504969e7..2ba7aef0 100644 --- a/src/libratbag-data.c +++ b/src/libratbag-data.c @@ -75,6 +75,9 @@ struct ratbag_device_data { struct data_hidpp20 hidpp20; struct data_hidpp10 hidpp10; }; + + enum ratbag_led_type led_types[20]; + size_t nled_types; }; static void @@ -178,6 +181,15 @@ ratbag_device_data_get_svg(const struct ratbag_device_data *data) return data->svg; } +enum ratbag_led_type +ratbag_device_data_get_led_type(const struct ratbag_device_data *data, + unsigned int index) +{ + assert(index < ARRAY_LENGTH(data->led_types)); + + return data->led_types[index]; +} + struct ratbag_device_data * ratbag_device_data_ref(struct ratbag_device_data *data) { @@ -218,6 +230,40 @@ ratbag_device_data_unref(struct ratbag_device_data *data) DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbag_device_data *, ratbag_device_data_unref); +static int +parse_ledtypes(char **strv, enum ratbag_led_type *types, size_t ntypes) +{ + unsigned int i; + int count = 0; + + for (i = 0; i < ntypes; i++) + types[i] = RATBAG_LED_TYPE_UNKNOWN; + + if (!strv) + return count; + + i = 0; + while(strv[i]) { + const char *s = strv[i]; + + if (streq(s, "logo")) + types[i] = RATBAG_LED_TYPE_LOGO; + else if (streq(s, "side")) + types[i] = RATBAG_LED_TYPE_SIDE; + else if (streq(s, "dpi")) + types[i] = RATBAG_LED_TYPE_SIDE; + else if (streq(s, "battery")) + types[i] = RATBAG_LED_TYPE_SIDE; + else + return -1; + + count++; + i++; + } + + return count; +} + static bool match(const struct input_id *id, char **strv) { @@ -250,7 +296,8 @@ file_data_matches(struct ratbag *ratbag, { _cleanup_(g_key_file_freep) GKeyFile *keyfile = NULL; _cleanup_(g_error_freep) GError *error = NULL; - _cleanup_(g_strfreevp) char **strv = NULL; + _cleanup_(g_strfreevp) char **match_strv = NULL; + _cleanup_(g_strfreevp) char **ledtypes_strv = NULL; _cleanup_(ratbag_device_data_unrefp) struct ratbag_device_data *data = NULL; int rc; @@ -261,13 +308,13 @@ file_data_matches(struct ratbag *ratbag, return false; } - strv = g_key_file_get_string_list(keyfile, GROUP_DEVICE, "DeviceMatch", NULL, NULL); - if (!strv) { + match_strv = g_key_file_get_string_list(keyfile, GROUP_DEVICE, "DeviceMatch", NULL, NULL); + if (!match_strv) { log_error(ratbag, "Missing DeviceMatch in %s\n", basename(path)); return false; } - if (!match(id, strv)) + if (!match(id, match_strv)) return false; data = zalloc(sizeof(*data)); @@ -303,6 +350,12 @@ file_data_matches(struct ratbag *ratbag, data->svg = g_key_file_get_string(keyfile, GROUP_DEVICE, "Svg", NULL); + ledtypes_strv = g_key_file_get_string_list(keyfile, GROUP_DEVICE, "LedTypes", NULL, NULL); + if (parse_ledtypes(ledtypes_strv, data->led_types, ARRAY_LENGTH(data->led_types)) < 0) { + log_error(ratbag, "Invalid LedTypes string in '%s'\n", basename(path)); + return false; + } + *data_out = data; data = NULL; diff --git a/src/libratbag-data.h b/src/libratbag-data.h index 4aa42cf3..8d0c2241 100644 --- a/src/libratbag-data.h +++ b/src/libratbag-data.h @@ -42,6 +42,9 @@ const char * ratbag_device_data_get_name(const struct ratbag_device_data *data); const char * ratbag_device_data_get_svg(const struct ratbag_device_data *data); +enum ratbag_led_type +ratbag_device_data_get_led_type(const struct ratbag_device_data *data, + unsigned int index); /* HID++ 1.0 */ /** diff --git a/src/libratbag.c b/src/libratbag.c index 34a0cbfb..be0d34d8 100644 --- a/src/libratbag.c +++ b/src/libratbag.c @@ -623,6 +623,8 @@ ratbag_create_led(struct ratbag_profile *profile, unsigned int index) led->index = index; led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888; led->type = RATBAG_LED_TYPE_UNKNOWN; + if (device->data) + led->type = ratbag_device_data_get_led_type(device->data, led->index); list_insert(&profile->leds, &led->link);