?? sl811-hcd.c
字號:
(mask & SL11H_INTMASK_DONE_B) ? " done_b" : "", (mask & SL11H_INTMASK_SOFINTR) ? " sof" : "", (mask & SL11H_INTMASK_INSRMV) ? " ins/rmv" : "", (mask & SL11H_INTMASK_RD) ? " rd" : "", (mask & SL11H_INTMASK_DP) ? " dp" : "");}static int proc_sl811h_show(struct seq_file *s, void *unused){ struct sl811 *sl811 = s->private; struct sl811h_ep *ep; unsigned i; seq_printf(s, "%s\n%s version %s\nportstatus[1] = %08x\n", sl811_to_hcd(sl811)->product_desc, hcd_name, DRIVER_VERSION, sl811->port1); seq_printf(s, "insert/remove: %ld\n", sl811->stat_insrmv); seq_printf(s, "current session: done_a %ld done_b %ld " "wake %ld sof %ld overrun %ld lost %ld\n\n", sl811->stat_a, sl811->stat_b, sl811->stat_wake, sl811->stat_sof, sl811->stat_overrun, sl811->stat_lost); 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 const 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); /* chip has been reset, VBUS power is off */ hcd->state = HC_STATE_RUNNING; if (sl811->board) { if (!device_can_wakeup(hcd->self.controller)) device_init_wakeup(hcd->self.controller, sl811->board->can_wakeup); hcd->power_budget = sl811->board->power * 2; } /* enable power and interupts */ port_power(sl811, 1); return 0;}/*-------------------------------------------------------------------------*/static struct hc_driver sl811h_hc_driver = { .description = hcd_name, .hcd_priv_size = sizeof(struct sl811), /* * generic hardware linkage */ .irq = sl811h_irq, .flags = HCD_USB11 | HCD_MEMORY, /* Basic lifecycle operations */ .start = sl811h_start, .stop = sl811h_stop, /* * 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, .bus_suspend = sl811h_bus_suspend, .bus_resume = sl811h_bus_resume,};/*-------------------------------------------------------------------------*/static int __devexitsl811h_remove(struct platform_device *dev){ struct usb_hcd *hcd = platform_get_drvdata(dev); struct sl811 *sl811 = hcd_to_sl811(hcd); struct resource *res; remove_debug_file(sl811); usb_remove_hcd(hcd); /* some platforms may use IORESOURCE_IO */ res = platform_get_resource(dev, IORESOURCE_MEM, 1); if (res) iounmap(sl811->data_reg); res = platform_get_resource(dev, IORESOURCE_MEM, 0); if (res) iounmap(sl811->addr_reg); usb_put_hcd(hcd); return 0;}static int __devinitsl811h_probe(struct platform_device *dev){ struct usb_hcd *hcd; struct sl811 *sl811; struct resource *addr, *data; int irq; void __iomem *addr_reg; void __iomem *data_reg; int retval; u8 tmp, ioaddr = 0; /* 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. */ irq = platform_get_irq(dev, 0); if (dev->num_resources < 3 || irq < 0) return -ENODEV; /* refuse to confuse usbcore */ if (dev->dev.dma_mask) { DBG("no we won't dma\n"); return -EINVAL; } /* the chip may be wired for either kind of addressing */ addr = platform_get_resource(dev, IORESOURCE_MEM, 0); data = platform_get_resource(dev, IORESOURCE_MEM, 1); retval = -EBUSY; if (!addr || !data) { addr = platform_get_resource(dev, IORESOURCE_IO, 0); data = platform_get_resource(dev, IORESOURCE_IO, 1); if (!addr || !data) return -ENODEV; ioaddr = 1; /* * NOTE: 64-bit resource->start is getting truncated * to avoid compiler warning, assuming that ->start * is always 32-bit for this case */ addr_reg = (void __iomem *) (unsigned long) addr->start; data_reg = (void __iomem *) (unsigned long) data->start; } else { addr_reg = ioremap(addr->start, 1); if (addr_reg == NULL) { retval = -ENOMEM; goto err2; } data_reg = ioremap(data->start, 1); if (data_reg == NULL) { retval = -ENOMEM; goto err4; } } /* allocate and initialize hcd */ hcd = usb_create_hcd(&sl811h_hc_driver, &dev->dev, dev->dev.bus_id); if (!hcd) { retval = -ENOMEM; goto err5; } hcd->rsrc_start = addr->start; sl811 = hcd_to_sl811(hcd); spin_lock_init(&sl811->lock); INIT_LIST_HEAD(&sl811->async); sl811->board = dev->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; } /* The chip's IRQ is level triggered, active high. A requirement * for platform device setup is to cope with things like signal * inverters (e.g. CF is active low) or working only with edge * triggers (e.g. most ARM CPUs). Initial driver stress testing * was on a system with single edge triggering, so most sorts of * triggering arrangement should work. */ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) goto err6; create_debug_file(sl811); return retval; err6: usb_put_hcd(hcd); err5: if (!ioaddr) iounmap(data_reg); err4: if (!ioaddr) iounmap(addr_reg); err2: 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 platform_device *dev, pm_message_t state){ struct usb_hcd *hcd = platform_get_drvdata(dev); struct sl811 *sl811 = hcd_to_sl811(hcd); int retval = 0; switch (state.event) { case PM_EVENT_FREEZE: retval = sl811h_bus_suspend(hcd); break; case PM_EVENT_SUSPEND: case PM_EVENT_PRETHAW: /* explicitly discard hw state */ port_power(sl811, 0); break; } if (retval == 0) dev->dev.power.power_state = state; return retval;}static intsl811h_resume(struct platform_device *dev){ struct usb_hcd *hcd = platform_get_drvdata(dev); struct sl811 *sl811 = hcd_to_sl811(hcd); /* 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->dev.power.power_state.event == PM_EVENT_SUSPEND || !device_can_wakeup(&hcd->self.root_hub->dev)) { sl811->port1 = 0; port_power(sl811, 1); usb_root_hub_lost_power(hcd->self.root_hub); return 0; } dev->dev.power.power_state = PMSG_ON; return sl811h_bus_resume(hcd);}#else#define sl811h_suspend NULL#define sl811h_resume NULL#endif/* this driver is exported so sl811_cs can depend on it */struct platform_driver sl811h_driver = { .probe = sl811h_probe, .remove = __devexit_p(sl811h_remove), .suspend = sl811h_suspend, .resume = sl811h_resume, .driver = { .name = (char *) hcd_name, .owner = THIS_MODULE, },};EXPORT_SYMBOL(sl811h_driver);/*-------------------------------------------------------------------------*/static int __init sl811h_init(void){ if (usb_disabled()) return -ENODEV; INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION); return platform_driver_register(&sl811h_driver);}module_init(sl811h_init);static void __exit sl811h_cleanup(void){ platform_driver_unregister(&sl811h_driver);}module_exit(sl811h_cleanup);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -