From fb2e543fb049ff74b83e195b4c7851b934fae114 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 26 Nov 2015 17:10:13 +0100 Subject: [PATCH] hidpp10: add support for Logitech G700 G700s should be the same Signed-off-by: Benjamin Tissoires --- hwdb/70-libratbag-mouse.hwdb | 6 ++ src/driver-hidpp10.c | 69 +++++++++++++++------ src/hidpp10.c | 112 ++++++++++++++++++++++++++++------- src/hidpp10.h | 1 + 4 files changed, 149 insertions(+), 39 deletions(-) diff --git a/hwdb/70-libratbag-mouse.hwdb b/hwdb/70-libratbag-mouse.hwdb index 841db688..fce7ffa9 100644 --- a/hwdb/70-libratbag-mouse.hwdb +++ b/hwdb/70-libratbag-mouse.hwdb @@ -109,6 +109,12 @@ mouse:usb:v046dpc24e:name:*: mouse:usb:v046dpc07d:name:*: RATBAG_DRIVER=hidpp20 +# G700 over USB +mouse:usb:v046dpc06b:name:*: + RATBAG_DRIVER=hidpp10 + RATBAG_HIDPP10_DPI=0:5700@23.53 + RATBAG_HIDPP10_PROFILE=G700 + # MX Master over unifying mouse:usb:v046dp4041:name:*: # MX Master over bluetooth diff --git a/src/driver-hidpp10.c b/src/driver-hidpp10.c index cf70a806..88fb96bb 100644 --- a/src/driver-hidpp10.c +++ b/src/driver-hidpp10.c @@ -57,25 +57,58 @@ static void hidpp10drv_read_button(struct ratbag_button *button) { enum ratbag_button_type type = RATBAG_BUTTON_TYPE_UNKNOWN; + struct ratbag_device *device = button->profile->device; + struct hidpp10drv_data *drv_data = ratbag_get_drv_data(device); + struct hidpp10_device *hidpp10 = drv_data->dev; - /* FIXME: this is valid for the G500s only */ - switch (button->index) { - case 0: type = RATBAG_BUTTON_TYPE_LEFT; break; - case 1: type = RATBAG_BUTTON_TYPE_MIDDLE; break; - case 2: type = RATBAG_BUTTON_TYPE_RIGHT; break; - case 3: type = RATBAG_BUTTON_TYPE_THUMB; break; - case 4: type = RATBAG_BUTTON_TYPE_THUMB2; break; - case 5: type = RATBAG_BUTTON_TYPE_THUMB3; break; - case 6: type = RATBAG_BUTTON_TYPE_WHEEL_LEFT; break; - case 7: type = RATBAG_BUTTON_TYPE_WHEEL_RIGHT; break; - case 8: type = RATBAG_BUTTON_TYPE_RESOLUTION_UP; break; - case 9: type = RATBAG_BUTTON_TYPE_RESOLUTION_DOWN; break; - case 10: - case 11: - case 12: /* these don't actually exist on the device */ - type = RATBAG_BUTTON_TYPE_UNKNOWN; break; - default: + switch (hidpp10->profile_type) { + case HIDPP10_PROFILE_G500: + switch (button->index) { + case 0: type = RATBAG_BUTTON_TYPE_LEFT; break; + case 1: type = RATBAG_BUTTON_TYPE_MIDDLE; break; + case 2: type = RATBAG_BUTTON_TYPE_RIGHT; break; + case 3: type = RATBAG_BUTTON_TYPE_THUMB; break; + case 4: type = RATBAG_BUTTON_TYPE_THUMB2; break; + case 5: type = RATBAG_BUTTON_TYPE_THUMB3; break; + case 6: type = RATBAG_BUTTON_TYPE_WHEEL_LEFT; break; + case 7: type = RATBAG_BUTTON_TYPE_WHEEL_RIGHT; break; + case 8: type = RATBAG_BUTTON_TYPE_RESOLUTION_UP; break; + case 9: type = RATBAG_BUTTON_TYPE_RESOLUTION_DOWN; break; + case 10: + case 11: + case 12: /* these don't actually exist on the device */ + type = RATBAG_BUTTON_TYPE_UNKNOWN; break; + default: + break; + } break; + case HIDPP10_PROFILE_G700: + switch (button->index) { + case 0: type = RATBAG_BUTTON_TYPE_LEFT; break; + case 1: type = RATBAG_BUTTON_TYPE_MIDDLE; break; + case 2: type = RATBAG_BUTTON_TYPE_RIGHT; break; + case 3: type = RATBAG_BUTTON_TYPE_THUMB; break; + case 4: type = RATBAG_BUTTON_TYPE_THUMB2; break; + case 5: type = RATBAG_BUTTON_TYPE_THUMB3; break; + case 6: type = RATBAG_BUTTON_TYPE_THUMB4; break; + case 7: type = RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP; break; + case 8: type = RATBAG_BUTTON_TYPE_RESOLUTION_DOWN; break; + case 9: type = RATBAG_BUTTON_TYPE_RESOLUTION_UP; break; + case 10: type = RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP; break; + case 11: type = RATBAG_BUTTON_TYPE_WHEEL_LEFT; break; + case 12: type = RATBAG_BUTTON_TYPE_WHEEL_RIGHT; break; + default: + break; + } + break; + default: + switch (button->index) { + case 0: type = RATBAG_BUTTON_TYPE_LEFT; break; + case 1: type = RATBAG_BUTTON_TYPE_MIDDLE; break; + case 2: type = RATBAG_BUTTON_TYPE_RIGHT; break; + default: + break; + } } button->type = type; @@ -241,6 +274,8 @@ hidpp10drv_probe(struct ratbag_device *device) if (prop) { if (strcasecmp("G500", prop) == 0) type = HIDPP10_PROFILE_G500; + else if (strcasecmp("G700", prop) == 0) + type = HIDPP10_PROFILE_G700; } /* We can treat all devices as wired devices here. If we talk to the * correct hidraw device the kernel adjusts the device index for us, diff --git a/src/hidpp10.c b/src/hidpp10.c index 27c5d703..9e91ca4c 100644 --- a/src/hidpp10.c +++ b/src/hidpp10.c @@ -520,7 +520,17 @@ hidpp10_get_battery_mileage(struct hidpp10_device *dev, } \ } -struct _hidpp10_dpi_mode { +struct _hidpp10_dpi_mode_8 { + uint8_t xres; + uint8_t yres; + uint8_t led1:4; + uint8_t led2:4; + uint8_t led3:4; + uint8_t led4:4; +} __attribute__((packed)); +_Static_assert(sizeof(struct _hidpp10_dpi_mode_8) == 4, "Invalid size"); + +struct _hidpp10_dpi_mode_16 { uint16_t xres; uint16_t yres; uint8_t led1:4; @@ -528,7 +538,7 @@ struct _hidpp10_dpi_mode { uint8_t led3:4; uint8_t led4:4; } __attribute__((packed)); -_Static_assert(sizeof(struct _hidpp10_dpi_mode) == 6, "Invalid size"); +_Static_assert(sizeof(struct _hidpp10_dpi_mode_16) == 6, "Invalid size"); union _hidpp10_button_binding { struct { @@ -564,23 +574,37 @@ union _hidpp10_button_binding { } __attribute__((packed)); _Static_assert(sizeof(union _hidpp10_button_binding) == 3, "Invalid size"); -struct _hidpp10_profile { +struct _hidpp10_profile_500 { uint8_t red; uint8_t green; uint8_t blue; uint8_t unknown; - struct _hidpp10_dpi_mode dpi_modes[PROFILE_NUM_DPI_MODES]; + struct _hidpp10_dpi_mode_16 dpi_modes[PROFILE_NUM_DPI_MODES]; uint8_t angle_correction; uint8_t default_dpi_mode; uint8_t unknown2[2]; uint8_t usb_refresh_rate; union _hidpp10_button_binding buttons[PROFILE_NUM_BUTTONS]; } __attribute__((packed)); -_Static_assert(sizeof(struct _hidpp10_profile) == 78, "Invalid size"); +_Static_assert(sizeof(struct _hidpp10_profile_500) == 78, "Invalid size"); + +struct _hidpp10_profile_700 { + struct _hidpp10_dpi_mode_8 dpi_modes[PROFILE_NUM_DPI_MODES]; + uint8_t default_dpi_mode; + uint8_t unknown1[3]; + uint8_t usb_refresh_rate; + uint8_t unknown2[10]; + union _hidpp10_button_binding buttons[PROFILE_NUM_BUTTONS]; + uint8_t unknown3[5]; + uint16_t name[23]; + uint16_t macro_names[17][11]; +} __attribute__((packed)); +_Static_assert(sizeof(struct _hidpp10_profile_700) == 499, "Invalid size"); union _hidpp10_profile_data { - struct _hidpp10_profile profile; - uint8_t data[((sizeof(struct _hidpp10_profile) + 15)/16)*16]; + struct _hidpp10_profile_500 profile_500; + struct _hidpp10_profile_700 profile_700; + uint8_t data[HIDPP10_PAGE_SIZE]; }; _Static_assert((sizeof(union _hidpp10_profile_data) % 16) == 0, "Invalid size"); @@ -740,17 +764,39 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, int8_t *current_profile) } static void -hidpp10_fill_dpi_modes(struct hidpp10_device *dev, - struct hidpp10_profile *profile, - struct _hidpp10_dpi_mode *dpi_list, - unsigned int count) +hidpp10_fill_dpi_modes_8(struct hidpp10_device *dev, + struct hidpp10_profile *profile, + struct _hidpp10_dpi_mode_8 *dpi_list, + unsigned int count) +{ + unsigned int i; + + profile->num_dpi_modes = count; + for (i = 0; i < count; i++) { + struct _hidpp10_dpi_mode_8 *dpi = &dpi_list[i]; + + profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, dpi->xres); + profile->dpi_modes[i].yres = hidpp10_get_dpi_value(dev, dpi->yres); + + profile->dpi_modes[i].led[0] = dpi->led1 == 0x2; + profile->dpi_modes[i].led[1] = dpi->led2 == 0x2; + profile->dpi_modes[i].led[2] = dpi->led3 == 0x2; + profile->dpi_modes[i].led[3] = dpi->led4 == 0x2; + } +} + +static void +hidpp10_fill_dpi_modes_16(struct hidpp10_device *dev, + struct hidpp10_profile *profile, + struct _hidpp10_dpi_mode_16 *dpi_list, + unsigned int count) { unsigned int i; profile->num_dpi_modes = count; for (i = 0; i < count; i++) { uint8_t *be; /* in big endian */ - struct _hidpp10_dpi_mode *dpi = &dpi_list[i]; + struct _hidpp10_dpi_mode_16 *dpi = &dpi_list[i]; be = (uint8_t*)&dpi->xres; profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, hidpp_get_unaligned_be_u16(be)); @@ -806,7 +852,8 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr { uint8_t page_data[HIDPP10_PAGE_SIZE]; union _hidpp10_profile_data *data = (union _hidpp10_profile_data *)page_data; - struct _hidpp10_profile *p = &data->profile; + struct _hidpp10_profile_500 *p500 = &data->profile_500; + struct _hidpp10_profile_700 *p700 = &data->profile_700; size_t i; int res; struct hidpp10_profile *profile; @@ -839,7 +886,16 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr return -EINVAL; } - buttons = p->buttons; + switch (dev->profile_type) { + case HIDPP10_PROFILE_G500: + buttons = p500->buttons; + break; + case HIDPP10_PROFILE_G700: + buttons = p700->buttons; + break; + default: + hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n"); + } profile = &dev->profiles[number]; if (!profile->initialized) { @@ -849,16 +905,28 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr if (res) return res; - profile->red = p->red; - profile->green = p->green; - profile->blue = p->blue; - profile->angle_correction = p->angle_correction; - profile->default_dpi_mode = p->default_dpi_mode; - profile->refresh_rate = p->usb_refresh_rate ? 1000/p->usb_refresh_rate : 0; + switch (dev->profile_type) { + case HIDPP10_PROFILE_G500: + profile->red = p500->red; + profile->green = p500->green; + profile->blue = p500->blue; + profile->angle_correction = p500->angle_correction; + profile->default_dpi_mode = p500->default_dpi_mode; + profile->refresh_rate = p500->usb_refresh_rate ? 1000/p500->usb_refresh_rate : 0; - hidpp10_fill_dpi_modes(dev, profile, p->dpi_modes, PROFILE_NUM_DPI_MODES); + hidpp10_fill_dpi_modes_16(dev, profile, p500->dpi_modes, PROFILE_NUM_DPI_MODES); + hidpp10_fill_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS); + break; + case HIDPP10_PROFILE_G700: + profile->default_dpi_mode = p700->default_dpi_mode; + profile->refresh_rate = p700->usb_refresh_rate ? 1000/p700->usb_refresh_rate : 0; - hidpp10_fill_buttons(dev, profile, p->buttons, PROFILE_NUM_BUTTONS); + hidpp10_fill_dpi_modes_8(dev, profile, p700->dpi_modes, PROFILE_NUM_DPI_MODES); + hidpp10_fill_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS); + break; + default: + hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n"); + } profile->initialized = 1; } diff --git a/src/hidpp10.h b/src/hidpp10.h index faaa6c48..2f6cf7c8 100644 --- a/src/hidpp10.h +++ b/src/hidpp10.h @@ -43,6 +43,7 @@ enum hidpp10_profile_type { HIDPP10_PROFILE_UNKNOWN = -1, HIDPP10_PROFILE_G500, + HIDPP10_PROFILE_G700, }; struct hidpp10_directory;