📄 ohci-pnx8550.c
字号:
/* * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> * (C) Copyright 2002 Hewlett-Packard Company * (C) Copyright 2005 Embedded Alley Solutions, Inc. * * Bus Glue for PNX8550 * * Written by Christopher Hoover <ch@hpl.hp.com> * Based on fragments of previous driver by Russell King et al. * * Modified for LH7A404 from ohci-sa1111.c * by Durgesh Pattamatta <pattamattad@sharpsec.com> * * Modified for pxa27x from ohci-lh7a404.c * by Nick Bane <nick@cecomputing.co.uk> 26-8-2004 * * Modified for PNX8550 from ohci-pxa27x.c * by Embedded Alley Solutions, Inc. * * Modified for Linux 2.6.17 * by Chris Steel (Philips). * * This file is licenced under the GPL. */#include <linux/device.h>#include <linux/signal.h>#include <linux/platform_device.h>#include <asm/mach-pnx8550/usb.h>#include <asm/mach-pnx8550/int.h>#include <asm/mach-pnx8550/pci.h>#ifndef CONFIG_PNX8550#error "This file is PNX8550 bus glue. CONFIG_PNX8550 must be defined."#endifextern int usb_disabled(void);/*-------------------------------------------------------------------------*/static void pnx8550_start_hc(struct device *dev){ /* * Set register CLK48CTL to enable and 48MHz */ outl(0x00000003, PCI_BASE | 0x0004770c); /* * Set register CLK12CTL to enable and 48MHz */ outl(0x00000003, PCI_BASE | 0x00047710); udelay(100);}static void pnx8550_stop_hc(struct device *dev){ udelay(10);}/*-------------------------------------------------------------------------*//* configure so an HC device and id are always provided *//* always called with process context; sleeping is OK *//** * usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs * Context: !in_interrupt() * * Allocates basic resources for this USB host controller, and * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. * */int usb_hcd_pnx8550_probe (const struct hc_driver *driver, struct platform_device *pdev){ int retval; struct usb_hcd *hcd = 0; if (pdev->resource[1].flags != IORESOURCE_IRQ) { pr_debug ("resource[1] is not IORESOURCE_IRQ"); return -ENOMEM; } hcd = usb_create_hcd (driver, &pdev->dev, "pnx8550"); if (!hcd) return -ENOMEM; hcd->rsrc_start = pdev->resource[0].start; hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; hcd->regs = ioremap(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); if (!hcd->regs) { pr_debug("ioremap failed"); retval = -ENOMEM; goto err1; } pnx8550_start_hc(&pdev->dev); ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT); if (retval == 0) return retval; pnx8550_stop_hc(&pdev->dev); err1: iounmap(hcd->regs); usb_put_hcd(hcd); return retval;}/* may be called without controller electrically present *//* may be called with controller, bus, and devices active *//** * usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs * @dev: USB Host Controller being removed * Context: !in_interrupt() * * Reverses the effect of usb_hcd_pnx8550_probe(), first invoking * the HCD's stop() method. It is always called from a thread * context, normally "rmmod", "apmd", or something similar. * */void usb_hcd_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *pdev){ usb_remove_hcd(hcd); pnx8550_stop_hc(&pdev->dev); iounmap(hcd->regs); usb_put_hcd(hcd);}/*-------------------------------------------------------------------------*/static int __devinitohci_pnx8550_start (struct usb_hcd *hcd){ struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci); if ((ret = ohci_init(ohci)) < 0) return ret; if ((ret = ohci_run (ohci)) < 0) { err ("can't start %s", hcd->self.bus_name); ohci_stop (hcd); return ret; } return 0;}/*-------------------------------------------------------------------------*/static const struct hc_driver ohci_pnx8550_hc_driver = { .description = hcd_name, .product_desc = "PNX8550 builtin USB 1.1 Host Controller", .hcd_priv_size = sizeof(struct ohci_hcd), /* * generic hardware linkage */ .irq = ohci_irq, .flags = HCD_USB11 | HCD_MEMORY, /* * basic lifecycle operations */ .start = ohci_pnx8550_start, .stop = ohci_stop, /* * managing i/o requests and associated device resources */ .urb_enqueue = ohci_urb_enqueue, .urb_dequeue = ohci_urb_dequeue, .endpoint_disable = ohci_endpoint_disable, /* * scheduling support */ .get_frame_number = ohci_get_frame, /* * root hub support */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control,#ifdef CONFIG_USB_SUSPEND .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume,#endif .start_port_reset = ohci_start_port_reset,};/*-------------------------------------------------------------------------*/static int ohci_hcd_pnx8550_drv_probe(struct platform_device *dev){ int ret; pr_debug ("In ohci_hcd_pnx8550_drv_probe"); if (usb_disabled()) return -ENODEV; ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, dev); return ret;}static int ohci_hcd_pnx8550_drv_remove(struct platform_device *pdev){ struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_hcd_pnx8550_remove(hcd, pdev); platform_set_drvdata(pdev, NULL); return 0;}#ifdef CONFIG_PMstatic int ohci_hcd_pnx8550_drv_suspend(struct platform_device *pdev, pm_message_t state){ struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; pnx8550_stop_hc(&pdev->dev); hcd->state = HC_STATE_SUSPENDED; pdev->dev.power.power_state = PMSG_SUSPEND; return 0;}static int ohci_hcd_pnx8550_drv_resume(struct platform_device *pdev){ struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; pnx8550_start_hc(&pdev->dev) pdev->dev.power.power_state = PMSG_ON; usb_hcd_resume_root_hub(hcd); return 0;}#endifstatic struct platform_driver ohci_hcd_pnx8550_driver = { .probe = ohci_hcd_pnx8550_drv_probe, .remove = ohci_hcd_pnx8550_drv_remove,#ifdef CONFIG_PM .suspend = ohci_hcd_pnx8550_drv_suspend, .resume = ohci_hcd_pnx8550_drv_resume,#endif .driver = { .name = "pnx8550-ohci", },};static int __init ohci_hcd_pnx8550_init (void){ pr_debug (DRIVER_INFO " (pnx8550)"); pr_debug ("block sizes: ed %d td %d\n", sizeof (struct ed), sizeof (struct td)); return platform_driver_register(&ohci_hcd_pnx8550_driver);}static void __exit ohci_hcd_pnx8550_cleanup (void){ platform_driver_unregister(&ohci_hcd_pnx8550_driver);}module_init (ohci_hcd_pnx8550_init);module_exit (ohci_hcd_pnx8550_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -