📄 hid-core.c
字号:
if (hid_add_usage(parser, n)) { dbg("hid_add_usage failed\n"); return -1; } return 0; default: dbg("unknown local item tag 0x%x", item->tag); return 0; } return 0;}/* * Process a main item. */static int hid_parser_main(struct hid_parser *parser, struct hid_item *item){ __u32 data; int ret; data = item_udata(item); switch (item->tag) { case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: ret = open_collection(parser, data & 3); break; case HID_MAIN_ITEM_TAG_END_COLLECTION: ret = close_collection(parser); break; case HID_MAIN_ITEM_TAG_INPUT: ret = hid_add_field(parser, HID_INPUT_REPORT, data); break; case HID_MAIN_ITEM_TAG_OUTPUT: ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); break; case HID_MAIN_ITEM_TAG_FEATURE: ret = hid_add_field(parser, HID_FEATURE_REPORT, data); break; default: dbg("unknown main item tag 0x%x", item->tag); ret = 0; } memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ return ret;}/* * Process a reserved item. */static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item){ dbg("reserved item type, tag 0x%x", item->tag); return 0;}/* * Free a report and all registered fields. The field->usage and * field->value table's are allocated behind the field, so we need * only to free(field) itself. */static void hid_free_report(struct hid_report *report){ unsigned n; for (n = 0; n < report->maxfield; n++) kfree(report->field[n]); if (report->data) kfree(report->data); kfree(report);}/* * Free a device structure, all reports, and all fields. */static void hid_free_device(struct hid_device *device){ unsigned i,j; for (i = 0; i < HID_REPORT_TYPES; i++) { struct hid_report_enum *report_enum = device->report_enum + i; for (j = 0; j < 256; j++) { struct hid_report *report = report_enum->report_id_hash[j]; if (report) hid_free_report(report); } } if (device->rdesc) kfree(device->rdesc);}/* * Fetch a report description item from the data stream. We support long * items, though they are not used yet. */static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item){ if ((end - start) > 0) { __u8 b = *start++; item->type = (b >> 2) & 3; item->tag = (b >> 4) & 15; if (item->tag == HID_ITEM_TAG_LONG) { item->format = HID_ITEM_FORMAT_LONG; if ((end - start) >= 2) { item->size = *start++; item->tag = *start++; if ((end - start) >= item->size) { item->data.longdata = start; start += item->size; return start; } } } else { item->format = HID_ITEM_FORMAT_SHORT; item->size = b & 3; switch (item->size) { case 0: return start; case 1: if ((end - start) >= 1) { item->data.u8 = *start++; return start; } break; case 2: if ((end - start) >= 2) { item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++)); return start; } case 3: item->size++; if ((end - start) >= 4) { item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++)); return start; } } } } return NULL;}/* * Parse a report description into a hid_device structure. Reports are * enumerated, fields are attached to these reports. */static struct hid_device *hid_parse_report(__u8 *start, unsigned size){ struct hid_device *device; struct hid_parser *parser; struct hid_item item; __u8 *end; unsigned i; static int (*dispatch_type[])(struct hid_parser *parser, struct hid_item *item) = { hid_parser_main, hid_parser_global, hid_parser_local, hid_parser_reserved }; if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL))) return NULL; memset(device, 0, sizeof(struct hid_device)); for (i = 0; i < HID_REPORT_TYPES; i++) INIT_LIST_HEAD(&device->report_enum[i].report_list); if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { kfree(device); return NULL; } memcpy(device->rdesc, start, size); if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) { kfree(device->rdesc); kfree(device); return NULL; } memset(parser, 0, sizeof(struct hid_parser)); parser->device = device; end = start + size; while ((start = fetch_item(start, end, &item)) != 0) { if (item.format != HID_ITEM_FORMAT_SHORT) { dbg("unexpected long global item"); hid_free_device(device); kfree(parser); return NULL; } if (dispatch_type[item.type](parser, &item)) { dbg("item %u %u %u %u parsing failed\n", item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); hid_free_device(device); kfree(parser); return NULL; } if (start == end) { if (parser->collection_stack_ptr) { dbg("unbalanced collection at end of report description"); hid_free_device(device); kfree(parser); return NULL; } if (parser->local.delimiter_depth) { dbg("unbalanced delimiter at end of report description"); hid_free_device(device); kfree(parser); return NULL; } kfree(parser); return device; } } dbg("item fetching failed at offset %d\n", (int)(end - start)); hid_free_device(device); kfree(parser); return NULL;}/* * Convert a signed n-bit integer to signed 32-bit integer. Common * cases are done through the compiler, the screwed things has to be * done by hand. */static __inline__ __s32 snto32(__u32 value, unsigned n){ switch (n) { case 8: return ((__s8)value); case 16: return ((__s16)value); case 32: return ((__s32)value); } return value & (1 << (n - 1)) ? value | (-1 << n) : value;}/* * Convert a signed 32-bit integer to a signed n-bit integer. */static __inline__ __u32 s32ton(__s32 value, unsigned n){ __s32 a = value >> (n - 1); if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; return value & ((1 << n) - 1);}/* * Extract/implement a data field from/to a report. */static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n){ report += (offset >> 5) << 2; offset &= 31; return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1);}static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value){ report += (offset >> 5) << 2; offset &= 31; put_unaligned((get_unaligned((__u64*)report) & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) | cpu_to_le64((__u64)value << offset), (__u64*)report);}/* * Search an array for a value. */static __inline__ int search(__s32 *array, __s32 value, unsigned n){ while (n--) if (*array++ == value) return 0; return -1;}static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value){ hid_dump_input(usage, value); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_hid_event(hid, field, usage, value);#ifdef CONFIG_USB_HIDDEV if (hid->claimed & HID_CLAIMED_HIDDEV) hiddev_hid_event(hid, usage->hid, value);#endif}/* * Analyse a received field, and fetch the data from it. The field * content is stored for next report processing (we do differential * reporting to the layer). */static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data){ unsigned n; unsigned count = field->report_count; unsigned offset = field->report_offset; unsigned size = field->report_size; __s32 min = field->logical_minimum; __s32 max = field->logical_maximum; __s32 value[count]; /* WARNING: gcc specific */ for (n = 0; n < count; n++) { value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : extract(data, offset + n * size, size); if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ && value[n] >= min && value[n] <= max && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) return; } for (n = 0; n < count; n++) { if (HID_MAIN_ITEM_VARIABLE & field->flags) { if (field->flags & HID_MAIN_ITEM_RELATIVE) { if (!value[n]) continue; } else { if (value[n] == field->value[n]) continue; } hid_process_event(hid, field, &field->usage[n], value[n]); continue; } if (field->value[n] >= min && field->value[n] <= max && field->usage[field->value[n] - min].hid && search(value, field->value[n], count)) hid_process_event(hid, field, &field->usage[field->value[n] - min], 0); if (value[n] >= min && value[n] <= max && field->usage[value[n] - min].hid && search(field->value, value[n], count)) hid_process_event(hid, field, &field->usage[value[n] - min], 1); } memcpy(field->value, value, count * sizeof(__s32));}static int hid_input_report(int type, u8 *data, int len, struct hid_device *hid){ struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report *report; int n, size; if (!len) { dbg("empty report"); return -1; }#ifdef DEBUG_DATA printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");#endif n = 0; /* Normally report number is 0 */ if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ n = *data++; len--; } if (!(report = report_enum->report_id_hash[n])) { dbg("undefined report_id %d received", n);#ifdef DEBUG printk(KERN_DEBUG __FILE__ ": report (size %u) = ", len); for (n = 0; n < len; n++) printk(" %02x", data[n]); printk("\n");#endif return -1; } size = ((report->size - 1) >> 3) + 1; if (len < size) { if (size <= 8) { dbg("report %d is too short, (%d < %d)", report->id, len, size); return -1; } /* * Some low-speed devices have large reports and maxpacketsize 8. * We buffer the data in that case and parse it when we got it all. * Works only for unnumbered reports. Doesn't make sense for numbered * reports anyway - then they don't need to be large. */ if (!report->data) if (!(report->data = kmalloc(size, GFP_ATOMIC))) { dbg("couldn't allocate report buffer"); return -1; } if (report->idx + len > size) { dbg("report data buffer overflow"); report->idx = 0; return -1; } memcpy(report->data + report->idx, data, len); report->idx += len; if (report->idx < size) return 0; data = report->data; } for (n = 0; n < report->maxfield; n++) hid_input_field(hid, report->field[n], data); report->idx = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -