📄 hid.c
字号:
&& field->usage[value[n] - min].hid /* nonzero usage */ && search(field->value, value[n], count)) hid_process_event(&dev->input, &dev->quirks, field, &field->usage[value[n] - min], 1); } } memcpy(field->value, value, count * sizeof(__s32));}/* * Interrupt input handler - analyse a received report. */static void hid_irq(struct urb *urb){ struct hid_device *device = urb->context; struct hid_report_enum *report_enum = device->report_enum + HID_INPUT_REPORT; struct hid_report *report; __u8 *data = urb->transfer_buffer; int len = urb->actual_length; int n; if (urb->status) { dbg("nonzero status in irq %d", urb->status); return; } if (!len) { dbg("empty report"); return; }#ifdef DEBUG_DATA printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered) = ", len, report_enum->numbered ? "" : "un"); for (n = 0; n < len; n++) printk(" %02x", data[n]); printk("\n");#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; } if (len < ((report->size - 1) >> 3) + 1) { dbg("report %d is too short, (%d < %d)", report->id, len, ((report->size - 1) >> 3) + 1); return; } for (n = 0; n < report->maxfield; n++) hid_input_field(device, report->field[n], data); return;}/* * hid_read_report() s intended to read the hid devices values even * before the input device is registered, so that the userland interface * modules start with real values. This is especially important for joydev.c * automagic calibration. Doesn't work yet, though. Don't know why, the control * request just times out on most devices I have and returns nonsense on others. */static void hid_read_report(struct hid_device *hid, struct hid_report *report){#if 0 int rlen = ((report->size - 1) >> 3) + 1; char rdata[rlen]; struct urb urb; int read, j; memset(&urb, 0, sizeof(struct urb)); memset(rdata, 0, rlen); urb.transfer_buffer = rdata; urb.actual_length = rlen; urb.context = hid; dbg("getting report type %d id %d len %d", report->type + 1, report->id, rlen); if ((read = usb_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, rdata, rlen)) != rlen) { dbg("reading report failed rlen %d read %d", rlen, read);#ifdef DEBUG printk(KERN_DEBUG __FILE__ ": report = "); for (j = 0; j < rlen; j++) printk(" %02x", rdata[j]); printk("\n");#endif return; } hid_irq(&urb);#endif}/* * Output the field into the report. */static void hid_output_field(struct hid_field *field, __u8 *data){ unsigned count = field->report_count; unsigned offset = field->report_offset; unsigned size = field->report_size; unsigned n; for (n = 0; n < count; n++) { if (field->logical_minimum < 0) /* signed values */ implement(data, offset + n * size, size, s32ton(field->value[n], size)); else /* unsigned values */ implement(data, offset + n * size, size, field->value[n]); }}/* * Create a report. */void hid_output_report(struct hid_report *report, __u8 *data){ unsigned n; for (n = 0; n < report->maxfield; n++) hid_output_field(report->field[n], data);};/* * Set a field value. The report this field belongs to has to be * created and transfered to the device, to set this value in the * device. */int hid_set_field(struct hid_field *field, unsigned offset, __s32 value){ unsigned size = field->report_size; hid_dump_input(field->usage + offset, value); if (offset >= field->report_count) { dbg("offset exceeds report_count"); return -1; } if (field->logical_minimum < 0) { if (value != snto32(s32ton(value, size), size)) { dbg("value %d is out of range", value); return -1; } } if ( (value > field->logical_maximum) || (value < field->logical_minimum)) { dbg("value %d is invalid", value); return -1; } field->value[offset] = value; return 0;}static int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field){ struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT; struct list_head *list = report_enum->report_list.next; int i, j; while (list != &report_enum->report_list) { struct hid_report *report = (struct hid_report *) list; list = list->next; for (i = 0; i < report->maxfield; i++) { *field = report->field[i]; for (j = 0; j < (*field)->maxusage; j++) if ((*field)->usage[j].type == type && (*field)->usage[j].code == code) return j; } } return -1;}static int hid_submit_out(struct hid_device *hid){ hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length; hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); hid->urbout.dev = hid->dev; if (usb_submit_urb(&hid->urbout)) { err("usb_submit_urb(out) failed"); return -1; } return 0;}static void hid_ctrl(struct urb *urb){ struct hid_device *hid = urb->context; if (urb->status) warn("ctrl urb status %d received", urb->status); hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->outhead != hid->outtail) hid_submit_out(hid);} static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code, int value){ struct hid_device *hid = dev->private; struct hid_field *field = NULL; int offset; if ((offset = hid_find_field(hid, type, code, &field)) == -1) { warn("event field not found"); return -1; } hid_set_field(field, offset, value); hid_output_report(field->report, hid->out[hid->outhead].buffer); hid->out[hid->outhead].dr.value = 0x200 | field->report->id; hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1; hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->outhead == hid->outtail) hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->urbout.status != -EINPROGRESS) hid_submit_out(hid); return 0;}static int hid_open(struct input_dev *dev){ struct hid_device *hid = dev->private; if (hid->open++) return 0; hid->urb.dev = hid->dev; if (usb_submit_urb(&hid->urb)) return -EIO; return 0;}static void hid_close(struct input_dev *dev){ struct hid_device *hid = dev->private; if (!--hid->open) usb_unlink_urb(&hid->urb);}/* * Configure the input layer interface * Read all reports and initalize the absoulte field values. */static void hid_init_input(struct hid_device *hid){ struct hid_report_enum *report_enum; struct list_head *list; int i, j, k; hid->input.private = hid; hid->input.event = hid_event; hid->input.open = hid_open; hid->input.close = hid_close; for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { report_enum = hid->report_enum + k; list = report_enum->report_list.next; while (list != &report_enum->report_list) { struct hid_report *report = (struct hid_report *) list; list = list->next; for (i = 0; i < report->maxfield; i++) for (j = 0; j < report->field[i]->maxusage; j++) hid_configure_usage(hid, report->field[i], report->field[i]->usage + j); if (k == HID_INPUT_REPORT) { usb_set_idle(hid->dev, hid->ifnum, 0, report->id); hid_read_report(hid, report); } } }}#define USB_VENDOR_ID_WACOM 0x056a#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010#define USB_DEVICE_ID_WACOM_INTUOS 0x0020struct hid_blacklist { __u16 idVendor; __u16 idProduct;} hid_blacklist[] = { { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1}, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2}, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3}, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4}, { 0, 0 }};static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, char *name){ struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; struct hid_descriptor *hdesc; struct hid_device *hid; unsigned rsize = 0; int n; for (n = 0; hid_blacklist[n].idVendor; n++) if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) && (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL; if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc) && usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc)) { dbg("class descriptor not present\n"); return NULL; } for (n = 0; n < hdesc->bNumDescriptors; n++) if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT) rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { dbg("weird size of report descriptor (%u)", rsize); return NULL; } { __u8 rdesc[rsize]; if ((n = usb_get_class_descriptor(dev, interface->bInterfaceNumber, USB_DT_REPORT, 0, rdesc, rsize)) < 0) { dbg("reading report descriptor failed"); return NULL; }#ifdef DEBUG_DATA printk(KERN_DEBUG __FILE__ ": report (size %u, read %d) = ", rsize, n); for (n = 0; n < rsize; n++) printk(" %02x", (unsigned) rdesc[n]); printk("\n");#endif if (!(hid = hid_parse_report(rdesc, rsize))) { dbg("parsing report descriptor failed"); return NULL; } } for (n = 0; n < interface->bNumEndpoints; n++) { struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; int pipe, maxp; if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ continue; if (!(endpoint->bEndpointAddress & 0x80)) /* Not an input endpoint */ continue; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval); break; } if (n == interface->bNumEndpoints) { dbg("couldn't find an input interrupt endpoint"); hid_free_device(hid); return NULL; } hid->version = hdesc->bcdHID; hid->country = hdesc->bCountryCode; hid->dev = dev; hid->ifnum = interface->bInterfaceNumber; for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) { hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; hid->out[n].dr.request = USB_REQ_SET_REPORT; hid->out[n].dr.index = hid->ifnum; } hid->input.name = hid->name; hid->input.idbus = BUS_USB; hid->input.idvendor = dev->descriptor.idVendor; hid->input.idproduct = dev->descriptor.idProduct; hid->input.idversion = dev->descriptor.bcdDevice; if (strlen(name)) strcpy(hid->name, name); else sprintf(hid->name, "USB HID %s %04x:%04x", ((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ? hid_types[hid->application & 0xffff] : "Device", hid->input.idvendor, hid->input.idproduct); FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0), (void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid); if (interface->bInterfaceSubClass == 1) usb_set_protocol(dev, hid->ifnum, 1); return hid;}static void* hid_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ struct hid_device *hid; char name[128]; char *buf; dbg("HID probe called for ifnum %d", ifnum); name[0] = 0; if (!(buf = kmalloc(63, GFP_KERNEL))) return NULL; if (dev->descriptor.iManufacturer && usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) strcat(name, buf); if (dev->descriptor.iProduct && usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) sprintf(name, "%s %s", name, buf); kfree(buf); if (!(hid = usb_hid_configure(dev, ifnum, name))) return NULL; hid_dump_device(hid); hid_init_input(hid); input_register_device(&hid->input); printk(KERN_INFO "input%d: USB HID v%x.%02x %s", hid->input.number, hid->version >> 8, hid->version & 0xff, ((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ? hid_types[hid->application & 0xffff] : "Device"); if (strlen(name)) printk(" [%s]", name); else printk(" [%04x:%04x]", hid->input.idvendor, hid->input.idproduct); printk(" on usb%d:%d.%d\n", dev->bus->busnum, dev->devnum, ifnum); return hid;}static void hid_disconnect(struct usb_device *dev, void *ptr){ struct hid_device *hid = ptr; dbg("cleanup called"); usb_unlink_urb(&hid->urb); input_unregister_device(&hid->input); hid_free_device(hid);}static struct usb_device_id hid_usb_ids [] = { { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, bInterfaceClass: USB_INTERFACE_CLASS_HID}, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, hid_usb_ids);static struct usb_driver hid_driver = { name: "hid", probe: hid_probe, disconnect: hid_disconnect, id_table: hid_usb_ids,};static int __init hid_init(void){ usb_register(&hid_driver); return 0;}static void __exit hid_exit(void){ usb_deregister(&hid_driver);}module_init(hid_init);module_exit(hid_exit);MODULE_AUTHOR("Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>");MODULE_DESCRIPTION("USB HID support drivers");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -