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