Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb231054 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

USB: add urb->unlinked field



This patch (as970) adds a new urb->unlinked field, which is used to
store the status of unlinked URBs since we can't use urb->status for
that purpose any more.  To help simplify the HCDs, usbcore will check
urb->unlinked before calling the completion handler; if the value is
set it will automatically override the status reported by the HCD.

Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
CC: David Brownell <david-b@pacbell.net>
CC: Olav Kongas <ok@artecdesign.ee>
CC: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
CC: Tony Olech <tony.olech@elandigitalsystems.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b0d9efba
Loading
Loading
Loading
Loading
+12 −7
Original line number Original line Diff line number Diff line
@@ -532,7 +532,6 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)


	/* any errors get returned through the urb completion */
	/* any errors get returned through the urb completion */
	spin_lock_irq(&hcd_root_hub_lock);
	spin_lock_irq(&hcd_root_hub_lock);
	if (urb->status == -EINPROGRESS)
	urb->status = status;
	urb->status = status;
	usb_hcd_unlink_urb_from_ep(hcd, urb);
	usb_hcd_unlink_urb_from_ep(hcd, urb);


@@ -1024,6 +1023,7 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
	switch (hcd->state) {
	switch (hcd->state) {
	case HC_STATE_RUNNING:
	case HC_STATE_RUNNING:
	case HC_STATE_RESUMING:
	case HC_STATE_RESUMING:
		urb->unlinked = 0;
		list_add_tail(&urb->urb_list, &urb->ep->urb_list);
		list_add_tail(&urb->urb_list, &urb->ep->urb_list);
		break;
		break;
	default:
	default:
@@ -1071,9 +1071,9 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
	/* Any status except -EINPROGRESS means something already started to
	/* Any status except -EINPROGRESS means something already started to
	 * unlink this URB from the hardware.  So there's no more work to do.
	 * unlink this URB from the hardware.  So there's no more work to do.
	 */
	 */
	if (urb->status != -EINPROGRESS)
	if (urb->unlinked)
		return -EBUSY;
		return -EBUSY;
	urb->status = status;
	urb->unlinked = status;


	/* IRQ setup can easily be broken so that USB controllers
	/* IRQ setup can easily be broken so that USB controllers
	 * never get completion IRQs ... maybe even the ones we need to
	 * never get completion IRQs ... maybe even the ones we need to
@@ -1259,6 +1259,10 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
 * (and is done using urb->hcpriv).  It also released all HCD locks;
 * (and is done using urb->hcpriv).  It also released all HCD locks;
 * the device driver won't cause problems if it frees, modifies,
 * the device driver won't cause problems if it frees, modifies,
 * or resubmits this URB.
 * or resubmits this URB.
 *
 * If @urb was unlinked, the value of @urb->status will be overridden by
 * @urb->unlinked.  Erroneous short transfers are detected in case
 * the HCD hasn't checked for them.
 */
 */
void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
{
{
@@ -1266,7 +1270,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
	usbmon_urb_complete (&hcd->self, urb);
	usbmon_urb_complete (&hcd->self, urb);
	usb_unanchor_urb(urb);
	usb_unanchor_urb(urb);
	urb->hcpriv = NULL;
	urb->hcpriv = NULL;
	if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
	if (unlikely(urb->unlinked))
		urb->status = urb->unlinked;
	else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
			urb->actual_length < urb->transfer_buffer_length &&
			urb->actual_length < urb->transfer_buffer_length &&
			!urb->status))
			!urb->status))
		urb->status = -EREMOTEIO;
		urb->status = -EREMOTEIO;
