aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-08-08 11:48:02 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:55:10 -0400
commite9df41c5c5899259541dc928872cad4d07b82076 (patch)
tree12bb0917eeecbe62b2b5d3dc576806c7f2728550 /drivers/usb/host/uhci-q.c
parentb0e396e3097ce4914c643bc3f0c2fe0098f551eb (diff)
USB: make HCDs responsible for managing endpoint queues
This patch (as954) implements a suggestion of David Brownell's. Now the host controller drivers are responsible for linking and unlinking URBs to/from their endpoint queues. This eliminates the possiblity of strange situations where usbcore thinks an URB is linked but the HCD thinks it isn't. It also means HCDs no longer have to check for URBs being dequeued before they were fully enqueued. In addition to the core changes, this requires changing every host controller driver and the root-hub URB handler. For the most part the required changes are fairly small; drivers have to call usb_hcd_link_urb_to_ep() in their urb_enqueue method, usb_hcd_check_unlink_urb() in their urb_dequeue method, and usb_hcd_unlink_urb_from_ep() before giving URBs back. A few HCDs make matters more complicated by the way they split up the flow of control. In addition some method interfaces get changed. The endpoint argument for urb_enqueue is now redundant so it is removed. The unlink status is required by usb_hcd_check_unlink_urb(), so it has been added to urb_dequeue. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: David Brownell <david-b@pacbell.net> CC: Olav Kongas <ok@artecdesign.ee> CC: Tony Olech <tony.olech@elandigitalsystems.com> CC: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c32
1 files changed, 17 insertions, 15 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 3bb908ca38e..bff200cb3d2 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -1376,7 +1376,6 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
1376} 1376}
1377 1377
1378static int uhci_urb_enqueue(struct usb_hcd *hcd, 1378static int uhci_urb_enqueue(struct usb_hcd *hcd,
1379 struct usb_host_endpoint *hep,
1380 struct urb *urb, gfp_t mem_flags) 1379 struct urb *urb, gfp_t mem_flags)
1381{ 1380{
1382 int ret; 1381 int ret;
@@ -1387,19 +1386,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
1387 1386
1388 spin_lock_irqsave(&uhci->lock, flags); 1387 spin_lock_irqsave(&uhci->lock, flags);
1389 1388
1390 ret = urb->status; 1389 ret = usb_hcd_link_urb_to_ep(hcd, urb);
1391 if (ret != -EINPROGRESS) /* URB already unlinked! */ 1390 if (ret)
1392 goto done; 1391 goto done_not_linked;
1393 1392
1394 ret = -ENOMEM; 1393 ret = -ENOMEM;
1395 urbp = uhci_alloc_urb_priv(uhci, urb); 1394 urbp = uhci_alloc_urb_priv(uhci, urb);
1396 if (!urbp) 1395 if (!urbp)
1397 goto done; 1396 goto done;
1398 1397
1399 if (hep->hcpriv) 1398 if (urb->ep->hcpriv)
1400 qh = (struct uhci_qh *) hep->hcpriv; 1399 qh = urb->ep->hcpriv;
1401 else { 1400 else {
1402 qh = uhci_alloc_qh(uhci, urb->dev, hep); 1401 qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
1403 if (!qh) 1402 if (!qh)
1404 goto err_no_qh; 1403 goto err_no_qh;
1405 } 1404 }
@@ -1440,27 +1439,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
1440err_submit_failed: 1439err_submit_failed:
1441 if (qh->state == QH_STATE_IDLE) 1440 if (qh->state == QH_STATE_IDLE)
1442 uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */ 1441 uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */
1443
1444err_no_qh: 1442err_no_qh:
1445 uhci_free_urb_priv(uhci, urbp); 1443 uhci_free_urb_priv(uhci, urbp);
1446
1447done: 1444done:
1445 if (ret)
1446 usb_hcd_unlink_urb_from_ep(hcd, urb);
1447done_not_linked:
1448 spin_unlock_irqrestore(&uhci->lock, flags); 1448 spin_unlock_irqrestore(&uhci->lock, flags);
1449 return ret; 1449 return ret;
1450} 1450}
1451 1451
1452static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) 1452static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
1453{ 1453{
1454 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 1454 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
1455 unsigned long flags; 1455 unsigned long flags;
1456 struct urb_priv *urbp;
1457 struct uhci_qh *qh; 1456 struct uhci_qh *qh;
1457 int rc;
1458 1458
1459 spin_lock_irqsave(&uhci->lock, flags); 1459 spin_lock_irqsave(&uhci->lock, flags);
1460 urbp = urb->hcpriv; 1460 rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1461 if (!urbp) /* URB was never linked! */ 1461 if (rc)
1462 goto done; 1462 goto done;
1463 qh = urbp->qh; 1463
1464 qh = ((struct urb_priv *) urb->hcpriv)->qh;
1464 1465
1465 /* Remove Isochronous TDs from the frame list ASAP */ 1466 /* Remove Isochronous TDs from the frame list ASAP */
1466 if (qh->type == USB_ENDPOINT_XFER_ISOC) { 1467 if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1477,7 +1478,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
1477 1478
1478done: 1479done:
1479 spin_unlock_irqrestore(&uhci->lock, flags); 1480 spin_unlock_irqrestore(&uhci->lock, flags);
1480 return 0; 1481 return rc;
1481} 1482}
1482 1483
1483/* 1484/*
@@ -1529,6 +1530,7 @@ __acquires(uhci->lock)
1529 } 1530 }
1530 1531
1531 uhci_free_urb_priv(uhci, urbp); 1532 uhci_free_urb_priv(uhci, urbp);
1533 usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
1532 1534
1533 spin_unlock(&uhci->lock); 1535 spin_unlock(&uhci->lock);
1534 usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); 1536 usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);