Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=67f5dde3d4961032aeeecaf0d1c7a9232bef3f44
Commit:     67f5dde3d4961032aeeecaf0d1c7a9232bef3f44
Parent:     a12b8db02035673153bbf19bb3641a08bed9e4b8
Author:     Alan Stern <[EMAIL PROTECTED]>
AuthorDate: Tue Jul 24 18:23:23 2007 -0400
Committer:  Greg Kroah-Hartman <[EMAIL PROTECTED]>
CommitDate: Mon Jul 30 13:27:45 2007 -0700

    USB: Fix a bug in usb_start_wait_urb
    
    This patch (as941) fixes a bug recently added to the USB synchronous
    API.  The status of a completed URB must be preserved separately
    across a completion callback.  Also, the actual_length value isn't
    available until after the URB has fully completed.
    
    Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
    Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
---
 drivers/usb/core/message.c |   26 ++++++++++++++++----------
 1 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index ad4b956..b6bd05e 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -18,9 +18,17 @@
 #include "hcd.h"       /* for usbcore internals */
 #include "usb.h"
 
+struct api_context {
+       struct completion       done;
+       int                     status;
+};
+
 static void usb_api_blocking_completion(struct urb *urb)
 {
-       complete((struct completion *)urb->context);
+       struct api_context *ctx = urb->context;
+
+       ctx->status = urb->status;
+       complete(&ctx->done);
 }
 
 
@@ -32,20 +40,21 @@ static void usb_api_blocking_completion(struct urb *urb)
  */
 static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
 { 
-       struct completion done;
+       struct api_context ctx;
        unsigned long expire;
        int retval;
-       int status = urb->status;
 
-       init_completion(&done);         
-       urb->context = &done;
+       init_completion(&ctx.done);
+       urb->context = &ctx;
        urb->actual_length = 0;
        retval = usb_submit_urb(urb, GFP_NOIO);
        if (unlikely(retval))
                goto out;
 
        expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
-       if (!wait_for_completion_timeout(&done, expire)) {
+       if (!wait_for_completion_timeout(&ctx.done, expire)) {
+               usb_kill_urb(urb);
+               retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
 
                dev_dbg(&urb->dev->dev,
                        "%s timed out on ep%d%s len=%d/%d\n",
@@ -54,11 +63,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, 
int *actual_length)
                        usb_pipein(urb->pipe) ? "in" : "out",
                        urb->actual_length,
                        urb->transfer_buffer_length);
-
-               usb_kill_urb(urb);
-               retval = status == -ENOENT ? -ETIMEDOUT : status;
        } else
-               retval = status;
+               retval = ctx.status;
 out:
        if (actual_length)
                *actual_length = urb->actual_length;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to