aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/message.c73
1 files changed, 29 insertions, 44 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 4cc8d3e67db..49cfd7928a1 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
26static 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 32static 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
36static 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 */ 60out:
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}