From 835a694c4b53deb3760b2a72d7b42eebe7fcc8dd Mon Sep 17 00:00:00 2001 From: Ogier Bouvier Date: Wed, 20 Sep 2017 16:52:12 +0200 Subject: [PATCH] driver-hidpp20: add feature discovery for 0x1300 fix #325 Signed-off-by: Ogier Bouvier --- src/driver-hidpp20.c | 183 +++++++++++++++++++++++++++++++++++++++---- src/libratbag.h | 4 +- 2 files changed, 171 insertions(+), 16 deletions(-) diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index 1d7175b2..12d76bec 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -54,7 +54,7 @@ #define HIDPP_CAP_KBD_REPROGRAMMABLE_KEYS_1b00 (1 << 4) #define HIDPP_CAP_COLOR_LED_EFFECTS_8070 (1 << 5) #define HIDPP_CAP_ONBOARD_PROFILES_8100 (1 << 6) -#define HIDPP_CAP_LED_SW_CONTROL (1 << 7) +#define HIDPP_CAP_LED_SW_CONTROL_1300 (1 << 7) struct hidpp20drv_data { struct hidpp20_device *dev; @@ -247,17 +247,63 @@ hidpp20drv_read_button(struct ratbag_button *button) } static void -hidpp20drv_read_led(struct ratbag_led *led) +hidpp20drv_read_led_1300(struct ratbag_led *led, struct hidpp20drv_data* data) { - struct ratbag_device *device = led->profile->device; - struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device); - struct hidpp20_profile *profile; - struct hidpp20_color_led_zone_info *led_info; - struct hidpp20_led *h_led; + struct hidpp20_led_sw_ctrl_led_state state; + struct hidpp20_led_sw_ctrl_led_info *info; + int rc; - if (!(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070)) + info = &data->led_infos.leds[led->index]; + + rc = hidpp20_led_sw_control_get_led_state(data->dev, led->index, &state); + + if (rc != 0) return; + led->colordepth = RATBAG_LED_COLORDEPTH_MONOCHROME; + + switch (info->type) + { + case HIDPP20_LED_TYPE_LOGO: + led->type = RATBAG_LED_TYPE_LOGO; + break; + case HIDPP20_LED_TYPE_BATTERY: + led->type = RATBAG_LED_TYPE_BATTERY; + break; + case HIDPP20_LED_TYPE_DPI: + led->type = RATBAG_LED_TYPE_DPI; + break; + case HIDPP20_LED_TYPE_PROFILE: + case HIDPP20_LED_TYPE_COSMETIC: + led->type = RATBAG_LED_TYPE_SIDE; + break; + } + + switch (state.mode) + { + case HIDPP20_LED_MODE_OFF: + led->mode = RATBAG_LED_OFF; + break; + case HIDPP20_LED_MODE_ON: + led->mode = RATBAG_LED_ON; + break; + case HIDPP20_LED_MODE_BREATHING: + led->mode = RATBAG_LED_BREATHING; + led->hz = state.breathing.period; + led->brightness = state.breathing.brightness; + break; + default: + led->mode = RATBAG_LED_ON; + } +} + +static void +hidpp20drv_read_led_8070(struct ratbag_led *led, struct hidpp20drv_data* drv_data) +{ + struct hidpp20_profile *profile; + struct hidpp20_led *h_led; + struct hidpp20_color_led_zone_info* led_info; + led_info = &drv_data->led_infos.color_leds[led->index]; profile = &drv_data->profiles->profiles[led->profile->index]; h_led = &profile->leds[led->index]; @@ -285,6 +331,18 @@ hidpp20drv_read_led(struct ratbag_led *led) led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888; } +static void +hidpp20drv_read_led(struct ratbag_led *led) +{ + struct ratbag_device *device = led->profile->device; + struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device); + + if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070) + hidpp20drv_read_led_8070(led, drv_data); + else if (drv_data->capabilities & HIDPP_CAP_LED_SW_CONTROL_1300) + hidpp20drv_read_led_1300(led, drv_data); +} + static int hidpp20drv_write_button_1b04(struct ratbag_button *button, const struct ratbag_button_action *action) @@ -389,17 +447,61 @@ hidpp20drv_update_button(struct ratbag_button *button, } static int -hidpp20drv_update_led(struct ratbag_led *led) +hidpp20drv_update_led_1300(struct ratbag_led *led, struct hidpp20drv_data *data) +{ + const uint16_t led_caps = data->led_infos.leds[led->index].caps; + struct hidpp20_led_sw_ctrl_led_state h_led; + int rc; + + h_led.index = led->index; + + switch(led->mode) + { + case RATBAG_LED_BREATHING: + h_led.mode = HIDPP20_LED_MODE_BREATHING; + h_led.breathing.brightness = led->brightness; + h_led.breathing.period = led->hz; + h_led.breathing.timeout = 300; + break; + case RATBAG_LED_OFF: + h_led.mode = HIDPP20_LED_MODE_OFF; + h_led.on.index = HIDPP20_LED_SW_CONTROL_LED_INDEX_ALL; + break; + case RATBAG_LED_ON: + h_led.mode = HIDPP20_LED_MODE_ON; + h_led.on.index = HIDPP20_LED_SW_CONTROL_LED_INDEX_ALL; + break; + case RATBAG_LED_CYCLE: + return -ENOTSUP; + } + + if (!(h_led.mode & led_caps)) { + hidpp_log_error(&data->dev->base, "LED %d does not support effect %s(%04x), supports %04x\n", + led->index, hidpp20_sw_led_control_get_mode_string(h_led.mode), + h_led.mode, led_caps); + return -ENOTSUP; + } + + if (!hidpp20_led_sw_control_get_sw_ctrl(data->dev)) { + rc = hidpp20_led_sw_control_set_sw_ctrl(data->dev, true); + if (rc) + return rc; + } + + rc = hidpp20_led_sw_control_set_led_state(data->dev, &h_led); + if (rc) + return rc; + + return RATBAG_SUCCESS; +} + +static int +hidpp20drv_update_led_8070(struct ratbag_led *led, struct ratbag_profile* profile, + struct hidpp20drv_data *drv_data) { - struct ratbag_profile *profile = led->profile; - struct ratbag_device *device = profile->device; - struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device); struct hidpp20_profile *h_profile; struct hidpp20_led *h_led; - if (!(drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070)) - return -ENOTSUP; - h_profile = &drv_data->profiles->profiles[profile->index]; h_led = &(h_profile->leds[led->index]); @@ -430,6 +532,22 @@ hidpp20drv_update_led(struct ratbag_led *led) return RATBAG_SUCCESS; } +static int +hidpp20drv_update_led(struct ratbag_led *led) +{ + struct ratbag_profile *profile = led->profile; + struct ratbag_device *device = profile->device; + struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device); + + if (drv_data->capabilities & HIDPP_CAP_COLOR_LED_EFFECTS_8070) + return hidpp20drv_update_led_8070(led, profile, drv_data); + + if (drv_data->capabilities & HIDPP_CAP_LED_SW_CONTROL_1300) + return hidpp20drv_update_led_1300(led, drv_data); + + return RATBAG_ERROR_CAPABILITY; +} + static int hidpp20drv_current_profile(struct ratbag_device *device) { @@ -692,6 +810,27 @@ hidpp20drv_read_color_leds(struct ratbag_device *device) return rc; } +static int +hidpp20drv_read_leds(struct ratbag_device *device) +{ + struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device); + int rc; + + if (!(drv_data->capabilities & HIDPP_CAP_LED_SW_CONTROL_1300)) + return 0; + + free(drv_data->led_infos.leds); + drv_data->led_infos.leds = NULL; + + rc = hidpp20_led_sw_control_read_leds(drv_data->dev, &drv_data->led_infos.leds); + if (rc > 0) { + drv_data->num_leds = rc; + rc = 0; + } + + return rc; +} + static void hidpp20drv_read_profile_8100(struct ratbag_profile *profile, unsigned int index) { @@ -847,6 +986,20 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature) device->num_leds = drv_data->num_leds; break; } + case HIDPP_PAGE_LED_SW_CONTROL: { + log_debug(ratbag, "device has non-rgb leds\n"); + drv_data->capabilities |= HIDPP_CAP_LED_SW_CONTROL_1300; + + if (drv_data->capabilities & HIDPP_PAGE_COLOR_LED_EFFECTS) + return 0; + + if (hidpp20drv_read_leds(device)) + return 0; + + ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_LED); + device->num_leds = drv_data->num_leds; + break; + } case HIDPP_PAGE_ONBOARD_PROFILES: { log_debug(ratbag, "device has onboard profiles\n"); drv_data->capabilities |= HIDPP_CAP_ONBOARD_PROFILES_8100; diff --git a/src/libratbag.h b/src/libratbag.h index 4feb7d6e..2f3adb58 100644 --- a/src/libratbag.h +++ b/src/libratbag.h @@ -1460,7 +1460,9 @@ enum ratbag_led_mode { enum ratbag_led_type { RATBAG_LED_TYPE_UNKNOWN = -1, RATBAG_LED_TYPE_LOGO = 0, - RATBAG_LED_TYPE_SIDE + RATBAG_LED_TYPE_SIDE, + RATBAG_LED_TYPE_BATTERY, + RATBAG_LED_TYPE_DPI, }; /**