> For the urb to complete. The schedule_timeout() returned without > that completion. We only forced the completion path to start, with > the unlink; if it wasn't already starting (maybe on another CPU).
So you are doing the conventional wait stuff only to implement the timeout, aren't you? This seems kind of convoluted to me. May I suggest doing the timeout explicitely like this: diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Sat Aug 9 10:15:31 2003 +++ b/drivers/usb/core/message.c Sat Aug 9 10:15:31 2003 @@ -16,77 +16,71 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/mm.h> +#include <linux/timer.h> #include <asm/byteorder.h> #include "hcd.h" /* for usbcore internals */ #include "usb.h" struct usb_api_data { - wait_queue_head_t wqh; - int done; + struct completion cpl; + int timeout; }; static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) { - struct usb_api_data *awd = (struct usb_api_data *)urb->context; + struct usb_api_data *ct = (struct usb_api_data *)urb->context; + + ct->timeout = (urb->status == -ECONNRESET); + complete(&ct->cpl); +} + - awd->done = 1; - wmb(); - wake_up(&awd->wqh); +static void timeout_kill (unsigned long d) +{ + struct urb *u = (struct urb *)d; + + usb_unlink_urb(u); } // Starts urb and waits for completion or timeout static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) { - DECLARE_WAITQUEUE(wait, current); struct usb_api_data awd; + struct timer_list timeout_killer; int status; - init_waitqueue_head(&awd.wqh); - awd.done = 0; - - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&awd.wqh, &wait); + init_completion(&awd.cpl); urb->context = &awd; - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - // something went wrong - usb_free_urb(urb); - set_current_state(TASK_RUNNING); - remove_wait_queue(&awd.wqh, &wait); - return status; - } + urb->transfer_flags |= URB_ASYNC_UNLINK; + status = usb_submit_urb(urb, GFP_NOIO); + if (status) + goto out_err; + + init_timer(&timeout_killer); + timeout_killer.expires = jiffies + (timeout ? timeout : MAX_SCHEDULE_TIMEOUT); + timeout_killer.data = (unsigned long)urb; + timeout_killer.function = timeout_kill; + add_timer(&timeout_killer); - while (timeout && !awd.done) - { - timeout = schedule_timeout(timeout); - set_current_state(TASK_UNINTERRUPTIBLE); - rmb(); - } + wait_for_completion(&awd.cpl); - set_current_state(TASK_RUNNING); - remove_wait_queue(&awd.wqh, &wait); + del_timer_sync(&timeout_killer); - if (!timeout && !awd.done) { - if (urb->status != -EINPROGRESS) { /* No callback?!! */ - printk(KERN_ERR "usb: raced timeout, " - "pipe 0x%x status %d time left %d\n", - urb->pipe, urb->status, timeout); - status = urb->status; - } else { - warn("usb_control/bulk_msg: timeout"); - usb_unlink_urb(urb); // remove urb safely - status = -ETIMEDOUT; - } - } else + if (!awd.timeout) { status = urb->status; + } else { + warn("usb_control/bulk_msg: timeout"); + status = -ETIMEDOUT; + } if (actual_length) *actual_length = urb->actual_length; +out_err: usb_free_urb(urb); - return status; + return status; } /*-------------------------------------------------------------------*/ ------------------------------------------------------- This SF.Net email sponsored by: Free pre-built ASP.NET sites including Data Reports, E-commerce, Portals, and Forums are available now. Download today and enter to win an XBOX or Visual Studio .NET. http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel