diff options
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 93 |
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 | */ | ||
522 | unsigned 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 | */ | ||
536 | int 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 | */ | ||
560 | int 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); | ||
592 | exit: | ||
593 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | /* Remove from hardware lists | ||
598 | * completions normally happen asynchronously | ||
599 | */ | ||
600 | int 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 |