forked from drath/libratbag
hidpp10: add support for Logitech G700
G700s should be the same Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
112
src/hidpp10.c
112
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
enum hidpp10_profile_type {
|
||||
HIDPP10_PROFILE_UNKNOWN = -1,
|
||||
HIDPP10_PROFILE_G500,
|
||||
HIDPP10_PROFILE_G700,
|
||||
};
|
||||
|
||||
struct hidpp10_directory;
|
||||
|
||||
Reference in New Issue
Block a user