]>
Commit | Line | Data |
---|---|---|
1143c684 SL |
1 | From 51878761d65fa02c43a15d339bd1a756bbf6a03d Mon Sep 17 00:00:00 2001 |
2 | From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de> | |
3 | Date: Wed, 27 Mar 2019 11:18:48 +0100 | |
4 | Subject: HID: core: move Usage Page concatenation to Main item | |
5 | ||
6 | [ Upstream commit 58e75155009cc800005629955d3482f36a1e0eec ] | |
7 | ||
8 | As seen on some USB wireless keyboards manufactured by Primax, the HID | |
9 | parser was using some assumptions that are not always true. In this case | |
10 | it's s the fact that, inside the scope of a main item, an Usage Page | |
11 | will always precede an Usage. | |
12 | ||
13 | The spec is not pretty clear as 6.2.2.7 states "Any usage that follows | |
14 | is interpreted as a Usage ID and concatenated with the Usage Page". | |
15 | While 6.2.2.8 states "When the parser encounters a main item it | |
16 | concatenates the last declared Usage Page with a Usage to form a | |
17 | complete usage value." Being somewhat contradictory it was decided to | |
18 | match Window's implementation, which follows 6.2.2.8. | |
19 | ||
20 | In summary, the patch moves the Usage Page concatenation from the local | |
21 | item parsing function to the main item parsing function. | |
22 | ||
23 | Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de> | |
24 | Reviewed-by: Terry Junge <terry.junge@poly.com> | |
25 | Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> | |
26 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
27 | --- | |
28 | drivers/hid/hid-core.c | 36 ++++++++++++++++++++++++------------ | |
29 | include/linux/hid.h | 1 + | |
30 | 2 files changed, 25 insertions(+), 12 deletions(-) | |
31 | ||
32 | diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c | |
33 | index 4564ecf711815..9b2b41d683dea 100644 | |
34 | --- a/drivers/hid/hid-core.c | |
35 | +++ b/drivers/hid/hid-core.c | |
36 | @@ -200,13 +200,14 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) | |
37 | * Add a usage to the temporary parser table. | |
38 | */ | |
39 | ||
40 | -static int hid_add_usage(struct hid_parser *parser, unsigned usage) | |
41 | +static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size) | |
42 | { | |
43 | if (parser->local.usage_index >= HID_MAX_USAGES) { | |
44 | hid_err(parser->device, "usage index exceeded\n"); | |
45 | return -1; | |
46 | } | |
47 | parser->local.usage[parser->local.usage_index] = usage; | |
48 | + parser->local.usage_size[parser->local.usage_index] = size; | |
49 | parser->local.collection_index[parser->local.usage_index] = | |
50 | parser->collection_stack_ptr ? | |
51 | parser->collection_stack[parser->collection_stack_ptr - 1] : 0; | |
52 | @@ -463,10 +464,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) | |
53 | return 0; | |
54 | } | |
55 | ||
56 | - if (item->size <= 2) | |
57 | - data = (parser->global.usage_page << 16) + data; | |
58 | - | |
59 | - return hid_add_usage(parser, data); | |
60 | + return hid_add_usage(parser, data, item->size); | |
61 | ||
62 | case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: | |
63 | ||
64 | @@ -475,9 +473,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) | |
65 | return 0; | |
66 | } | |
67 | ||
68 | - if (item->size <= 2) | |
69 | - data = (parser->global.usage_page << 16) + data; | |
70 | - | |
71 | parser->local.usage_minimum = data; | |
72 | return 0; | |
73 | ||
74 | @@ -488,9 +483,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) | |
75 | return 0; | |
76 | } | |
77 | ||
78 | - if (item->size <= 2) | |
79 | - data = (parser->global.usage_page << 16) + data; | |
80 | - | |
81 | count = data - parser->local.usage_minimum; | |
82 | if (count + parser->local.usage_index >= HID_MAX_USAGES) { | |
83 | /* | |
84 | @@ -510,7 +502,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) | |
85 | } | |
86 | ||
87 | for (n = parser->local.usage_minimum; n <= data; n++) | |
88 | - if (hid_add_usage(parser, n)) { | |
89 | + if (hid_add_usage(parser, n, item->size)) { | |
90 | dbg_hid("hid_add_usage failed\n"); | |
91 | return -1; | |
92 | } | |
93 | @@ -524,6 +516,22 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) | |
94 | return 0; | |
95 | } | |
96 | ||
97 | +/* | |
98 | + * Concatenate Usage Pages into Usages where relevant: | |
99 | + * As per specification, 6.2.2.8: "When the parser encounters a main item it | |
100 | + * concatenates the last declared Usage Page with a Usage to form a complete | |
101 | + * usage value." | |
102 | + */ | |
103 | + | |
104 | +static void hid_concatenate_usage_page(struct hid_parser *parser) | |
105 | +{ | |
106 | + int i; | |
107 | + | |
108 | + for (i = 0; i < parser->local.usage_index; i++) | |
109 | + if (parser->local.usage_size[i] <= 2) | |
110 | + parser->local.usage[i] += parser->global.usage_page << 16; | |
111 | +} | |
112 | + | |
113 | /* | |
114 | * Process a main item. | |
115 | */ | |
116 | @@ -533,6 +541,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) | |
117 | __u32 data; | |
118 | int ret; | |
119 | ||
120 | + hid_concatenate_usage_page(parser); | |
121 | + | |
122 | data = item_udata(item); | |
123 | ||
124 | switch (item->tag) { | |
125 | @@ -746,6 +756,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) | |
126 | __u32 data; | |
127 | int i; | |
128 | ||
129 | + hid_concatenate_usage_page(parser); | |
130 | + | |
131 | data = item_udata(item); | |
132 | ||
133 | switch (item->tag) { | |
134 | diff --git a/include/linux/hid.h b/include/linux/hid.h | |
135 | index fd86687f81196..5f31318851366 100644 | |
136 | --- a/include/linux/hid.h | |
137 | +++ b/include/linux/hid.h | |
138 | @@ -372,6 +372,7 @@ struct hid_global { | |
139 | ||
140 | struct hid_local { | |
141 | unsigned usage[HID_MAX_USAGES]; /* usage array */ | |
142 | + u8 usage_size[HID_MAX_USAGES]; /* usage size array */ | |
143 | unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ | |
144 | unsigned usage_index; | |
145 | unsigned usage_minimum; | |
146 | -- | |
147 | 2.20.1 | |
148 |