📄 ohci-sl811.c
字号:
err1: driver->hcd_free(hcd); out: return retval;}/* may be called without controller electrically present *//* may be called with controller, bus, and devices active *//** * usb_hcd_sl811_remove - shutdown processing for HC-SL811-based HCDs * @dev: USB Host Controller being removed * Context: !in_interrupt() * * Reverses the effect of usb_hcd_sl811_probe(), first invoking * the HCD's stop() method. It is always called from a thread * context, normally "rmmod", "apmd", or something similar. * */static int usb_hcd_sl811_remove(struct usb_hcd *hcd, struct hc_sl811_dev *dev){ struct usb_device *hub; BUG_ON(in_interrupt()); if (HCD_IS_RUNNING(hcd->state)) { hcd->state = USB_STATE_QUIESCING; } hub = hcd->self.root_hub; dev_dbg(hcd->self.controller, "%s: roothub graceful disconnect\n", hcd->self.bus_name); usb_disconnect(&hub); sl811_stop_hc(dev); hcd->driver->stop(hcd); hcd->state = USB_STATE_HALT; free_irq(hcd->irq, hcd); tasklet_kill(&dev->usb_reset_bh); hcd_buffer_destroy(hcd); hc_sl811_set_drvdata(dev, NULL); usb_deregister_bus(&hcd->self); hcd->driver->hcd_free(hcd); return 0;}/* * perform OHCI (PCI) bus reset */static int ohci_sl811_reset(struct usb_hcd *hcd){ int ret; struct ohci_hcd *ohci = hcd_to_ohci(hcd); ohci->regs = hcd->regs; sl811_reset_hc(hcd, 1); // initialize controller registers ret = hc_reset(ohci); return ret;}static int __devinit ohci_sl811_start(struct usb_hcd *hcd){ struct ohci_hcd *ohci = hcd_to_ohci(hcd); int ret; ohci->hcca = dma_alloc_coherent(hcd->self.controller, sizeof(*ohci->hcca), &ohci->hcca_dma, 0); if (!ohci->hcca) { return -ENOMEM; } memset(ohci->hcca, 0, sizeof(struct ohci_hcca)); ret = ohci_mem_init(ohci); if (ret < 0) { ohci_stop(hcd); return ret; } if (hc_start(ohci) < 0) { err("can't start %s", ohci->hcd.self.bus_name); ohci_stop(hcd); return -EBUSY; } create_debug_files(ohci); sl811_start_hc(hcd);#ifdef DEBUG ohci_dump(ohci, 1);#endif return 0;}/*-------------------------------------------------------------------------*/#ifdef CONFIG_PMstatic int ohci_sl811_suspend(struct usb_hcd *hcd, u32 state){ struct ohci_hcd *ohci = hcd_to_ohci (hcd); /* suspend root hub, hoping it keeps power during suspend */ while (time_before(jiffies, ohci->next_statechange)) { msleep(100); }#ifdef CONFIG_USB_SUSPEND (void)usb_suspend_device(hcd->self.root_hub);#else down(&hcd->self.root_hub->serialize); (void)ohci_hub_suspend(hcd); up(&hcd->self.root_hub->serialize);#endif /* let things settle down a bit */ msleep(100); return 0;}static int ohci_sl811_resume(struct usb_hcd *hcd){ int retval; struct ohci_hcd *ohci = hcd_to_ohci (hcd); /* resume root hub */ while (time_before(jiffies, ohci->next_statechange)) { msleep(100); }#ifdef CONFIG_USB_SUSPEND /* get extra cleanup even if remote wakeup isn't in use */ retval = usb_resume_device(hcd->self.root_hub);#else down(&hcd->self.root_hub->serialize); retval = ohci_hub_resume(hcd); up(&hcd->self.root_hub->serialize);#endif retval = hc_restart(hcd_to_ohci(hcd)); if (retval == 0) { hcd->self.controller->power.power_state = 0; } sl811_start_hc(hcd); return retval;}#endifstatic struct hc_driver ohci_sl811_hc_driver = { .description = hcd_name, /* * generic hardware linkage */ .irq = ohci_irq, .flags = HCD_MEMORY | HCD_USB11, /* * basic lifecycle operations */ .reset = ohci_sl811_reset, .start = ohci_sl811_start,#ifdef CONFIG_PM .suspend = ohci_sl811_suspend, .resume = ohci_sl811_resume,#endif .stop = ohci_stop, /* * memory lifecycle (except per-request) */ .hcd_alloc = ohci_hcd_alloc, .hcd_free = ohci_hcd_free, /* * 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};/*-------------------------------------------------------------------------*/#define res_len(p) ((p)->end - (p)->start + 1)static int ohci_hcd_sl811_drv_probe(struct hc_sl811_dev *dev){ struct usb_hcd *hcd = NULL; struct platform_device *pdev = to_platform_device(dev->dev.parent); struct resource *res; //int req = -1; int io_len = 0; int ret; if (usb_disabled()) { return -ENODEV; } if (pdev->num_resources < 2) { return -ENODEV; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { return -ENODEV; } if (!request_mem_region(res->start, res_len(res), hcd_name)) { ret = -EBUSY; goto out; } io_len = res_len(res); //dev->addr_reg = ioremap(res->start, res_len(res)); dev->addr_reg = ioremap(0x04700000, 0x00100000); if (dev->addr_reg == NULL) { ret = -ENOMEM; goto out; }#ifdef CONFIG_ARCH_FS_PXA255 dev->data_reg = dev->addr_reg+0x10;#else res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { if (!request_mem_region(res->start, res_len(res), hcd_name)) { ret = -EBUSY; goto out; } dev->data_reg = ioremap(res->start, res_len(res)); if (dev->data_reg == NULL) { ret = -ENOMEM; goto out; } } else { dev->data_reg = dev->addr_reg + io_len - 1; }#endif dev->irq = platform_get_irq(pdev, 0); ret = hc_sl811_chip_probe(dev); printk("sl811hs probe %s\n", ret?"fail":"success"); if (ret != 0) { goto out; } ret = usb_hcd_sl811_probe(&ohci_sl811_hc_driver, &hcd, dev); if (ret == 0) { return ret; } out: if (dev->addr_reg) { iounmap(dev->addr_reg); dev->addr_reg = NULL; } if (res) { if (dev->data_reg) { iounmap(dev->data_reg); dev->data_reg = NULL; } release_mem_region(res->start, res_len(res)); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) { release_mem_region(res->start, io_len); } return ret;}static int ohci_hcd_sl811_drv_remove(struct hc_sl811_dev *dev){ struct usb_hcd *hcd = hc_sl811_get_drvdata(dev); struct platform_device *pdev = to_platform_device(dev->dev.parent); struct resource *res; usb_hcd_sl811_remove(hcd, dev); iounmap(dev->addr_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, res_len(res));#ifndef CONFIG_ARCH_FS_PXA255 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { iounmap(dev->data_reg); release_mem_region(res->start, res_len(res)); }#endif return 0;}static void __sl811_release(struct device *dev){ struct hc_sl811_dev *sl811_dev = dev_get_drvdata(dev); printk("%s: dev=%08x\n", __FUNCTION__, (u32)dev); if (sl811_dev != NULL) { kfree(sl811_dev); }}#define MALLOC_SIZE sizeof(struct hc_sl811_dev)static int __sl811_probe(struct device *dev, struct resource *mem, struct resource *irq){ int ret; struct hc_sl811_dev *sl811_dev; sl811_dev = kmalloc(MALLOC_SIZE, GFP_KERNEL); if (sl811_dev == NULL) { return -ENOMEM; } memset(sl811_dev, 0, MALLOC_SIZE); sl811_dev->irq = NO_IRQ; sl811_dev->dev.parent = dev; sl811_dev->dev.bus = &platform_bus_type; sl811_dev->dev.release = __sl811_release; //spin_lock_init(&sl811_dev->irq_lock); dev_set_drvdata(dev, sl811_dev); ret = ohci_hcd_sl811_drv_probe(sl811_dev); if (ret != 0) { dev_set_drvdata(dev, NULL); } return ret;}#ifdef CONFIG_PMstatic int usb_hcd_sl811_suspend(struct hc_sl811_dev *dev, u32 state){ struct usb_hcd *hcd; int retval = 0; hcd = hc_sl811_get_drvdata(dev); dev_dbg(hcd->self.controller, "suspend D%d --> D%d\n", dev->pm_state, state); switch (hcd->state) { case USB_STATE_HALT: dev_dbg (hcd->self.controller, "halted; hcd not suspended\n"); break; case HCD_STATE_SUSPENDED: dev_dbg (hcd->self.controller, "hcd already suspended\n"); break; default: retval = hcd->driver->suspend(hcd, state); if (retval) { dev_dbg(hcd->self.controller, "suspend fail, retval %d\n", retval); } else { hcd->state = HCD_STATE_SUSPENDED; //pci_save_state (dev, hcd->pci_state);#ifdef CONFIG_USB_SUSPEND //pci_enable_wake (dev, state, hcd->remote_wakeup); //pci_enable_wake (dev, 4, hcd->remote_wakeup);#endif /* no DMA or IRQs except in D0 */ //pci_disable_device (dev); sl811_stop_hc(dev); free_irq(hcd->irq, hcd); //if (has_pci_pm) //retval = pci_set_power_state (dev, state); dev->dev.power.power_state = state; } } return retval;}/* * usb_hcd_sl811_resume - power management resume of an SL811HS based HCD * @dev: USB Host Controller being resumed * * Store this function in the HCD's struct hc_sl811_driver as resume(). */static int usb_hcd_sl811_resume(struct hc_sl811_dev *dev){ struct usb_hcd *hcd; int retval; hcd = hc_sl811_get_drvdata(dev); dev_dbg(hcd->self.controller, "resume from state D%d\n", dev->pm_state); if (hcd->state != HCD_STATE_SUSPENDED) { dev_dbg(hcd->self.controller, "can't resume, not suspended!\n"); return -EL3HLT; } hcd->state = USB_STATE_RESUMING; dev->dev.power.power_state = 0; retval = request_irq(dev->irq, ohci_sl811_interrupt, SA_INTERRUPT, hcd->description, hcd); if (retval < 0) { dev_err(hcd->self.controller, "can't restore IRQ after resume!\n"); return retval; } //pci_set_master (dev); //pci_restore_state (dev, hcd->pci_state);#ifdef CONFIG_USB_SUSPEND //pci_enable_wake (dev, dev->pm_state, 0); //pci_enable_wake (dev, 4, 0);#endif dev->pm_state = 0; retval = hcd->driver->resume(hcd); if (!HCD_IS_RUNNING(hcd->state)) { dev_dbg(hcd->self.controller, "resume fail, retval %d\n", retval); usb_hc_died (hcd); } return retval;}#endif /* CONFIG_PM */static struct hc_sl811_driver ohci_hcd_sl811_driver = { .drv = { .name = "sl811hs-ohci", .bus = &platform_bus_type, }, .devid = 0, .probe = ohci_hcd_sl811_drv_probe, .remove = ohci_hcd_sl811_drv_remove,#ifdef CONFIG_PM .suspend = usb_hcd_sl811_suspend, .resume = usb_hcd_sl811_resume,#endif};static int sl811_bus_probe(struct device *dev){ struct platform_device *pdev = to_platform_device(dev); struct resource *mem, *irq = NULL; int ret = -ENODEV; mem = &pdev->resource[0]; if (pdev->num_resources == 2) { irq = &pdev->resource[1]; } ret = __sl811_probe(dev, mem, irq); return ret;}static int sl811_bus_remove(struct device *dev){ int ret = 0; struct hc_sl811_dev *sl811_dev = dev_get_drvdata(dev); struct hc_sl811_driver *drv = SL811_DRV(dev->driver); if (drv->remove) { ret = drv->remove(sl811_dev); } return ret;}static int sl811_bus_suspend(struct device *dev, u32 state, u32 level){ int ret = 0; struct hc_sl811_dev *sl811_dev = dev_get_drvdata(dev); struct hc_sl811_driver *drv = SL811_DRV(dev->driver); if (drv->suspend) { ret = drv->suspend(sl811_dev, state); } return ret;}static int sl811_bus_resume(struct device *dev, u32 level){ int ret = 0; struct hc_sl811_dev *sl811_dev = dev_get_drvdata(dev); struct hc_sl811_driver *drv = SL811_DRV(dev->driver); if (drv->resume) { ret = drv->resume(sl811_dev); } return ret;}static int hc_sl811_driver_register(struct hc_sl811_driver *driver){ int ret; WARN_ON(driver->drv.suspend || driver->drv.resume || driver->drv.probe || driver->drv.remove); driver->drv.probe = sl811_bus_probe; driver->drv.remove = sl811_bus_remove; driver->drv.suspend = sl811_bus_suspend; driver->drv.resume = sl811_bus_resume; ret = driver_register(&driver->drv); return ret;}static void hc_sl811_driver_unregister(struct hc_sl811_driver *driver){ driver_unregister(&driver->drv);}static int __init ohci_hcd_sl811_init(void){ int ret = 0; printk(DRIVER_INFO " (HC-SL811HS)\n"); ret = hc_sl811_driver_register(&ohci_hcd_sl811_driver); return ret;}static void __exit ohci_hcd_sl811_cleanup(void){ hc_sl811_driver_unregister(&ohci_hcd_sl811_driver);}module_init(ohci_hcd_sl811_init);module_exit(ohci_hcd_sl811_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -