Skip to content

Commit 5c20000

Browse files
bentissJiri Kosina
authored andcommitted
HID: input: accommodate priorities for slotted devices
Multitouch devices in hybrid mode are reporting multiple times the same collection. We should accommodate for this in our handling of priorities by defining the slots they belong to. 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 87562fc commit 5c20000

2 files changed

Lines changed: 96 additions & 8 deletions

File tree

drivers/hid/hid-input.c

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ 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+
struct usage_priority {
52+
__u32 usage; /* the HID usage associated */
53+
bool global; /* we assume all usages to be slotted,
54+
* unless global
55+
*/
56+
unsigned int slot_overwrite; /* for globals: allows to set the usage
57+
* before or after the slots
58+
*/
59+
};
60+
5161
/*
5262
* hid-input will convert this list into priorities:
5363
* the first element will have the highest priority
@@ -57,17 +67,30 @@ static const struct {
5767
* hid-input will then shift the priority by 8 bits to leave some space
5868
* in case drivers want to interleave other fields.
5969
*
70+
* To accommodate slotted devices, the slot priority is
71+
* defined in the next 8 bits (defined by 0xff - slot).
72+
*
6073
* If drivers want to add fields before those, hid-input will
6174
* leave out the first 8 bits of the priority value.
6275
*
6376
* This still leaves us 65535 individual priority values.
6477
*/
65-
static const __u32 hidinput_usages_priorities[] = {
66-
HID_DG_ERASER, /* Eraser (eraser touching) must always come before tipswitch */
67-
HID_DG_INVERT, /* Invert must always come before In Range */
68-
HID_DG_TIPSWITCH, /* Is the tip of the tool touching? */
69-
HID_DG_TIPPRESSURE, /* Tip Pressure might emulate tip switch */
70-
HID_DG_INRANGE, /* In Range needs to come after the other tool states */
78+
static const struct usage_priority hidinput_usages_priorities[] = {
79+
{ /* Eraser (eraser touching) must always come before tipswitch */
80+
.usage = HID_DG_ERASER,
81+
},
82+
{ /* Invert must always come before In Range */
83+
.usage = HID_DG_INVERT,
84+
},
85+
{ /* Is the tip of the tool touching? */
86+
.usage = HID_DG_TIPSWITCH,
87+
},
88+
{ /* Tip Pressure might emulate tip switch */
89+
.usage = HID_DG_TIPPRESSURE,
90+
},
91+
{ /* In Range needs to come after the other tool states */
92+
.usage = HID_DG_INRANGE,
93+
},
7194
};
7295

7396
#define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
@@ -612,6 +635,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
612635
{
613636
struct input_dev *input = hidinput->input;
614637
struct hid_device *device = input_get_drvdata(input);
638+
const struct usage_priority *usage_priority = NULL;
615639
int max = 0, code;
616640
unsigned int i = 0;
617641
unsigned long *bit = NULL;
@@ -633,13 +657,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
633657

634658
/* assign a priority based on the static list declared here */
635659
for (i = 0; i < ARRAY_SIZE(hidinput_usages_priorities); i++) {
636-
if (usage->hid == hidinput_usages_priorities[i]) {
660+
if (usage->hid == hidinput_usages_priorities[i].usage) {
661+
usage_priority = &hidinput_usages_priorities[i];
662+
637663
field->usages_priorities[usage_index] =
638664
(ARRAY_SIZE(hidinput_usages_priorities) - i) << 8;
639665
break;
640666
}
641667
}
642668

669+
/*
670+
* For slotted devices, we need to also add the slot index
671+
* in the priority.
672+
*/
673+
if (usage_priority && usage_priority->global)
674+
field->usages_priorities[usage_index] |=
675+
usage_priority->slot_overwrite;
676+
else
677+
field->usages_priorities[usage_index] |=
678+
(0xff - field->slot_idx) << 16;
679+
643680
if (device->driver->input_mapping) {
644681
int ret = device->driver->input_mapping(device, hidinput, field,
645682
usage, &bit, &max);
@@ -2068,7 +2105,57 @@ static struct hid_input *hidinput_match_application(struct hid_report *report)
20682105
static inline void hidinput_configure_usages(struct hid_input *hidinput,
20692106
struct hid_report *report)
20702107
{
2071-
int i, j;
2108+
int i, j, k;
2109+
int first_field_index = 0;
2110+
int slot_collection_index = -1;
2111+
int prev_collection_index = -1;
2112+
unsigned int slot_idx = 0;
2113+
struct hid_field *field;
2114+
2115+
/*
2116+
* First tag all the fields that are part of a slot,
2117+
* a slot needs to have one Contact ID in the collection
2118+
*/
2119+
for (i = 0; i < report->maxfield; i++) {
2120+
field = report->field[i];
2121+
2122+
/* ignore fields without usage */
2123+
if (field->maxusage < 1)
2124+
continue;
2125+
2126+
/*
2127+
* janitoring when collection_index changes
2128+
*/
2129+
if (prev_collection_index != field->usage->collection_index) {
2130+
prev_collection_index = field->usage->collection_index;
2131+
first_field_index = i;
2132+
}
2133+
2134+
/*
2135+
* if we already found a Contact ID in the collection,
2136+
* tag and continue to the next.
2137+
*/
2138+
if (slot_collection_index == field->usage->collection_index) {
2139+
field->slot_idx = slot_idx;
2140+
continue;
2141+
}
2142+
2143+
/* check if the current field has Contact ID */
2144+
for (j = 0; j < field->maxusage; j++) {
2145+
if (field->usage[j].hid == HID_DG_CONTACTID) {
2146+
slot_collection_index = field->usage->collection_index;
2147+
slot_idx++;
2148+
2149+
/*
2150+
* mark all previous fields and this one in the
2151+
* current collection to be slotted.
2152+
*/
2153+
for (k = first_field_index; k <= i; k++)
2154+
report->field[k]->slot_idx = slot_idx;
2155+
break;
2156+
}
2157+
}
2158+
}
20722159

20732160
for (i = 0; i < report->maxfield; i++)
20742161
for (j = 0; j < report->field[i]->maxusage; j++)

include/linux/hid.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ struct hid_field {
492492
/* hidinput data */
493493
struct hid_input *hidinput; /* associated input structure */
494494
__u16 dpad; /* dpad input code */
495+
unsigned int slot_idx; /* slot index in a report */
495496
};
496497

497498
#define HID_MAX_FIELDS 256

0 commit comments

Comments
 (0)