📄 sl811-hcd.c
字号:
spin_lock_irq(&sl811->lock); if (sl811->ctrl1 & SL11H_CTL1MASK_SUSPEND) seq_printf(s, "(suspended)\n\n"); else { u8 t = sl811_read(sl811, SL11H_CTLREG1); seq_printf(s, "ctrl1 %02x%s%s%s%s\n", t, (t & SL11H_CTL1MASK_SOF_ENA) ? " sofgen" : "", ({char *s; switch (t & SL11H_CTL1MASK_FORCE) { case SL11H_CTL1MASK_NORMAL: s = ""; break; case SL11H_CTL1MASK_SE0: s = " se0/reset"; break; case SL11H_CTL1MASK_K: s = " k/resume"; break; default: s = "j"; break; }; s; }), (t & SL11H_CTL1MASK_LSPD) ? " lowspeed" : "", (t & SL11H_CTL1MASK_SUSPEND) ? " suspend" : ""); dump_irq(s, "irq_enable", sl811_read(sl811, SL11H_IRQ_ENABLE)); dump_irq(s, "irq_status", sl811_read(sl811, SL11H_IRQ_STATUS)); seq_printf(s, "frame clocks remaining: %d\n", sl811_read(sl811, SL11H_SOFTMRREG) << 6); } seq_printf(s, "A: qh%p ctl %02x sts %02x\n", sl811->active_a, sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)), sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG))); seq_printf(s, "B: qh%p ctl %02x sts %02x\n", sl811->active_b, sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)), sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG))); seq_printf(s, "\n"); list_for_each_entry (ep, &sl811->async, schedule) { struct urb *urb; seq_printf(s, "%s%sqh%p, ep%d%s, maxpacket %d" " nak %d err %d\n", (ep == sl811->active_a) ? "(A) " : "", (ep == sl811->active_b) ? "(B) " : "", ep, ep->epnum, ({ char *s; switch (ep->nextpid) { case USB_PID_IN: s = "in"; break; case USB_PID_OUT: s = "out"; break; case USB_PID_SETUP: s = "setup"; break; case USB_PID_ACK: s = "status"; break; default: s = "?"; break; }; s;}), ep->maxpacket, ep->nak_count, ep->error_count); list_for_each_entry (urb, &ep->hep->urb_list, urb_list) { seq_printf(s, " urb%p, %d/%d\n", urb, urb->actual_length, urb->transfer_buffer_length); } } if (!list_empty(&sl811->async)) seq_printf(s, "\n"); seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE); for (i = 0; i < PERIODIC_SIZE; i++) { ep = sl811->periodic[i]; if (!ep) continue; seq_printf(s, "%2d [%3d]:\n", i, sl811->load[i]); /* DUMB: prints shared entries multiple times */ do { seq_printf(s, " %s%sqh%d/%p (%sdev%d ep%d%s max %d) " "err %d\n", (ep == sl811->active_a) ? "(A) " : "", (ep == sl811->active_b) ? "(B) " : "", ep->period, ep, (ep->udev->speed == USB_SPEED_FULL) ? "" : "ls ", ep->udev->devnum, ep->epnum, (ep->epnum == 0) ? "" : ((ep->nextpid == USB_PID_IN) ? "in" : "out"), ep->maxpacket, ep->error_count); ep = ep->next; } while (ep); } spin_unlock_irq(&sl811->lock); seq_printf(s, "\n"); return 0;}static int proc_sl811h_open(struct inode *inode, struct file *file){ return single_open(file, proc_sl811h_show, PDE(inode)->data);}static struct file_operations proc_ops = { .open = proc_sl811h_open, .read = seq_read, .llseek = seq_lseek, .release = single_release,};/* expect just one sl811 per system */static const char proc_filename[] = "driver/sl811h";static void create_debug_file(struct sl811 *sl811){ struct proc_dir_entry *pde; pde = create_proc_entry(proc_filename, 0, NULL); if (pde == NULL) return; pde->proc_fops = &proc_ops; pde->data = sl811; sl811->pde = pde;}static void remove_debug_file(struct sl811 *sl811){ if (sl811->pde) remove_proc_entry(proc_filename, NULL);}#endif/*-------------------------------------------------------------------------*/static voidsl811h_stop(struct usb_hcd *hcd){ struct sl811 *sl811 = hcd_to_sl811(hcd); unsigned long flags; del_timer_sync(&hcd->rh_timer); spin_lock_irqsave(&sl811->lock, flags); port_power(sl811, 0); spin_unlock_irqrestore(&sl811->lock, flags);}static intsl811h_start(struct usb_hcd *hcd){ struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_device *udev; /* chip has been reset, VBUS power is off */ udev = usb_alloc_dev(NULL, &hcd->self, 0); if (!udev) return -ENOMEM; udev->speed = USB_SPEED_FULL; hcd->state = USB_STATE_RUNNING; if (sl811->board) hcd->can_wakeup = sl811->board->can_wakeup; if (hcd_register_root(udev, hcd) != 0) { usb_put_dev(udev); sl811h_stop(hcd); return -ENODEV; } if (sl811->board && sl811->board->power) hub_set_power_budget(udev, sl811->board->power * 2); return 0;}/*-------------------------------------------------------------------------*/static struct hc_driver sl811h_hc_driver = { .description = hcd_name, .hcd_priv_size = sizeof(struct sl811), /* * generic hardware linkage */ .flags = HCD_USB11, /* * managing i/o requests and associated device resources */ .urb_enqueue = sl811h_urb_enqueue, .urb_dequeue = sl811h_urb_dequeue, .endpoint_disable = sl811h_endpoint_disable, /* * periodic schedule support */ .get_frame_number = sl811h_get_frame, /* * root hub support */ .hub_status_data = sl811h_hub_status_data, .hub_control = sl811h_hub_control, .hub_suspend = sl811h_hub_suspend, .hub_resume = sl811h_hub_resume,};/*-------------------------------------------------------------------------*/static int __init_or_modulesl811h_remove(struct device *dev){ struct sl811 *sl811 = dev_get_drvdata(dev); struct usb_hcd *hcd = sl811_to_hcd(sl811); struct platform_device *pdev; struct resource *res; pdev = container_of(dev, struct platform_device, dev); if (HCD_IS_RUNNING(hcd->state)) hcd->state = USB_STATE_QUIESCING; usb_disconnect(&hcd->self.root_hub); remove_debug_file(sl811); sl811h_stop(hcd); usb_deregister_bus(&hcd->self); free_irq(hcd->irq, hcd); iounmap(sl811->data_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); release_mem_region(res->start, 1); iounmap(sl811->addr_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, 1); usb_put_hcd(hcd); return 0;}#define resource_len(r) (((r)->end - (r)->start) + 1)static int __initsl811h_probe(struct device *dev){ struct usb_hcd *hcd; struct sl811 *sl811; struct platform_device *pdev; struct resource *addr, *data; int irq; void __iomem *addr_reg; void __iomem *data_reg; int retval; u8 tmp; /* basic sanity checks first. board-specific init logic should * have initialized these three resources and probably board * specific platform_data. we don't probe for IRQs, and do only * minimal sanity checking. */ pdev = container_of(dev, struct platform_device, dev); if (pdev->num_resources < 3) return -ENODEV; addr = platform_get_resource(pdev, IORESOURCE_MEM, 0); data = platform_get_resource(pdev, IORESOURCE_MEM, 1); irq = platform_get_irq(pdev, 0); if (!addr || !data || irq < 0) return -ENODEV; /* refuse to confuse usbcore */ if (dev->dma_mask) { DBG("no we won't dma\n"); return -EINVAL; } if (!request_mem_region(addr->start, 1, hcd_name)) { retval = -EBUSY; goto err1; } addr_reg = ioremap(addr->start, resource_len(addr)); if (addr_reg == NULL) { retval = -ENOMEM; goto err2; } if (!request_mem_region(data->start, 1, hcd_name)) { retval = -EBUSY; goto err3; } data_reg = ioremap(data->start, resource_len(addr)); if (data_reg == NULL) { retval = -ENOMEM; goto err4; } /* allocate and initialize hcd */ hcd = usb_create_hcd(&sl811h_hc_driver); if (!hcd) { retval = 0; goto err5; } sl811 = hcd_to_sl811(hcd); dev_set_drvdata(dev, sl811); hcd->self.controller = dev; hcd->self.bus_name = dev->bus_id; hcd->irq = irq; hcd->regs = addr_reg; spin_lock_init(&sl811->lock); INIT_LIST_HEAD(&sl811->async); sl811->board = dev->platform_data; init_timer(&sl811->timer); sl811->timer.function = sl811h_timer; sl811->timer.data = (unsigned long) sl811; sl811->addr_reg = addr_reg; sl811->data_reg = data_reg; spin_lock_irq(&sl811->lock); port_power(sl811, 0); spin_unlock_irq(&sl811->lock); msleep(200); tmp = sl811_read(sl811, SL11H_HWREVREG); switch (tmp >> 4) { case 1: hcd->product_desc = "SL811HS v1.2"; break; case 2: hcd->product_desc = "SL811HS v1.5"; break; default: /* reject case 0, SL11S is less functional */ DBG("chiprev %02x\n", tmp); retval = -ENXIO; goto err6; } /* sl811s would need a different handler for this irq */#ifdef CONFIG_ARM /* Cypress docs say the IRQ is IRQT_HIGH ... */ set_irq_type(irq, IRQT_RISING);#endif retval = request_irq(irq, sl811h_irq, SA_INTERRUPT, hcd->driver->description, hcd); if (retval != 0) goto err6; INFO("%s, irq %d\n", hcd->product_desc, irq); retval = usb_register_bus(&hcd->self); if (retval < 0) goto err7; retval = sl811h_start(hcd); if (retval < 0) goto err8; create_debug_file(sl811); return 0; err8: usb_deregister_bus(&hcd->self); err7: free_irq(hcd->irq, hcd); err6: usb_put_hcd(hcd); err5: iounmap(data_reg); err4: release_mem_region(data->start, 1); err3: iounmap(addr_reg); err2: release_mem_region(addr->start, 1); err1: DBG("init error, %d\n", retval); return retval;}#ifdef CONFIG_PM/* for this device there's no useful distinction between the controller * and its root hub, except that the root hub only gets direct PM calls * when CONFIG_USB_SUSPEND is enabled. */static intsl811h_suspend(struct device *dev, u32 state, u32 phase){ struct sl811 *sl811 = dev_get_drvdata(dev); int retval = 0; if (phase != SUSPEND_POWER_DOWN) return retval; if (state <= PM_SUSPEND_MEM) retval = sl811h_hub_suspend(sl811_to_hcd(sl811)); else port_power(sl811, 0); if (retval == 0) dev->power.power_state = state; return retval;}static intsl811h_resume(struct device *dev, u32 phase){ struct sl811 *sl811 = dev_get_drvdata(dev); if (phase != RESUME_POWER_ON) return 0; /* with no "check to see if VBUS is still powered" board hook, * let's assume it'd only be powered to enable remote wakeup. */ if (dev->power.power_state > PM_SUSPEND_MEM || !sl811_to_hcd(sl811)->can_wakeup) { sl811->port1 = 0; port_power(sl811, 1); return 0; } dev->power.power_state = PM_SUSPEND_ON; return sl811h_hub_resume(sl811_to_hcd(sl811));}#else#define sl811h_suspend NULL#define sl811h_resume NULL#endifstatic struct device_driver sl811h_driver = { .name = (char *) hcd_name, .bus = &platform_bus_type, .probe = sl811h_probe, .remove = sl811h_remove, .suspend = sl811h_suspend, .resume = sl811h_resume,};/*-------------------------------------------------------------------------*/ static int __init sl811h_init(void) { if (usb_disabled()) return -ENODEV; INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION); return driver_register(&sl811h_driver);}module_init(sl811h_init);static void __exit sl811h_cleanup(void) { driver_unregister(&sl811h_driver);}module_exit(sl811h_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -