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: Alan 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: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 22a098b..ec17fc4 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -532,8 +532,7 @@
 
 	/* any errors get returned through the urb completion */
 	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);
 
 	/* This peculiar use of spinlocks echoes what real HC drivers do.
@@ -1024,6 +1023,7 @@
 	switch (hcd->state) {
 	case HC_STATE_RUNNING:
 	case HC_STATE_RESUMING:
+		urb->unlinked = 0;
 		list_add_tail(&urb->urb_list, &urb->ep->urb_list);
 		break;
 	default:
@@ -1071,9 +1071,9 @@
 	/* Any status except -EINPROGRESS means something already started to
 	 * unlink this URB from the hardware.  So there's no more work to do.
 	 */
-	if (urb->status != -EINPROGRESS)
+	if (urb->unlinked)
 		return -EBUSY;
-	urb->status = status;
+	urb->unlinked = status;
 
 	/* IRQ setup can easily be broken so that USB controllers
 	 * never get completion IRQs ... maybe even the ones we need to
@@ -1259,6 +1259,10 @@
  * (and is done using urb->hcpriv).  It also released all HCD locks;
  * the device driver won't cause problems if it frees, modifies,
  * 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)
 {
@@ -1266,7 +1270,9 @@
 	usbmon_urb_complete (&hcd->self, urb);
 	usb_unanchor_urb(urb);
 	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->status))
 		urb->status = -EREMOTEIO;
@@ -1305,8 +1311,7 @@
 	list_for_each_entry (urb, &ep->urb_list, urb_list) {
 		int	is_in;
 
-		/* the urb may already have been unlinked */
-		if (urb->status != -EINPROGRESS)
+		if (urb->unlinked)
 			continue;
 		usb_get_urb (urb);
 		is_in = usb_urb_dir_in(urb);