aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hcd.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-08-21 15:40:36 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:55:19 -0400
commiteb23105462304fd35571fd0cab1de7aec79a9ec5 (patch)
tree3579e74b3f1a6e68d42de01c122d206447454d4b /drivers/usb/core/hcd.c
parentb0d9efba3ec53468984aecef8eeaf079089f2e5a (diff)
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>
Diffstat (limited to 'drivers/usb/core/hcd.c')
-rw-r--r--drivers/usb/core/hcd.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 22a098b318c..ec17fc4d286 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -532,8 +532,7 @@ error:
532 532
533 /* any errors get returned through the urb completion */ 533 /* any errors get returned through the urb completion */
534 spin_lock_irq(&hcd_root_hub_lock); 534 spin_lock_irq(&hcd_root_hub_lock);
535 if (urb->status == -EINPROGRESS) 535 urb->status = status;
536 urb->status = status;
537 usb_hcd_unlink_urb_from_ep(hcd, urb); 536 usb_hcd_unlink_urb_from_ep(hcd, urb);
538 537
539 /* This peculiar use of spinlocks echoes what real HC drivers do. 538 /* This peculiar use of spinlocks echoes what real HC drivers do.
@@ -1024,6 +1023,7 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
1024 switch (hcd->state) { 1023 switch (hcd->state) {
1025 case HC_STATE_RUNNING: 1024 case HC_STATE_RUNNING:
1026 case HC_STATE_RESUMING: 1025 case HC_STATE_RESUMING:
1026 urb->unlinked = 0;
1027 list_add_tail(&urb->urb_list, &urb->ep->urb_list); 1027 list_add_tail(&urb->urb_list, &urb->ep->urb_list);
1028 break; 1028 break;
1029 default: 1029 default:
@@ -1071,9 +1071,9 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
1071 /* Any status except -EINPROGRESS means something already started to 1071 /* Any status except -EINPROGRESS means something already started to
1072 * unlink this URB from the hardware. So there's no more work to do. 1072 * unlink this URB from the hardware. So there's no more work to do.
1073 */ 1073 */
1074 if (urb->status != -EINPROGRESS) 1074 if (urb->unlinked)
1075 return -EBUSY; 1075 return -EBUSY;
1076 urb->status = status; 1076 urb->unlinked = status;
1077 1077
1078 /* IRQ setup can easily be broken so that USB controllers 1078 /* IRQ setup can easily be broken so that USB controllers
1079 * never get completion IRQs ... maybe even the ones we need to 1079 * 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)
1259 * (and is done using urb->hcpriv). It also released all HCD locks; 1259 * (and is done using urb->hcpriv). It also released all HCD locks;
1260 * the device driver won't cause problems if it frees, modifies, 1260 * the device driver won't cause problems if it frees, modifies,
1261 * or resubmits this URB. 1261 * or resubmits this URB.
1262 *
1263 * If @urb was unlinked, the value of @urb->status will be overridden by
1264 * @urb->unlinked. Erroneous short transfers are detected in case
1265 * the HCD hasn't checked for them.
1262 */ 1266 */
1263void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) 1267void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
1264{ 1268{
@@ -1266,7 +1270,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
1266 usbmon_urb_complete (&hcd->self, urb); 1270 usbmon_urb_complete (&hcd->self, urb);
1267 usb_unanchor_urb(urb); 1271 usb_unanchor_urb(urb);
1268 urb->hcpriv = NULL; 1272 urb->hcpriv = NULL;
1269 if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && 1273 if (unlikely(urb->unlinked))
1274 urb->status = urb->unlinked;
1275 else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
1270 urb->actual_length < urb->transfer_buffer_length && 1276 urb->actual_length < urb->transfer_buffer_length &&
1271 !urb->status)) 1277 !urb->status))
1272 urb->status = -EREMOTEIO; 1278 urb->status = -EREMOTEIO;
@@ -1305,8 +1311,7 @@ rescan:
1305 list_for_each_entry (urb, &ep->urb_list, urb_list) { 1311 list_for_each_entry (urb, &ep->urb_list, urb_list) {
1306 int is_in; 1312 int is_in;
1307 1313
1308 /* the urb may already have been unlinked */ 1314 if (urb->unlinked)
1309 if (urb->status != -EINPROGRESS)
1310 continue; 1315 continue;
1311 usb_get_urb (urb); 1316 usb_get_urb (urb);
1312 is_in = usb_urb_dir_in(urb); 1317 is_in = usb_urb_dir_in(urb);