?? hid-core.c
字號:
} return 0;}static int hid_submit_ctrl(struct hid_device *hid){ struct hid_report *report; unsigned char dir; report = hid->ctrl[hid->ctrltail].report; dir = hid->ctrl[hid->ctrltail].dir; if (dir == USB_DIR_OUT) hid_output_report(report, hid->ctrlbuf); hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + ((report->id > 0) && (dir != USB_DIR_OUT)); hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0); hid->urbctrl->dev = hid->dev; hid->cr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; hid->cr.bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; hid->cr.wValue = ((report->type + 1) << 8) | report->id; hid->cr.wIndex = cpu_to_le16(hid->ifnum); hid->cr.wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length); dbg("submitting ctrl urb"); if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) { err("usb_submit_urb(ctrl) failed"); return -1; } return 0;}/* * Output interrupt completion handler. */static void hid_irq_out(struct urb *urb){ struct hid_device *hid = urb->context; unsigned long flags; if (urb->status) warn("output irq status %d received", urb->status); spin_lock_irqsave(&hid->outlock, flags); hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); if (hid->outhead != hid->outtail) { hid_submit_out(hid); spin_unlock_irqrestore(&hid->outlock, flags); return; } clear_bit(HID_OUT_RUNNING, &hid->iofl); spin_unlock_irqrestore(&hid->outlock, flags); wake_up(&hid->wait);}/* * Control pipe completion handler. */static void hid_ctrl(struct urb *urb){ struct hid_device *hid = urb->context; unsigned long flags; if (urb->status) warn("ctrl urb status %d received", urb->status); spin_lock_irqsave(&hid->ctrllock, flags); if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb); hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->ctrlhead != hid->ctrltail) { hid_submit_ctrl(hid); spin_unlock_irqrestore(&hid->ctrllock, flags); return; } clear_bit(HID_CTRL_RUNNING, &hid->iofl); spin_unlock_irqrestore(&hid->ctrllock, flags); wake_up(&hid->wait);}void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir){ int head; unsigned long flags; if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) return; if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { spin_lock_irqsave(&hid->outlock, flags); if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) { spin_unlock_irqrestore(&hid->outlock, flags); warn("output queue full"); return; } hid->out[hid->outhead] = report; hid->outhead = head; if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) hid_submit_out(hid); spin_unlock_irqrestore(&hid->outlock, flags); return; } spin_lock_irqsave(&hid->ctrllock, flags); if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) { spin_unlock_irqrestore(&hid->ctrllock, flags); warn("control queue full"); return; } hid->ctrl[hid->ctrlhead].report = report; hid->ctrl[hid->ctrlhead].dir = dir; hid->ctrlhead = head; if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) hid_submit_ctrl(hid); spin_unlock_irqrestore(&hid->ctrllock, flags);}int hid_wait_io(struct hid_device *hid){ DECLARE_WAITQUEUE(wait, current); int timeout = 10*HZ; set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&hid->wait, &wait); while (timeout && test_bit(HID_CTRL_RUNNING, &hid->iofl) && test_bit(HID_OUT_RUNNING, &hid->iofl)) timeout = schedule_timeout(timeout); set_current_state(TASK_RUNNING); remove_wait_queue(&hid->wait, &wait); if (!timeout) { dbg("timeout waiting for ctrl or out queue to clear"); return -1; } return 0;}static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, unsigned char type, void *buf, int size){ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, (type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT);}int hid_open(struct hid_device *hid){ if (hid->open++) return 0; hid->urbin->dev = hid->dev; if (usb_submit_urb(hid->urbin, GFP_KERNEL)) return -EIO; return 0;}void hid_close(struct hid_device *hid){ if (!--hid->open) usb_unlink_urb(hid->urbin);}/* * Initialize all reports */void hid_init_reports(struct hid_device *hid){ struct hid_report_enum *report_enum; struct hid_report *report; struct list_head *list; int len; report_enum = hid->report_enum + HID_INPUT_REPORT; list = report_enum->report_list.next; while (list != &report_enum->report_list) { report = (struct hid_report *) list; hid_submit_report(hid, report, USB_DIR_IN); list = list->next; } report_enum = hid->report_enum + HID_FEATURE_REPORT; list = report_enum->report_list.next; while (list != &report_enum->report_list) { report = (struct hid_report *) list; hid_submit_report(hid, report, USB_DIR_IN); list = list->next; } if (hid_wait_io(hid)) { warn("timeout initializing reports\n"); return; } report_enum = hid->report_enum + HID_INPUT_REPORT; list = report_enum->report_list.next; while (list != &report_enum->report_list) { report = (struct hid_report *) list; len = ((report->size - 1) >> 3) + 1 + report_enum->numbered; if (len > hid->urbin->transfer_buffer_length) hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE; usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id, hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); list = list->next; }}#define USB_VENDOR_ID_WACOM 0x056a#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010#define USB_DEVICE_ID_WACOM_INTUOS 0x0020#define USB_VENDOR_ID_GRIFFIN 0x077d#define USB_DEVICE_ID_POWERMATE 0x0410#define USB_DEVICE_ID_SOUNDKNOB 0x04AA#define USB_VENDOR_ID_ATEN 0x0557 #define USB_DEVICE_ID_ATEN_UC100KM 0x2004#define USB_DEVICE_ID_ATEN_CS124U 0x2202#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204struct hid_blacklist { __u16 idVendor; __u16 idProduct; unsigned quirks;} hid_blacklist[] = { { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { 0, 0 }};static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum){ struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; struct hid_descriptor *hdesc; struct hid_device *hid; unsigned quirks = 0, rsize = 0; char *buf; 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)) quirks = hid_blacklist[n].quirks; if (quirks & HID_QUIRK_IGNORE) return NULL; if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && ((!interface->bNumEndpoints) || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { dbg("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("weird size of report descriptor (%u)", rsize); return NULL; } { __u8 rdesc[rsize]; if ((n = hid_get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { dbg("reading report descriptor failed"); return NULL; }#ifdef DEBUG_DATA printk(KERN_DEBUG __FILE__ ": report descriptor (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; } } hid->quirks = quirks; for (n = 0; n < interface->bNumEndpoints; n++) { struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; int pipe; if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ continue; if (endpoint->bEndpointAddress & USB_DIR_IN) { if (hid->urbin) continue; if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); FILL_INT_URB(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval); } else { if (hid->urbout) continue; if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress); FILL_BULK_URB(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid); } } if (!hid->urbin) { err("couldn't find an input interrupt endpoint"); goto fail; } init_waitqueue_head(&hid->wait); hid->outlock = SPIN_LOCK_UNLOCKED; hid->ctrllock = SPIN_LOCK_UNLOCKED; hid->version = hdesc->bcdHID; hid->country = hdesc->bCountryCode; hid->dev = dev; hid->ifnum = interface->bInterfaceNumber; hid->name[0] = 0; if (!(buf = kmalloc(64, GFP_KERNEL))) goto fail; if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) { strcat(hid->name, buf); if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) sprintf(hid->name, "%s %s", hid->name, buf); } else sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct); usb_make_path(dev, buf, 63); sprintf(hid->phys, "%s/input%d", buf, ifnum); if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) hid->uniq[0] = 0; kfree(buf); hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); FILL_CONTROL_URB(hid->urbctrl, dev, 0, (void*) &hid->cr, hid->ctrlbuf, 1, hid_ctrl, hid); return hid;fail: hid_free_device(hid); if (hid->urbin) usb_free_urb(hid->urbin); if (hid->urbout) usb_free_urb(hid->urbout); if (hid->urbctrl) usb_free_urb(hid->urbctrl); return NULL;}static void* hid_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ struct hid_device *hid; char path[64]; int i; char *c; dbg("HID probe called for ifnum %d", ifnum); if (!(hid = usb_hid_configure(dev, ifnum))) return NULL; hid_init_reports(hid); hid_dump_device(hid); if (!hidinput_connect(hid)) hid->claimed |= HID_CLAIMED_INPUT; if (!hiddev_connect(hid)) hid->claimed |= HID_CLAIMED_HIDDEV; if (!hid->claimed) { hid_free_device(hid); return NULL; } printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) printk("input"); if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) printk(","); if (hid->claimed & HID_CLAIMED_HIDDEV) printk("hiddev%d", hid->minor); c = "Device"; for (i = 0; i < hid->maxapplication; i++) if ((hid->application[i] & 0xffff) < ARRAY_SIZE(hid_types)) { c = hid_types[hid->application[i] & 0xffff]; break; } usb_make_path(dev, path, 63); printk(": USB HID v%x.%02x %s [%s] on %s\n", hid->version >> 8, hid->version & 0xff, c, hid->name, path); return hid;}static void hid_disconnect(struct usb_device *dev, void *ptr){ struct hid_device *hid = ptr; usb_unlink_urb(hid->urbin); usb_unlink_urb(hid->urbout); usb_unlink_urb(hid->urbctrl); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); if (hid->claimed & HID_CLAIMED_HIDDEV) hiddev_disconnect(hid); usb_free_urb(hid->urbin); usb_free_urb(hid->urbctrl); if (hid->urbout) usb_free_urb(hid->urbout); 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){ hiddev_init(); usb_register(&hid_driver); info(DRIVER_VERSION ":" DRIVER_DESC); return 0;}static void __exit hid_exit(void){ hiddev_exit(); usb_deregister(&hid_driver);}module_init(hid_init);module_exit(hid_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE(DRIVER_LICENSE);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -