Index: usb-devel/drivers/usb/core/message.c =================================================================== --- usb-devel.orig/drivers/usb/core/message.c +++ usb-devel/drivers/usb/core/message.c @@ -25,6 +25,8 @@ #include "usb.h" +#define MAX_UNINTERRUPTIBLE_TIMEOUT_MS 60000 + static void cancel_async_set_config(struct usb_device *udev); struct api_context { @@ -42,16 +44,16 @@ static void usb_api_blocking_completion( /* - * Starts urb and waits for completion or timeout. Note that this call - * is NOT interruptible. Many device driver i/o requests should be - * interruptible and therefore these drivers should implement their - * own interruptible routines. + * Starts urb and waits for completion or timeout. Timeout lengths <= 0 + * are taken to be as long as possible. + * The wait is NOT interruptible if the timeout period is no longer than + * MAX_UNINTERRUPTIBLE_TIMEOUT_MS, otherwise it IS interruptible. */ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) { struct api_context ctx; unsigned long expire; - int retval; + int rc, retval; init_completion(&ctx.done); urb->context = &ctx; @@ -60,8 +62,14 @@ static int usb_start_wait_urb(struct urb if (unlikely(retval)) goto out; - expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; - if (!wait_for_completion_timeout(&ctx.done, expire)) { + expire = (timeout > 0) ? msecs_to_jiffies(timeout) : + MAX_SCHEDULE_TIMEOUT; + if (expire <= msecs_to_jiffies(MAX_UNINTERRUPTIBLE_TIMEOUT_MS)) + rc = (wait_for_completion_timeout(&ctx.done, expire) > 0); + else + rc = (wait_for_completion_interruptible_timeout( + &ctx.done, expire) > 0); + if (!rc) { usb_kill_urb(urb); retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);