Commit ecdc0a59 authored by Franck Bui-Huu's avatar Franck Bui-Huu Committed by Greg Kroah-Hartman

USB: usbcore get rid of the timer in usb_start_wait_urb()

This patch uses completion timeout instead of a timer to implement
a timeout when submitting an URB in usb_start_wait_urb().

It also fixes a small issue. With the previous code, if no timeout
happened and the URB's status was set to ECONNRESET value, the code
assumed wrongly that a timeout had occured.
Signed-off-by: default avatarFranck Bui-Huu <vagabon.xyz@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 014aa2a3
...@@ -23,59 +23,44 @@ static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) ...@@ -23,59 +23,44 @@ static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
} }
static void timeout_kill(unsigned long data) /*
{ * Starts urb and waits for completion or timeout. Note that this call
struct urb *urb = (struct urb *) data; * is NOT interruptible. Many device driver i/o requests should be
* interruptible and therefore these drivers should implement their
usb_unlink_urb(urb); * own interruptible routines.
} */
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
// Starts urb and waits for completion or timeout
// note that this call is NOT interruptible, while
// many device driver i/o requests should be interruptible
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{ {
struct completion done; struct completion done;
struct timer_list timer; unsigned long expire;
int status; int status;
init_completion(&done); init_completion(&done);
urb->context = &done; urb->context = &done;
urb->actual_length = 0; urb->actual_length = 0;
status = usb_submit_urb(urb, GFP_NOIO); status = usb_submit_urb(urb, GFP_NOIO);
if (unlikely(status))
if (status == 0) { goto out;
if (timeout > 0) {
init_timer(&timer); expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
timer.expires = jiffies + msecs_to_jiffies(timeout); if (!wait_for_completion_timeout(&done, expire)) {
timer.data = (unsigned long)urb;
timer.function = timeout_kill; dev_dbg(&urb->dev->dev,
/* grr. timeout _should_ include submit delays. */ "%s timed out on ep%d%s len=%d/%d\n",
add_timer(&timer); current->comm,
} usb_pipeendpoint(urb->pipe),
wait_for_completion(&done); usb_pipein(urb->pipe) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
usb_kill_urb(urb);
status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
} else
status = urb->status; status = urb->status;
/* note: HCDs return ETIMEDOUT for other reasons too */ out:
if (status == -ECONNRESET) {
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length
);
if (urb->actual_length > 0)
status = 0;
else
status = -ETIMEDOUT;
}
if (timeout > 0)
del_timer_sync(&timer);
}
if (actual_length) if (actual_length)
*actual_length = urb->actual_length; *actual_length = urb->actual_length;
usb_free_urb(urb); usb_free_urb(urb);
return status; return status;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment