Skip to content

Commit 22f4b02

Browse files
bentissJiri Kosina
authored andcommitted
HID: compute an ordered list of input fields to process
This will be used in a later commit: we build a list of input fields (and usage_index) that is ordered based on a usage priority. Changing the usage priority allows to re-order the processed list, meaning that we can enforce some usages to be process before others. For instance, before processing InRange in the HID tablets, we need to know if we are using the eraser (side or button). Enforcing a higher (lower number) priority for Invert allows to force the input stack to process that field before. 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 187ccd6 commit 22f4b02

2 files changed

Lines changed: 114 additions & 1 deletion

File tree

drivers/hid/hid-core.c

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ struct hid_report *hid_register_report(struct hid_device *device,
8181
report_enum->report_id_hash[id] = report;
8282

8383
list_add_tail(&report->list, &report_enum->report_list);
84+
INIT_LIST_HEAD(&report->field_entry_list);
8485

8586
return report;
8687
}
@@ -101,7 +102,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
101102

102103
field = kzalloc((sizeof(struct hid_field) +
103104
usages * sizeof(struct hid_usage) +
104-
2 * usages * sizeof(unsigned int)), GFP_KERNEL);
105+
3 * usages * sizeof(unsigned int)), GFP_KERNEL);
105106
if (!field)
106107
return NULL;
107108

@@ -110,6 +111,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
110111
field->usage = (struct hid_usage *)(field + 1);
111112
field->value = (s32 *)(field->usage + usages);
112113
field->new_value = (s32 *)(field->value + usages);
114+
field->usages_priorities = (s32 *)(field->new_value + usages);
113115
field->report = report;
114116

115117
return field;
@@ -657,6 +659,8 @@ static void hid_free_report(struct hid_report *report)
657659
{
658660
unsigned n;
659661

662+
kfree(report->field_entries);
663+
660664
for (n = 0; n < report->maxfield; n++)
661665
kfree(report->field[n]);
662666
kfree(report);
@@ -1667,6 +1671,103 @@ static void hid_process_report(struct hid_device *hid,
16671671
}
16681672
}
16691673

1674+
/*
1675+
* Insert a given usage_index in a field in the list
1676+
* of processed usages in the report.
1677+
*
1678+
* The elements of lower priority score are processed
1679+
* first.
1680+
*/
1681+
static void __hid_insert_field_entry(struct hid_device *hid,
1682+
struct hid_report *report,
1683+
struct hid_field_entry *entry,
1684+
struct hid_field *field,
1685+
unsigned int usage_index)
1686+
{
1687+
struct hid_field_entry *next;
1688+
1689+
entry->field = field;
1690+
entry->index = usage_index;
1691+
entry->priority = field->usages_priorities[usage_index];
1692+
1693+
/* insert the element at the correct position */
1694+
list_for_each_entry(next,
1695+
&report->field_entry_list,
1696+
list) {
1697+
/*
1698+
* the priority of our element is strictly higher
1699+
* than the next one, insert it before
1700+
*/
1701+
if (entry->priority > next->priority) {
1702+
list_add_tail(&entry->list, &next->list);
1703+
return;
1704+
}
1705+
}
1706+
1707+
/* lowest priority score: insert at the end */
1708+
list_add_tail(&entry->list, &report->field_entry_list);
1709+
}
1710+
1711+
static void hid_report_process_ordering(struct hid_device *hid,
1712+
struct hid_report *report)
1713+
{
1714+
struct hid_field *field;
1715+
struct hid_field_entry *entries;
1716+
unsigned int a, u, usages;
1717+
unsigned int count = 0;
1718+
1719+
/* count the number of individual fields in the report */
1720+
for (a = 0; a < report->maxfield; a++) {
1721+
field = report->field[a];
1722+
1723+
if (field->flags & HID_MAIN_ITEM_VARIABLE)
1724+
count += field->report_count;
1725+
else
1726+
count++;
1727+
}
1728+
1729+
/* allocate the memory to process the fields */
1730+
entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
1731+
if (!entries)
1732+
return;
1733+
1734+
report->field_entries = entries;
1735+
1736+
/*
1737+
* walk through all fields in the report and
1738+
* store them by priority order in report->field_entry_list
1739+
*
1740+
* - Var elements are individualized (field + usage_index)
1741+
* - Arrays are taken as one, we can not chose an order for them
1742+
*/
1743+
usages = 0;
1744+
for (a = 0; a < report->maxfield; a++) {
1745+
field = report->field[a];
1746+
1747+
if (field->flags & HID_MAIN_ITEM_VARIABLE) {
1748+
for (u = 0; u < field->report_count; u++) {
1749+
__hid_insert_field_entry(hid, report,
1750+
&entries[usages],
1751+
field, u);
1752+
usages++;
1753+
}
1754+
} else {
1755+
__hid_insert_field_entry(hid, report, &entries[usages],
1756+
field, 0);
1757+
usages++;
1758+
}
1759+
}
1760+
}
1761+
1762+
static void hid_process_ordering(struct hid_device *hid)
1763+
{
1764+
struct hid_report *report;
1765+
struct hid_report_enum *report_enum = &hid->report_enum[HID_INPUT_REPORT];
1766+
1767+
list_for_each_entry(report, &report_enum->report_list, list)
1768+
hid_report_process_ordering(hid, report);
1769+
}
1770+
16701771
/*
16711772
* Output the field into the report.
16721773
*/
@@ -2050,6 +2151,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
20502151
return -ENODEV;
20512152
}
20522153

2154+
hid_process_ordering(hdev);
2155+
20532156
if ((hdev->claimed & HID_CLAIMED_INPUT) &&
20542157
(connect_mask & HID_CONNECT_FF) && hdev->ff_init)
20552158
hdev->ff_init(hdev);

include/linux/hid.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ 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 */
480481
__s32 logical_minimum;
481482
__s32 logical_maximum;
482483
__s32 physical_minimum;
@@ -493,13 +494,22 @@ struct hid_field {
493494

494495
#define HID_MAX_FIELDS 256
495496

497+
struct hid_field_entry {
498+
struct list_head list;
499+
struct hid_field *field;
500+
unsigned int index;
501+
__s32 priority;
502+
};
503+
496504
struct hid_report {
497505
struct list_head list;
498506
struct list_head hidinput_list;
507+
struct list_head field_entry_list; /* ordered list of input fields */
499508
unsigned int id; /* id of this report */
500509
unsigned int type; /* report type */
501510
unsigned int application; /* application usage for this report */
502511
struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */
512+
struct hid_field_entry *field_entries; /* allocated memory of input field_entry */
503513
unsigned maxfield; /* maximum valid field index */
504514
unsigned size; /* size of the report (bits) */
505515
struct hid_device *device; /* associated device */

0 commit comments

Comments
 (0)