Commit 6f0168d2dacd7972d887e1ca27943ef8af7512a5
Committed by
Jiri Kosina
1 parent
9063974cdb
Exists in
master
and in
7 other branches
HID: use get/put_unaligned_* helpers
Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Showing 1 changed file with 5 additions and 5 deletions Inline Diff
drivers/hid/hid-core.c
1 | /* | 1 | /* |
2 | * HID support for Linux | 2 | * HID support for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 1999 Andreas Gal | 4 | * Copyright (c) 1999 Andreas Gal |
5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
8 | */ | 8 | */ |
9 | 9 | ||
10 | /* | 10 | /* |
11 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is free software; you can redistribute it and/or modify it |
12 | * under the terms of the GNU General Public License as published by the Free | 12 | * under the terms of the GNU General Public License as published by the Free |
13 | * Software Foundation; either version 2 of the License, or (at your option) | 13 | * Software Foundation; either version 2 of the License, or (at your option) |
14 | * any later version. | 14 | * any later version. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <asm/unaligned.h> | 24 | #include <asm/unaligned.h> |
25 | #include <asm/byteorder.h> | 25 | #include <asm/byteorder.h> |
26 | #include <linux/input.h> | 26 | #include <linux/input.h> |
27 | #include <linux/wait.h> | 27 | #include <linux/wait.h> |
28 | #include <linux/vmalloc.h> | 28 | #include <linux/vmalloc.h> |
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | 30 | ||
31 | #include <linux/hid.h> | 31 | #include <linux/hid.h> |
32 | #include <linux/hiddev.h> | 32 | #include <linux/hiddev.h> |
33 | #include <linux/hid-debug.h> | 33 | #include <linux/hid-debug.h> |
34 | #include <linux/hidraw.h> | 34 | #include <linux/hidraw.h> |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Version Information | 37 | * Version Information |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #define DRIVER_VERSION "v2.6" | 40 | #define DRIVER_VERSION "v2.6" |
41 | #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina" | 41 | #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina" |
42 | #define DRIVER_DESC "HID core driver" | 42 | #define DRIVER_DESC "HID core driver" |
43 | #define DRIVER_LICENSE "GPL" | 43 | #define DRIVER_LICENSE "GPL" |
44 | 44 | ||
45 | #ifdef CONFIG_HID_DEBUG | 45 | #ifdef CONFIG_HID_DEBUG |
46 | int hid_debug = 0; | 46 | int hid_debug = 0; |
47 | module_param_named(debug, hid_debug, int, 0600); | 47 | module_param_named(debug, hid_debug, int, 0600); |
48 | MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)"); | 48 | MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)"); |
49 | EXPORT_SYMBOL_GPL(hid_debug); | 49 | EXPORT_SYMBOL_GPL(hid_debug); |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * Register a new report for a device. | 53 | * Register a new report for a device. |
54 | */ | 54 | */ |
55 | 55 | ||
56 | static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) | 56 | static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) |
57 | { | 57 | { |
58 | struct hid_report_enum *report_enum = device->report_enum + type; | 58 | struct hid_report_enum *report_enum = device->report_enum + type; |
59 | struct hid_report *report; | 59 | struct hid_report *report; |
60 | 60 | ||
61 | if (report_enum->report_id_hash[id]) | 61 | if (report_enum->report_id_hash[id]) |
62 | return report_enum->report_id_hash[id]; | 62 | return report_enum->report_id_hash[id]; |
63 | 63 | ||
64 | if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL))) | 64 | if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL))) |
65 | return NULL; | 65 | return NULL; |
66 | 66 | ||
67 | if (id != 0) | 67 | if (id != 0) |
68 | report_enum->numbered = 1; | 68 | report_enum->numbered = 1; |
69 | 69 | ||
70 | report->id = id; | 70 | report->id = id; |
71 | report->type = type; | 71 | report->type = type; |
72 | report->size = 0; | 72 | report->size = 0; |
73 | report->device = device; | 73 | report->device = device; |
74 | report_enum->report_id_hash[id] = report; | 74 | report_enum->report_id_hash[id] = report; |
75 | 75 | ||
76 | list_add_tail(&report->list, &report_enum->report_list); | 76 | list_add_tail(&report->list, &report_enum->report_list); |
77 | 77 | ||
78 | return report; | 78 | return report; |
79 | } | 79 | } |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * Register a new field for this report. | 82 | * Register a new field for this report. |
83 | */ | 83 | */ |
84 | 84 | ||
85 | static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) | 85 | static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) |
86 | { | 86 | { |
87 | struct hid_field *field; | 87 | struct hid_field *field; |
88 | 88 | ||
89 | if (report->maxfield == HID_MAX_FIELDS) { | 89 | if (report->maxfield == HID_MAX_FIELDS) { |
90 | dbg_hid("too many fields in report\n"); | 90 | dbg_hid("too many fields in report\n"); |
91 | return NULL; | 91 | return NULL; |
92 | } | 92 | } |
93 | 93 | ||
94 | if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) | 94 | if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) |
95 | + values * sizeof(unsigned), GFP_KERNEL))) return NULL; | 95 | + values * sizeof(unsigned), GFP_KERNEL))) return NULL; |
96 | 96 | ||
97 | field->index = report->maxfield++; | 97 | field->index = report->maxfield++; |
98 | report->field[field->index] = field; | 98 | report->field[field->index] = field; |
99 | field->usage = (struct hid_usage *)(field + 1); | 99 | field->usage = (struct hid_usage *)(field + 1); |
100 | field->value = (s32 *)(field->usage + usages); | 100 | field->value = (s32 *)(field->usage + usages); |
101 | field->report = report; | 101 | field->report = report; |
102 | 102 | ||
103 | return field; | 103 | return field; |
104 | } | 104 | } |
105 | 105 | ||
106 | /* | 106 | /* |
107 | * Open a collection. The type/usage is pushed on the stack. | 107 | * Open a collection. The type/usage is pushed on the stack. |
108 | */ | 108 | */ |
109 | 109 | ||
110 | static int open_collection(struct hid_parser *parser, unsigned type) | 110 | static int open_collection(struct hid_parser *parser, unsigned type) |
111 | { | 111 | { |
112 | struct hid_collection *collection; | 112 | struct hid_collection *collection; |
113 | unsigned usage; | 113 | unsigned usage; |
114 | 114 | ||
115 | usage = parser->local.usage[0]; | 115 | usage = parser->local.usage[0]; |
116 | 116 | ||
117 | if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { | 117 | if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { |
118 | dbg_hid("collection stack overflow\n"); | 118 | dbg_hid("collection stack overflow\n"); |
119 | return -1; | 119 | return -1; |
120 | } | 120 | } |
121 | 121 | ||
122 | if (parser->device->maxcollection == parser->device->collection_size) { | 122 | if (parser->device->maxcollection == parser->device->collection_size) { |
123 | collection = kmalloc(sizeof(struct hid_collection) * | 123 | collection = kmalloc(sizeof(struct hid_collection) * |
124 | parser->device->collection_size * 2, GFP_KERNEL); | 124 | parser->device->collection_size * 2, GFP_KERNEL); |
125 | if (collection == NULL) { | 125 | if (collection == NULL) { |
126 | dbg_hid("failed to reallocate collection array\n"); | 126 | dbg_hid("failed to reallocate collection array\n"); |
127 | return -1; | 127 | return -1; |
128 | } | 128 | } |
129 | memcpy(collection, parser->device->collection, | 129 | memcpy(collection, parser->device->collection, |
130 | sizeof(struct hid_collection) * | 130 | sizeof(struct hid_collection) * |
131 | parser->device->collection_size); | 131 | parser->device->collection_size); |
132 | memset(collection + parser->device->collection_size, 0, | 132 | memset(collection + parser->device->collection_size, 0, |
133 | sizeof(struct hid_collection) * | 133 | sizeof(struct hid_collection) * |
134 | parser->device->collection_size); | 134 | parser->device->collection_size); |
135 | kfree(parser->device->collection); | 135 | kfree(parser->device->collection); |
136 | parser->device->collection = collection; | 136 | parser->device->collection = collection; |
137 | parser->device->collection_size *= 2; | 137 | parser->device->collection_size *= 2; |
138 | } | 138 | } |
139 | 139 | ||
140 | parser->collection_stack[parser->collection_stack_ptr++] = | 140 | parser->collection_stack[parser->collection_stack_ptr++] = |
141 | parser->device->maxcollection; | 141 | parser->device->maxcollection; |
142 | 142 | ||
143 | collection = parser->device->collection + | 143 | collection = parser->device->collection + |
144 | parser->device->maxcollection++; | 144 | parser->device->maxcollection++; |
145 | collection->type = type; | 145 | collection->type = type; |
146 | collection->usage = usage; | 146 | collection->usage = usage; |
147 | collection->level = parser->collection_stack_ptr - 1; | 147 | collection->level = parser->collection_stack_ptr - 1; |
148 | 148 | ||
149 | if (type == HID_COLLECTION_APPLICATION) | 149 | if (type == HID_COLLECTION_APPLICATION) |
150 | parser->device->maxapplication++; | 150 | parser->device->maxapplication++; |
151 | 151 | ||
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | /* | 155 | /* |
156 | * Close a collection. | 156 | * Close a collection. |
157 | */ | 157 | */ |
158 | 158 | ||
159 | static int close_collection(struct hid_parser *parser) | 159 | static int close_collection(struct hid_parser *parser) |
160 | { | 160 | { |
161 | if (!parser->collection_stack_ptr) { | 161 | if (!parser->collection_stack_ptr) { |
162 | dbg_hid("collection stack underflow\n"); | 162 | dbg_hid("collection stack underflow\n"); |
163 | return -1; | 163 | return -1; |
164 | } | 164 | } |
165 | parser->collection_stack_ptr--; | 165 | parser->collection_stack_ptr--; |
166 | return 0; | 166 | return 0; |
167 | } | 167 | } |
168 | 168 | ||
169 | /* | 169 | /* |
170 | * Climb up the stack, search for the specified collection type | 170 | * Climb up the stack, search for the specified collection type |
171 | * and return the usage. | 171 | * and return the usage. |
172 | */ | 172 | */ |
173 | 173 | ||
174 | static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) | 174 | static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) |
175 | { | 175 | { |
176 | int n; | 176 | int n; |
177 | for (n = parser->collection_stack_ptr - 1; n >= 0; n--) | 177 | for (n = parser->collection_stack_ptr - 1; n >= 0; n--) |
178 | if (parser->device->collection[parser->collection_stack[n]].type == type) | 178 | if (parser->device->collection[parser->collection_stack[n]].type == type) |
179 | return parser->device->collection[parser->collection_stack[n]].usage; | 179 | return parser->device->collection[parser->collection_stack[n]].usage; |
180 | return 0; /* we know nothing about this usage type */ | 180 | return 0; /* we know nothing about this usage type */ |
181 | } | 181 | } |
182 | 182 | ||
183 | /* | 183 | /* |
184 | * Add a usage to the temporary parser table. | 184 | * Add a usage to the temporary parser table. |
185 | */ | 185 | */ |
186 | 186 | ||
187 | static int hid_add_usage(struct hid_parser *parser, unsigned usage) | 187 | static int hid_add_usage(struct hid_parser *parser, unsigned usage) |
188 | { | 188 | { |
189 | if (parser->local.usage_index >= HID_MAX_USAGES) { | 189 | if (parser->local.usage_index >= HID_MAX_USAGES) { |
190 | dbg_hid("usage index exceeded\n"); | 190 | dbg_hid("usage index exceeded\n"); |
191 | return -1; | 191 | return -1; |
192 | } | 192 | } |
193 | parser->local.usage[parser->local.usage_index] = usage; | 193 | parser->local.usage[parser->local.usage_index] = usage; |
194 | parser->local.collection_index[parser->local.usage_index] = | 194 | parser->local.collection_index[parser->local.usage_index] = |
195 | parser->collection_stack_ptr ? | 195 | parser->collection_stack_ptr ? |
196 | parser->collection_stack[parser->collection_stack_ptr - 1] : 0; | 196 | parser->collection_stack[parser->collection_stack_ptr - 1] : 0; |
197 | parser->local.usage_index++; | 197 | parser->local.usage_index++; |
198 | return 0; | 198 | return 0; |
199 | } | 199 | } |
200 | 200 | ||
201 | /* | 201 | /* |
202 | * Register a new field for this report. | 202 | * Register a new field for this report. |
203 | */ | 203 | */ |
204 | 204 | ||
205 | static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) | 205 | static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) |
206 | { | 206 | { |
207 | struct hid_report *report; | 207 | struct hid_report *report; |
208 | struct hid_field *field; | 208 | struct hid_field *field; |
209 | int usages; | 209 | int usages; |
210 | unsigned offset; | 210 | unsigned offset; |
211 | int i; | 211 | int i; |
212 | 212 | ||
213 | if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { | 213 | if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { |
214 | dbg_hid("hid_register_report failed\n"); | 214 | dbg_hid("hid_register_report failed\n"); |
215 | return -1; | 215 | return -1; |
216 | } | 216 | } |
217 | 217 | ||
218 | if (parser->global.logical_maximum < parser->global.logical_minimum) { | 218 | if (parser->global.logical_maximum < parser->global.logical_minimum) { |
219 | dbg_hid("logical range invalid %d %d\n", parser->global.logical_minimum, parser->global.logical_maximum); | 219 | dbg_hid("logical range invalid %d %d\n", parser->global.logical_minimum, parser->global.logical_maximum); |
220 | return -1; | 220 | return -1; |
221 | } | 221 | } |
222 | 222 | ||
223 | offset = report->size; | 223 | offset = report->size; |
224 | report->size += parser->global.report_size * parser->global.report_count; | 224 | report->size += parser->global.report_size * parser->global.report_count; |
225 | 225 | ||
226 | if (!parser->local.usage_index) /* Ignore padding fields */ | 226 | if (!parser->local.usage_index) /* Ignore padding fields */ |
227 | return 0; | 227 | return 0; |
228 | 228 | ||
229 | usages = max_t(int, parser->local.usage_index, parser->global.report_count); | 229 | usages = max_t(int, parser->local.usage_index, parser->global.report_count); |
230 | 230 | ||
231 | if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) | 231 | if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) |
232 | return 0; | 232 | return 0; |
233 | 233 | ||
234 | field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); | 234 | field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); |
235 | field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); | 235 | field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); |
236 | field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); | 236 | field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); |
237 | 237 | ||
238 | for (i = 0; i < usages; i++) { | 238 | for (i = 0; i < usages; i++) { |
239 | int j = i; | 239 | int j = i; |
240 | /* Duplicate the last usage we parsed if we have excess values */ | 240 | /* Duplicate the last usage we parsed if we have excess values */ |
241 | if (i >= parser->local.usage_index) | 241 | if (i >= parser->local.usage_index) |
242 | j = parser->local.usage_index - 1; | 242 | j = parser->local.usage_index - 1; |
243 | field->usage[i].hid = parser->local.usage[j]; | 243 | field->usage[i].hid = parser->local.usage[j]; |
244 | field->usage[i].collection_index = | 244 | field->usage[i].collection_index = |
245 | parser->local.collection_index[j]; | 245 | parser->local.collection_index[j]; |
246 | } | 246 | } |
247 | 247 | ||
248 | field->maxusage = usages; | 248 | field->maxusage = usages; |
249 | field->flags = flags; | 249 | field->flags = flags; |
250 | field->report_offset = offset; | 250 | field->report_offset = offset; |
251 | field->report_type = report_type; | 251 | field->report_type = report_type; |
252 | field->report_size = parser->global.report_size; | 252 | field->report_size = parser->global.report_size; |
253 | field->report_count = parser->global.report_count; | 253 | field->report_count = parser->global.report_count; |
254 | field->logical_minimum = parser->global.logical_minimum; | 254 | field->logical_minimum = parser->global.logical_minimum; |
255 | field->logical_maximum = parser->global.logical_maximum; | 255 | field->logical_maximum = parser->global.logical_maximum; |
256 | field->physical_minimum = parser->global.physical_minimum; | 256 | field->physical_minimum = parser->global.physical_minimum; |
257 | field->physical_maximum = parser->global.physical_maximum; | 257 | field->physical_maximum = parser->global.physical_maximum; |
258 | field->unit_exponent = parser->global.unit_exponent; | 258 | field->unit_exponent = parser->global.unit_exponent; |
259 | field->unit = parser->global.unit; | 259 | field->unit = parser->global.unit; |
260 | 260 | ||
261 | return 0; | 261 | return 0; |
262 | } | 262 | } |
263 | 263 | ||
264 | /* | 264 | /* |
265 | * Read data value from item. | 265 | * Read data value from item. |
266 | */ | 266 | */ |
267 | 267 | ||
268 | static u32 item_udata(struct hid_item *item) | 268 | static u32 item_udata(struct hid_item *item) |
269 | { | 269 | { |
270 | switch (item->size) { | 270 | switch (item->size) { |
271 | case 1: return item->data.u8; | 271 | case 1: return item->data.u8; |
272 | case 2: return item->data.u16; | 272 | case 2: return item->data.u16; |
273 | case 4: return item->data.u32; | 273 | case 4: return item->data.u32; |
274 | } | 274 | } |
275 | return 0; | 275 | return 0; |
276 | } | 276 | } |
277 | 277 | ||
278 | static s32 item_sdata(struct hid_item *item) | 278 | static s32 item_sdata(struct hid_item *item) |
279 | { | 279 | { |
280 | switch (item->size) { | 280 | switch (item->size) { |
281 | case 1: return item->data.s8; | 281 | case 1: return item->data.s8; |
282 | case 2: return item->data.s16; | 282 | case 2: return item->data.s16; |
283 | case 4: return item->data.s32; | 283 | case 4: return item->data.s32; |
284 | } | 284 | } |
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | /* | 288 | /* |
289 | * Process a global item. | 289 | * Process a global item. |
290 | */ | 290 | */ |
291 | 291 | ||
292 | static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) | 292 | static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) |
293 | { | 293 | { |
294 | switch (item->tag) { | 294 | switch (item->tag) { |
295 | 295 | ||
296 | case HID_GLOBAL_ITEM_TAG_PUSH: | 296 | case HID_GLOBAL_ITEM_TAG_PUSH: |
297 | 297 | ||
298 | if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { | 298 | if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { |
299 | dbg_hid("global enviroment stack overflow\n"); | 299 | dbg_hid("global enviroment stack overflow\n"); |
300 | return -1; | 300 | return -1; |
301 | } | 301 | } |
302 | 302 | ||
303 | memcpy(parser->global_stack + parser->global_stack_ptr++, | 303 | memcpy(parser->global_stack + parser->global_stack_ptr++, |
304 | &parser->global, sizeof(struct hid_global)); | 304 | &parser->global, sizeof(struct hid_global)); |
305 | return 0; | 305 | return 0; |
306 | 306 | ||
307 | case HID_GLOBAL_ITEM_TAG_POP: | 307 | case HID_GLOBAL_ITEM_TAG_POP: |
308 | 308 | ||
309 | if (!parser->global_stack_ptr) { | 309 | if (!parser->global_stack_ptr) { |
310 | dbg_hid("global enviroment stack underflow\n"); | 310 | dbg_hid("global enviroment stack underflow\n"); |
311 | return -1; | 311 | return -1; |
312 | } | 312 | } |
313 | 313 | ||
314 | memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, | 314 | memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, |
315 | sizeof(struct hid_global)); | 315 | sizeof(struct hid_global)); |
316 | return 0; | 316 | return 0; |
317 | 317 | ||
318 | case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: | 318 | case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: |
319 | parser->global.usage_page = item_udata(item); | 319 | parser->global.usage_page = item_udata(item); |
320 | return 0; | 320 | return 0; |
321 | 321 | ||
322 | case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: | 322 | case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: |
323 | parser->global.logical_minimum = item_sdata(item); | 323 | parser->global.logical_minimum = item_sdata(item); |
324 | return 0; | 324 | return 0; |
325 | 325 | ||
326 | case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: | 326 | case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: |
327 | if (parser->global.logical_minimum < 0) | 327 | if (parser->global.logical_minimum < 0) |
328 | parser->global.logical_maximum = item_sdata(item); | 328 | parser->global.logical_maximum = item_sdata(item); |
329 | else | 329 | else |
330 | parser->global.logical_maximum = item_udata(item); | 330 | parser->global.logical_maximum = item_udata(item); |
331 | return 0; | 331 | return 0; |
332 | 332 | ||
333 | case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: | 333 | case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: |
334 | parser->global.physical_minimum = item_sdata(item); | 334 | parser->global.physical_minimum = item_sdata(item); |
335 | return 0; | 335 | return 0; |
336 | 336 | ||
337 | case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: | 337 | case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: |
338 | if (parser->global.physical_minimum < 0) | 338 | if (parser->global.physical_minimum < 0) |
339 | parser->global.physical_maximum = item_sdata(item); | 339 | parser->global.physical_maximum = item_sdata(item); |
340 | else | 340 | else |
341 | parser->global.physical_maximum = item_udata(item); | 341 | parser->global.physical_maximum = item_udata(item); |
342 | return 0; | 342 | return 0; |
343 | 343 | ||
344 | case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: | 344 | case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: |
345 | parser->global.unit_exponent = item_sdata(item); | 345 | parser->global.unit_exponent = item_sdata(item); |
346 | return 0; | 346 | return 0; |
347 | 347 | ||
348 | case HID_GLOBAL_ITEM_TAG_UNIT: | 348 | case HID_GLOBAL_ITEM_TAG_UNIT: |
349 | parser->global.unit = item_udata(item); | 349 | parser->global.unit = item_udata(item); |
350 | return 0; | 350 | return 0; |
351 | 351 | ||
352 | case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: | 352 | case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: |
353 | if ((parser->global.report_size = item_udata(item)) > 32) { | 353 | if ((parser->global.report_size = item_udata(item)) > 32) { |
354 | dbg_hid("invalid report_size %d\n", parser->global.report_size); | 354 | dbg_hid("invalid report_size %d\n", parser->global.report_size); |
355 | return -1; | 355 | return -1; |
356 | } | 356 | } |
357 | return 0; | 357 | return 0; |
358 | 358 | ||
359 | case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: | 359 | case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: |
360 | if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { | 360 | if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { |
361 | dbg_hid("invalid report_count %d\n", parser->global.report_count); | 361 | dbg_hid("invalid report_count %d\n", parser->global.report_count); |
362 | return -1; | 362 | return -1; |
363 | } | 363 | } |
364 | return 0; | 364 | return 0; |
365 | 365 | ||
366 | case HID_GLOBAL_ITEM_TAG_REPORT_ID: | 366 | case HID_GLOBAL_ITEM_TAG_REPORT_ID: |
367 | if ((parser->global.report_id = item_udata(item)) == 0) { | 367 | if ((parser->global.report_id = item_udata(item)) == 0) { |
368 | dbg_hid("report_id 0 is invalid\n"); | 368 | dbg_hid("report_id 0 is invalid\n"); |
369 | return -1; | 369 | return -1; |
370 | } | 370 | } |
371 | return 0; | 371 | return 0; |
372 | 372 | ||
373 | default: | 373 | default: |
374 | dbg_hid("unknown global tag 0x%x\n", item->tag); | 374 | dbg_hid("unknown global tag 0x%x\n", item->tag); |
375 | return -1; | 375 | return -1; |
376 | } | 376 | } |
377 | } | 377 | } |
378 | 378 | ||
379 | /* | 379 | /* |
380 | * Process a local item. | 380 | * Process a local item. |
381 | */ | 381 | */ |
382 | 382 | ||
383 | static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) | 383 | static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) |
384 | { | 384 | { |
385 | __u32 data; | 385 | __u32 data; |
386 | unsigned n; | 386 | unsigned n; |
387 | 387 | ||
388 | if (item->size == 0) { | 388 | if (item->size == 0) { |
389 | dbg_hid("item data expected for local item\n"); | 389 | dbg_hid("item data expected for local item\n"); |
390 | return -1; | 390 | return -1; |
391 | } | 391 | } |
392 | 392 | ||
393 | data = item_udata(item); | 393 | data = item_udata(item); |
394 | 394 | ||
395 | switch (item->tag) { | 395 | switch (item->tag) { |
396 | 396 | ||
397 | case HID_LOCAL_ITEM_TAG_DELIMITER: | 397 | case HID_LOCAL_ITEM_TAG_DELIMITER: |
398 | 398 | ||
399 | if (data) { | 399 | if (data) { |
400 | /* | 400 | /* |
401 | * We treat items before the first delimiter | 401 | * We treat items before the first delimiter |
402 | * as global to all usage sets (branch 0). | 402 | * as global to all usage sets (branch 0). |
403 | * In the moment we process only these global | 403 | * In the moment we process only these global |
404 | * items and the first delimiter set. | 404 | * items and the first delimiter set. |
405 | */ | 405 | */ |
406 | if (parser->local.delimiter_depth != 0) { | 406 | if (parser->local.delimiter_depth != 0) { |
407 | dbg_hid("nested delimiters\n"); | 407 | dbg_hid("nested delimiters\n"); |
408 | return -1; | 408 | return -1; |
409 | } | 409 | } |
410 | parser->local.delimiter_depth++; | 410 | parser->local.delimiter_depth++; |
411 | parser->local.delimiter_branch++; | 411 | parser->local.delimiter_branch++; |
412 | } else { | 412 | } else { |
413 | if (parser->local.delimiter_depth < 1) { | 413 | if (parser->local.delimiter_depth < 1) { |
414 | dbg_hid("bogus close delimiter\n"); | 414 | dbg_hid("bogus close delimiter\n"); |
415 | return -1; | 415 | return -1; |
416 | } | 416 | } |
417 | parser->local.delimiter_depth--; | 417 | parser->local.delimiter_depth--; |
418 | } | 418 | } |
419 | return 1; | 419 | return 1; |
420 | 420 | ||
421 | case HID_LOCAL_ITEM_TAG_USAGE: | 421 | case HID_LOCAL_ITEM_TAG_USAGE: |
422 | 422 | ||
423 | if (parser->local.delimiter_branch > 1) { | 423 | if (parser->local.delimiter_branch > 1) { |
424 | dbg_hid("alternative usage ignored\n"); | 424 | dbg_hid("alternative usage ignored\n"); |
425 | return 0; | 425 | return 0; |
426 | } | 426 | } |
427 | 427 | ||
428 | if (item->size <= 2) | 428 | if (item->size <= 2) |
429 | data = (parser->global.usage_page << 16) + data; | 429 | data = (parser->global.usage_page << 16) + data; |
430 | 430 | ||
431 | return hid_add_usage(parser, data); | 431 | return hid_add_usage(parser, data); |
432 | 432 | ||
433 | case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: | 433 | case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: |
434 | 434 | ||
435 | if (parser->local.delimiter_branch > 1) { | 435 | if (parser->local.delimiter_branch > 1) { |
436 | dbg_hid("alternative usage ignored\n"); | 436 | dbg_hid("alternative usage ignored\n"); |
437 | return 0; | 437 | return 0; |
438 | } | 438 | } |
439 | 439 | ||
440 | if (item->size <= 2) | 440 | if (item->size <= 2) |
441 | data = (parser->global.usage_page << 16) + data; | 441 | data = (parser->global.usage_page << 16) + data; |
442 | 442 | ||
443 | parser->local.usage_minimum = data; | 443 | parser->local.usage_minimum = data; |
444 | return 0; | 444 | return 0; |
445 | 445 | ||
446 | case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: | 446 | case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: |
447 | 447 | ||
448 | if (parser->local.delimiter_branch > 1) { | 448 | if (parser->local.delimiter_branch > 1) { |
449 | dbg_hid("alternative usage ignored\n"); | 449 | dbg_hid("alternative usage ignored\n"); |
450 | return 0; | 450 | return 0; |
451 | } | 451 | } |
452 | 452 | ||
453 | if (item->size <= 2) | 453 | if (item->size <= 2) |
454 | data = (parser->global.usage_page << 16) + data; | 454 | data = (parser->global.usage_page << 16) + data; |
455 | 455 | ||
456 | for (n = parser->local.usage_minimum; n <= data; n++) | 456 | for (n = parser->local.usage_minimum; n <= data; n++) |
457 | if (hid_add_usage(parser, n)) { | 457 | if (hid_add_usage(parser, n)) { |
458 | dbg_hid("hid_add_usage failed\n"); | 458 | dbg_hid("hid_add_usage failed\n"); |
459 | return -1; | 459 | return -1; |
460 | } | 460 | } |
461 | return 0; | 461 | return 0; |
462 | 462 | ||
463 | default: | 463 | default: |
464 | 464 | ||
465 | dbg_hid("unknown local item tag 0x%x\n", item->tag); | 465 | dbg_hid("unknown local item tag 0x%x\n", item->tag); |
466 | return 0; | 466 | return 0; |
467 | } | 467 | } |
468 | return 0; | 468 | return 0; |
469 | } | 469 | } |
470 | 470 | ||
471 | /* | 471 | /* |
472 | * Process a main item. | 472 | * Process a main item. |
473 | */ | 473 | */ |
474 | 474 | ||
475 | static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) | 475 | static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) |
476 | { | 476 | { |
477 | __u32 data; | 477 | __u32 data; |
478 | int ret; | 478 | int ret; |
479 | 479 | ||
480 | data = item_udata(item); | 480 | data = item_udata(item); |
481 | 481 | ||
482 | switch (item->tag) { | 482 | switch (item->tag) { |
483 | case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: | 483 | case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: |
484 | ret = open_collection(parser, data & 0xff); | 484 | ret = open_collection(parser, data & 0xff); |
485 | break; | 485 | break; |
486 | case HID_MAIN_ITEM_TAG_END_COLLECTION: | 486 | case HID_MAIN_ITEM_TAG_END_COLLECTION: |
487 | ret = close_collection(parser); | 487 | ret = close_collection(parser); |
488 | break; | 488 | break; |
489 | case HID_MAIN_ITEM_TAG_INPUT: | 489 | case HID_MAIN_ITEM_TAG_INPUT: |
490 | ret = hid_add_field(parser, HID_INPUT_REPORT, data); | 490 | ret = hid_add_field(parser, HID_INPUT_REPORT, data); |
491 | break; | 491 | break; |
492 | case HID_MAIN_ITEM_TAG_OUTPUT: | 492 | case HID_MAIN_ITEM_TAG_OUTPUT: |
493 | ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); | 493 | ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); |
494 | break; | 494 | break; |
495 | case HID_MAIN_ITEM_TAG_FEATURE: | 495 | case HID_MAIN_ITEM_TAG_FEATURE: |
496 | ret = hid_add_field(parser, HID_FEATURE_REPORT, data); | 496 | ret = hid_add_field(parser, HID_FEATURE_REPORT, data); |
497 | break; | 497 | break; |
498 | default: | 498 | default: |
499 | dbg_hid("unknown main item tag 0x%x\n", item->tag); | 499 | dbg_hid("unknown main item tag 0x%x\n", item->tag); |
500 | ret = 0; | 500 | ret = 0; |
501 | } | 501 | } |
502 | 502 | ||
503 | memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ | 503 | memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ |
504 | 504 | ||
505 | return ret; | 505 | return ret; |
506 | } | 506 | } |
507 | 507 | ||
508 | /* | 508 | /* |
509 | * Process a reserved item. | 509 | * Process a reserved item. |
510 | */ | 510 | */ |
511 | 511 | ||
512 | static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) | 512 | static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) |
513 | { | 513 | { |
514 | dbg_hid("reserved item type, tag 0x%x\n", item->tag); | 514 | dbg_hid("reserved item type, tag 0x%x\n", item->tag); |
515 | return 0; | 515 | return 0; |
516 | } | 516 | } |
517 | 517 | ||
518 | /* | 518 | /* |
519 | * Free a report and all registered fields. The field->usage and | 519 | * Free a report and all registered fields. The field->usage and |
520 | * field->value table's are allocated behind the field, so we need | 520 | * field->value table's are allocated behind the field, so we need |
521 | * only to free(field) itself. | 521 | * only to free(field) itself. |
522 | */ | 522 | */ |
523 | 523 | ||
524 | static void hid_free_report(struct hid_report *report) | 524 | static void hid_free_report(struct hid_report *report) |
525 | { | 525 | { |
526 | unsigned n; | 526 | unsigned n; |
527 | 527 | ||
528 | for (n = 0; n < report->maxfield; n++) | 528 | for (n = 0; n < report->maxfield; n++) |
529 | kfree(report->field[n]); | 529 | kfree(report->field[n]); |
530 | kfree(report); | 530 | kfree(report); |
531 | } | 531 | } |
532 | 532 | ||
533 | /* | 533 | /* |
534 | * Free a device structure, all reports, and all fields. | 534 | * Free a device structure, all reports, and all fields. |
535 | */ | 535 | */ |
536 | 536 | ||
537 | void hid_free_device(struct hid_device *device) | 537 | void hid_free_device(struct hid_device *device) |
538 | { | 538 | { |
539 | unsigned i,j; | 539 | unsigned i,j; |
540 | 540 | ||
541 | for (i = 0; i < HID_REPORT_TYPES; i++) { | 541 | for (i = 0; i < HID_REPORT_TYPES; i++) { |
542 | struct hid_report_enum *report_enum = device->report_enum + i; | 542 | struct hid_report_enum *report_enum = device->report_enum + i; |
543 | 543 | ||
544 | for (j = 0; j < 256; j++) { | 544 | for (j = 0; j < 256; j++) { |
545 | struct hid_report *report = report_enum->report_id_hash[j]; | 545 | struct hid_report *report = report_enum->report_id_hash[j]; |
546 | if (report) | 546 | if (report) |
547 | hid_free_report(report); | 547 | hid_free_report(report); |
548 | } | 548 | } |
549 | } | 549 | } |
550 | 550 | ||
551 | kfree(device->rdesc); | 551 | kfree(device->rdesc); |
552 | kfree(device->collection); | 552 | kfree(device->collection); |
553 | kfree(device); | 553 | kfree(device); |
554 | } | 554 | } |
555 | EXPORT_SYMBOL_GPL(hid_free_device); | 555 | EXPORT_SYMBOL_GPL(hid_free_device); |
556 | 556 | ||
557 | /* | 557 | /* |
558 | * Fetch a report description item from the data stream. We support long | 558 | * Fetch a report description item from the data stream. We support long |
559 | * items, though they are not used yet. | 559 | * items, though they are not used yet. |
560 | */ | 560 | */ |
561 | 561 | ||
562 | static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) | 562 | static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) |
563 | { | 563 | { |
564 | u8 b; | 564 | u8 b; |
565 | 565 | ||
566 | if ((end - start) <= 0) | 566 | if ((end - start) <= 0) |
567 | return NULL; | 567 | return NULL; |
568 | 568 | ||
569 | b = *start++; | 569 | b = *start++; |
570 | 570 | ||
571 | item->type = (b >> 2) & 3; | 571 | item->type = (b >> 2) & 3; |
572 | item->tag = (b >> 4) & 15; | 572 | item->tag = (b >> 4) & 15; |
573 | 573 | ||
574 | if (item->tag == HID_ITEM_TAG_LONG) { | 574 | if (item->tag == HID_ITEM_TAG_LONG) { |
575 | 575 | ||
576 | item->format = HID_ITEM_FORMAT_LONG; | 576 | item->format = HID_ITEM_FORMAT_LONG; |
577 | 577 | ||
578 | if ((end - start) < 2) | 578 | if ((end - start) < 2) |
579 | return NULL; | 579 | return NULL; |
580 | 580 | ||
581 | item->size = *start++; | 581 | item->size = *start++; |
582 | item->tag = *start++; | 582 | item->tag = *start++; |
583 | 583 | ||
584 | if ((end - start) < item->size) | 584 | if ((end - start) < item->size) |
585 | return NULL; | 585 | return NULL; |
586 | 586 | ||
587 | item->data.longdata = start; | 587 | item->data.longdata = start; |
588 | start += item->size; | 588 | start += item->size; |
589 | return start; | 589 | return start; |
590 | } | 590 | } |
591 | 591 | ||
592 | item->format = HID_ITEM_FORMAT_SHORT; | 592 | item->format = HID_ITEM_FORMAT_SHORT; |
593 | item->size = b & 3; | 593 | item->size = b & 3; |
594 | 594 | ||
595 | switch (item->size) { | 595 | switch (item->size) { |
596 | 596 | ||
597 | case 0: | 597 | case 0: |
598 | return start; | 598 | return start; |
599 | 599 | ||
600 | case 1: | 600 | case 1: |
601 | if ((end - start) < 1) | 601 | if ((end - start) < 1) |
602 | return NULL; | 602 | return NULL; |
603 | item->data.u8 = *start++; | 603 | item->data.u8 = *start++; |
604 | return start; | 604 | return start; |
605 | 605 | ||
606 | case 2: | 606 | case 2: |
607 | if ((end - start) < 2) | 607 | if ((end - start) < 2) |
608 | return NULL; | 608 | return NULL; |
609 | item->data.u16 = get_unaligned_le16(start); | 609 | item->data.u16 = get_unaligned_le16(start); |
610 | start = (__u8 *)((__le16 *)start + 1); | 610 | start = (__u8 *)((__le16 *)start + 1); |
611 | return start; | 611 | return start; |
612 | 612 | ||
613 | case 3: | 613 | case 3: |
614 | item->size++; | 614 | item->size++; |
615 | if ((end - start) < 4) | 615 | if ((end - start) < 4) |
616 | return NULL; | 616 | return NULL; |
617 | item->data.u32 = get_unaligned_le32(start); | 617 | item->data.u32 = get_unaligned_le32(start); |
618 | start = (__u8 *)((__le32 *)start + 1); | 618 | start = (__u8 *)((__le32 *)start + 1); |
619 | return start; | 619 | return start; |
620 | } | 620 | } |
621 | 621 | ||
622 | return NULL; | 622 | return NULL; |
623 | } | 623 | } |
624 | 624 | ||
625 | /* | 625 | /* |
626 | * Parse a report description into a hid_device structure. Reports are | 626 | * Parse a report description into a hid_device structure. Reports are |
627 | * enumerated, fields are attached to these reports. | 627 | * enumerated, fields are attached to these reports. |
628 | */ | 628 | */ |
629 | 629 | ||
630 | struct hid_device *hid_parse_report(__u8 *start, unsigned size) | 630 | struct hid_device *hid_parse_report(__u8 *start, unsigned size) |
631 | { | 631 | { |
632 | struct hid_device *device; | 632 | struct hid_device *device; |
633 | struct hid_parser *parser; | 633 | struct hid_parser *parser; |
634 | struct hid_item item; | 634 | struct hid_item item; |
635 | __u8 *end; | 635 | __u8 *end; |
636 | unsigned i; | 636 | unsigned i; |
637 | static int (*dispatch_type[])(struct hid_parser *parser, | 637 | static int (*dispatch_type[])(struct hid_parser *parser, |
638 | struct hid_item *item) = { | 638 | struct hid_item *item) = { |
639 | hid_parser_main, | 639 | hid_parser_main, |
640 | hid_parser_global, | 640 | hid_parser_global, |
641 | hid_parser_local, | 641 | hid_parser_local, |
642 | hid_parser_reserved | 642 | hid_parser_reserved |
643 | }; | 643 | }; |
644 | 644 | ||
645 | if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL))) | 645 | if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL))) |
646 | return NULL; | 646 | return NULL; |
647 | 647 | ||
648 | if (!(device->collection = kzalloc(sizeof(struct hid_collection) * | 648 | if (!(device->collection = kzalloc(sizeof(struct hid_collection) * |
649 | HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { | 649 | HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { |
650 | kfree(device); | 650 | kfree(device); |
651 | return NULL; | 651 | return NULL; |
652 | } | 652 | } |
653 | device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; | 653 | device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; |
654 | 654 | ||
655 | for (i = 0; i < HID_REPORT_TYPES; i++) | 655 | for (i = 0; i < HID_REPORT_TYPES; i++) |
656 | INIT_LIST_HEAD(&device->report_enum[i].report_list); | 656 | INIT_LIST_HEAD(&device->report_enum[i].report_list); |
657 | 657 | ||
658 | if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) { | 658 | if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) { |
659 | kfree(device->collection); | 659 | kfree(device->collection); |
660 | kfree(device); | 660 | kfree(device); |
661 | return NULL; | 661 | return NULL; |
662 | } | 662 | } |
663 | memcpy(device->rdesc, start, size); | 663 | memcpy(device->rdesc, start, size); |
664 | device->rsize = size; | 664 | device->rsize = size; |
665 | 665 | ||
666 | if (!(parser = vmalloc(sizeof(struct hid_parser)))) { | 666 | if (!(parser = vmalloc(sizeof(struct hid_parser)))) { |
667 | kfree(device->rdesc); | 667 | kfree(device->rdesc); |
668 | kfree(device->collection); | 668 | kfree(device->collection); |
669 | kfree(device); | 669 | kfree(device); |
670 | return NULL; | 670 | return NULL; |
671 | } | 671 | } |
672 | memset(parser, 0, sizeof(struct hid_parser)); | 672 | memset(parser, 0, sizeof(struct hid_parser)); |
673 | parser->device = device; | 673 | parser->device = device; |
674 | 674 | ||
675 | end = start + size; | 675 | end = start + size; |
676 | while ((start = fetch_item(start, end, &item)) != NULL) { | 676 | while ((start = fetch_item(start, end, &item)) != NULL) { |
677 | 677 | ||
678 | if (item.format != HID_ITEM_FORMAT_SHORT) { | 678 | if (item.format != HID_ITEM_FORMAT_SHORT) { |
679 | dbg_hid("unexpected long global item\n"); | 679 | dbg_hid("unexpected long global item\n"); |
680 | hid_free_device(device); | 680 | hid_free_device(device); |
681 | vfree(parser); | 681 | vfree(parser); |
682 | return NULL; | 682 | return NULL; |
683 | } | 683 | } |
684 | 684 | ||
685 | if (dispatch_type[item.type](parser, &item)) { | 685 | if (dispatch_type[item.type](parser, &item)) { |
686 | dbg_hid("item %u %u %u %u parsing failed\n", | 686 | dbg_hid("item %u %u %u %u parsing failed\n", |
687 | item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); | 687 | item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); |
688 | hid_free_device(device); | 688 | hid_free_device(device); |
689 | vfree(parser); | 689 | vfree(parser); |
690 | return NULL; | 690 | return NULL; |
691 | } | 691 | } |
692 | 692 | ||
693 | if (start == end) { | 693 | if (start == end) { |
694 | if (parser->collection_stack_ptr) { | 694 | if (parser->collection_stack_ptr) { |
695 | dbg_hid("unbalanced collection at end of report description\n"); | 695 | dbg_hid("unbalanced collection at end of report description\n"); |
696 | hid_free_device(device); | 696 | hid_free_device(device); |
697 | vfree(parser); | 697 | vfree(parser); |
698 | return NULL; | 698 | return NULL; |
699 | } | 699 | } |
700 | if (parser->local.delimiter_depth) { | 700 | if (parser->local.delimiter_depth) { |
701 | dbg_hid("unbalanced delimiter at end of report description\n"); | 701 | dbg_hid("unbalanced delimiter at end of report description\n"); |
702 | hid_free_device(device); | 702 | hid_free_device(device); |
703 | vfree(parser); | 703 | vfree(parser); |
704 | return NULL; | 704 | return NULL; |
705 | } | 705 | } |
706 | vfree(parser); | 706 | vfree(parser); |
707 | return device; | 707 | return device; |
708 | } | 708 | } |
709 | } | 709 | } |
710 | 710 | ||
711 | dbg_hid("item fetching failed at offset %d\n", (int)(end - start)); | 711 | dbg_hid("item fetching failed at offset %d\n", (int)(end - start)); |
712 | hid_free_device(device); | 712 | hid_free_device(device); |
713 | vfree(parser); | 713 | vfree(parser); |
714 | return NULL; | 714 | return NULL; |
715 | } | 715 | } |
716 | EXPORT_SYMBOL_GPL(hid_parse_report); | 716 | EXPORT_SYMBOL_GPL(hid_parse_report); |
717 | 717 | ||
718 | /* | 718 | /* |
719 | * Convert a signed n-bit integer to signed 32-bit integer. Common | 719 | * Convert a signed n-bit integer to signed 32-bit integer. Common |
720 | * cases are done through the compiler, the screwed things has to be | 720 | * cases are done through the compiler, the screwed things has to be |
721 | * done by hand. | 721 | * done by hand. |
722 | */ | 722 | */ |
723 | 723 | ||
724 | static s32 snto32(__u32 value, unsigned n) | 724 | static s32 snto32(__u32 value, unsigned n) |
725 | { | 725 | { |
726 | switch (n) { | 726 | switch (n) { |
727 | case 8: return ((__s8)value); | 727 | case 8: return ((__s8)value); |
728 | case 16: return ((__s16)value); | 728 | case 16: return ((__s16)value); |
729 | case 32: return ((__s32)value); | 729 | case 32: return ((__s32)value); |
730 | } | 730 | } |
731 | return value & (1 << (n - 1)) ? value | (-1 << n) : value; | 731 | return value & (1 << (n - 1)) ? value | (-1 << n) : value; |
732 | } | 732 | } |
733 | 733 | ||
734 | /* | 734 | /* |
735 | * Convert a signed 32-bit integer to a signed n-bit integer. | 735 | * Convert a signed 32-bit integer to a signed n-bit integer. |
736 | */ | 736 | */ |
737 | 737 | ||
738 | static u32 s32ton(__s32 value, unsigned n) | 738 | static u32 s32ton(__s32 value, unsigned n) |
739 | { | 739 | { |
740 | s32 a = value >> (n - 1); | 740 | s32 a = value >> (n - 1); |
741 | if (a && a != -1) | 741 | if (a && a != -1) |
742 | return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; | 742 | return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; |
743 | return value & ((1 << n) - 1); | 743 | return value & ((1 << n) - 1); |
744 | } | 744 | } |
745 | 745 | ||
746 | /* | 746 | /* |
747 | * Extract/implement a data field from/to a little endian report (bit array). | 747 | * Extract/implement a data field from/to a little endian report (bit array). |
748 | * | 748 | * |
749 | * Code sort-of follows HID spec: | 749 | * Code sort-of follows HID spec: |
750 | * http://www.usb.org/developers/devclass_docs/HID1_11.pdf | 750 | * http://www.usb.org/developers/devclass_docs/HID1_11.pdf |
751 | * | 751 | * |
752 | * While the USB HID spec allows unlimited length bit fields in "report | 752 | * While the USB HID spec allows unlimited length bit fields in "report |
753 | * descriptors", most devices never use more than 16 bits. | 753 | * descriptors", most devices never use more than 16 bits. |
754 | * One model of UPS is claimed to report "LINEV" as a 32-bit field. | 754 | * One model of UPS is claimed to report "LINEV" as a 32-bit field. |
755 | * Search linux-kernel and linux-usb-devel archives for "hid-core extract". | 755 | * Search linux-kernel and linux-usb-devel archives for "hid-core extract". |
756 | */ | 756 | */ |
757 | 757 | ||
758 | static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) | 758 | static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) |
759 | { | 759 | { |
760 | u64 x; | 760 | u64 x; |
761 | 761 | ||
762 | if (n > 32) | 762 | if (n > 32) |
763 | printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n", | 763 | printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n", |
764 | n, current->comm); | 764 | n, current->comm); |
765 | 765 | ||
766 | report += offset >> 3; /* adjust byte index */ | 766 | report += offset >> 3; /* adjust byte index */ |
767 | offset &= 7; /* now only need bit offset into one byte */ | 767 | offset &= 7; /* now only need bit offset into one byte */ |
768 | x = get_unaligned_le64(report); | 768 | x = get_unaligned_le64(report); |
769 | x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ | 769 | x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ |
770 | return (u32) x; | 770 | return (u32) x; |
771 | } | 771 | } |
772 | 772 | ||
773 | /* | 773 | /* |
774 | * "implement" : set bits in a little endian bit stream. | 774 | * "implement" : set bits in a little endian bit stream. |
775 | * Same concepts as "extract" (see comments above). | 775 | * Same concepts as "extract" (see comments above). |
776 | * The data mangled in the bit stream remains in little endian | 776 | * The data mangled in the bit stream remains in little endian |
777 | * order the whole time. It make more sense to talk about | 777 | * order the whole time. It make more sense to talk about |
778 | * endianness of register values by considering a register | 778 | * endianness of register values by considering a register |
779 | * a "cached" copy of the little endiad bit stream. | 779 | * a "cached" copy of the little endiad bit stream. |
780 | */ | 780 | */ |
781 | static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) | 781 | static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) |
782 | { | 782 | { |
783 | __le64 x; | 783 | u64 x; |
784 | u64 m = (1ULL << n) - 1; | 784 | u64 m = (1ULL << n) - 1; |
785 | 785 | ||
786 | if (n > 32) | 786 | if (n > 32) |
787 | printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n", | 787 | printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n", |
788 | n, current->comm); | 788 | n, current->comm); |
789 | 789 | ||
790 | if (value > m) | 790 | if (value > m) |
791 | printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n", | 791 | printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n", |
792 | value, current->comm); | 792 | value, current->comm); |
793 | WARN_ON(value > m); | 793 | WARN_ON(value > m); |
794 | value &= m; | 794 | value &= m; |
795 | 795 | ||
796 | report += offset >> 3; | 796 | report += offset >> 3; |
797 | offset &= 7; | 797 | offset &= 7; |
798 | 798 | ||
799 | x = get_unaligned((__le64 *)report); | 799 | x = get_unaligned_le64(report); |
800 | x &= cpu_to_le64(~(m << offset)); | 800 | x &= ~(m << offset); |
801 | x |= cpu_to_le64(((u64) value) << offset); | 801 | x |= ((u64)value) << offset; |
802 | put_unaligned(x, (__le64 *) report); | 802 | put_unaligned_le64(x, report); |
803 | } | 803 | } |
804 | 804 | ||
805 | /* | 805 | /* |
806 | * Search an array for a value. | 806 | * Search an array for a value. |
807 | */ | 807 | */ |
808 | 808 | ||
809 | static __inline__ int search(__s32 *array, __s32 value, unsigned n) | 809 | static __inline__ int search(__s32 *array, __s32 value, unsigned n) |
810 | { | 810 | { |
811 | while (n--) { | 811 | while (n--) { |
812 | if (*array++ == value) | 812 | if (*array++ == value) |
813 | return 0; | 813 | return 0; |
814 | } | 814 | } |
815 | return -1; | 815 | return -1; |
816 | } | 816 | } |
817 | 817 | ||
818 | static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt) | 818 | static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt) |
819 | { | 819 | { |
820 | hid_dump_input(usage, value); | 820 | hid_dump_input(usage, value); |
821 | if (hid->claimed & HID_CLAIMED_INPUT) | 821 | if (hid->claimed & HID_CLAIMED_INPUT) |
822 | hidinput_hid_event(hid, field, usage, value); | 822 | hidinput_hid_event(hid, field, usage, value); |
823 | if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event) | 823 | if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event) |
824 | hid->hiddev_hid_event(hid, field, usage, value); | 824 | hid->hiddev_hid_event(hid, field, usage, value); |
825 | } | 825 | } |
826 | 826 | ||
827 | /* | 827 | /* |
828 | * Analyse a received field, and fetch the data from it. The field | 828 | * Analyse a received field, and fetch the data from it. The field |
829 | * content is stored for next report processing (we do differential | 829 | * content is stored for next report processing (we do differential |
830 | * reporting to the layer). | 830 | * reporting to the layer). |
831 | */ | 831 | */ |
832 | 832 | ||
833 | static void hid_input_field(struct hid_device *hid, struct hid_field *field, | 833 | static void hid_input_field(struct hid_device *hid, struct hid_field *field, |
834 | __u8 *data, int interrupt) | 834 | __u8 *data, int interrupt) |
835 | { | 835 | { |
836 | unsigned n; | 836 | unsigned n; |
837 | unsigned count = field->report_count; | 837 | unsigned count = field->report_count; |
838 | unsigned offset = field->report_offset; | 838 | unsigned offset = field->report_offset; |
839 | unsigned size = field->report_size; | 839 | unsigned size = field->report_size; |
840 | __s32 min = field->logical_minimum; | 840 | __s32 min = field->logical_minimum; |
841 | __s32 max = field->logical_maximum; | 841 | __s32 max = field->logical_maximum; |
842 | __s32 *value; | 842 | __s32 *value; |
843 | 843 | ||
844 | if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC))) | 844 | if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC))) |
845 | return; | 845 | return; |
846 | 846 | ||
847 | for (n = 0; n < count; n++) { | 847 | for (n = 0; n < count; n++) { |
848 | 848 | ||
849 | value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : | 849 | value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : |
850 | extract(data, offset + n * size, size); | 850 | extract(data, offset + n * size, size); |
851 | 851 | ||
852 | if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ | 852 | if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ |
853 | && value[n] >= min && value[n] <= max | 853 | && value[n] >= min && value[n] <= max |
854 | && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) | 854 | && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) |
855 | goto exit; | 855 | goto exit; |
856 | } | 856 | } |
857 | 857 | ||
858 | for (n = 0; n < count; n++) { | 858 | for (n = 0; n < count; n++) { |
859 | 859 | ||
860 | if (HID_MAIN_ITEM_VARIABLE & field->flags) { | 860 | if (HID_MAIN_ITEM_VARIABLE & field->flags) { |
861 | hid_process_event(hid, field, &field->usage[n], value[n], interrupt); | 861 | hid_process_event(hid, field, &field->usage[n], value[n], interrupt); |
862 | continue; | 862 | continue; |
863 | } | 863 | } |
864 | 864 | ||
865 | if (field->value[n] >= min && field->value[n] <= max | 865 | if (field->value[n] >= min && field->value[n] <= max |
866 | && field->usage[field->value[n] - min].hid | 866 | && field->usage[field->value[n] - min].hid |
867 | && search(value, field->value[n], count)) | 867 | && search(value, field->value[n], count)) |
868 | hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); | 868 | hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); |
869 | 869 | ||
870 | if (value[n] >= min && value[n] <= max | 870 | if (value[n] >= min && value[n] <= max |
871 | && field->usage[value[n] - min].hid | 871 | && field->usage[value[n] - min].hid |
872 | && search(field->value, value[n], count)) | 872 | && search(field->value, value[n], count)) |
873 | hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); | 873 | hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); |
874 | } | 874 | } |
875 | 875 | ||
876 | memcpy(field->value, value, count * sizeof(__s32)); | 876 | memcpy(field->value, value, count * sizeof(__s32)); |
877 | exit: | 877 | exit: |
878 | kfree(value); | 878 | kfree(value); |
879 | } | 879 | } |
880 | 880 | ||
881 | /* | 881 | /* |
882 | * Output the field into the report. | 882 | * Output the field into the report. |
883 | */ | 883 | */ |
884 | 884 | ||
885 | static void hid_output_field(struct hid_field *field, __u8 *data) | 885 | static void hid_output_field(struct hid_field *field, __u8 *data) |
886 | { | 886 | { |
887 | unsigned count = field->report_count; | 887 | unsigned count = field->report_count; |
888 | unsigned offset = field->report_offset; | 888 | unsigned offset = field->report_offset; |
889 | unsigned size = field->report_size; | 889 | unsigned size = field->report_size; |
890 | unsigned bitsused = offset + count * size; | 890 | unsigned bitsused = offset + count * size; |
891 | unsigned n; | 891 | unsigned n; |
892 | 892 | ||
893 | /* make sure the unused bits in the last byte are zeros */ | 893 | /* make sure the unused bits in the last byte are zeros */ |
894 | if (count > 0 && size > 0 && (bitsused % 8) != 0) | 894 | if (count > 0 && size > 0 && (bitsused % 8) != 0) |
895 | data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1; | 895 | data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1; |
896 | 896 | ||
897 | for (n = 0; n < count; n++) { | 897 | for (n = 0; n < count; n++) { |
898 | if (field->logical_minimum < 0) /* signed values */ | 898 | if (field->logical_minimum < 0) /* signed values */ |
899 | implement(data, offset + n * size, size, s32ton(field->value[n], size)); | 899 | implement(data, offset + n * size, size, s32ton(field->value[n], size)); |
900 | else /* unsigned values */ | 900 | else /* unsigned values */ |
901 | implement(data, offset + n * size, size, field->value[n]); | 901 | implement(data, offset + n * size, size, field->value[n]); |
902 | } | 902 | } |
903 | } | 903 | } |
904 | 904 | ||
905 | /* | 905 | /* |
906 | * Create a report. | 906 | * Create a report. |
907 | */ | 907 | */ |
908 | 908 | ||
909 | void hid_output_report(struct hid_report *report, __u8 *data) | 909 | void hid_output_report(struct hid_report *report, __u8 *data) |
910 | { | 910 | { |
911 | unsigned n; | 911 | unsigned n; |
912 | 912 | ||
913 | if (report->id > 0) | 913 | if (report->id > 0) |
914 | *data++ = report->id; | 914 | *data++ = report->id; |
915 | 915 | ||
916 | for (n = 0; n < report->maxfield; n++) | 916 | for (n = 0; n < report->maxfield; n++) |
917 | hid_output_field(report->field[n], data); | 917 | hid_output_field(report->field[n], data); |
918 | } | 918 | } |
919 | EXPORT_SYMBOL_GPL(hid_output_report); | 919 | EXPORT_SYMBOL_GPL(hid_output_report); |
920 | 920 | ||
921 | /* | 921 | /* |
922 | * Set a field value. The report this field belongs to has to be | 922 | * Set a field value. The report this field belongs to has to be |
923 | * created and transferred to the device, to set this value in the | 923 | * created and transferred to the device, to set this value in the |
924 | * device. | 924 | * device. |
925 | */ | 925 | */ |
926 | 926 | ||
927 | int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) | 927 | int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) |
928 | { | 928 | { |
929 | unsigned size = field->report_size; | 929 | unsigned size = field->report_size; |
930 | 930 | ||
931 | hid_dump_input(field->usage + offset, value); | 931 | hid_dump_input(field->usage + offset, value); |
932 | 932 | ||
933 | if (offset >= field->report_count) { | 933 | if (offset >= field->report_count) { |
934 | dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count); | 934 | dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count); |
935 | hid_dump_field(field, 8); | 935 | hid_dump_field(field, 8); |
936 | return -1; | 936 | return -1; |
937 | } | 937 | } |
938 | if (field->logical_minimum < 0) { | 938 | if (field->logical_minimum < 0) { |
939 | if (value != snto32(s32ton(value, size), size)) { | 939 | if (value != snto32(s32ton(value, size), size)) { |
940 | dbg_hid("value %d is out of range\n", value); | 940 | dbg_hid("value %d is out of range\n", value); |
941 | return -1; | 941 | return -1; |
942 | } | 942 | } |
943 | } | 943 | } |
944 | field->value[offset] = value; | 944 | field->value[offset] = value; |
945 | return 0; | 945 | return 0; |
946 | } | 946 | } |
947 | EXPORT_SYMBOL_GPL(hid_set_field); | 947 | EXPORT_SYMBOL_GPL(hid_set_field); |
948 | 948 | ||
949 | int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt) | 949 | int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt) |
950 | { | 950 | { |
951 | struct hid_report_enum *report_enum = hid->report_enum + type; | 951 | struct hid_report_enum *report_enum = hid->report_enum + type; |
952 | struct hid_report *report; | 952 | struct hid_report *report; |
953 | int n, rsize, i; | 953 | int n, rsize, i; |
954 | 954 | ||
955 | if (!hid) | 955 | if (!hid) |
956 | return -ENODEV; | 956 | return -ENODEV; |
957 | 957 | ||
958 | if (!size) { | 958 | if (!size) { |
959 | dbg_hid("empty report\n"); | 959 | dbg_hid("empty report\n"); |
960 | return -1; | 960 | return -1; |
961 | } | 961 | } |
962 | 962 | ||
963 | dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); | 963 | dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); |
964 | 964 | ||
965 | n = 0; /* Normally report number is 0 */ | 965 | n = 0; /* Normally report number is 0 */ |
966 | if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ | 966 | if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ |
967 | n = *data++; | 967 | n = *data++; |
968 | size--; | 968 | size--; |
969 | } | 969 | } |
970 | 970 | ||
971 | /* dump the report */ | 971 | /* dump the report */ |
972 | dbg_hid("report %d (size %u) = ", n, size); | 972 | dbg_hid("report %d (size %u) = ", n, size); |
973 | for (i = 0; i < size; i++) | 973 | for (i = 0; i < size; i++) |
974 | dbg_hid_line(" %02x", data[i]); | 974 | dbg_hid_line(" %02x", data[i]); |
975 | dbg_hid_line("\n"); | 975 | dbg_hid_line("\n"); |
976 | 976 | ||
977 | if (!(report = report_enum->report_id_hash[n])) { | 977 | if (!(report = report_enum->report_id_hash[n])) { |
978 | dbg_hid("undefined report_id %d received\n", n); | 978 | dbg_hid("undefined report_id %d received\n", n); |
979 | return -1; | 979 | return -1; |
980 | } | 980 | } |
981 | 981 | ||
982 | rsize = ((report->size - 1) >> 3) + 1; | 982 | rsize = ((report->size - 1) >> 3) + 1; |
983 | 983 | ||
984 | if (size < rsize) { | 984 | if (size < rsize) { |
985 | dbg_hid("report %d is too short, (%d < %d)\n", report->id, size, rsize); | 985 | dbg_hid("report %d is too short, (%d < %d)\n", report->id, size, rsize); |
986 | memset(data + size, 0, rsize - size); | 986 | memset(data + size, 0, rsize - size); |
987 | } | 987 | } |
988 | 988 | ||
989 | if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) | 989 | if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) |
990 | hid->hiddev_report_event(hid, report); | 990 | hid->hiddev_report_event(hid, report); |
991 | if (hid->claimed & HID_CLAIMED_HIDRAW) { | 991 | if (hid->claimed & HID_CLAIMED_HIDRAW) { |
992 | /* numbered reports need to be passed with the report num */ | 992 | /* numbered reports need to be passed with the report num */ |
993 | if (report_enum->numbered) | 993 | if (report_enum->numbered) |
994 | hidraw_report_event(hid, data - 1, size + 1); | 994 | hidraw_report_event(hid, data - 1, size + 1); |
995 | else | 995 | else |
996 | hidraw_report_event(hid, data, size); | 996 | hidraw_report_event(hid, data, size); |
997 | } | 997 | } |
998 | 998 | ||
999 | for (n = 0; n < report->maxfield; n++) | 999 | for (n = 0; n < report->maxfield; n++) |
1000 | hid_input_field(hid, report->field[n], data, interrupt); | 1000 | hid_input_field(hid, report->field[n], data, interrupt); |
1001 | 1001 | ||
1002 | if (hid->claimed & HID_CLAIMED_INPUT) | 1002 | if (hid->claimed & HID_CLAIMED_INPUT) |
1003 | hidinput_report_event(hid, report); | 1003 | hidinput_report_event(hid, report); |
1004 | 1004 | ||
1005 | return 0; | 1005 | return 0; |
1006 | } | 1006 | } |
1007 | EXPORT_SYMBOL_GPL(hid_input_report); | 1007 | EXPORT_SYMBOL_GPL(hid_input_report); |
1008 | 1008 | ||
1009 | static int __init hid_init(void) | 1009 | static int __init hid_init(void) |
1010 | { | 1010 | { |
1011 | return hidraw_init(); | 1011 | return hidraw_init(); |
1012 | } | 1012 | } |
1013 | 1013 | ||
1014 | static void __exit hid_exit(void) | 1014 | static void __exit hid_exit(void) |
1015 | { | 1015 | { |
1016 | hidraw_exit(); | 1016 | hidraw_exit(); |
1017 | } | 1017 | } |
1018 | 1018 | ||
1019 | module_init(hid_init); | 1019 | module_init(hid_init); |
1020 | module_exit(hid_exit); | 1020 | module_exit(hid_exit); |
1021 | 1021 | ||
1022 | MODULE_LICENSE(DRIVER_LICENSE); | 1022 | MODULE_LICENSE(DRIVER_LICENSE); |
1023 | 1023 | ||
1024 | 1024 |