diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index b084be5b..56ec92b0 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -109,24 +109,28 @@ hidpp20drv_read_button_8100(struct ratbag_button *button) profile = &drv_data->profiles->profiles[button->profile->index]; - switch (profile->buttons[button->index].type) { - case HIDPP20_BUTTON_HID_MOUSE: - button->action.type = RATBAG_BUTTON_ACTION_TYPE_BUTTON; - button->action.action.button = profile->buttons[button->index].code; - break; - case HIDPP20_BUTTON_HID_KEYBOARD: - button->action.type = RATBAG_BUTTON_ACTION_TYPE_KEY; - button->action.action.key.key = ratbag_hidraw_get_keycode_from_keyboard_usage(device, - profile->buttons[button->index].code); - break; - case HIDPP20_BUTTON_HID_CONSUMER_CONTROL: - button->action.type = RATBAG_BUTTON_ACTION_TYPE_KEY; - button->action.action.key.key = ratbag_hidraw_get_keycode_from_consumer_usage(device, - profile->buttons[button->index].code); + switch (profile->buttons[button->index].any.type) { + case HIDPP20_BUTTON_HID_TYPE: + switch (profile->buttons[button->index].subany.subtype) { + case HIDPP20_BUTTON_HID_TYPE_MOUSE: + button->action.type = RATBAG_BUTTON_ACTION_TYPE_BUTTON; + button->action.action.button = profile->buttons[button->index].button.buttons; + break; + case HIDPP20_BUTTON_HID_TYPE_KEYBOARD: + button->action.type = RATBAG_BUTTON_ACTION_TYPE_KEY; + button->action.action.key.key = ratbag_hidraw_get_keycode_from_keyboard_usage(device, + profile->buttons[button->index].keyboard_keys.key); + break; + case HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL: + button->action.type = RATBAG_BUTTON_ACTION_TYPE_KEY; + button->action.action.key.key = ratbag_hidraw_get_keycode_from_consumer_usage(device, + profile->buttons[button->index].consumer_control.consumer_control); + break; + } break; case HIDPP20_BUTTON_SPECIAL: button->action.type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL; - button->action.action.special = hidpp20_onboard_profiles_get_special(profile->buttons[button->index].code); + button->action.action.special = hidpp20_onboard_profiles_get_special(profile->buttons[button->index].special.special); break; default: button->action.type = RATBAG_BUTTON_ACTION_TYPE_UNKNOWN; @@ -187,7 +191,7 @@ hidpp20drv_write_button_8100(struct ratbag_button *button, struct ratbag_device *device = button->profile->device; struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device); struct hidpp20_profile *profile; - uint8_t code, type; + uint8_t code, type, subtype; if (!(drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100)) return -ENOTSUP; @@ -196,27 +200,33 @@ hidpp20drv_write_button_8100(struct ratbag_button *button, switch (action->type) { case RATBAG_BUTTON_ACTION_TYPE_BUTTON: - profile->buttons[button->index].type = HIDPP20_BUTTON_HID_MOUSE; - profile->buttons[button->index].code = action->action.button; + profile->buttons[button->index].button.type = HIDPP20_BUTTON_HID_TYPE; + profile->buttons[button->index].button.subtype = HIDPP20_BUTTON_HID_TYPE_MOUSE; + profile->buttons[button->index].button.buttons = action->action.button; break; case RATBAG_BUTTON_ACTION_TYPE_KEY: - type = HIDPP20_BUTTON_HID_KEYBOARD; + type = HIDPP20_BUTTON_HID_TYPE; + subtype = HIDPP20_BUTTON_HID_TYPE_KEYBOARD; code = ratbag_hidraw_get_keyboard_usage_from_keycode(device, action->action.key.key); if (code == 0) { - type = HIDPP20_BUTTON_HID_CONSUMER_CONTROL; + subtype = HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL; code = ratbag_hidraw_get_consumer_usage_from_keycode(device, action->action.key.key); if (code == 0) return -EINVAL; } - profile->buttons[button->index].type = type; - profile->buttons[button->index].code = code; + profile->buttons[button->index].subany.type = type; + profile->buttons[button->index].subany.subtype = subtype; + if (subtype == HIDPP20_BUTTON_HID_TYPE_KEYBOARD) + profile->buttons[button->index].keyboard_keys.key = code; + else + profile->buttons[button->index].consumer_control.consumer_control = code; break; case RATBAG_BUTTON_ACTION_TYPE_SPECIAL: code = hidpp20_onboard_profiles_get_code_from_special(action->action.special); if (code == 0) return -EINVAL; - profile->buttons[button->index].type = HIDPP20_BUTTON_SPECIAL; - profile->buttons[button->index].code = code; + profile->buttons[button->index].special.type = HIDPP20_BUTTON_SPECIAL; + profile->buttons[button->index].special.special = code; break; case RATBAG_BUTTON_ACTION_TYPE_MACRO: default: diff --git a/src/hidpp20.c b/src/hidpp20.c index 5def9de9..00512f99 100644 --- a/src/hidpp20.c +++ b/src/hidpp20.c @@ -1256,23 +1256,6 @@ hidpp20_onboard_profiles_enable_profile(struct hidpp20_device *device, return hidpp20_onboard_profiles_write_page(device, 0x00, data); } -struct hidpp20_internal_button { - uint8_t type; - union { - struct { - uint8_t subtype; - union { - struct { - uint8_t modifier; - uint8_t code; - } key; - uint16_t button; - } __attribute__((packed)); - } __attribute__((packed)) hid; - uint8_t special; - } value; -} __attribute__((packed)); - union hidpp20_internal_profile { uint8_t data[HIDPP20_PROFILE_SIZE]; struct { @@ -1282,8 +1265,8 @@ union hidpp20_internal_profile { uint16_t dpi[7]; uint8_t zero; uint8_t padding[14]; - struct hidpp20_internal_button buttons[16]; - struct hidpp20_internal_button alternate_buttons[16]; + union hidpp20_button_binding buttons[16]; + union hidpp20_button_binding alternate_buttons[16]; union { char txt[16 * 3]; uint8_t raw[16 * 3]; @@ -1294,6 +1277,90 @@ union hidpp20_internal_profile { }; _Static_assert(sizeof(union hidpp20_internal_profile) == HIDPP20_PROFILE_SIZE, "Invalid size"); +static void +hidpp20_buttons_to_cpu(struct hidpp20_profile *profile, + union hidpp20_button_binding *buttons, + unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + union hidpp20_button_binding *b = &buttons[i]; + union hidpp20_button_binding *button = &profile->buttons[i]; + + button->any.type = b->any.type; + + switch (b->any.type) { + case HIDPP20_BUTTON_HID_TYPE: + button->subany.subtype = b->subany.subtype; + switch (b->subany.subtype) { + case HIDPP20_BUTTON_HID_TYPE_MOUSE: + button->button.buttons = ffs(hidpp_be_u16_to_cpu(b->button.buttons)); + break; + case HIDPP20_BUTTON_HID_TYPE_KEYBOARD: + button->keyboard_keys.modifier_flags = b->keyboard_keys.modifier_flags; + button->keyboard_keys.key = b->keyboard_keys.key; + break; + case HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL: + button->consumer_control.consumer_control = + hidpp_be_u16_to_cpu(b->consumer_control.consumer_control); + break; + } + break; + case HIDPP20_BUTTON_SPECIAL: + button->special.special = b->special.special; + break; + case HIDPP20_BUTTON_DISABLED: + break; + default: + break; + } + } +} + +static void +hidpp20_buttons_from_cpu(struct hidpp20_profile *profile, + union hidpp20_button_binding *buttons, + unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + union hidpp20_button_binding *button = &buttons[i]; + union hidpp20_button_binding *b = &profile->buttons[i]; + + button->any.type = b->any.type; + + switch (b->any.type) { + case HIDPP20_BUTTON_HID_TYPE: + button->subany.subtype = b->subany.subtype; + switch (b->subany.subtype) { + case HIDPP20_BUTTON_HID_TYPE_MOUSE: + button->button.buttons = hidpp_cpu_to_be_u16(1U << (b->button.buttons - 1)); + break; + case HIDPP20_BUTTON_HID_TYPE_KEYBOARD: + button->keyboard_keys.modifier_flags = b->keyboard_keys.modifier_flags; + button->keyboard_keys.key = b->keyboard_keys.key; + break; + case HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL: + button->consumer_control.type = HIDPP20_BUTTON_HID_TYPE; + button->consumer_control.subtype = HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL; + button->consumer_control.consumer_control = + hidpp_cpu_to_be_u16(b->consumer_control.consumer_control); + break; + } + break; + case HIDPP20_BUTTON_SPECIAL: + button->special.special = b->special.special; + break; + case HIDPP20_BUTTON_DISABLED: + break; + default: + break; + } + } +} + int hidpp20_onboard_profiles_read(struct hidpp20_device *device, unsigned int index, struct hidpp20_profiles *profiles_list) @@ -1319,27 +1386,7 @@ int hidpp20_onboard_profiles_read(struct hidpp20_device *device, profile->dpi[i] = hidpp_get_unaligned_le_u16(&data[2 * i + 3]); } - for (i = 0; i < profiles_list->num_buttons; i++) { - struct hidpp20_internal_button *button = &pdata.profile.buttons[i]; - - profile->buttons[i].type = button->type; - - if (button->type == HIDPP20_BUTTON_HID) { - profile->buttons[i].type |= button->value.hid.subtype; - - if (profile->buttons[i].type == HIDPP20_BUTTON_HID_KEYBOARD) { - profile->buttons[i].modifiers = button->value.hid.key.modifier; - profile->buttons[i].code = button->value.hid.key.code; - } else if (profile->buttons[i].type == HIDPP20_BUTTON_HID_CONSUMER_CONTROL) { - profile->buttons[i].modifiers = button->value.hid.key.modifier; - profile->buttons[i].code = button->value.hid.key.code; - } else { - profile->buttons[i].code = ffs(hidpp_be_u16_to_cpu(button->value.hid.button)); - } - } else if (button->type == HIDPP20_BUTTON_SPECIAL) { - profile->buttons[i].code = button->value.special; - } - } + hidpp20_buttons_to_cpu(profile, pdata.profile.buttons, profiles_list->num_buttons); memcpy(profile->name, pdata.profile.name.txt, sizeof(profile->name)); /* force terminating '\0' */ @@ -1385,24 +1432,7 @@ int hidpp20_onboard_profiles_write(struct hidpp20_device *device, pdata.profile.dpi[i] = hidpp_cpu_to_le_u16(profile->dpi[i]); } - for (i = 0; i < profiles_list->num_buttons; i++) { - struct hidpp20_internal_button *button = &pdata.profile.buttons[i]; - - button->type = profile->buttons[i].type & 0xf0; - - if (button->type == HIDPP20_BUTTON_HID) { - button->value.hid.subtype = profile->buttons[i].type & 0x0f; - - if (button->value.hid.subtype == HIDPP20_BUTTON_HID_KEYBOARD) { - button->value.hid.key.modifier = profile->buttons[i].modifiers; - button->value.hid.key.code = profile->buttons[i].code; - } else { - button->value.hid.button = hidpp_cpu_to_be_u16(1U << (profile->buttons[i].code - 1)); - } - } else if (button->type == HIDPP20_BUTTON_SPECIAL) { - button->value.special = profile->buttons[i].code; - } - } + hidpp20_buttons_from_cpu(profile, pdata.profile.buttons, profiles_list->num_buttons); memcpy(pdata.profile.name.txt, profile->name, sizeof(profile->name)); diff --git a/src/hidpp20.h b/src/hidpp20.h index 23d6b7f0..96e22ca2 100644 --- a/src/hidpp20.h +++ b/src/hidpp20.h @@ -264,14 +264,49 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device, #define HIDPP_PAGE_ONBOARD_PROFILES 0x8100 -#define HIDPP20_BUTTON_HID_MOUSE 0x81 -#define HIDPP20_BUTTON_HID_KEYBOARD 0x82 -#define HIDPP20_BUTTON_HID_CONSUMER_CONTROL 0x83 -#define HIDPP20_BUTTON_SPECIAL 0x90 -#define HIDPP20_BUTTON_DISABLED 0xFF +#define HIDPP20_BUTTON_HID_TYPE 0x80 +#define HIDPP20_BUTTON_HID_TYPE_MOUSE 0x01 +#define HIDPP20_BUTTON_HID_TYPE_KEYBOARD 0x02 +#define HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL 0x03 +#define HIDPP20_BUTTON_SPECIAL 0x90 +#define HIDPP20_BUTTON_DISABLED 0xFF -#define HIDPP20_MODIFIER_KEY_CTRL 0x01 -#define HIDPP20_MODIFIER_KEY_SHIFT 0x02 +#define HIDPP20_MODIFIER_KEY_CTRL 0x01 +#define HIDPP20_MODIFIER_KEY_SHIFT 0x02 + +union hidpp20_button_binding { + struct { + uint8_t type; + } any; + struct { + uint8_t type; + uint8_t subtype; + } subany; + struct { + uint8_t type; /* HIDPP20_BUTTON_HID_TYPE */ + uint8_t subtype; /* HIDPP20_BUTTON_HID_TYPE_MOUSE */ + uint16_t buttons; /* flags when internal */ + } __attribute__((packed)) button; + struct { + uint8_t type; /* HIDPP20_BUTTON_HID_TYPE */ + uint8_t subtype; /* HIDPP20_BUTTON_HID_TYPE_KEYBOARD */ + uint8_t modifier_flags; + uint8_t key; + } __attribute__((packed)) keyboard_keys; + struct { + uint8_t type; /* HIDPP20_BUTTON_HID_TYPE */ + uint8_t subtype; /* HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL */ + uint16_t consumer_control; + } __attribute__((packed)) consumer_control; + struct { + uint8_t type; /* HIDPP20_BUTTON_SPECIAL */ + uint8_t special; + } __attribute__((packed)) special; + struct { + uint8_t type; /* PROFILE_BUTTON_TYPE_DISABLED */ + } disabled; +} __attribute__((packed)); +_Static_assert(sizeof(union hidpp20_button_binding) == 4, "Invalid size"); struct hidpp20_profile { uint8_t index; @@ -281,11 +316,7 @@ struct hidpp20_profile { unsigned default_dpi; unsigned switched_dpi; uint16_t dpi[5]; - struct { - uint8_t type; - uint8_t modifiers; - uint8_t code; - } buttons[32]; + union hidpp20_button_binding buttons[32]; }; struct hidpp20_profiles {