📄 fsl_usb2_udc.c
字号:
(tmp_reg & USB_FRINDEX_MASKS)); size -= t; next += t; tmp_reg = fsl_readl(&dr_regs->deviceaddr); t = scnprintf(next, size, "USB Device Address Reg:" "Device Addr is 0x%x\n\n", (tmp_reg & USB_DEVICE_ADDRESS_MASK)); size -= t; next += t; tmp_reg = fsl_readl(&dr_regs->endpointlistaddr); t = scnprintf(next, size, "USB Endpoint List Address Reg:" "Device Addr is 0x%x\n\n", (tmp_reg & USB_EP_LIST_ADDRESS_MASK)); size -= t; next += t; tmp_reg = fsl_readl(&dr_regs->portsc1); t = scnprintf(next, size, "USB Port Status&Control Reg:\n" "Port Transceiver Type : %s" "Port Speed: %s \n" "PHY Low Power Suspend: %s" "Port Reset: %s" "Port Suspend Mode: %s \n" "Over-current Change: %s" "Port Enable/Disable Change: %s\n" "Port Enabled/Disabled: %s" "Current Connect Status: %s\n\n", ( { char *s; switch (tmp_reg & PORTSCX_PTS_FSLS) { case PORTSCX_PTS_UTMI: s = "UTMI"; break; case PORTSCX_PTS_ULPI: s = "ULPI "; break; case PORTSCX_PTS_FSLS: s = "FS/LS Serial"; break; default: s = "None"; break; } s;} ), ( { char *s; switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) { case PORTSCX_PORT_SPEED_FULL: s = "Full Speed"; break; case PORTSCX_PORT_SPEED_LOW: s = "Low Speed"; break; case PORTSCX_PORT_SPEED_HIGH: s = "High Speed"; break; default: s = "Undefined"; break; } s; } ), (tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ? "Normal PHY mode" : "Low power mode", (tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" : "Not in Reset", (tmp_reg & PORTSCX_PORT_SUSPEND) ? "In " : "Not in", (tmp_reg & PORTSCX_OVER_CURRENT_CHG) ? "Dected" : "No", (tmp_reg & PORTSCX_PORT_EN_DIS_CHANGE) ? "Disable" : "Not change", (tmp_reg & PORTSCX_PORT_ENABLE) ? "Enable" : "Not correct", (tmp_reg & PORTSCX_CURRENT_CONNECT_STATUS) ? "Attached" : "Not-Att"); size -= t; next += t; tmp_reg = fsl_readl(&dr_regs->usbmode); t = scnprintf(next, size, "USB Mode Reg:" "Controller Mode is : %s\n\n", ( { char *s; switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) { case USB_MODE_CTRL_MODE_IDLE: s = "Idle"; break; case USB_MODE_CTRL_MODE_DEVICE: s = "Device Controller"; break; case USB_MODE_CTRL_MODE_HOST: s = "Host Controller"; break; default: s = "None"; break; } s; } )); size -= t; next += t; tmp_reg = fsl_readl(&dr_regs->endptsetupstat); t = scnprintf(next, size, "Endpoint Setup Status Reg:" "SETUP on ep 0x%x\n\n", (tmp_reg & EP_SETUP_STATUS_MASK)); size -= t; next += t; for (i = 0; i < udc->max_ep / 2; i++) { tmp_reg = fsl_readl(&dr_regs->endptctrl[i]); t = scnprintf(next, size, "EP Ctrl Reg [0x%x]: = [0x%x]\n", i, tmp_reg); size -= t; next += t; } tmp_reg = fsl_readl(&dr_regs->endpointprime); t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n", tmp_reg); size -= t; next += t; tmp_reg = usb_sys_regs->snoop1; t = scnprintf(next, size, "\nSnoop1 Reg : = [0x%x]\n\n", tmp_reg); size -= t; next += t; tmp_reg = usb_sys_regs->control; t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n", tmp_reg); size -= t; next += t; /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */ ep = &udc->eps[0]; t = scnprintf(next, size, "For %s Maxpkt is 0x%x index is 0x%x\n", ep->ep.name, ep_maxpacket(ep), ep_index(ep)); size -= t; next += t; if (list_empty(&ep->queue)) { t = scnprintf(next, size, "its req queue is empty\n\n"); size -= t; next += t; } else { list_for_each_entry(req, &ep->queue, queue) { t = scnprintf(next, size, "req %p actual 0x%x length 0x%x buf %p\n", &req->req, req->req.actual, req->req.length, req->req.buf); size -= t; next += t; } } /* other gadget->eplist ep */ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { if (ep->desc) { t = scnprintf(next, size, "\nFor %s Maxpkt is 0x%x " "index is 0x%x\n", ep->ep.name, ep_maxpacket(ep), ep_index(ep)); size -= t; next += t; if (list_empty(&ep->queue)) { t = scnprintf(next, size, "its req queue is empty\n\n"); size -= t; next += t; } else { list_for_each_entry(req, &ep->queue, queue) { t = scnprintf(next, size, "req %p actual 0x%x length" "0x%x buf %p\n", &req->req, req->req.actual, req->req.length, req->req.buf); size -= t; next += t; } /* end for each_entry of ep req */ } /* end for else */ } /* end for if(ep->queue) */ } /* end (ep->desc) */ spin_unlock_irqrestore(&udc->lock, flags); *eof = 1; return count - size;}#define create_proc_file() create_proc_read_entry(proc_filename, \ 0, NULL, fsl_proc_read, NULL)#define remove_proc_file() remove_proc_entry(proc_filename, NULL)#else /* !CONFIG_USB_GADGET_DEBUG_FILES */#define create_proc_file() do {} while (0)#define remove_proc_file() do {} while (0)#endif /* CONFIG_USB_GADGET_DEBUG_FILES *//*-------------------------------------------------------------------------*//* Release udc structures */static void fsl_udc_release(struct device *dev){ complete(udc_controller->done); dma_free_coherent(dev, udc_controller->ep_qh_size, udc_controller->ep_qh, udc_controller->ep_qh_dma); kfree(udc_controller);}/****************************************************************** Internal structure setup functions*******************************************************************//*------------------------------------------------------------------ * init resource for globle controller * Return the udc handle on success or NULL on failure ------------------------------------------------------------------*/static int __init struct_udc_setup(struct fsl_udc *udc, struct platform_device *pdev){ struct fsl_usb2_platform_data *pdata; size_t size; pdata = pdev->dev.platform_data; udc->phy_mode = pdata->phy_mode; udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); if (!udc->eps) { ERR("malloc fsl_ep failed\n"); return -1; } /* initialized QHs, take care of alignment */ size = udc->max_ep * sizeof(struct ep_queue_head); if (size < QH_ALIGNMENT) size = QH_ALIGNMENT; else if ((size % QH_ALIGNMENT) != 0) { size += QH_ALIGNMENT + 1; size &= ~(QH_ALIGNMENT - 1); } udc->ep_qh = dma_alloc_coherent(&pdev->dev, size, &udc->ep_qh_dma, GFP_KERNEL); if (!udc->ep_qh) { ERR("malloc QHs for udc failed\n"); kfree(udc->eps); return -1; } udc->ep_qh_size = size; /* Initialize ep0 status request structure */ /* FIXME: fsl_alloc_request() ignores ep argument */ udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL), struct fsl_req, req); /* allocate a small amount of memory to get valid address */ udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf); udc->resume_state = USB_STATE_NOTATTACHED; udc->usb_state = USB_STATE_POWERED; udc->ep0_dir = 0; udc->remote_wakeup = 0; /* default to 0 on reset */ spin_lock_init(&udc->lock); return 0;}/*---------------------------------------------------------------- * Setup the fsl_ep struct for eps * Link fsl_ep->ep to gadget->ep_list * ep0out is not used so do nothing here * ep0in should be taken care *--------------------------------------------------------------*/static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, char *name, int link){ struct fsl_ep *ep = &udc->eps[index]; ep->udc = udc; strcpy(ep->name, name); ep->ep.name = ep->name; ep->ep.ops = &fsl_ep_ops; ep->stopped = 0; /* for ep0: maxP defined in desc * for other eps, maxP is set by epautoconfig() called by gadget layer */ ep->ep.maxpacket = (unsigned short) ~0; /* the queue lists any req for this ep */ INIT_LIST_HEAD(&ep->queue); /* gagdet.ep_list used for ep_autoconfig so no ep0 */ if (link) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); ep->gadget = &udc->gadget; ep->qh = &udc->ep_qh[index]; return 0;}/* Driver probe function * all intialization operations implemented here except enabling usb_intr reg * board setup should have been done in the platform code */static int __init fsl_udc_probe(struct platform_device *pdev){ struct resource *res; int ret = -ENODEV; unsigned int i; u32 dccparams; if (strcmp(pdev->name, driver_name)) { VDBG("Wrong device\n"); return -ENODEV; } udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); if (udc_controller == NULL) { ERR("malloc udc failed\n"); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { kfree(udc_controller); return -ENXIO; } if (!request_mem_region(res->start, res->end - res->start + 1, driver_name)) { ERR("request mem region for %s failed \n", pdev->name); kfree(udc_controller); return -EBUSY; } dr_regs = ioremap(res->start, res->end - res->start + 1); if (!dr_regs) { ret = -ENOMEM; goto err1; } usb_sys_regs = (struct usb_sys_interface *) ((u32)dr_regs + USB_DR_SYS_OFFSET); /* Read Device Controller Capability Parameters register */ dccparams = fsl_readl(&dr_regs->dccparams); if (!(dccparams & DCCPARAMS_DC)) { ERR("This SOC doesn't support device role\n"); ret = -ENODEV; goto err2; } /* Get max device endpoints */ /* DEN is bidirectional ep number, max_ep doubles the number */ udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2; udc_controller->irq = platform_get_irq(pdev, 0); if (!udc_controller->irq) { ret = -ENODEV; goto err2; } ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED, driver_name, udc_controller); if (ret != 0) { ERR("cannot request irq %d err %d \n", udc_controller->irq, ret); goto err2; } /* Initialize the udc structure including QH member and other member */ if (struct_udc_setup(udc_controller, pdev)) { ERR("Can't initialize udc data structure\n"); ret = -ENOMEM; goto err3; } /* initialize usb hw reg except for regs for EP, * leave usbintr reg untouched */ dr_controller_setup(udc_controller); /* Setup gadget structure */ udc_controller->gadget.ops = &fsl_gadget_ops; udc_controller->gadget.is_dualspeed = 1; udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; INIT_LIST_HEAD(&udc_controller->gadget.ep_list); udc_controller->gadget.speed = USB_SPEED_UNKNOWN; udc_controller->gadget.name = driver_name; /* Setup gadget.dev and register with kernel */ strcpy(udc_controller->gadget.dev.bus_id, "gadget"); udc_controller->gadget.dev.release = fsl_udc_release; udc_controller->gadget.dev.parent = &pdev->dev; ret = device_register(&udc_controller->gadget.dev); if (ret < 0) goto err3; /* setup QH and epctrl for ep0 */ ep0_setup(udc_controller); /* setup udc->eps[] for ep0 */ struct_ep_setup(udc_controller, 0, "ep0", 0); /* for ep0: the desc defined here; * for other eps, gadget layer called ep_enable with defined desc */ udc_controller->eps[0].desc = &fsl_ep0_desc; udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD; /* setup the udc->eps[] for non-control endpoints and link * to gadget.ep_list */ for (i = 1; i < (int)(udc_controller->max_ep / 2); i++) { char name[14]; sprintf(name, "ep%dout", i); struct_ep_setup(udc_controller, i * 2, name, 1); sprintf(name, "ep%din", i); struct_ep_setup(udc_controller, i * 2 + 1, name, 1); } /* use dma_pool for TD management */ udc_controller->td_pool = dma_pool_create("udc_td", &pdev->dev, sizeof(struct ep_td_struct), DTD_ALIGNMENT, UDC_DMA_BOUNDARY); if (udc_controller->td_pool == NULL) { ret = -ENOMEM; goto err4; } create_proc_file(); return 0;err4: device_unregister(&udc_controller->gadget.dev);err3: free_irq(udc_controller->irq, udc_controller);err2: iounmap(dr_regs);err1: release_mem_region(res->start, res->end - res->start + 1); kfree(udc_controller); return ret;}/* Driver removal function * Free resources and finish pending transactions */static int __exit fsl_udc_remove(struct platform_device *pdev){ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); DECLARE_COMPLETION(done); if (!udc_controller) return -ENODEV; udc_controller->done = &done; /* DR has been stopped in usb_gadget_unregister_driver() */ remove_proc_file(); /* Free allocated memory */ kfree(udc_controller->status_req->req.buf); kfree(udc_controller->status_req); kfree(udc_controller->eps); dma_pool_destroy(udc_controller->td_pool); free_irq(udc_controller->irq, udc_controller); iounmap(dr_regs); release_mem_region(res->start, res->end - res->start + 1); device_unregister(&udc_controller->gadget.dev); /* free udc --wait for the release() finished */ wait_for_completion(&done); return 0;}/*----------------------------------------------------------------- * Modify Power management attributes * Used by OTG statemachine to disable gadget temporarily -----------------------------------------------------------------*/static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state){ dr_controller_stop(udc_controller); return 0;}/*----------------------------------------------------------------- * Invoked on USB resume. May be called in_interrupt. * Here we start the DR controller and enable the irq *-----------------------------------------------------------------*/static int fsl_udc_resume(struct platform_device *pdev){ /* Enable DR irq reg and set controller Run */ if (udc_controller->stopped) { dr_controller_setup(udc_controller); dr_controller_run(udc_controller); } udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_state = WAIT_FOR_SETUP; udc_controller->e
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -