hidpp20: clean the button mapping code

The button mapping of the hid++ 2.0 devices is close to the one from
HID++ 1.0, but not entirely (1.0 have a size of 3 while and 2.0 a size
of 4).
The parsing was not clean, so reuse a the same logic than hidpp10.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
This commit is contained in:
Benjamin Tissoires
2015-12-08 17:43:06 +01:00
parent dcf5e45797
commit dd7de2225c
3 changed files with 165 additions and 94 deletions

View File

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

View File

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

View File

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