From 6414f7901fc4f3a702da75396ddd53b284e1ac8b Mon Sep 17 00:00:00 2001 From: Ilya Guterman Date: Sat, 28 Jan 2017 04:16:27 +0200 Subject: [PATCH] hidpp20: Implement feature 0x8070: LED effects --- src/hidpp-generic.c | 41 ++++++++++++++++ src/hidpp-generic.h | 6 +++ src/hidpp20.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ src/hidpp20.h | 52 ++++++++++++++++++++ src/libratbag.h | 10 ++++ 5 files changed, 221 insertions(+) diff --git a/src/hidpp-generic.c b/src/hidpp-generic.c index 04b7eacb..889ca708 100644 --- a/src/hidpp-generic.c +++ b/src/hidpp-generic.c @@ -138,6 +138,21 @@ static const struct hidpp20_1b04_physical_mapping hidpp20_1b04_physical_mapping[ BUTTON_PHYS_MAPPING(221, "LedToggle" , RATBAG_BUTTON_TYPE_UNKNOWN), }; +struct hidpp20_8070_location_mapping { + uint16_t value; + const char *name; + enum ratbag_led_type type; +}; + +#define LED_LOC_MAPPING(v_, n_, t_) \ + { v_, n_, t_ } + +static const struct hidpp20_8070_location_mapping hidpp20_8070_location_mapping[] = { + LED_LOC_MAPPING(0, "None", RATBAG_LED_TYPE_UNKNOWN), + LED_LOC_MAPPING(256, "Logo LED", RATBAG_LED_TYPE_LOGO), + LED_LOC_MAPPING(512, "Side LED", RATBAG_LED_TYPE_SIDE), +}; + const struct ratbag_button_action * hidpp20_1b04_get_logical_mapping(uint16_t value) { @@ -203,6 +218,32 @@ hidpp20_1b04_get_physical_mapping_name(uint16_t value) return "UNKNOWN"; } +enum ratbag_led_type +hidpp20_8070_get_location_mapping(uint16_t value) +{ + const struct hidpp20_8070_location_mapping *map; + + ARRAY_FOR_EACH(hidpp20_8070_location_mapping, map) { + if (map->value == value) + return map->type; + } + + return RATBAG_LED_TYPE_UNKNOWN; +} + +const char * +hidpp20_8070_get_location_mapping_name(uint16_t value) +{ + const struct hidpp20_8070_location_mapping *map; + + ARRAY_FOR_EACH(hidpp20_8070_location_mapping, map) { + if (map->value == value) + return map->name; + } + + return "UNKNOWN"; +} + int hidpp_write_command(struct hidpp_device *dev, uint8_t *cmd, int size) { diff --git a/src/hidpp-generic.h b/src/hidpp-generic.h index df242f1b..db26a42c 100644 --- a/src/hidpp-generic.h +++ b/src/hidpp-generic.h @@ -106,6 +106,12 @@ hidpp20_1b04_get_physical_mapping_name(uint16_t value); enum ratbag_button_type hidpp20_1b04_get_physical_mapping(uint16_t value); +enum ratbag_led_type +hidpp20_8070_get_location_mapping(uint16_t value); + +const char * +hidpp20_8070_get_location_mapping_name(uint16_t value); + const char * hidpp20_1b04_get_logical_mapping_name(uint16_t value); diff --git a/src/hidpp20.c b/src/hidpp20.c index cd4c1735..d8edf9a6 100644 --- a/src/hidpp20.c +++ b/src/hidpp20.c @@ -500,6 +500,118 @@ err: return rc; } +/* -------------------------------------------------------------------------- */ +/* 0x8070 - Color LED effects */ +/* -------------------------------------------------------------------------- */ + +#define CMD_COLOR_LED_EFFECTS_GET_INFO 0x00 +#define CMD_COLOR_LED_EFFECTS_GET_ZONE_INFO 0x10 + +static int +hidpp20_color_led_zones_get_count(struct hidpp20_device *device, uint8_t reg) +{ + int rc; + union hidpp20_message msg = { + .msg.report_id = REPORT_ID_SHORT, + .msg.device_idx = device->index, + .msg.address = CMD_COLOR_LED_EFFECTS_GET_INFO, + }; + struct hidpp20_color_led_info *info; + uint8_t feature_index; + + feature_index = hidpp_root_get_feature_idx(device, + HIDPP_PAGE_COLOR_LED_EFFECTS); + if (feature_index == 0) + return -ENOTSUP; + + msg.msg.sub_id = feature_index; + + rc = hidpp20_request_command(device, &msg); + if (rc) + return rc; + + info = (struct hidpp20_color_led_info *)msg.msg.parameters; + + return info->zone_count; +} + +int +hidpp20_color_led_effects_get_zone_info(struct hidpp20_device *device, + uint8_t reg, + struct hidpp20_color_led_zone_info *info) +{ + int rc; + struct hidpp20_color_led_zone_info *msg_info; + union hidpp20_message msg = { + .msg.report_id = REPORT_ID_LONG, + .msg.device_idx = device->index, + .msg.sub_id = reg, + .msg.address = CMD_COLOR_LED_EFFECTS_GET_ZONE_INFO, + .msg.parameters[0] = info->index, + }; + + rc = hidpp20_request_command(device, &msg); + if (rc) + return rc; + + msg_info = (struct hidpp20_color_led_zone_info *)msg.msg.parameters; + info->location = msg_info->location; + info->num_effects = msg_info->num_effects; + info->persistency_caps = msg_info->persistency_caps; + + return 0; +} + +int +hidpp20_color_led_effects_get_zone_infos(struct hidpp20_device *device, + struct hidpp20_color_led_zone_info **infos_list) +{ + uint8_t feature_index; + struct hidpp20_color_led_zone_info *i_list, *info; + uint8_t num_infos; + unsigned i; + int rc; + + feature_index = hidpp_root_get_feature_idx(device, + HIDPP_PAGE_COLOR_LED_EFFECTS); + if (feature_index == 0) + return -ENOTSUP; + + rc = hidpp20_color_led_zones_get_count(device, feature_index); + if (rc < 0) + return rc; + + num_infos = rc; + if (num_infos == 0) { + *infos_list = NULL; + return 0; + } + + i_list = zalloc(num_infos * sizeof(struct hidpp20_color_led_zone_info)); + + for (i = 0; i < num_infos; i++) { + info = &i_list[i]; + info->index = i; + rc = hidpp20_color_led_effects_get_zone_info(device, feature_index, info); + if (rc) + goto err; + + hidpp_log_raw(&device->base, + "led_info %d: location: %d type %s num_effects: %d persistency_caps: 0x%02x\n", + info->index, + info->location, + hidpp20_8070_get_location_mapping_name(info->location), + info->num_effects, + info->persistency_caps); + } + + *infos_list = i_list; + return num_infos; +err: + free(i_list); + return rc; +} + /* -------------------------------------------------------------------------- */ /* 0x1b04: Special keys and mouse buttons */ /* -------------------------------------------------------------------------- */ diff --git a/src/hidpp20.h b/src/hidpp20.h index b4f9addb..ed3668a8 100644 --- a/src/hidpp20.h +++ b/src/hidpp20.h @@ -265,6 +265,41 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device, #define HIDPP_PAGE_COLOR_LED_EFFECTS 0x8070 + +struct hidpp20_color_led_info; + +struct hidpp20_color_led_zone_info; + +int +hidpp20_color_led_effects_get_zone_info(struct hidpp20_device *device, + uint8_t reg, struct hidpp20_color_led_zone_info *info); + +int +hidpp20_color_led_effects_get_zone_infos(struct hidpp20_device *device, + struct hidpp20_color_led_zone_info **infos_list); + +enum hidpp20_color_led_location { + HIDPP20_COLOR_LED_LOCATION_UNDEFINED = 0, + HIDPP20_COLOR_LED_LOCATION_PRIMARY, + HIDPP20_COLOR_LED_LOCATION_LOGO, + HIDPP20_COLOR_LED_LOCATION_LEFT, + HIDPP20_COLOR_LED_LOCATION_RIGHT, + HIDPP20_COLOR_LED_LOCATION_COMBINED, + HIDPP20_COLOR_LED_LOCATION_PRIMARY_1, + HIDPP20_COLOR_LED_LOCATION_PRIMARY_2, + HIDPP20_COLOR_LED_LOCATION_PRIMARY_3, + HIDPP20_COLOR_LED_LOCATION_PRIMARY_4, + HIDPP20_COLOR_LED_LOCATION_PRIMARY_5, + HIDPP20_COLOR_LED_LOCATION_PRIMARY_6, +}; + +enum hidpp20_color_led_persistency { + HIDPP20_COLOR_LED_PERSISTENCY_UNSUPPORTED, + HIDPP20_COLOR_LED_PERSISTENCY_ON, + HIDPP20_COLOR_LED_PERSISTENCY_OFF, + HIDPP20_COLOR_LED_PERSISTENCY_ON_OFF, +}; + /* -------------------------------------------------------------------------- */ /* 0x8100 - Onboard Profiles */ /* -------------------------------------------------------------------------- */ @@ -325,6 +360,23 @@ union hidpp20_button_binding { } __attribute__((packed)); _Static_assert(sizeof(union hidpp20_button_binding) == 4, "Invalid size"); +struct hidpp20_color_led_info { + uint8_t zone_count; + /* we don't care about NV capabilities for libratbag, they just + * indicate sale demo effects */ + uint16_t nv_caps; + uint16_t ext_caps; +} __attribute__((packed)); +_Static_assert(sizeof(struct hidpp20_color_led_info) == 5, "Invalid size"); + +struct hidpp20_color_led_zone_info { + uint8_t index; + uint16_t location; + uint8_t num_effects; + uint8_t persistency_caps; +} __attribute__((packed)); +_Static_assert(sizeof(struct hidpp20_color_led_zone_info) == 5, "Invalid size"); + struct hidpp20_color { uint8_t red; uint8_t green; diff --git a/src/libratbag.h b/src/libratbag.h index ba34e72a..a698d33e 100644 --- a/src/libratbag.h +++ b/src/libratbag.h @@ -1317,6 +1317,16 @@ ratbag_button_set_button(struct ratbag_button *button, enum ratbag_button_action_special ratbag_button_get_special(struct ratbag_button *button); +/** + * @ingroup led + * + * LED types, usually based on their physical location + */ +enum ratbag_led_type { + RATBAG_LED_TYPE_UNKNOWN = -1, + RATBAG_LED_TYPE_LOGO = 0, + RATBAG_LED_TYPE_SIDE +}; /** * @ingroup button *