aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hcd.c
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-04-27 22:58:01 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:49 -0400
commitd0e96f5a71a032ced0c35f521c1cbd67e816922a (patch)
tree402e4d1ce20682fd2efd3ffd2ad23ffd097b1436 /drivers/usb/host/xhci-hcd.c
parent6d65b78a093552fb42448480d4c66bf093a6d4cf (diff)
USB: xhci: Control transfer support.
Allow device drivers to enqueue URBs to control endpoints on devices under an xHCI host controller. Each control transfer is represented by a series of Transfer Descriptors (TDs) written to an endpoint ring. There is one TD for the Setup phase, (optionally) one TD for the Data phase, and one TD for the Status phase. Enqueue these TDs onto the endpoint ring that represents the control endpoint. The host controller hardware will return an event on the event ring that points to the (DMA) address of one of the TDs on the endpoint ring. If the transfer was successful, the transfer event TRB will have a completion code of success, and it will point to the Status phase TD. Anything else is considered an error. This should work for control endpoints besides the default endpoint, but that hasn't been tested. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r--drivers/usb/host/xhci-hcd.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index a01d2ee7435a..5d94b4ffac92 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -509,6 +509,99 @@ void xhci_shutdown(struct usb_hcd *hcd)
509 509
510/*-------------------------------------------------------------------------*/ 510/*-------------------------------------------------------------------------*/
511 511
512/**
513 * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and
514 * HCDs. Find the index for an endpoint given its descriptor. Use the return
515 * value to right shift 1 for the bitmask.
516 *
517 * Index = (epnum * 2) + direction - 1,
518 * where direction = 0 for OUT, 1 for IN.
519 * For control endpoints, the IN index is used (OUT index is unused), so
520 * index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2)
521 */
522unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc)
523{
524 unsigned int index;
525 if (usb_endpoint_xfer_control(desc))
526 index = (unsigned int) (usb_endpoint_num(desc)*2);
527 else
528 index = (unsigned int) (usb_endpoint_num(desc)*2) +
529 (usb_endpoint_dir_in(desc) ? 1 : 0) - 1;
530 return index;
531}
532
533/* Returns 1 if the arguments are OK;
534 * returns 0 this is a root hub; returns -EINVAL for NULL pointers.
535 */
536int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
537 struct usb_host_endpoint *ep, int check_ep, const char *func) {
538 if (!hcd || (check_ep && !ep) || !udev) {
539 printk(KERN_DEBUG "xHCI %s called with invalid args\n",
540 func);
541 return -EINVAL;
542 }
543 if (!udev->parent) {
544 printk(KERN_DEBUG "xHCI %s called for root hub\n",
545 func);
546 return 0;
547 }
548 if (!udev->slot_id) {
549 printk(KERN_DEBUG "xHCI %s called with unaddressed device\n",
550 func);
551 return -EINVAL;
552 }
553 return 1;
554}
555
556/*
557 * non-error returns are a promise to giveback() the urb later
558 * we drop ownership so next owner (or urb unlink) can get it
559 */
560int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
561{
562 struct xhci_hcd *xhci = hcd_to_xhci(hcd);
563 unsigned long flags;
564 int ret = 0;
565 unsigned int slot_id, ep_index;
566
567 if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
568 return -EINVAL;
569
570 slot_id = urb->dev->slot_id;
571 ep_index = xhci_get_endpoint_index(&urb->ep->desc);
572 /* Only support ep 0 control transfers for now */
573 if (ep_index != 0) {
574 xhci_dbg(xhci, "WARN: urb submitted to unsupported ep %x\n",
575 urb->ep->desc.bEndpointAddress);
576 return -ENOSYS;
577 }
578
579 spin_lock_irqsave(&xhci->lock, flags);
580 if (!xhci->devs || !xhci->devs[slot_id]) {
581 if (!in_interrupt())
582 dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
583 return -EINVAL;
584 }
585 if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
586 if (!in_interrupt())
587 xhci_dbg(xhci, "urb submitted during PCI suspend\n");
588 ret = -ESHUTDOWN;
589 goto exit;
590 }
591 ret = queue_ctrl_tx(xhci, mem_flags, urb, slot_id, ep_index);
592exit:
593 spin_unlock_irqrestore(&xhci->lock, flags);
594 return ret;
595}
596
597/* Remove from hardware lists
598 * completions normally happen asynchronously
599 */
600int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
601{
602 return -ENOSYS;
603}
604
512/* 605/*
513 * At this point, the struct usb_device is about to go away, the device has 606 * At this point, the struct usb_device is about to go away, the device has
514 * disconnected, and all traffic has been stopped and the endpoints have been 607 * disconnected, and all traffic has been stopped and the endpoints have been