📄 hid.c
字号:
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; return value & ((1 << n) - 1);}/* * Extract/implement a data field from/to a report. We use 64-bit unsigned, * 32-bit aligned, so that we can possibly have alignment problems on some * odd architectures. */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; *(__u64*)report &= cpu_to_le64(~((((__u64) 1 << n) - 1) << offset)); *(__u64*)report |= cpu_to_le64((__u64)value << offset);}static void hid_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage){ struct input_dev *input = &device->input; int max; unsigned long *bit; switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_KEYBOARD: set_bit(EV_REP, input->evbit); usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; if ((usage->hid & HID_USAGE) < 256) { if (!(usage->code = hid_keyboard[usage->hid & HID_USAGE])) return; clear_bit(usage->code, bit); } else usage->code = KEY_UNKNOWN; break; case HID_UP_BUTTON: usage->code = ((usage->hid - 1) & 0xf) + 0x100; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; switch (device->application) { case HID_GD_GAMEPAD: usage->code += 0x10; case HID_GD_JOYSTICK: usage->code += 0x10; case HID_GD_MOUSE: usage->code += 0x10; break; default: if (field->physical == HID_GD_POINTER) usage->code += 0x10; break; } break; case HID_UP_GENDESK: if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ switch (usage->hid & 0xf) { case 0x1: usage->code = KEY_POWER; break; case 0x2: usage->code = KEY_SLEEP; break; case 0x3: usage->code = KEY_WAKEUP; break; default: usage->code = KEY_UNKNOWN; break; } usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; break; } usage->code = usage->hid & 0xf; if (field->report_size == 1) { usage->code = BTN_MISC; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; break; } if (field->flags & HID_MAIN_ITEM_RELATIVE) { usage->type = EV_REL; bit = input->relbit; max = REL_MAX; break; } usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; if (usage->hid == HID_GD_HATSWITCH) { usage->code = ABS_HAT0X; usage->hat = 1 + (field->logical_maximum == 4); } break; case HID_UP_LED: usage->code = (usage->hid - 1) & 0xf; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; break; case HID_UP_DIGITIZER: switch (usage->hid & 0xff) { case 0x30: /* TipPressure */ if (!test_bit(BTN_TOUCH, input->keybit)) { device->quirks |= HID_QUIRK_NOTOUCH; set_bit(EV_KEY, input->evbit); set_bit(BTN_TOUCH, input->keybit); } usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; usage->code = ABS_PRESSURE; clear_bit(usage->code, bit); break; case 0x32: /* InRange */ usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; switch (field->physical & 0xff) { case 0x21: usage->code = BTN_TOOL_MOUSE; break; case 0x22: usage->code = BTN_TOOL_FINGER; break; default: usage->code = BTN_TOOL_PEN; break; } break; case 0x3c: /* Invert */ usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; usage->code = BTN_TOOL_RUBBER; clear_bit(usage->code, bit); break; case 0x33: /* Touch */ case 0x42: /* TipSwitch */ case 0x43: /* TipSwitch2 */ device->quirks &= ~HID_QUIRK_NOTOUCH; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; usage->code = BTN_TOUCH; clear_bit(usage->code, bit); break; case 0x44: /* BarrelSwitch */ usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; usage->code = BTN_STYLUS; clear_bit(usage->code, bit); break; default: goto unknown; } break; case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ switch (usage->hid & HID_USAGE) { case 0x000: usage->code = 0; break; case 0x034: usage->code = KEY_SLEEP; break; case 0x036: usage->code = BTN_MISC; break; case 0x08a: usage->code = KEY_WWW; break; case 0x095: usage->code = KEY_HELP; break; case 0x0b4: usage->code = KEY_REWIND; break; case 0x0b5: usage->code = KEY_NEXTSONG; break; case 0x0b6: usage->code = KEY_PREVIOUSSONG; break; case 0x0b7: usage->code = KEY_STOPCD; break; case 0x0b8: usage->code = KEY_EJECTCD; break; case 0x0cd: usage->code = KEY_PLAYPAUSE; break; case 0x0e2: usage->code = KEY_MUTE; break; case 0x0e9: usage->code = KEY_VOLUMEUP; break; case 0x0ea: usage->code = KEY_VOLUMEDOWN; break; case 0x183: usage->code = KEY_CONFIG; break; case 0x18a: usage->code = KEY_MAIL; break; case 0x192: usage->code = KEY_CALC; break; case 0x194: usage->code = KEY_FILE; break; case 0x21a: usage->code = KEY_UNDO; break; case 0x21b: usage->code = KEY_COPY; break; case 0x21c: usage->code = KEY_CUT; break; case 0x21d: usage->code = KEY_PASTE; break; case 0x221: usage->code = KEY_FIND; break; case 0x223: usage->code = KEY_HOMEPAGE; break; case 0x224: usage->code = KEY_BACK; break; case 0x225: usage->code = KEY_FORWARD; break; case 0x226: usage->code = KEY_STOP; break; case 0x227: usage->code = KEY_REFRESH; break; case 0x22a: usage->code = KEY_BOOKMARKS; break; default: usage->code = KEY_UNKNOWN; break; } usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; break; default: unknown: if (field->report_size == 1) { usage->code = BTN_MISC; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; break; } if (field->flags & HID_MAIN_ITEM_RELATIVE) { usage->code = REL_MISC; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; break; } usage->code = ABS_MISC; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; break; } set_bit(usage->type, input->evbit); while (usage->code <= max && test_and_set_bit(usage->code, bit)) { usage->code = find_next_zero_bit(bit, max + 1, usage->code); } if (usage->code > max) return; if (usage->type == EV_ABS) { int a = field->logical_minimum; int b = field->logical_maximum; input->absmin[usage->code] = a; input->absmax[usage->code] = b; input->absfuzz[usage->code] = (b - a) >> 8; input->absflat[usage->code] = (b - a) >> 4; } if (usage->hat) { int i; for (i = usage->code; i < usage->code + 2 && i <= max; i++) { input->absmax[i] = 1; input->absmin[i] = -1; input->absfuzz[i] = 0; input->absflat[i] = 0; } set_bit(usage->code + 1, input->absbit); }}static void hid_process_event(struct input_dev *input, int *quirks, struct hid_field *field, struct hid_usage *usage, __s32 value){ hid_dump_input(usage, value); if (usage->hat) { if (usage->hat == 2) value = value * 2; if (value > 8) value = 8; input_event(input, usage->type, usage->code , hid_hat_to_axis[value].x); input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y); return; } if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); return; } if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ if (value) { input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); return; } input_event(input, usage->type, usage->code, 0); input_event(input, usage->type, BTN_TOOL_RUBBER, 0); return; } if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ int a = field->logical_minimum; int b = field->logical_maximum; input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); } if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */ return; input_event(input, usage->type, usage->code, value); if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) input_event(input, usage->type, usage->code, 0);}/* * 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;}/* * 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 *dev, 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); 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(&dev->input, &dev->quirks, field, &field->usage[n], value[n]); } else { if (field->value[n] >= min && field->value[n] <= max /* non-NULL value */ && field->usage[field->value[n] - min].hid /* nonzero usage */ && search(value, field->value[n], count)) hid_process_event(&dev->input, &dev->quirks, field, &field->usage[field->value[n] - min], 0); if (value[n] >= min && value[n] <= max /* non-NULL value */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -