HID: usbhid: introduce timeout for stuck ctrl/out URBs

Some devices do not react to a control request (seen on APC UPS's) resulting in
a slow stream of messages, "generic-usb ... control queue full".  Therefore
request needs a timeout.

Cc: stable@kernel.org
Signed-off-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: David Fries <david@fries.net>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
Oliver Neukum 2010-02-12 13:02:28 +01:00 committed by Jiri Kosina
parent c8a8602b76
commit 858155fbcc
2 changed files with 28 additions and 2 deletions

View File

@ -316,6 +316,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.
@ -377,6 +378,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.
@ -512,9 +514,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;
}
@ -535,9 +548,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)

View File

@ -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) */