NOT FOR MERGING!!! it will make it simpler to re-use the stack if it's not tied to a particular bus. Later patches should come to phase PCI bus to a separate piece of code which doesn't touch xhci.c. NYET-Signed-off-by: Felipe Balbi <balbi@xxxxxx> --- drivers/usb/host/xhci.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 178 insertions(+), 1 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 06e7023..fe06de1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/slab.h> +#include <linux/platform_device.h> #include "xhci.h" @@ -175,6 +176,13 @@ int xhci_reset(struct xhci_hcd *xhci) return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); } +static int xhci_hcd_reset(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return xhci_reset(xhci); +} + /* * Free IRQs * free all IRQs request @@ -2997,6 +3005,173 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_LICENSE("GPL"); +static const struct hc_driver xhci_hc_driver = { + .description = "xhci-hcd", + .product_desc = "xHCI Host Controller", + .hcd_priv_size = sizeof(struct xhci_hcd *), + + /* + * generic hardware linkage + */ + .irq = xhci_irq, + .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, + + /* + * basic lifecycle operations + */ + .reset = xhci_hcd_reset, + .start = xhci_run, + .stop = xhci_stop, + .shutdown = xhci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = xhci_urb_enqueue, + .urb_dequeue = xhci_urb_dequeue, + .alloc_dev = xhci_alloc_dev, + .free_dev = xhci_free_dev, + .alloc_streams = xhci_alloc_streams, + .free_streams = xhci_free_streams, + .add_endpoint = xhci_add_endpoint, + .drop_endpoint = xhci_drop_endpoint, + .endpoint_reset = xhci_endpoint_reset, + .check_bandwidth = xhci_check_bandwidth, + .reset_bandwidth = xhci_reset_bandwidth, + .address_device = xhci_address_device, + .update_hub_device = xhci_update_hub_device, + .reset_device = xhci_discover_or_reset_device, + + /* + * scheduling support + */ + .get_frame_number = xhci_get_frame, + + /* Root hub support */ + .hub_control = xhci_hub_control, + .hub_status_data = xhci_hub_status_data, + .bus_suspend = xhci_bus_suspend, + .bus_resume = xhci_bus_resume, +}; + +static int xhci_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct xhci_hcd *xhci; + struct resource *res; + + int irq; + int ret; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (!irq) { + dev_err(&pdev->dev, "No IRQ found\n"); + ret = -ENODEV; + goto err0; + } + + hcd = usb_create_hcd(&xhci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + ret = -ENOMEM; + goto err0; + } + + platform_set_drvdata(pdev, hcd); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing memory resource\n"); + ret = -ENOMEM; + goto err1; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + xhci_hc_driver.description)) { + dev_err(&pdev->dev, "controller already in use\n"); + ret = -EBUSY; + goto err1; + } + + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&pdev->dev, "error mapping memory\n"); + ret = -EFAULT; + goto err2; + } + + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret != 0) { + dev_err(&pdev->dev, "failed to add XHCI HCD\n"); + goto err3; + } + + xhci = hcd_to_xhci(hcd); + xhci->shared_hcd = usb_create_shared_hcd(&xhci_hc_driver, &pdev->dev, + dev_name(&pdev->dev), hcd); + if (!xhci->shared_hcd) { + dev_err(&pdev->dev, "failed to create shared HCD\n"); + ret = -ENOMEM; + goto err4; + } + + *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; + + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(&pdev->dev, "failed to add shared HCD\n"); + goto err5; + } + + return 0; + +err5: + usb_put_hcd(xhci->shared_hcd); + +err4: + usb_remove_hcd(hcd); + +err3: + iounmap(hcd->regs); + +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + +err1: + usb_put_hcd(hcd); + +err0: + return ret; +} + +static int __devexit xhci_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_remove_hcd(hcd); + usb_put_hcd(hcd); + usb_remove_hcd(xhci->shared_hcd); + usb_put_hcd(xhci->shared_hcd); + + return 0; +} + +static struct platform_driver xhci_driver = { + .probe = xhci_probe, + .remove = __devexit_p(xhci_remove), + .driver = { + .name = "xhci", + }, +}; + static int __init xhci_hcd_init(void) { #ifdef CONFIG_PCI @@ -3027,7 +3202,8 @@ static int __init xhci_hcd_init(void) /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); - return 0; + + return platform_driver_register(&xhci_driver); } module_init(xhci_hcd_init); @@ -3036,5 +3212,6 @@ static void __exit xhci_hcd_cleanup(void) #ifdef CONFIG_PCI xhci_unregister_pci(); #endif + platform_driver_unregister(&xhci_driver); } module_exit(xhci_hcd_cleanup); -- 1.7.6.rc1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html