diff options
| author | Franck Bui-Huu <vagabon.xyz@gmail.com> | 2006-07-12 10:09:41 +0200 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-09-27 11:58:51 -0700 | 
| commit | ecdc0a590268f1926ed8534a040a390c77d20948 (patch) | |
| tree | 2815f3ad943ed71e16ce02b8e87dccfd41609a00 /drivers/usb/core/message.c | |
| 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>
Diffstat (limited to 'drivers/usb/core/message.c')
| -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 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)  } -static void timeout_kill(unsigned long data) -{ -	struct urb	*urb = (struct urb *) data; - -	usb_unlink_urb(urb); -} - -// Starts urb and waits for completion or timeout -// note that this call is NOT interruptible, while -// many device driver i/o requests should be interruptible -static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) +/* + * 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. + */ +static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)  {  -	struct completion	done; -	struct timer_list	timer; -	int			status; +	struct completion done; +	unsigned long expire; +	int status;  	init_completion(&done); 	  	urb->context = &done;  	urb->actual_length = 0;  	status = usb_submit_urb(urb, GFP_NOIO); - -	if (status == 0) { -		if (timeout > 0) { -			init_timer(&timer); -			timer.expires = jiffies + msecs_to_jiffies(timeout); -			timer.data = (unsigned long)urb; -			timer.function = timeout_kill; -			/* grr.  timeout _should_ include submit delays. */ -			add_timer(&timer); -		} -		wait_for_completion(&done); +	if (unlikely(status)) +		goto out; + +	expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; +	if (!wait_for_completion_timeout(&done, expire)) { + +		dev_dbg(&urb->dev->dev, +			"%s timed out on ep%d%s len=%d/%d\n", +			current->comm, +			usb_pipeendpoint(urb->pipe), +			usb_pipein(urb->pipe) ? "in" : "out", +			urb->actual_length, +			urb->transfer_buffer_length); + +		usb_kill_urb(urb); +		status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status; +	} else  		status = urb->status; -		/* note:  HCDs return ETIMEDOUT for other reasons too */ -		if (status == -ECONNRESET) { -			dev_dbg(&urb->dev->dev, -				"%s timed out on ep%d%s len=%d/%d\n", -				current->comm, -				usb_pipeendpoint(urb->pipe), -				usb_pipein(urb->pipe) ? "in" : "out", -				urb->actual_length, -				urb->transfer_buffer_length -				); -			if (urb->actual_length > 0) -				status = 0; -			else -				status = -ETIMEDOUT; -		} -		if (timeout > 0) -			del_timer_sync(&timer); -	} - +out:  	if (actual_length)  		*actual_length = urb->actual_length; +  	usb_free_urb(urb);  	return status;  } | 
