diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 65 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbmouse.c | 7 |
2 files changed, 61 insertions, 11 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index df3789f5d9a..482f936fc29 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -211,7 +211,7 @@ static int usbhid_restart_out_queue(struct usbhid_device *usbhid) return 0; if ((kicked = (usbhid->outhead != usbhid->outtail))) { - dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); + hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); r = usb_autopm_get_interface_async(usbhid->intf); if (r < 0) @@ -238,7 +238,7 @@ static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid) return 0; if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) { - dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); + hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); r = usb_autopm_get_interface_async(usbhid->intf); if (r < 0) @@ -407,6 +407,16 @@ static int hid_submit_ctrl(struct hid_device *hid) * Output interrupt completion handler. */ +static int irq_out_pump_restart(struct hid_device *hid) +{ + struct usbhid_device *usbhid = hid->driver_data; + + if (usbhid->outhead != usbhid->outtail) + return hid_submit_out(hid); + else + return -1; +} + static void hid_irq_out(struct urb *urb) { struct hid_device *hid = urb->context; @@ -436,7 +446,7 @@ static void hid_irq_out(struct urb *urb) else usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); - if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) { + if (!irq_out_pump_restart(hid)) { /* Successfully submitted next urb in queue */ spin_unlock_irqrestore(&usbhid->lock, flags); return; @@ -451,6 +461,15 @@ static void hid_irq_out(struct urb *urb) /* * Control pipe completion handler. */ +static int ctrl_pump_restart(struct hid_device *hid) +{ + struct usbhid_device *usbhid = hid->driver_data; + + if (usbhid->ctrlhead != usbhid->ctrltail) + return hid_submit_ctrl(hid); + else + return -1; +} static void hid_ctrl(struct urb *urb) { @@ -484,7 +503,7 @@ static void hid_ctrl(struct urb *urb) else usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) { + if (!ctrl_pump_restart(hid)) { /* Successfully submitted next urb in queue */ spin_unlock(&usbhid->lock); return; @@ -543,11 +562,27 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re * 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 + * no race because the URB is blocked under * spinlock */ - if (time_after(jiffies, usbhid->last_out + HZ * 5)) + if (time_after(jiffies, usbhid->last_out + HZ * 5)) { + usb_block_urb(usbhid->urbout); + /* drop lock to not deadlock if the callback is called */ + spin_unlock(&usbhid->lock); usb_unlink_urb(usbhid->urbout); + spin_lock(&usbhid->lock); + usb_unblock_urb(usbhid->urbout); + /* + * if the unlinking has already completed + * the pump will have been stopped + * it must be restarted now + */ + if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) + if (!irq_out_pump_restart(hid)) + set_bit(HID_OUT_RUNNING, &usbhid->iofl); + + + } } return; } @@ -591,11 +626,25 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re * 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 + * no race because the URB is blocked under * spinlock */ - if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) + if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) { + usb_block_urb(usbhid->urbctrl); + /* drop lock to not deadlock if the callback is called */ + spin_unlock(&usbhid->lock); usb_unlink_urb(usbhid->urbctrl); + spin_lock(&usbhid->lock); + usb_unblock_urb(usbhid->urbctrl); + /* + * if the unlinking has already completed + * the pump will have been stopped + * it must be restarted now + */ + if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + if (!ctrl_pump_restart(hid)) + set_bit(HID_CTRL_RUNNING, &usbhid->iofl); + } } } diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c index 0f6be45d43d..bf16d72dc37 100644 --- a/drivers/hid/usbhid/usbmouse.c +++ b/drivers/hid/usbhid/usbmouse.c @@ -92,9 +92,10 @@ static void usb_mouse_irq(struct urb *urb) resubmit: status = usb_submit_urb (urb, GFP_ATOMIC); if (status) - err ("can't resubmit intr, %s-%s/input0, status %d", - mouse->usbdev->bus->bus_name, - mouse->usbdev->devpath, status); + dev_err(&mouse->usbdev->dev, + "can't resubmit intr, %s-%s/input0, status %d\n", + mouse->usbdev->bus->bus_name, + mouse->usbdev->devpath, status); } static int usb_mouse_open(struct input_dev *dev) |