📄 hid-core.c
字号:
case -EPIPE: /* report not available */ break; default: /* error */ warn("ctrl urb status %d received", urb->status); } if (unplug) usbhid->ctrltail = usbhid->ctrlhead; else usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (usbhid->ctrlhead != usbhid->ctrltail) { if (hid_submit_ctrl(hid)) { clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); wake_up(&hid->wait); } spin_unlock_irqrestore(&usbhid->ctrllock, flags); return; } clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->ctrllock, flags); wake_up(&hid->wait);}void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir){ int head; unsigned long flags; struct usbhid_device *usbhid = hid->driver_data; if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) return; if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { spin_lock_irqsave(&usbhid->outlock, flags); if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) { spin_unlock_irqrestore(&usbhid->outlock, flags); warn("output queue full"); return; } usbhid->out[usbhid->outhead] = report; usbhid->outhead = head; if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) if (hid_submit_out(hid)) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->outlock, flags); return; } spin_lock_irqsave(&usbhid->ctrllock, flags); if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) { spin_unlock_irqrestore(&usbhid->ctrllock, flags); warn("control queue full"); return; } usbhid->ctrl[usbhid->ctrlhead].report = report; usbhid->ctrl[usbhid->ctrlhead].dir = dir; usbhid->ctrlhead = head; if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) if (hid_submit_ctrl(hid)) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->ctrllock, flags);}static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value){ struct hid_device *hid = input_get_drvdata(dev); struct hid_field *field; int offset; if (type == EV_FF) return input_ff_event(dev, type, code, value); if (type != EV_LED) return -1; if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { warn("event field not found"); return -1; } hid_set_field(field, offset, value); usbhid_submit_report(hid, field->report, USB_DIR_OUT); return 0;}int usbhid_wait_io(struct hid_device *hid){ struct usbhid_device *usbhid = hid->driver_data; if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), 10*HZ)) { dbg_hid("timeout waiting for ctrl or out queue to clear\n"); return -1; } return 0;}static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report, ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);}static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, unsigned char type, void *buf, int size){ int result, retries = 4; memset(buf, 0, size); do { result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, (type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT); retries--; } while (result < size && retries); return result;}int usbhid_open(struct hid_device *hid){ struct usbhid_device *usbhid = hid->driver_data; int res; if (!hid->open++) { res = usb_autopm_get_interface(usbhid->intf); if (res < 0) { hid->open--; return -EIO; } } if (hid_start_in(hid)) hid_io_error(hid); return 0;}void usbhid_close(struct hid_device *hid){ struct usbhid_device *usbhid = hid->driver_data; if (!--hid->open) { usb_kill_urb(usbhid->urbin); usb_autopm_put_interface(usbhid->intf); }}/* * Initialize all reports */void usbhid_init_reports(struct hid_device *hid){ struct hid_report *report; struct usbhid_device *usbhid = hid->driver_data; int err, ret; list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) usbhid_submit_report(hid, report, USB_DIR_IN); list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) usbhid_submit_report(hid, report, USB_DIR_IN); err = 0; ret = usbhid_wait_io(hid); while (ret) { err |= ret; if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) usb_kill_urb(usbhid->urbctrl); if (test_bit(HID_OUT_RUNNING, &usbhid->iofl)) usb_kill_urb(usbhid->urbout); ret = usbhid_wait_io(hid); } if (err) warn("timeout initializing reports");}/* * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01). */static int hid_find_field_early(struct hid_device *hid, unsigned int page, unsigned int hid_code, struct hid_field **pfield){ struct hid_report *report; struct hid_field *field; struct hid_usage *usage; int i, j; list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) { for (i = 0; i < report->maxfield; i++) { field = report->field[i]; for (j = 0; j < field->maxusage; j++) { usage = &field->usage[j]; if ((usage->hid & HID_USAGE_PAGE) == page && (usage->hid & 0xFFFF) == hid_code) { *pfield = field; return j; } } } } return -1;}static void usbhid_set_leds(struct hid_device *hid){ struct hid_field *field; int offset; if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) { hid_set_field(field, offset, 0); usbhid_submit_report(hid, field->report, USB_DIR_OUT); }}/* * Traverse the supplied list of reports and find the longest */static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max){ struct hid_report *report; int size; list_for_each_entry(report, &hid->report_enum[type].report_list, list) { size = ((report->size - 1) >> 3) + 1; if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered) size++; if (*max < size) *max = size; }}static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid){ struct usbhid_device *usbhid = hid->driver_data; if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma))) return -1; if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma))) return -1; if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma))) return -1; if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma))) return -1; return 0;}static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count){ struct usbhid_device *usbhid = hid->driver_data; struct usb_device *dev = hid_to_usb_dev(hid); struct usb_interface *intf = usbhid->intf; struct usb_host_interface *interface = intf->cur_altsetting; int ret; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_REPORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf), interface->desc.bInterfaceNumber, buf + 1, count - 1, USB_CTRL_SET_TIMEOUT); /* count also the report id */ if (ret > 0) ret++; return ret;}static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid){ struct usbhid_device *usbhid = hid->driver_data; usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma); usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma); usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma); usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);}/* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller * to "operational". Without this, the ps3 controller will not report any * events. */static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum){ int result; char *buf = kmalloc(18, GFP_KERNEL); if (!buf) return; result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), HID_REQ_GET_REPORT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, (3 << 8) | 0xf2, ifnum, buf, 17, USB_CTRL_GET_TIMEOUT); if (result < 0) err_hid("%s failed: %d\n", __func__, result); kfree(buf);}static struct hid_device *usb_hid_configure(struct usb_interface *intf){ struct usb_host_interface *interface = intf->cur_altsetting; struct usb_device *dev = interface_to_usbdev (intf); struct hid_descriptor *hdesc; struct hid_device *hid; u32 quirks = 0; unsigned rsize = 0; char *rdesc; int n, len, insize = 0; struct usbhid_device *usbhid; quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); /* Many keyboards and mice don't like to be polled for reports, * so we will always set the HID_QUIRK_NOGET flag for them. */ if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD || interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) quirks |= HID_QUIRK_NOGET; } if (quirks & HID_QUIRK_IGNORE) return NULL; if ((quirks & HID_QUIRK_IGNORE_MOUSE) && (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)) return NULL; if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && (!interface->desc.bNumEndpoints || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { dbg_hid("class descriptor not present\n"); return NULL; } for (n = 0; n < hdesc->bNumDescriptors; n++) if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT) rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { dbg_hid("weird size of report descriptor (%u)\n", rsize); return NULL; } if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) { dbg_hid("couldn't allocate rdesc memory\n"); return NULL; } hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0); if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { dbg_hid("reading report descriptor failed\n"); kfree(rdesc); return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -