📄 dwc_otg_pcd.c
字号:
srp_timer->expires = jiffies + (HZ * 6); add_timer(srp_timer);}/** * Tasklet * */extern void start_next_request(dwc_otg_pcd_ep_t * _ep);static void start_xfer_tasklet_func(unsigned long data){ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data; dwc_otg_core_if_t *core_if = pcd->otg_dev->core_if; int i; depctl_data_t diepctl; DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n"); diepctl.d32 = dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl); if (pcd->ep0.queue_sof) { pcd->ep0.queue_sof = 0; start_next_request(&pcd->ep0); // break; } for (i = 0; i < core_if->dev_if->num_in_eps; i++) { depctl_data_t diepctl; diepctl.d32 = dwc_read_reg32(&core_if->dev_if->in_ep_regs[i]->diepctl); if (pcd->in_ep[i].queue_sof) { pcd->in_ep[i].queue_sof = 0; start_next_request(&pcd->in_ep[i]); // break; } } return;}static struct tasklet_struct start_xfer_tasklet = { .next = NULL, .state = 0, .count = ATOMIC_INIT(0), .func = start_xfer_tasklet_func, .data = 0,};/** * This function initialized the pcd Dp structures to there default * state. * * @param _pcd the pcd structure. */void dwc_otg_pcd_reinit(dwc_otg_pcd_t * _pcd){ static const char *names[] = { "ep0", "ep1in", "ep2in", "ep3in", "ep4in", "ep5in", "ep6in", "ep7in", "ep8in", "ep9in", "ep10in", "ep11in", "ep12in", "ep13in", "ep14in", "ep15in", "ep1out", "ep2out", "ep3out", "ep4out", "ep5out", "ep6out", "ep7out", "ep8out", "ep9out", "ep10out", "ep11out", "ep12out", "ep13out", "ep14out", "ep15out" }; int i; int in_ep_cntr, out_ep_cntr; uint32_t hwcfg1; uint32_t num_in_eps = (GET_CORE_IF(_pcd))->dev_if->num_in_eps; uint32_t num_out_eps = (GET_CORE_IF(_pcd))->dev_if->num_out_eps; dwc_otg_pcd_ep_t *ep; DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd); INIT_LIST_HEAD(&_pcd->gadget.ep_list); _pcd->gadget.ep0 = &_pcd->ep0.ep; _pcd->gadget.speed = USB_SPEED_UNKNOWN; INIT_LIST_HEAD(&_pcd->gadget.ep0->ep_list); /** * Initialize the EP0 structure. */ ep = &_pcd->ep0; /* Init EP structure */ ep->desc = 0; ep->pcd = _pcd; ep->stopped = 1; /* Init DWC ep structure */ ep->dwc_ep.num = 0; ep->dwc_ep.active = 0; ep->dwc_ep.tx_fifo_num = 0; /* Control until ep is actvated */ ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL; ep->dwc_ep.maxpacket = MAX_PACKET_SIZE; ep->dwc_ep.dma_addr = 0; ep->dwc_ep.start_xfer_buff = 0; ep->dwc_ep.xfer_buff = 0; ep->dwc_ep.xfer_len = 0; ep->dwc_ep.xfer_count = 0; ep->dwc_ep.sent_zlp = 0; ep->dwc_ep.total_len = 0; ep->queue_sof = 0; /* Init the usb_ep structure. */ ep->ep.name = names[0]; ep->ep.ops = (struct usb_ep_ops *) &dwc_otg_pcd_ep_ops; /** * @todo NGS: What should the max packet size be set to * here? Before EP type is set? */ ep->ep.maxpacket = MAX_PACKET_SIZE; list_add_tail(&ep->ep.ep_list, &_pcd->gadget.ep_list); INIT_LIST_HEAD(&ep->queue); /** * Initialize the EP structures. */ in_ep_cntr = 0; hwcfg1 = (GET_CORE_IF(_pcd))->hwcfg1.d32 >> 3; for (i = 1; in_ep_cntr < num_in_eps; i++) { if ((hwcfg1 & 0x1) == 0) { dwc_otg_pcd_ep_t *ep = &_pcd->in_ep[in_ep_cntr]; in_ep_cntr++; /* Init EP structure */ ep->desc = 0; ep->pcd = _pcd; ep->stopped = 1; /* Init DWC ep structure */ ep->dwc_ep.is_in = 1; ep->dwc_ep.num = i; ep->dwc_ep.active = 0; ep->dwc_ep.tx_fifo_num = 0; /* Control until ep is actvated */ ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL; ep->dwc_ep.maxpacket = MAX_PACKET_SIZE; ep->dwc_ep.dma_addr = 0; ep->dwc_ep.start_xfer_buff = 0; ep->dwc_ep.xfer_buff = 0; ep->dwc_ep.xfer_len = 0; ep->dwc_ep.xfer_count = 0; ep->dwc_ep.sent_zlp = 0; ep->dwc_ep.total_len = 0; ep->queue_sof = 0; /* Init the usb_ep structure. */ /** * @todo NGS: Add direction to EP, based on contents * of HWCFG1. Need a copy of HWCFG1 in pcd structure? * sprintf( ";r */ ep->ep.name = names[i]; ep->ep.ops = (struct usb_ep_ops *) &dwc_otg_pcd_ep_ops; /** * @todo NGS: What should the max packet size be set to * here? Before EP type is set? */ ep->ep.maxpacket = MAX_PACKET_SIZE; list_add_tail(&ep->ep.ep_list, &_pcd->gadget.ep_list); INIT_LIST_HEAD(&ep->queue); } hwcfg1 >>= 2; } out_ep_cntr = 0; hwcfg1 = (GET_CORE_IF(_pcd))->hwcfg1.d32 >> 2; for (i = 1; out_ep_cntr < num_out_eps; i++) { if ((hwcfg1 & 0x1) == 0) { dwc_otg_pcd_ep_t *ep = &_pcd->out_ep[out_ep_cntr]; out_ep_cntr++; /* Init EP structure */ ep->desc = 0; ep->pcd = _pcd; ep->stopped = 1; /* Init DWC ep structure */ ep->dwc_ep.is_in = 0; ep->dwc_ep.num = i; ep->dwc_ep.active = 0; ep->dwc_ep.tx_fifo_num = 0; /* Control until ep is actvated */ ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL; ep->dwc_ep.maxpacket = MAX_PACKET_SIZE; ep->dwc_ep.dma_addr = 0; ep->dwc_ep.start_xfer_buff = 0; ep->dwc_ep.xfer_buff = 0; ep->dwc_ep.xfer_len = 0; ep->dwc_ep.xfer_count = 0; ep->dwc_ep.sent_zlp = 0; ep->dwc_ep.total_len = 0; ep->queue_sof = 0; /* Init the usb_ep structure. */ /** * @todo NGS: Add direction to EP, based on contents * of HWCFG1. Need a copy of HWCFG1 in pcd structure? * sprintf( ";r */ ep->ep.name = names[15 + i]; ep->ep.ops = (struct usb_ep_ops *) &dwc_otg_pcd_ep_ops; /** * @todo NGS: What should the max packet size be set to * here? Before EP type is set? */ ep->ep.maxpacket = MAX_PACKET_SIZE; list_add_tail(&ep->ep.ep_list, &_pcd->gadget.ep_list); INIT_LIST_HEAD(&ep->queue); } hwcfg1 >>= 2; } /* remove ep0 from the list. There is a ep0 pointer. */ list_del_init(&_pcd->ep0.ep.ep_list); _pcd->ep0state = EP0_DISCONNECT; _pcd->ep0.ep.maxpacket = MAX_EP0_SIZE; _pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE; _pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;}/** * This function releases the Gadget device. * required by device_unregister(). * * @todo Should this do something? Should it free the PCD? */static void dwc_otg_pcd_gadget_release(struct device *_dev){ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);}/** * This function initialized the PCD portion of the driver. * */int dwc_otg_pcd_init(struct lm_device *_lmdev){ static char pcd_name[] = "dwc_otg_pcd"; dwc_otg_pcd_t *pcd; dwc_otg_core_if_t *core_if; dwc_otg_dev_if_t *dev_if; dwc_otg_device_t *otg_dev = lm_get_drvdata(_lmdev); int retval = 0; DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _lmdev); /* * Allocate PCD structure */ pcd = kmalloc(sizeof(dwc_otg_pcd_t), GFP_KERNEL); if (pcd == 0) { return -ENOMEM; } memset(pcd, 0, sizeof(dwc_otg_pcd_t)); spin_lock_init(&pcd->lock); otg_dev->pcd = pcd; s_pcd = pcd; pcd->gadget.name = pcd_name; strcpy(pcd->gadget.dev.bus_id, "gadget"); pcd->otg_dev = lm_get_drvdata(_lmdev); pcd->gadget.dev.parent = &_lmdev->dev; pcd->gadget.dev.release = dwc_otg_pcd_gadget_release; pcd->gadget.ops = &dwc_otg_pcd_ops; core_if = GET_CORE_IF(pcd); dev_if = core_if->dev_if; if (core_if->hwcfg4.b.ded_fifo_en) { DWC_PRINT("Dedicated Tx FIFOs mode\n"); } else { DWC_PRINT("Shared Tx FIFO mode\n"); } /* If the module is set to FS or if the PHY_TYPE is FS then the gadget * should not report as dual-speed capable. replace the following line * with the block of code below it once the software is debugged for * this. If is_dualspeed = 0 then the gadget driver should not report * a device qualifier descriptor when queried. */ if ((GET_CORE_IF(pcd)->core_params->speed == DWC_SPEED_PARAM_FULL) || ((GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type == 2) && (GET_CORE_IF(pcd)->hwcfg2.b.fs_phy_type == 1) && (GET_CORE_IF(pcd)->core_params->ulpi_fs_ls))) { pcd->gadget.is_dualspeed = 0; } else { pcd->gadget.is_dualspeed = 1; } if ((otg_dev->core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE) || (otg_dev->core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST) || (otg_dev->core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || (otg_dev->core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) { pcd->gadget.is_otg = 0; } else { pcd->gadget.is_otg = 1; } pcd->driver = 0; /* Register the gadget device */ device_register(&pcd->gadget.dev); /* * Initialized the Core for Device mode. */ if (dwc_otg_is_device_mode(core_if)) { dwc_otg_core_dev_init(core_if); } /* * Initialize EP structures */ dwc_otg_pcd_reinit(pcd); /* * Register the PCD Callbacks. */ dwc_otg_cil_register_pcd_callbacks(otg_dev->core_if, &pcd_callbacks, pcd); /* * Setup interupt handler */ DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", _lmdev->irq); retval = request_irq(_lmdev->irq, dwc_otg_pcd_irq, SA_SHIRQ, pcd->gadget.name, pcd); if (retval != 0) { DWC_ERROR("request of irq%d failed\n", _lmdev->irq); kfree(pcd); return -EBUSY; } /* * Initialize the DMA buffer for SETUP packets */ if (GET_CORE_IF(pcd)->dma_enable) { pcd->setup_pkt = dma_alloc_coherent(NULL, sizeof(*pcd->setup_pkt) * 5, &pcd->setup_pkt_dma_handle, 0); pcd->status_buf = dma_alloc_coherent(NULL, sizeof(uint16_t), &pcd->status_buf_dma_handle, 0); if (GET_CORE_IF(pcd)->dma_desc_enable) { dev_if->setup_desc_addr[0] = ep_alloc_desc(&dev_if->dma_setup_desc_addr[0]); dev_if->setup_desc_addr[1] = ep_alloc_desc(&dev_if->dma_setup_desc_addr[1]); dev_if->in_desc_addr = ep_alloc_desc(&dev_if->dma_in_desc_addr); dev_if->out_desc_addr = ep_alloc_desc(&dev_if->dma_out_desc_addr); } } else { pcd->setup_pkt = kmalloc(sizeof(*pcd->setup_pkt) * 5, GFP_KERNEL); pcd->status_buf = kmalloc(sizeof(uint16_t), GFP_KERNEL); } if (pcd->setup_pkt == 0) { kfree(pcd); return -ENOMEM; } /* Initialize tasklet */ start_xfer_tasklet.data = (unsigned long) pcd; pcd->start_xfer_tasklet = &start_xfer_tasklet; return 0;}/** * Cleanup the PCD. */void dwc_otg_pcd_remove(struct lm_device *_lmdev){ dwc_otg_device_t *otg_dev = lm_get_drvdata(_lmdev); dwc_otg_pcd_t *pcd = otg_dev->pcd; dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if; DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _lmdev); /* * Free the IRQ */ free_irq(_lmdev->irq, pcd); /* start with the driver above us */ if (pcd->driver) { /* should have been done already by driver model core */ DWC_WARN("driver '%s' is still registered\n", pcd->driver->driver.name); usb_gadget_unregister_driver(pcd->driver); } device_unregister(&pcd->gadget.dev); if (GET_CORE_IF(pcd)->dma_enable) { dma_free_coherent(NULL, sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt, pcd->setup_pkt_dma_handle); dma_free_coherent(NULL, sizeof(uint16_t), pcd->status_buf, pcd->status_buf_dma_handle); if (GET_CORE_IF(pcd)->dma_desc_enable) { ep_free_desc(dev_if->setup_desc_addr[0], dev_if->dma_setup_desc_addr[0]); ep_free_desc(dev_if->setup_desc_addr[1], dev_if->dma_setup_desc_addr[1]); ep_free_desc(dev_if->in_desc_addr, dev_if->dma_in_desc_addr); ep_free_desc(dev_if->out_desc_addr, dev_if->dma_out_desc_addr); } } else { kfree(pcd->setup_pkt); kfree(pcd->status_buf); } kfree(pcd); otg_dev->pcd = 0;}/** * This function registers a gadget driver with the PCD. * * When a driver is successfully registered, it will receive control * requests including set_configuration(), which enables non-control * requests. then usb traffic follows until a disconnect is reported. * then a host may connect again, or the driver might get unbound. * * @param _driver The driver being registered */int usb_gadget_register_driver(struct usb_gadget_driver *_driver){ int retval; DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n", _driver->driver.name); if (!_driver || _driver->speed == USB_SPEED_UNKNOWN || !_driver->bind || !_driver->unbind || !_driver->disconnect || !_driver->setup) { DWC_DEBUGPL(DBG_PCDV, "EINVAL\n"); return -EINVAL; } if (s_pcd == 0) { DWC_DEBUGPL(DBG_PCDV, "ENODEV\n"); return -ENODEV; } if (s_pcd->driver != 0) { DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", s_pcd->driver); return -EBUSY; } /* hook up the driver */ s_pcd->driver = _driver; s_pcd->gadget.dev.driver = &_driver->driver; DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", _driver->driver.name); retval = _driver->bind(&s_pcd->gadget); if (retval) { DWC_ERROR("bind to driver %s --> error %d\n", _driver->driver.name, retval); s_pcd->driver = 0; s_pcd->gadget.dev.driver = 0; return retval; } DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n", _driver->driver.name); return 0;}EXPORT_SYMBOL(usb_gadget_register_driver);/** * This function unregisters a gadget driver * * @param _driver The driver being unregistered */int usb_gadget_unregister_driver(struct usb_gadget_driver *_driver){ //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver); if (s_pcd == 0) { DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__, -ENODEV); return -ENODEV; } if (_driver == 0 || _driver != s_pcd->driver) { DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__, -EINVAL); return -EINVAL; } _driver->unbind(&s_pcd->gadget); s_pcd->driver = 0; DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", _driver->driver.name); return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);#endif /* DWC_HOST_ONLY */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -