From 14ca639270f3f7fb0b59be1f5ee49e3192d1568d Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Thu, 7 Jan 2016 22:18:11 +0100 Subject: [PATCH] hidpp10: Parse G9 profile This allows to read but not write profiles from the G9. The dpi mode sturct is a little different as the mouse only supports symetrical dpi for x/y. Given the current naming a suffix of _sym was the best I could come up with. The G9 profile has some additional unknown bytes compared to the others. Unfortunately the content of them varies for the 4 first profiles and the last. So adding a default value for the like with the G700 is not possible. For this reason I dropped implementing the write part for now. Something else to address is that this mouse only has 10 buttons compared to the usual 13 that we have in PROFILE_NUM_BUTTONS. For now I just hardcoded it in the profile and hidpp10_get_profile. --- hwdb/70-libratbag-mouse.hwdb | 1 + src/driver-hidpp10.c | 2 ++ src/hidpp10.c | 59 ++++++++++++++++++++++++++++++++++++ src/hidpp10.h | 1 + 4 files changed, 63 insertions(+) diff --git a/hwdb/70-libratbag-mouse.hwdb b/hwdb/70-libratbag-mouse.hwdb index c2bcd5b8..9acf1b5b 100644 --- a/hwdb/70-libratbag-mouse.hwdb +++ b/hwdb/70-libratbag-mouse.hwdb @@ -81,6 +81,7 @@ mouse:usb:v046dpc51a:name:*: mouse:usb:v046dpc048:name:*: RATBAG_DRIVER=hidpp10 RATBAG_HIDPP10_DPI_LIST=0;200;400;600;800;1000;1200;1400;1600;1800;2000;2200;2400;2600;2800;3000;3200 + RATBAG_HIDPP10_PROFILE=G9 # G9x [Original] mouse:usb:v046dpc066:name:*: diff --git a/src/driver-hidpp10.c b/src/driver-hidpp10.c index f25c2518..0454304c 100644 --- a/src/driver-hidpp10.c +++ b/src/driver-hidpp10.c @@ -520,6 +520,8 @@ hidpp10drv_probe(struct ratbag_device *device) type = HIDPP10_PROFILE_G500; else if (strcasecmp("G700", prop) == 0) type = HIDPP10_PROFILE_G700; + else if (strcasecmp("G9", prop) == 0) + type = HIDPP10_PROFILE_G9; } prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_INDEX"); diff --git a/src/hidpp10.c b/src/hidpp10.c index c98ea82a..6219ca69 100644 --- a/src/hidpp10.c +++ b/src/hidpp10.c @@ -520,6 +520,15 @@ hidpp10_get_battery_mileage(struct hidpp10_device *dev, } \ } +struct _hidpp10_dpi_mode_8_sym { + uint8_t res; + 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_sym) == 3, "Invalid size"); + struct _hidpp10_dpi_mode_8 { uint8_t xres; uint8_t yres; @@ -617,9 +626,25 @@ struct _hidpp10_profile_700 { } __attribute__((packed)); _Static_assert(sizeof(struct _hidpp10_profile_700) == 499, "Invalid size"); +struct _hidpp10_profile_9 { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t unknown1; + struct _hidpp10_dpi_mode_8_sym dpi_modes[PROFILE_NUM_DPI_MODES]; + uint8_t default_dpi_mode; + uint8_t unknown2[2]; + uint8_t usb_refresh_rate; + union _hidpp10_button_binding buttons[10]; + uint8_t unknown3[3]; + union _hidpp10_profile_metadata metadata; +} __attribute__((packed)); +_Static_assert(sizeof(struct _hidpp10_profile_500) == 503, "Invalid size"); + union _hidpp10_profile_data { struct _hidpp10_profile_500 profile_500; struct _hidpp10_profile_700 profile_700; + struct _hidpp10_profile_9 profile_9; uint8_t data[HIDPP10_PAGE_SIZE]; }; _Static_assert((sizeof(union _hidpp10_profile_data) % 16) == 0, "Invalid size"); @@ -833,6 +858,28 @@ hidpp10_set_current_profile(struct hidpp10_device *dev, int16_t current_profile) PROFILE_TYPE_INDEX); } +static void +hidpp10_fill_dpi_modes_8_sym(struct hidpp10_device *dev, + struct hidpp10_profile *profile, + struct _hidpp10_dpi_mode_8_sym *dpi_list, + unsigned int count) +{ + unsigned int i; + + profile->num_dpi_modes = count; + for (i = 0; i < count; i++) { + struct _hidpp10_dpi_mode_8_sym *dpi = &dpi_list[i]; + + profile->dpi_modes[i].xres = hidpp10_get_dpi_value(dev, dpi->res); + profile->dpi_modes[i].yres = hidpp10_get_dpi_value(dev, dpi->res); + + 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_8(struct hidpp10_device *dev, struct hidpp10_profile *profile, @@ -1345,6 +1392,7 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr union _hidpp10_profile_data *data = (union _hidpp10_profile_data *)page_data; struct _hidpp10_profile_500 *p500 = &data->profile_500; struct _hidpp10_profile_700 *p700 = &data->profile_700; + struct _hidpp10_profile_9 *p9 = &data->profile_9; size_t i; int res; struct hidpp10_profile *profile; @@ -1384,6 +1432,9 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr case HIDPP10_PROFILE_G700: buttons = p700->buttons; break; + case HIDPP10_PROFILE_G9: + buttons = p9->buttons; + break; default: hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n"); } @@ -1427,6 +1478,14 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr hidpp10_profile_parse_names(dev, profile, number, &p700->metadata); hidpp10_fill_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS); break; + case HIDPP10_PROFILE_G9: + profile->default_dpi_mode = p9->default_dpi_mode; + profile->refresh_rate = p9->usb_refresh_rate ? 1000/p9->usb_refresh_rate : 0; + + hidpp10_fill_dpi_modes_8_sym(dev, profile, p9->dpi_modes, PROFILE_NUM_DPI_MODES); + hidpp10_profile_parse_names(dev, profile, number, &p9->metadata); + hidpp10_fill_buttons(dev, profile, buttons, 10); + break; default: hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n"); } diff --git a/src/hidpp10.h b/src/hidpp10.h index 8a05c28f..473367f6 100644 --- a/src/hidpp10.h +++ b/src/hidpp10.h @@ -44,6 +44,7 @@ enum hidpp10_profile_type { HIDPP10_PROFILE_UNKNOWN = -1, HIDPP10_PROFILE_G500, HIDPP10_PROFILE_G700, + HIDPP10_PROFILE_G9, }; struct hidpp10_directory;