mirror of
https://github.com/torvalds/linux.git
synced 2024-10-27 23:31:45 +00:00
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:
parent
c8a8602b76
commit
858155fbcc
|
@ -316,6 +316,7 @@ static int hid_submit_out(struct hid_device *hid)
|
||||||
err_hid("usb_submit_urb(out) failed");
|
err_hid("usb_submit_urb(out) failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
usbhid->last_out = jiffies;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* queue work to wake up the device.
|
* 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");
|
err_hid("usb_submit_urb(ctrl) failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
usbhid->last_ctrl = jiffies;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* queue work to wake up the device.
|
* 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->out[usbhid->outhead].report = report;
|
||||||
usbhid->outhead = head;
|
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))
|
if (hid_submit_out(hid))
|
||||||
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
|
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;
|
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->ctrl[usbhid->ctrlhead].dir = dir;
|
||||||
usbhid->ctrlhead = head;
|
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))
|
if (hid_submit_ctrl(hid))
|
||||||
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
|
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)
|
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
|
||||||
|
|
|
@ -80,12 +80,14 @@ struct usbhid_device {
|
||||||
unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
|
unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
|
||||||
char *ctrlbuf; /* Control buffer */
|
char *ctrlbuf; /* Control buffer */
|
||||||
dma_addr_t ctrlbuf_dma; /* Control buffer dma */
|
dma_addr_t ctrlbuf_dma; /* Control buffer dma */
|
||||||
|
unsigned long last_ctrl; /* record of last output for timeouts */
|
||||||
|
|
||||||
struct urb *urbout; /* Output URB */
|
struct urb *urbout; /* Output URB */
|
||||||
struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
|
struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
|
||||||
unsigned char outhead, outtail; /* Output pipe fifo head & tail */
|
unsigned char outhead, outtail; /* Output pipe fifo head & tail */
|
||||||
char *outbuf; /* Output buffer */
|
char *outbuf; /* Output buffer */
|
||||||
dma_addr_t outbuf_dma; /* Output buffer dma */
|
dma_addr_t outbuf_dma; /* Output buffer dma */
|
||||||
|
unsigned long last_out; /* record of last output for timeouts */
|
||||||
|
|
||||||
spinlock_t lock; /* fifo spinlock */
|
spinlock_t lock; /* fifo spinlock */
|
||||||
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
|
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user