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:
Benjamin Tissoires
2015-11-26 17:10:13 +01:00
parent 9db8d2875d
commit fb2e543fb0
4 changed files with 149 additions and 39 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -43,6 +43,7 @@
enum hidpp10_profile_type {
HIDPP10_PROFILE_UNKNOWN = -1,
HIDPP10_PROFILE_G500,
HIDPP10_PROFILE_G700,
};
struct hidpp10_directory;