diff options
author | Franck Bui-Huu <vagabon.xyz@gmail.com> | 2006-07-12 04:09:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-09-27 14:58:51 -0400 |
commit | ecdc0a590268f1926ed8534a040a390c77d20948 (patch) | |
tree | 2815f3ad943ed71e16ce02b8e87dccfd41609a00 | |
parent | 014aa2a3c32ebe33f97e9d219d91d3c5c7231bf7 (diff) |
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: Franck Bui-Huu <vagabon.xyz@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/core/message.c | 73 |
1 files changed, 29 insertions, 44 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 4cc8d3e67db7..49cfd7928a1c 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -23,59 +23,44 @@ static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) | |||
23 | } | 23 | } |
24 | 24 | ||
25 | 25 | ||
26 | static void timeout_kill(unsigned long data) | 26 | /* |
27 | { | 27 | * Starts urb and waits for completion or timeout. Note that this call |
28 | struct urb *urb = (struct urb *) data; | 28 | * is NOT interruptible. Many device driver i/o requests should be |
29 | 29 | * interruptible and therefore these drivers should implement their | |
30 | usb_unlink_urb(urb); | 30 | * own interruptible routines. |
31 | } | 31 | */ |
32 | 32 | static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) | |
33 | // Starts urb and waits for completion or timeout | ||
34 | // note that this call is NOT interruptible, while | ||
35 | // many device driver i/o requests should be interruptible | ||
36 | static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) | ||
37 | { | 33 | { |
38 | struct completion done; | 34 | struct completion done; |
39 | struct timer_list timer; | 35 | unsigned long expire; |
40 | int status; | 36 | int status; |
41 | 37 | ||
42 | init_completion(&done); | 38 | init_completion(&done); |
43 | urb->context = &done; | 39 | urb->context = &done; |
44 | urb->actual_length = 0; | 40 | urb->actual_length = 0; |
45 | status = usb_submit_urb(urb, GFP_NOIO); | 41 | status = usb_submit_urb(urb, GFP_NOIO); |
46 | 42 | if (unlikely(status)) | |
47 | if (status == 0) { | 43 | goto out; |
48 | if (timeout > 0) { | 44 | |
49 | init_timer(&timer); | 45 | expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; |
50 | timer.expires = jiffies + msecs_to_jiffies(timeout); | 46 | if (!wait_for_completion_timeout(&done, expire)) { |
51 | timer.data = (unsigned long)urb; | 47 | |
52 | timer.function = timeout_kill; | 48 | dev_dbg(&urb->dev->dev, |
53 | /* grr. timeout _should_ include submit delays. */ | 49 | "%s timed out on ep%d%s len=%d/%d\n", |
54 | add_timer(&timer); | 50 | current->comm, |
55 | } | 51 | usb_pipeendpoint(urb->pipe), |
56 | wait_for_completion(&done); | 52 | usb_pipein(urb->pipe) ? "in" : "out", |
53 | urb->actual_length, | ||
54 | urb->transfer_buffer_length); | ||
55 | |||
56 | usb_kill_urb(urb); | ||
57 | status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status; | ||
58 | } else | ||
57 | status = urb->status; | 59 | status = urb->status; |
58 | /* note: HCDs return ETIMEDOUT for other reasons too */ | 60 | out: |
59 | if (status == -ECONNRESET) { | ||
60 | dev_dbg(&urb->dev->dev, | ||
61 | "%s timed out on ep%d%s len=%d/%d\n", | ||
62 | current->comm, | ||
63 | usb_pipeendpoint(urb->pipe), | ||
64 | usb_pipein(urb->pipe) ? "in" : "out", | ||
65 | urb->actual_length, | ||
66 | urb->transfer_buffer_length | ||
67 | ); | ||
68 | if (urb->actual_length > 0) | ||
69 | status = 0; | ||
70 | else | ||
71 | status = -ETIMEDOUT; | ||
72 | } | ||
73 | if (timeout > 0) | ||
74 | del_timer_sync(&timer); | ||
75 | } | ||
76 | |||
77 | if (actual_length) | 61 | if (actual_length) |
78 | *actual_length = urb->actual_length; | 62 | *actual_length = urb->actual_length; |
63 | |||
79 | usb_free_urb(urb); | 64 | usb_free_urb(urb); |
80 | return status; | 65 | return status; |
81 | } | 66 | } |