diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-08-21 15:40:36 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-12 17:55:19 -0400 |
commit | eb23105462304fd35571fd0cab1de7aec79a9ec5 (patch) | |
tree | 3579e74b3f1a6e68d42de01c122d206447454d4b /drivers/usb/core | |
parent | b0d9efba3ec53468984aecef8eeaf079089f2e5a (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')
-rw-r--r-- | drivers/usb/core/hcd.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 22a098b318c0..ec17fc4d2861 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 | */ |
1263 | void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) | 1267 | void 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); |