@@ -1305,8 +1311,7 @@ void usb_hcd_endpoint_disable (struct usb_device *udev,
	list_for_each_entry (urb, &ep->urb_list, urb_list) {
	list_for_each_entry (urb, &ep->urb_list, urb_list) {
		int	is_in;
		int	is_in;


		/* the urb may already have been unlinked */
		if (urb->unlinked)
		if (urb->status != -EINPROGRESS)
			continue;
			continue;
		usb_get_urb (urb);
		usb_get_urb (urb);
		is_in = usb_urb_dir_in(urb);
		is_in = usb_urb_dir_in(urb);
+3 −5
Original line number Original line Diff line number Diff line
@@ -1029,7 +1029,6 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
static void maybe_set_status (struct urb *urb, int status)
static void maybe_set_status (struct urb *urb, int status)
{
{
	spin_lock (&urb->lock);
	spin_lock (&urb->lock);
	if (urb->status == -EINPROGRESS)
	urb->status = status;
	urb->status = status;
	spin_unlock (&urb->lock);
	spin_unlock (&urb->lock);
}
}
@@ -1257,10 +1256,9 @@ static void dummy_timer (unsigned long _dum)
		int			type;
		int			type;


		urb = urbp->urb;
		urb = urbp->urb;
		if (urb->status != -EINPROGRESS) {
		if (urb->unlinked)
			/* likely it was just unlinked */
			goto return_urb;
			goto return_urb;
		} else if (dum->rh_state != DUMMY_RH_RUNNING)
		else if (dum->rh_state != DUMMY_RH_RUNNING)
			continue;
			continue;
		type = usb_pipetype (urb->pipe);
		type = usb_pipetype (urb->pipe);


+12 −17
Original line number Original line Diff line number Diff line
@@ -151,7 +151,7 @@ static void qtd_copy_status (
		urb->actual_length += length - QTD_LENGTH (token);
		urb->actual_length += length - QTD_LENGTH (token);


	/* don't modify error codes */
	/* don't modify error codes */
	if (unlikely (urb->status != -EINPROGRESS))
	if (unlikely(urb->unlinked))
		return;
		return;


	/* force cleanup after short read; not always an error */
	/* force cleanup after short read; not always an error */
@@ -232,21 +232,14 @@ __acquires(ehci->lock)
	}
	}


	spin_lock (&urb->lock);
	spin_lock (&urb->lock);
	switch (urb->status) {
	if (unlikely(urb->unlinked)) {
	case -EINPROGRESS:		/* success */
		COUNT(ehci->stats.unlink);
		urb->status = 0;
	} else {
	default:			/* fault */
		if (likely(urb->status == -EINPROGRESS ||
		COUNT (ehci->stats.complete);
				(urb->status == -EREMOTEIO &&
		break;
				 !(urb->transfer_flags & URB_SHORT_NOT_OK))))
	case -EREMOTEIO:		/* fault or normal */
		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
			urb->status = 0;
			urb->status = 0;
		COUNT(ehci->stats.complete);
		COUNT(ehci->stats.complete);
		break;
	case -ECONNRESET:		/* canceled */
	case -ENOENT:
		COUNT (ehci->stats.unlink);
		break;
	}
	}
	spin_unlock (&urb->lock);
	spin_unlock (&urb->lock);


@@ -364,7 +357,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
			 * for the urb faulted (including short read) or
			 * for the urb faulted (including short read) or
			 * its urb was canceled.  we may patch qh or qtds.
			 * its urb was canceled.  we may patch qh or qtds.
			 */
			 */
			if (likely (urb->status == -EINPROGRESS))
			if (likely(urb->status == -EINPROGRESS &&
					!urb->unlinked))
				continue;
				continue;


			/* issue status after short control reads */
			/* issue status after short control reads */
@@ -395,7 +389,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
		spin_lock (&urb->lock);
		spin_lock (&urb->lock);
		qtd_copy_status (ehci, urb, qtd->length, token);
		qtd_copy_status (ehci, urb, qtd->length, token);
		if (unlikely(urb->status == -EREMOTEIO)) {
		if (unlikely(urb->status == -EREMOTEIO)) {
			do_status = usb_pipecontrol(urb->pipe);
			do_status = (!urb->unlinked &&
					usb_pipecontrol(urb->pipe));
			urb->status = 0;
			urb->status = 0;
		}
		}
		spin_unlock (&urb->lock);
		spin_unlock (&urb->lock);
+2 −3
Original line number Original line Diff line number Diff line
@@ -455,11 +455,10 @@ static void postproc_atl_queue(struct isp116x *isp116x)
 done:
 done:
		if (status != -EINPROGRESS) {
		if (status != -EINPROGRESS) {
			spin_lock(&urb->lock);
			spin_lock(&urb->lock);
			if (urb->status == -EINPROGRESS)
			urb->status = status;
			urb->status = status;
			spin_unlock(&urb->lock);
			spin_unlock(&urb->lock);
		}
		}
		if (urb->status != -EINPROGRESS)
		if (urb->status != -EINPROGRESS || urb->unlinked)
			finish_request(isp116x, ep, urb);
			finish_request(isp116x, ep, urb);
	}
	}
}
}
+2 −3
Original line number Original line Diff line number Diff line
@@ -758,7 +758,6 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
			cc = TD_CC_NOERROR;
			cc = TD_CC_NOERROR;
		if (cc != TD_CC_NOERROR && cc < 0x0E) {
		if (cc != TD_CC_NOERROR && cc < 0x0E) {
			spin_lock (&urb->lock);
			spin_lock (&urb->lock);
			if (urb->status == -EINPROGRESS)
			urb->status = cc_to_error[cc];
			urb->status = cc_to_error[cc];
			spin_unlock (&urb->lock);
			spin_unlock (&urb->lock);
		}
		}
@@ -972,7 +971,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick)
			urb = td->urb;
			urb = td->urb;
			urb_priv = td->urb->hcpriv;
			urb_priv = td->urb->hcpriv;


			if (urb->status == -EINPROGRESS) {
			if (!urb->unlinked) {
				prev = &td->hwNextTD;
				prev = &td->hwNextTD;
				continue;
				continue;
			}
			}
Loading