Skip to content

Commit 048cddf

Browse files
bentissJiri Kosina
authored andcommitted
HID: input: enforce Invert usage to be processed before InRange
When a device exposes both Invert and InRange, Invert must be processed before InRange. If we keep the order of the device and we process them out of order, InRange will first set BTN_TOOL_PEN, and then Invert will set BTN_TOOL_RUBBER. Userspace knows how to deal with that situation, but fixing it in the kernel is now easier. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Reviewed-by: Ping Cheng <ping.cheng@wacom.com> Acked-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent bebcc52 commit 048cddf

2 files changed

Lines changed: 35 additions & 3 deletions

File tree

drivers/hid/hid-input.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ static const struct {
4848
__s32 y;
4949
} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
5050

51+
/*
52+
* hid-input will convert this list into priorities:
53+
* the first element will have the highest priority
54+
* (the length of the following array) and the last
55+
* element the lowest (1).
56+
*
57+
* hid-input will then shift the priority by 8 bits to leave some space
58+
* in case drivers want to interleave other fields.
59+
*
60+
* If drivers want to add fields before those, hid-input will
61+
* leave out the first 8 bits of the priority value.
62+
*
63+
* This still leaves us 65535 individual priority values.
64+
*/
65+
static const __u32 hidinput_usages_priorities[] = {
66+
HID_DG_INVERT, /* Invert must always come before In Range */
67+
HID_DG_INRANGE,
68+
};
69+
5170
#define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
5271
#define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
5372
#define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
@@ -586,11 +605,12 @@ static bool hidinput_field_in_collection(struct hid_device *device, struct hid_f
586605
}
587606

588607
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
589-
struct hid_usage *usage)
608+
struct hid_usage *usage, unsigned int usage_index)
590609
{
591610
struct input_dev *input = hidinput->input;
592611
struct hid_device *device = input_get_drvdata(input);
593612
int max = 0, code;
613+
unsigned int i = 0;
594614
unsigned long *bit = NULL;
595615

596616
field->hidinput = hidinput;
@@ -608,6 +628,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
608628
goto ignore;
609629
}
610630

631+
/* assign a priority based on the static list declared here */
632+
for (i = 0; i < ARRAY_SIZE(hidinput_usages_priorities); i++) {
633+
if (usage->hid == hidinput_usages_priorities[i]) {
634+
field->usages_priorities[usage_index] =
635+
(ARRAY_SIZE(hidinput_usages_priorities) - i) << 8;
636+
break;
637+
}
638+
}
639+
611640
if (device->driver->input_mapping) {
612641
int ret = device->driver->input_mapping(device, hidinput, field,
613642
usage, &bit, &max);
@@ -1962,7 +1991,8 @@ static inline void hidinput_configure_usages(struct hid_input *hidinput,
19621991
for (i = 0; i < report->maxfield; i++)
19631992
for (j = 0; j < report->field[i]->maxusage; j++)
19641993
hidinput_configure_usage(hidinput, report->field[i],
1965-
report->field[i]->usage + j);
1994+
report->field[i]->usage + j,
1995+
j);
19661996
}
19671997

19681998
/*

include/linux/hid.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,9 @@ struct hid_field {
477477
unsigned report_type; /* (input,output,feature) */
478478
__s32 *value; /* last known value(s) */
479479
__s32 *new_value; /* newly read value(s) */
480-
__s32 *usages_priorities; /* priority of each usage when reading the report */
480+
__s32 *usages_priorities; /* priority of each usage when reading the report
481+
* bits 8-16 are reserved for hid-input usage
482+
*/
481483
__s32 logical_minimum;
482484
__s32 logical_maximum;
483485
__s32 physical_minimum;

0 commit comments

Comments
 (0)