aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/usb/core/hcd.c19
-rw-r--r--drivers/usb/gadget/dummy_hcd.c8
-rw-r--r--drivers/usb/host/ehci-q.c29
-rw-r--r--drivers/usb/host/isp116x-hcd.c5
-rw-r--r--drivers/usb/host/ohci-q.c5
-rw-r--r--drivers/usb/host/r8a66597-hcd.c24
-rw-r--r--drivers/usb/host/sl811-hcd.c5
-rw-r--r--drivers/usb/host/u132-hcd.c124
-rw-r--r--drivers/usb/host/uhci-debug.c4
-rw-r--r--drivers/usb/host/uhci-q.c9
-rw-r--r--include/linux/usb.h1
11 files changed, 108 insertions, 125 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 */
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);
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 0cb032526ca2..f2b124cf3206 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -1029,8 +1029,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
1029static void maybe_set_status (struct urb *urb, int status) 1029static void maybe_set_status (struct urb *urb, int status)
1030{ 1030{
1031 spin_lock (&urb->lock); 1031 spin_lock (&urb->lock);
1032 if (urb->status == -EINPROGRESS) 1032 urb->status = status;
1033 urb->status = status;
1034 spin_unlock (&urb->lock); 1033 spin_unlock (&urb->lock);
1035} 1034}
1036 1035
@@ -1257,10 +1256,9 @@ restart:
1257 int type; 1256 int type;
1258 1257
1259 urb = urbp->urb; 1258 urb = urbp->urb;
1260 if (urb->status != -EINPROGRESS) { 1259 if (urb->unlinked)
1261 /* likely it was just unlinked */
1262 goto return_urb; 1260 goto return_urb;
1263 } else if (dum->rh_state != DUMMY_RH_RUNNING) 1261 else if (dum->rh_state != DUMMY_RH_RUNNING)
1264 continue; 1262 continue;
1265 type = usb_pipetype (urb->pipe); 1263 type = usb_pipetype (urb->pipe);
1266 1264
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index e80b5c417d74..a8f5408c161d 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -151,7 +151,7 @@ static void qtd_copy_status (
151 urb->actual_length += length - QTD_LENGTH (token); 151 urb->actual_length += length - QTD_LENGTH (token);
152 152
153 /* don't modify error codes */ 153 /* don't modify error codes */
154 if (unlikely (urb->status != -EINPROGRESS)) 154 if (unlikely(urb->unlinked))
155 return; 155 return;
156 156
157 /* force cleanup after short read; not always an error */ 157 /* force cleanup after short read; not always an error */
@@ -232,21 +232,14 @@ __acquires(ehci->lock)
232 } 232 }
233 233
234 spin_lock (&urb->lock); 234 spin_lock (&urb->lock);
235 switch (urb->status) { 235 if (unlikely(urb->unlinked)) {
236 case -EINPROGRESS: /* success */ 236 COUNT(ehci->stats.unlink);
237 urb->status = 0; 237 } else {
238 default: /* fault */ 238 if (likely(urb->status == -EINPROGRESS ||
239 COUNT (ehci->stats.complete); 239 (urb->status == -EREMOTEIO &&
240 break; 240 !(urb->transfer_flags & URB_SHORT_NOT_OK))))
241 case -EREMOTEIO: /* fault or normal */
242 if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
243 urb->status = 0; 241 urb->status = 0;
244 COUNT (ehci->stats.complete); 242 COUNT(ehci->stats.complete);
245 break;
246 case -ECONNRESET: /* canceled */
247 case -ENOENT:
248 COUNT (ehci->stats.unlink);
249 break;
250 } 243 }
251 spin_unlock (&urb->lock); 244 spin_unlock (&urb->lock);
252 245
@@ -364,7 +357,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
364 * for the urb faulted (including short read) or 357 * for the urb faulted (including short read) or
365 * its urb was canceled. we may patch qh or qtds. 358 * its urb was canceled. we may patch qh or qtds.
366 */ 359 */
367 if (likely (urb->status == -EINPROGRESS)) 360 if (likely(urb->status == -EINPROGRESS &&
361 !urb->unlinked))
368 continue; 362 continue;
369 363
370 /* issue status after short control reads */ 364 /* issue status after short control reads */
@@ -395,7 +389,8 @@ halt:
395 spin_lock (&urb->lock); 389 spin_lock (&urb->lock);
396 qtd_copy_status (ehci, urb, qtd->length, token); 390 qtd_copy_status (ehci, urb, qtd->length, token);
397 if (unlikely(urb->status == -EREMOTEIO)) { 391 if (unlikely(urb->status == -EREMOTEIO)) {
398 do_status = usb_pipecontrol(urb->pipe); 392 do_status = (!urb->unlinked &&
393 usb_pipecontrol(urb->pipe));
399 urb->status = 0; 394 urb->status = 0;
400 } 395 }
401 spin_unlock (&urb->lock); 396 spin_unlock (&urb->lock);
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index c2919dbc3f54..35b3507ff401 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -455,11 +455,10 @@ static void postproc_atl_queue(struct isp116x *isp116x)
455 done: 455 done:
456 if (status != -EINPROGRESS) { 456 if (status != -EINPROGRESS) {
457 spin_lock(&urb->lock); 457 spin_lock(&urb->lock);
458 if (urb->status == -EINPROGRESS) 458 urb->status = status;
459 urb->status = status;
460 spin_unlock(&urb->lock); 459 spin_unlock(&urb->lock);
461 } 460 }
462 if (urb->status != -EINPROGRESS) 461 if (urb->status != -EINPROGRESS || urb->unlinked)
463 finish_request(isp116x, ep, urb); 462 finish_request(isp116x, ep, urb);
464 } 463 }
465} 464}
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 8aad6199cdcc..3c793fad178d 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -758,8 +758,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
758 cc = TD_CC_NOERROR; 758 cc = TD_CC_NOERROR;
759 if (cc != TD_CC_NOERROR && cc < 0x0E) { 759 if (cc != TD_CC_NOERROR && cc < 0x0E) {
760 spin_lock (&urb->lock); 760 spin_lock (&urb->lock);
761 if (urb->status == -EINPROGRESS) 761 urb->status = cc_to_error[cc];
762 urb->status = cc_to_error [cc];
763 spin_unlock (&urb->lock); 762 spin_unlock (&urb->lock);
764 } 763 }
765 764
@@ -972,7 +971,7 @@ rescan_this:
972 urb = td->urb; 971 urb = td->urb;
973 urb_priv = td->urb->hcpriv; 972 urb_priv = td->urb->hcpriv;
974 973
975 if (urb->status == -EINPROGRESS) { 974 if (!urb->unlinked) {
976 prev = &td->hwNextTD; 975 prev = &td->hwNextTD;
977 continue; 976 continue;
978 } 977 }
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 60248b01ce14..98b9e0547544 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -1118,7 +1118,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock)
1118 r8a66597->timeout_map &= ~(1 << pipenum); 1118 r8a66597->timeout_map &= ~(1 << pipenum);
1119 1119
1120 if (likely(td)) { 1120 if (likely(td)) {
1121 if (td->set_address && urb->status != 0) 1121 if (td->set_address && (urb->status != 0 || urb->unlinked))
1122 r8a66597->address_map &= ~(1 << urb->setup_packet[2]); 1122 r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
1123 1123
1124 pipe_toggle_save(r8a66597, td->pipe, urb); 1124 pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1225,8 +1225,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
1225 } 1225 }
1226 1226
1227 if (finish && pipenum != 0) { 1227 if (finish && pipenum != 0) {
1228 if (td->urb->status == -EINPROGRESS) 1228 td->urb->status = status;
1229 td->urb->status = status;
1230 finish_request(r8a66597, td, pipenum, urb); 1229 finish_request(r8a66597, td, pipenum, urb);
1231 } 1230 }
1232} 1231}
@@ -1308,32 +1307,24 @@ static void check_next_phase(struct r8a66597 *r8a66597)
1308 switch (td->type) { 1307 switch (td->type) {
1309 case USB_PID_IN: 1308 case USB_PID_IN:
1310 case USB_PID_OUT: 1309 case USB_PID_OUT:
1311 if (urb->status != -EINPROGRESS) {
1312 finish = 1;
1313 break;
1314 }
1315 if (check_transfer_finish(td, urb)) 1310 if (check_transfer_finish(td, urb))
1316 td->type = USB_PID_ACK; 1311 td->type = USB_PID_ACK;
1317 break; 1312 break;
1318 case USB_PID_SETUP: 1313 case USB_PID_SETUP:
1319 if (urb->status != -EINPROGRESS) 1314 if (urb->transfer_buffer_length == urb->actual_length)
1320 finish = 1;
1321 else if (urb->transfer_buffer_length == urb->actual_length) {
1322 td->type = USB_PID_ACK; 1315 td->type = USB_PID_ACK;
1323 urb->status = 0; 1316 else if (usb_pipeout(urb->pipe))
1324 } else if (usb_pipeout(urb->pipe))
1325 td->type = USB_PID_OUT; 1317 td->type = USB_PID_OUT;
1326 else 1318 else
1327 td->type = USB_PID_IN; 1319 td->type = USB_PID_IN;
1328 break; 1320 break;
1329 case USB_PID_ACK: 1321 case USB_PID_ACK:
1330 finish = 1; 1322 finish = 1;
1331 if (urb->status == -EINPROGRESS) 1323 urb->status = 0;
1332 urb->status = 0;
1333 break; 1324 break;
1334 } 1325 }
1335 1326
1336 if (finish) 1327 if (finish || urb->unlinked)
1337 finish_request(r8a66597, td, 0, urb); 1328 finish_request(r8a66597, td, 0, urb);
1338 else 1329 else
1339 start_transfer(r8a66597, td); 1330 start_transfer(r8a66597, td);
@@ -1418,8 +1409,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
1418 if ((tmp & INBUFM) == 0) { 1409 if ((tmp & INBUFM) == 0) {
1419 disable_irq_empty(r8a66597, pipenum); 1410 disable_irq_empty(r8a66597, pipenum);
1420 pipe_irq_disable(r8a66597, pipenum); 1411 pipe_irq_disable(r8a66597, pipenum);
1421 if (td->urb->status == -EINPROGRESS) 1412 td->urb->status = 0;
1422 td->urb->status = 0;
1423 finish_request(r8a66597, td, pipenum, td->urb); 1413 finish_request(r8a66597, td, pipenum, td->urb);
1424 } 1414 }
1425 } 1415 }
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index e90953a9c9fb..f0fa94148d9d 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -436,8 +436,7 @@ static void finish_request(
436 ep->nextpid = USB_PID_SETUP; 436 ep->nextpid = USB_PID_SETUP;
437 437
438 spin_lock(&urb->lock); 438 spin_lock(&urb->lock);
439 if (urb->status == -EINPROGRESS) 439 urb->status = status;
440 urb->status = status;
441 spin_unlock(&urb->lock); 440 spin_unlock(&urb->lock);
442 441
443 usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); 442 usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
@@ -598,7 +597,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
598 bank, status, ep, urbstat); 597 bank, status, ep, urbstat);
599 } 598 }
600 599
601 if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS)) 600 if (urb && (urbstat != -EINPROGRESS || urb->unlinked))
602 finish_request(sl811, ep, urb, urbstat); 601 finish_request(sl811, ep, urb, urbstat);
603} 602}
604 603
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 1381275d448f..db800a434b83 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -645,12 +645,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
645 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 645 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
646 return; 646 return;
647 } else if (u132->going > 0) { 647 } else if (u132->going > 0) {
648 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 648 dev_err(&u132->platform_dev->dev, "device is being removed "
649 "%p status=%d\n", urb, urb->status); 649 "urb=%p\n", urb);
650 up(&u132->scheduler_lock); 650 up(&u132->scheduler_lock);
651 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 651 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
652 return; 652 return;
653 } else if (urb->status == -EINPROGRESS) { 653 } else if (!urb->unlinked) {
654 struct u132_ring *ring = endp->ring; 654 struct u132_ring *ring = endp->ring;
655 u8 *u = urb->transfer_buffer + urb->actual_length; 655 u8 *u = urb->transfer_buffer + urb->actual_length;
656 u8 *b = buf; 656 u8 *b = buf;
@@ -716,8 +716,8 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
716 return; 716 return;
717 } 717 }
718 } else { 718 } else {
719 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 719 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
720 "s=%d\n", urb, urb->status); 720 "unlinked=%d\n", urb, urb->unlinked);
721 up(&u132->scheduler_lock); 721 up(&u132->scheduler_lock);
722 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 722 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
723 return; 723 return;
@@ -744,12 +744,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
744 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 744 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
745 return; 745 return;
746 } else if (u132->going > 0) { 746 } else if (u132->going > 0) {
747 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 747 dev_err(&u132->platform_dev->dev, "device is being removed "
748 "%p status=%d\n", urb, urb->status); 748 "urb=%p\n", urb);
749 up(&u132->scheduler_lock); 749 up(&u132->scheduler_lock);
750 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 750 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
751 return; 751 return;
752 } else if (urb->status == -EINPROGRESS) { 752 } else if (!urb->unlinked) {
753 struct u132_ring *ring = endp->ring; 753 struct u132_ring *ring = endp->ring;
754 urb->actual_length += len; 754 urb->actual_length += len;
755 endp->toggle_bits = toggle_bits; 755 endp->toggle_bits = toggle_bits;
@@ -768,8 +768,8 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
768 return; 768 return;
769 } 769 }
770 } else { 770 } else {
771 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 771 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
772 "s=%d\n", urb, urb->status); 772 "unlinked=%d\n", urb, urb->unlinked);
773 up(&u132->scheduler_lock); 773 up(&u132->scheduler_lock);
774 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 774 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
775 return; 775 return;
@@ -797,12 +797,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
797 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 797 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
798 return; 798 return;
799 } else if (u132->going > 0) { 799 } else if (u132->going > 0) {
800 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 800 dev_err(&u132->platform_dev->dev, "device is being removed "
801 "%p status=%d\n", urb, urb->status); 801 "urb=%p\n", urb);
802 up(&u132->scheduler_lock); 802 up(&u132->scheduler_lock);
803 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 803 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
804 return; 804 return;
805 } else if (urb->status == -EINPROGRESS) { 805 } else if (!urb->unlinked) {
806 struct u132_ring *ring = endp->ring; 806 struct u132_ring *ring = endp->ring;
807 u8 *u = urb->transfer_buffer + urb->actual_length; 807 u8 *u = urb->transfer_buffer + urb->actual_length;
808 u8 *b = buf; 808 u8 *b = buf;
@@ -871,8 +871,8 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
871 return; 871 return;
872 } 872 }
873 } else { 873 } else {
874 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 874 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
875 "s=%d\n", urb, urb->status); 875 "unlinked=%d\n", urb, urb->unlinked);
876 up(&u132->scheduler_lock); 876 up(&u132->scheduler_lock);
877 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 877 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
878 return; 878 return;
@@ -898,18 +898,18 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
898 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 898 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
899 return; 899 return;
900 } else if (u132->going > 0) { 900 } else if (u132->going > 0) {
901 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 901 dev_err(&u132->platform_dev->dev, "device is being removed "
902 "%p status=%d\n", urb, urb->status); 902 "urb=%p\n", urb);
903 up(&u132->scheduler_lock); 903 up(&u132->scheduler_lock);
904 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 904 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
905 return; 905 return;
906 } else if (urb->status == -EINPROGRESS) { 906 } else if (!urb->unlinked) {
907 up(&u132->scheduler_lock); 907 up(&u132->scheduler_lock);
908 u132_hcd_giveback_urb(u132, endp, urb, 0); 908 u132_hcd_giveback_urb(u132, endp, urb, 0);
909 return; 909 return;
910 } else { 910 } else {
911 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 911 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
912 "s=%d\n", urb, urb->status); 912 "unlinked=%d\n", urb, urb->unlinked);
913 up(&u132->scheduler_lock); 913 up(&u132->scheduler_lock);
914 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 914 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
915 return; 915 return;
@@ -936,12 +936,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
936 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 936 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
937 return; 937 return;
938 } else if (u132->going > 0) { 938 } else if (u132->going > 0) {
939 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 939 dev_err(&u132->platform_dev->dev, "device is being removed "
940 "%p status=%d\n", urb, urb->status); 940 "urb=%p\n", urb);
941 up(&u132->scheduler_lock); 941 up(&u132->scheduler_lock);
942 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 942 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
943 return; 943 return;
944 } else if (urb->status == -EINPROGRESS) { 944 } else if (!urb->unlinked) {
945 struct u132_ring *ring = endp->ring; 945 struct u132_ring *ring = endp->ring;
946 u8 *u = urb->transfer_buffer; 946 u8 *u = urb->transfer_buffer;
947 u8 *b = buf; 947 u8 *b = buf;
@@ -980,8 +980,8 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
980 return; 980 return;
981 } 981 }
982 } else { 982 } else {
983 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 983 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
984 "s=%d\n", urb, urb->status); 984 "unlinked=%d\n", urb, urb->unlinked);
985 up(&u132->scheduler_lock); 985 up(&u132->scheduler_lock);
986 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 986 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
987 return; 987 return;
@@ -1007,18 +1007,18 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
1007 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 1007 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1008 return; 1008 return;
1009 } else if (u132->going > 0) { 1009 } else if (u132->going > 0) {
1010 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 1010 dev_err(&u132->platform_dev->dev, "device is being removed "
1011 "%p status=%d\n", urb, urb->status); 1011 "urb=%p\n", urb);
1012 up(&u132->scheduler_lock); 1012 up(&u132->scheduler_lock);
1013 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 1013 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1014 return; 1014 return;
1015 } else if (urb->status == -EINPROGRESS) { 1015 } else if (!urb->unlinked) {
1016 up(&u132->scheduler_lock); 1016 up(&u132->scheduler_lock);
1017 u132_hcd_giveback_urb(u132, endp, urb, 0); 1017 u132_hcd_giveback_urb(u132, endp, urb, 0);
1018 return; 1018 return;
1019 } else { 1019 } else {
1020 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 1020 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1021 "s=%d\n", urb, urb->status); 1021 "unlinked=%d\n", urb, urb->unlinked);
1022 up(&u132->scheduler_lock); 1022 up(&u132->scheduler_lock);
1023 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 1023 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
1024 return; 1024 return;
@@ -1045,12 +1045,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
1045 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 1045 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1046 return; 1046 return;
1047 } else if (u132->going > 0) { 1047 } else if (u132->going > 0) {
1048 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 1048 dev_err(&u132->platform_dev->dev, "device is being removed "
1049 "%p status=%d\n", urb, urb->status); 1049 "urb=%p\n", urb);
1050 up(&u132->scheduler_lock); 1050 up(&u132->scheduler_lock);
1051 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 1051 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1052 return; 1052 return;
1053 } else if (urb->status == -EINPROGRESS) { 1053 } else if (!urb->unlinked) {
1054 if (usb_pipein(urb->pipe)) { 1054 if (usb_pipein(urb->pipe)) {
1055 int retval; 1055 int retval;
1056 struct u132_ring *ring = endp->ring; 1056 struct u132_ring *ring = endp->ring;
@@ -1077,8 +1077,8 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
1077 return; 1077 return;
1078 } 1078 }
1079 } else { 1079 } else {
1080 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 1080 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1081 "s=%d\n", urb, urb->status); 1081 "unlinked=%d\n", urb, urb->unlinked);
1082 up(&u132->scheduler_lock); 1082 up(&u132->scheduler_lock);
1083 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 1083 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
1084 return; 1084 return;
@@ -1106,20 +1106,20 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
1106 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 1106 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1107 return; 1107 return;
1108 } else if (u132->going > 0) { 1108 } else if (u132->going > 0) {
1109 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 1109 dev_err(&u132->platform_dev->dev, "device is being removed "
1110 "%p status=%d\n", urb, urb->status); 1110 "urb=%p\n", urb);
1111 up(&u132->scheduler_lock); 1111 up(&u132->scheduler_lock);
1112 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 1112 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1113 return; 1113 return;
1114 } else if (urb->status == -EINPROGRESS) { 1114 } else if (!urb->unlinked) {
1115 u132->addr[0].address = 0; 1115 u132->addr[0].address = 0;
1116 endp->usb_addr = udev->usb_addr; 1116 endp->usb_addr = udev->usb_addr;
1117 up(&u132->scheduler_lock); 1117 up(&u132->scheduler_lock);
1118 u132_hcd_giveback_urb(u132, endp, urb, 0); 1118 u132_hcd_giveback_urb(u132, endp, urb, 0);
1119 return; 1119 return;
1120 } else { 1120 } else {
1121 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 1121 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1122 "s=%d\n", urb, urb->status); 1122 "unlinked=%d\n", urb, urb->unlinked);
1123 up(&u132->scheduler_lock); 1123 up(&u132->scheduler_lock);
1124 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 1124 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
1125 return; 1125 return;
@@ -1145,12 +1145,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
1145 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 1145 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1146 return; 1146 return;
1147 } else if (u132->going > 0) { 1147 } else if (u132->going > 0) {
1148 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 1148 dev_err(&u132->platform_dev->dev, "device is being removed "
1149 "%p status=%d\n", urb, urb->status); 1149 "urb=%p\n", urb);
1150 up(&u132->scheduler_lock); 1150 up(&u132->scheduler_lock);
1151 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 1151 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1152 return; 1152 return;
1153 } else if (urb->status == -EINPROGRESS) { 1153 } else if (!urb->unlinked) {
1154 int retval; 1154 int retval;
1155 struct u132_ring *ring = endp->ring; 1155 struct u132_ring *ring = endp->ring;
1156 up(&u132->scheduler_lock); 1156 up(&u132->scheduler_lock);
@@ -1162,8 +1162,8 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
1162 u132_hcd_giveback_urb(u132, endp, urb, retval); 1162 u132_hcd_giveback_urb(u132, endp, urb, retval);
1163 return; 1163 return;
1164 } else { 1164 } else {
1165 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 1165 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1166 "s=%d\n", urb, urb->status); 1166 "unlinked=%d\n", urb, urb->unlinked);
1167 up(&u132->scheduler_lock); 1167 up(&u132->scheduler_lock);
1168 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 1168 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
1169 return; 1169 return;
@@ -1189,18 +1189,18 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
1189 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 1189 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1190 return; 1190 return;
1191 } else if (u132->going > 0) { 1191 } else if (u132->going > 0) {
1192 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 1192 dev_err(&u132->platform_dev->dev, "device is being removed "
1193 "%p status=%d\n", urb, urb->status); 1193 "urb=%p\n", urb);
1194 up(&u132->scheduler_lock); 1194 up(&u132->scheduler_lock);
1195 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 1195 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1196 return; 1196 return;
1197 } else if (urb->status == -EINPROGRESS) { 1197 } else if (!urb->unlinked) {
1198 up(&u132->scheduler_lock); 1198 up(&u132->scheduler_lock);
1199 u132_hcd_giveback_urb(u132, endp, urb, 0); 1199 u132_hcd_giveback_urb(u132, endp, urb, 0);
1200 return; 1200 return;
1201 } else { 1201 } else {
1202 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 1202 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1203 "s=%d\n", urb, urb->status); 1203 "unlinked=%d\n", urb, urb->unlinked);
1204 up(&u132->scheduler_lock); 1204 up(&u132->scheduler_lock);
1205 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 1205 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
1206 return; 1206 return;
@@ -1227,12 +1227,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
1227 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 1227 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1228 return; 1228 return;
1229 } else if (u132->going > 0) { 1229 } else if (u132->going > 0) {
1230 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 1230 dev_err(&u132->platform_dev->dev, "device is being removed "
1231 "%p status=%d\n", urb, urb->status); 1231 "urb=%p\n", urb);
1232 up(&u132->scheduler_lock); 1232 up(&u132->scheduler_lock);
1233 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 1233 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1234 return; 1234 return;
1235 } else if (urb->status == -EINPROGRESS) { 1235 } else if (!urb->unlinked) {
1236 int retval; 1236 int retval;
1237 struct u132_ring *ring = endp->ring; 1237 struct u132_ring *ring = endp->ring;
1238 u8 *u = urb->transfer_buffer; 1238 u8 *u = urb->transfer_buffer;
@@ -1251,8 +1251,8 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
1251 u132_hcd_giveback_urb(u132, endp, urb, retval); 1251 u132_hcd_giveback_urb(u132, endp, urb, retval);
1252 return; 1252 return;
1253 } else { 1253 } else {
1254 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 1254 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1255 "s=%d\n", urb, urb->status); 1255 "unlinked=%d\n", urb, urb->unlinked);
1256 up(&u132->scheduler_lock); 1256 up(&u132->scheduler_lock);
1257 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 1257 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
1258 return; 1258 return;
@@ -1279,12 +1279,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
1279 u132_hcd_giveback_urb(u132, endp, urb, -EINTR); 1279 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1280 return; 1280 return;
1281 } else if (u132->going > 0) { 1281 } else if (u132->going > 0) {
1282 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 1282 dev_err(&u132->platform_dev->dev, "device is being removed "
1283 "%p status=%d\n", urb, urb->status); 1283 "urb=%p\n", urb);
1284 up(&u132->scheduler_lock); 1284 up(&u132->scheduler_lock);
1285 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); 1285 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1286 return; 1286 return;
1287 } else if (urb->status == -EINPROGRESS) { 1287 } else if (!urb->unlinked) {
1288 int retval; 1288 int retval;
1289 struct u132_ring *ring = endp->ring; 1289 struct u132_ring *ring = endp->ring;
1290 up(&u132->scheduler_lock); 1290 up(&u132->scheduler_lock);
@@ -1296,8 +1296,8 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
1296 u132_hcd_giveback_urb(u132, endp, urb, retval); 1296 u132_hcd_giveback_urb(u132, endp, urb, retval);
1297 return; 1297 return;
1298 } else { 1298 } else {
1299 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" 1299 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1300 "s=%d\n", urb, urb->status); 1300 "unlinked=%d\n", urb, urb->unlinked);
1301 up(&u132->scheduler_lock); 1301 up(&u132->scheduler_lock);
1302 u132_hcd_giveback_urb(u132, endp, urb, urb->status); 1302 u132_hcd_giveback_urb(u132, endp, urb, urb->status);
1303 return; 1303 return;
@@ -2279,8 +2279,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
2279 , u132->going); 2279 , u132->going);
2280 return -ENODEV; 2280 return -ENODEV;
2281 } else if (u132->going > 0) { 2281 } else if (u132->going > 0) {
2282 dev_err(&u132->platform_dev->dev, "device is being removed urb=" 2282 dev_err(&u132->platform_dev->dev, "device is being removed "
2283 "%p status=%d\n", urb, urb->status); 2283 "urb=%p\n", urb);
2284 return -ESHUTDOWN; 2284 return -ESHUTDOWN;
2285 } else { 2285 } else {
2286 u8 usb_addr = usb_pipedevice(urb->pipe); 2286 u8 usb_addr = usb_pipedevice(urb->pipe);
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 1497371583b9..20cc58b97807 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
120 out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); 120 out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
121 out += sprintf(out, " Actlen=%d", urbp->urb->actual_length); 121 out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
122 122
123 if (urbp->urb->status != -EINPROGRESS) 123 if (urbp->urb->unlinked)
124 out += sprintf(out, " Status=%d", urbp->urb->status); 124 out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
125 out += sprintf(out, "\n"); 125 out += sprintf(out, "\n");
126 126
127 i = nactive = ninactive = 0; 127 i = nactive = ninactive = 0;
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index fbc3af392c26..bab567266559 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -1557,15 +1557,12 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
1557 break; 1557 break;
1558 1558
1559 spin_lock(&urb->lock); 1559 spin_lock(&urb->lock);
1560 if (urb->status == -EINPROGRESS) /* Not dequeued */ 1560 urb->status = status;
1561 urb->status = status;
1562 else
1563 status = ECONNRESET; /* Not -ECONNRESET */
1564 spin_unlock(&urb->lock); 1561 spin_unlock(&urb->lock);
1565 1562
1566 /* Dequeued but completed URBs can't be given back unless 1563 /* Dequeued but completed URBs can't be given back unless
1567 * the QH is stopped or has finished unlinking. */ 1564 * the QH is stopped or has finished unlinking. */
1568 if (status == ECONNRESET) { 1565 if (urb->unlinked) {
1569 if (QH_FINISHED_UNLINKING(qh)) 1566 if (QH_FINISHED_UNLINKING(qh))
1570 qh->is_stopped = 1; 1567 qh->is_stopped = 1;
1571 else if (!qh->is_stopped) 1568 else if (!qh->is_stopped)
@@ -1588,7 +1585,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
1588restart: 1585restart:
1589 list_for_each_entry(urbp, &qh->queue, node) { 1586 list_for_each_entry(urbp, &qh->queue, node) {
1590 urb = urbp->urb; 1587 urb = urbp->urb;
1591 if (urb->status != -EINPROGRESS) { 1588 if (urb->unlinked) {
1592 1589
1593 /* Fix up the TD links and save the toggles for 1590 /* Fix up the TD links and save the toggles for
1594 * non-Isochronous queues. For Isochronous queues, 1591 * non-Isochronous queues. For Isochronous queues,
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 92d63c6b6fc6..5c7b79088add 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1245,6 +1245,7 @@ struct urb
1245 void *hcpriv; /* private data for host controller */ 1245 void *hcpriv; /* private data for host controller */
1246 atomic_t use_count; /* concurrent submissions counter */ 1246 atomic_t use_count; /* concurrent submissions counter */
1247 u8 reject; /* submissions will fail */ 1247 u8 reject; /* submissions will fail */
1248 int unlinked; /* unlink error code */
1248 1249
1249 /* public: documented fields in the urb that can be used by drivers */ 1250 /* public: documented fields in the urb that can be used by drivers */
1250 struct list_head urb_list; /* list head for use by the urb's 1251 struct list_head urb_list; /* list head for use by the urb's