diff options
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 49 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 3 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbhid.h | 2 |
3 files changed, 40 insertions, 14 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 03bd703255a3..e9add5b3481d 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -318,6 +318,7 @@ static int hid_submit_out(struct hid_device *hid) err_hid("usb_submit_urb(out) failed"); return -1; } + usbhid->last_out = jiffies; } else { /* * queue work to wake up the device. @@ -379,6 +380,7 @@ static int hid_submit_ctrl(struct hid_device *hid) err_hid("usb_submit_urb(ctrl) failed"); return -1; } + usbhid->last_ctrl = jiffies; } else { /* * queue work to wake up the device. @@ -514,9 +516,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re usbhid->out[usbhid->outhead].report = report; usbhid->outhead = head; - if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) + if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) { if (hid_submit_out(hid)) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); + } else { + /* + * the queue is known to run + * but an earlier request may be stuck + * we may need to time out + * no race because this is called under + * spinlock + */ + if (time_after(jiffies, usbhid->last_out + HZ * 5)) + usb_unlink_urb(usbhid->urbout); + } return; } @@ -537,9 +550,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re usbhid->ctrl[usbhid->ctrlhead].dir = dir; usbhid->ctrlhead = head; - if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) { if (hid_submit_ctrl(hid)) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); + } else { + /* + * the queue is known to run + * but an earlier request may be stuck + * we may need to time out + * no race because this is called under + * spinlock + */ + if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) + usb_unlink_urb(usbhid->urbctrl); + } } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) @@ -976,16 +1000,6 @@ static int usbhid_start(struct hid_device *hid) } } - init_waitqueue_head(&usbhid->wait); - INIT_WORK(&usbhid->reset_work, hid_reset); - INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues); - setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); - - spin_lock_init(&usbhid->lock); - - usbhid->intf = intf; - usbhid->ifnum = interface->desc.bInterfaceNumber; - usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); if (!usbhid->urbctrl) { ret = -ENOMEM; @@ -998,7 +1012,8 @@ static int usbhid_start(struct hid_device *hid) usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); - usbhid_init_reports(hid); + if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS)) + usbhid_init_reports(hid); set_bit(HID_STARTED, &usbhid->iofl); @@ -1155,6 +1170,14 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * hid->driver_data = usbhid; usbhid->hid = hid; + usbhid->intf = intf; + usbhid->ifnum = interface->desc.bInterfaceNumber; + + init_waitqueue_head(&usbhid->wait); + INIT_WORK(&usbhid->reset_work, hid_reset); + INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues); + setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); + spin_lock_init(&usbhid->lock); ret = hid_add_device(hid); if (ret) { diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0d9045aa2c4b..64c5dee27106 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -37,6 +37,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_NEXTWINDOW, USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN, HID_QUIRK_MULTI_INPUT}, { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, @@ -280,7 +281,7 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) if (idVendor == USB_VENDOR_ID_NCR && idProduct >= USB_DEVICE_ID_NCR_FIRST && idProduct <= USB_DEVICE_ID_NCR_LAST) - return HID_QUIRK_NOGET; + return HID_QUIRK_NO_INIT_REPORTS; down_read(&dquirks_rwsem); bl_entry = usbhid_exists_dquirk(idVendor, idProduct); diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 08f505ca2e3d..ec20400c7f29 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -80,12 +80,14 @@ struct usbhid_device { unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ char *ctrlbuf; /* Control buffer */ dma_addr_t ctrlbuf_dma; /* Control buffer dma */ + unsigned long last_ctrl; /* record of last output for timeouts */ struct urb *urbout; /* Output URB */ struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ unsigned char outhead, outtail; /* Output pipe fifo head & tail */ char *outbuf; /* Output buffer */ dma_addr_t outbuf_dma; /* Output buffer dma */ + unsigned long last_out; /* record of last output for timeouts */ spinlock_t lock; /* fifo spinlock */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ |