📄 dwc_otg_pcd_intr.c
字号:
#endif dcfg.b.devaddr = ctrl.wValue; dwc_modify_reg32( &dev_if->dev_global_regs->dcfg, 0, dcfg.d32); do_setup_in_status_phase( _pcd ); }}/** * This function processes SETUP commands. In Linux, the USB Command * processing is done in two places - the first being the PCD and the * second in the Gadget Driver (for example, the File-Backed Storage * Gadget Driver). * * <table> * <tr><td>Command </td><td>Driver </td><td>Description</td></tr> * * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as * defined in chapter 9 of the USB 2.0 Specification chapter 9 * </td></tr> * * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint * requests are the ENDPOINT_HALT feature is procesed, all others the * interface requests are ignored.</td></tr> * * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint * requests are processed by the PCD. Interface requests are passed * to the Gadget Driver.</td></tr> * * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg, * with device address received </td></tr> * * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the * requested descriptor</td></tr> * * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional - * not implemented by any of the existing Gadget Drivers.</td></tr> * * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable * all EPs and enable EPs for new configuration.</td></tr> * * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return * the current configuration</td></tr> * * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all * EPs and enable EPs for new configuration.</td></tr> * * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the * current interface.</td></tr> * * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug * message.</td></tr> * </table> * * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are * processed by pcd_setup. Calling the Function Driver's setup function from * pcd_setup processes the gadget SETUP commands. */static inline void pcd_setup( dwc_otg_pcd_t *_pcd ){ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd); dwc_otg_dev_if_t *dev_if = core_if->dev_if; struct usb_ctrlrequest ctrl = _pcd->setup_pkt->req; dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0; deptsiz0_data_t doeptsize0 = { .d32 = 0};#ifdef DEBUG_EP0 DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n", ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, ctrl.wIndex, ctrl.wLength);#endif doeptsize0.d32 = dwc_read_reg32( &dev_if->out_ep_regs[0]->doeptsiz ); /** @todo handle > 1 setup packet , assert error for now */ if (core_if->dma_enable && core_if->dma_desc_enable == 0 && (doeptsize0.b.supcnt < 2)) { DWC_ERROR ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n"); } /* Clean up the request queue */ request_nuke( ep0 ); ep0->stopped = 0; if (ctrl.bRequestType & USB_DIR_IN) { ep0->dwc_ep.is_in = 1; _pcd->ep0state = EP0_IN_DATA_PHASE; } else { ep0->dwc_ep.is_in = 0; _pcd->ep0state = EP0_OUT_DATA_PHASE; } if(ctrl.wLength == 0) { ep0->dwc_ep.is_in = 1; _pcd->ep0state = EP0_IN_STATUS_PHASE; } if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) { /* handle non-standard (class/vendor) requests in the gadget driver */ do_gadget_setup(_pcd, &ctrl ); return; } /** @todo NGS: Handle bad setup packet? *//////////////////////////////////////////////// --- Standard Request handling --- //// switch (ctrl.bRequest) { case USB_REQ_GET_STATUS: do_get_status( _pcd); break; case USB_REQ_CLEAR_FEATURE: do_clear_feature( _pcd ); break; case USB_REQ_SET_FEATURE: do_set_feature( _pcd ); break; case USB_REQ_SET_ADDRESS: do_set_address( _pcd ); break; case USB_REQ_SET_INTERFACE: case USB_REQ_SET_CONFIGURATION:// _pcd->request_config = 1; /* Configuration changed */ do_gadget_setup(_pcd, &ctrl ); break; case USB_REQ_SYNCH_FRAME: do_gadget_setup(_pcd, &ctrl ); break; default: /* Call the Gadget Driver's setup functions */ do_gadget_setup(_pcd, &ctrl ); break; }}/** * This function completes the ep0 control transfer. */static int32_t ep0_complete_request( dwc_otg_pcd_ep_t *_ep ){ dwc_otg_core_if_t *core_if = GET_CORE_IF(_ep->pcd); dwc_otg_dev_if_t *dev_if = core_if->dev_if; dwc_otg_dev_in_ep_regs_t *in_ep_regs = dev_if->in_ep_regs[_ep->dwc_ep.num];#ifdef DEBUG_EP0 dwc_otg_dev_out_ep_regs_t *out_ep_regs = dev_if->out_ep_regs[_ep->dwc_ep.num];#endif deptsiz0_data_t deptsiz; desc_sts_data_t desc_sts; dwc_otg_pcd_request_t *req; int is_last = 0; dwc_otg_pcd_t *pcd = _ep->pcd; //DWC_DEBUGPL(DBG_PCDV, "%s() %s\n", __func__, _ep->ep.name); if (pcd->ep0_pending && list_empty(&_ep->queue)) { if (_ep->dwc_ep.is_in) {#ifdef DEBUG_EP0 DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");#endif do_setup_out_status_phase(pcd); } else {#ifdef DEBUG_EP0 DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");#endif do_setup_in_status_phase(pcd); } pcd->ep0_pending = 0; return 1; } if (list_empty(&_ep->queue)) { return 0; } req = list_entry(_ep->queue.next, dwc_otg_pcd_request_t, queue); if (pcd->ep0state == EP0_OUT_STATUS_PHASE || pcd->ep0state == EP0_IN_STATUS_PHASE) { is_last = 1; } else if (_ep->dwc_ep.is_in) { deptsiz.d32 = dwc_read_reg32( &in_ep_regs->dieptsiz); if(core_if->dma_desc_enable != 0) desc_sts.d32 = readl(dev_if->in_desc_addr);#ifdef DEBUG_EP0 DWC_DEBUGPL(DBG_PCDV, "%s len=%d xfersize=%d pktcnt=%d\n", _ep->ep.name, _ep->dwc_ep.xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);#endif if (((core_if->dma_desc_enable == 0) && (deptsiz.b.xfersize == 0)) || ((core_if->dma_desc_enable != 0) && (desc_sts.b.bytes == 0))) { req->req.actual = _ep->dwc_ep.xfer_count; /* Is a Zero Len Packet needed? */ if (req->req.zero) {#ifdef DEBUG_EP0 DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");#endif req->req.zero = 0; } do_setup_out_status_phase(pcd); } } else { /* ep0-OUT */#ifdef DEBUG_EP0 deptsiz.d32 = dwc_read_reg32( &out_ep_regs->doeptsiz); DWC_DEBUGPL(DBG_PCDV, "%s len=%d xsize=%d pktcnt=%d\n", _ep->ep.name, _ep->dwc_ep.xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);#endif req->req.actual = _ep->dwc_ep.xfer_count; /* Is a Zero Len Packet needed? */ if (req->req.zero) {#ifdef DEBUG_EP0 DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");#endif req->req.zero = 0; } if(core_if->dma_desc_enable == 0) do_setup_in_status_phase(pcd); } /* Complete the request */ if (is_last) { request_done(_ep, req, 0); _ep->dwc_ep.start_xfer_buff = 0; _ep->dwc_ep.xfer_buff = 0; _ep->dwc_ep.xfer_len = 0; return 1; } return 0;}/** * This function completes the request for the EP. If there are * additional requests for the EP in the queue they will be started. */static void complete_ep( dwc_otg_pcd_ep_t *_ep ){ dwc_otg_core_if_t *core_if = GET_CORE_IF(_ep->pcd); dwc_otg_dev_if_t *dev_if = core_if->dev_if; dwc_otg_dev_in_ep_regs_t *in_ep_regs = dev_if->in_ep_regs[_ep->dwc_ep.num]; deptsiz_data_t deptsiz; desc_sts_data_t desc_sts; dwc_otg_pcd_request_t *req = 0; int is_last = 0; DWC_DEBUGPL(DBG_PCDV,"%s() %s-%s\n", __func__, _ep->ep.name, (_ep->dwc_ep.is_in?"IN":"OUT")); /* Get any pending requests */ if (!list_empty(&_ep->queue)) { req = list_entry(_ep->queue.next, dwc_otg_pcd_request_t, queue); if (!req) { printk("complete_ep 0x%p, req = NULL!\n", _ep); return; } } else { printk("complete_ep 0x%p, ep->queue empty!\n", _ep); return; } DWC_DEBUGPL(DBG_PCD, "Requests %d\n",_ep->pcd->request_pending); if (_ep->dwc_ep.is_in) { deptsiz.d32 = dwc_read_reg32( &in_ep_regs->dieptsiz); if(core_if->dma_desc_enable != 0) desc_sts.d32 = readl(_ep->dwc_ep.desc_addr); if (core_if->dma_enable) { if(core_if->dma_desc_enable == 0) { if (deptsiz.b.xfersize == 0) _ep->dwc_ep.xfer_count = _ep->dwc_ep.xfer_len; DWC_DEBUGPL(DBG_PCDV, "%s len=%d xfersize=%d pktcnt=%d\n", _ep->ep.name, _ep->dwc_ep.xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt); if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0 && _ep->dwc_ep.xfer_count == _ep->dwc_ep.xfer_len) { is_last = 1; } else { DWC_WARN("Incomplete transfer (%s-%s [siz=%d pkt=%d])\n", _ep->ep.name, (_ep->dwc_ep.is_in?"IN":"OUT"), deptsiz.b.xfersize, deptsiz.b.pktcnt); } } else { if(desc_sts.b.bytes == 0) { _ep->dwc_ep.xfer_count = _ep->dwc_ep.xfer_len; is_last = 1; } else { DWC_WARN("Incomplete transfer\n"); } } } else { DWC_DEBUGPL(DBG_PCDV, "%s len=%d xfersize=%d pktcnt=%d\n", _ep->ep.name, _ep->dwc_ep.xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt); if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0 && _ep->dwc_ep.xfer_count == _ep->dwc_ep.xfer_len) { is_last = 1; } else { DWC_WARN("Incomplete transfer (%s-%s [siz=%d pkt=%d])\n", _ep->ep.name, (_ep->dwc_ep.is_in?"IN":"OUT"), deptsiz.b.xfersize, deptsiz.b.pktcnt); } } } else { dwc_otg_dev_out_ep_regs_t *out_ep_regs = dev_if->out_ep_regs[_ep->dwc_ep.num]; desc_sts.d32 = 0; if(core_if->dma_desc_enable != 0) desc_sts.d32 = readl(_ep->dwc_ep.desc_addr); deptsiz.d32 = 0; deptsiz.d32 = dwc_read_reg32( &out_ep_regs->doeptsiz);#ifdef DEBUG DWC_DEBUGPL(DBG_PCDV, "addr %p, %s len=%d cnt=%d xsize=%d pktcnt=%d\n", &out_ep_regs->doeptsiz, _ep->ep.name, _ep->dwc_ep.xfer_len, _ep->dwc_ep.xfer_count, deptsiz.b.xfersize, deptsiz.b.pktcnt);#endif is_last = 1; } /* Complete the request */ if (is_last) { if (core_if->dma_enable) { if(core_if->dma_desc_enable == 0) { req->req.actual = _ep->dwc_ep.xfer_len - deptsiz.b.xfersize; } else { req->req.actual = _ep->dwc_ep.xfer_len - desc_sts.b.bytes; } } else { req->req.actual = _ep->dwc_ep.xfer_count; } request_done(_ep, req, 0); _ep->dwc_ep.start_xfer_buff = 0; _ep->dwc_ep.xfer_buff = 0; _ep->dwc_ep.xfer_len = 0; /* If there is a request in the queue start it.*/ start_next_request( _ep ); }}#ifdef _EN_ISOC_void make_descriptors_host_ready(dwc_otg_iso_dma_desc_t *dma_desc,int count,int is_in){ int i; if(is_in){ iso_in_sts_data_t sts = {.d32 = 0}; for(i = 0;i < count;++i,++dma_desc){ sts.d32 = readl(&dma_desc->status); sts.b.bs = BS_HOST_READY; writel(sts.d32,&dma_desc->status); } }else{ iso_out_sts_data_t sts = {.d32 = 0}; for(i = 0;i < count;++i,++dma_desc){ sts.d32 = readl(&dma_desc->status); sts.b.bs = BS_HOST_READY; writel(sts.d32,&dma_desc->status); } }}/** * This function is called when Transfer complete interrupt is asserted * for ISO EP. It provides the Gadget driver the data buffer already * processed by PCD and makes some setup for further processing of * periodic transfers */static void process_iso_data_buf( dwc_otg_pcd_ep_t *_ep ){ int i, j; dwc_ep_t *dwc_ep = &_ep->dwc_ep; dwc_otg_iso_dma_desc_t* dma_desc; dma_addr_t dma_ad; volatile uint32_t *addr; dwc_otg_pcd_t *pcd = _ep->pcd; depctl_data_t depctl = {.d32 = 0}; dwc_otg_core_if_t *core_if; if(_ep->iso_req->status == -ECONNRESET){ DWC_PRINT("Device has already disconnected\n"); /*Device has been disconnected*/ return; } if(dwc_ep->is_in == 0){ addr = &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->doepctl; }else{ addr = &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl; } /* * Core has disabled epena bit. * To continue transfers we need to enable it. */ depctl.d32 = dwc_read_reg32(addr); //depctl.b.epena = 1; //dwc_write_reg32(addr,depctl.d32); core_if = GET_CORE_IF(pcd); /** Reinit closed DMA Descriptors*/ if(dwc_ep->is_in == 0) /** ISO OUT EP */ { iso_out_sts_data_t sts = { .d32 =0 }; iso_out_sts_data_t stsTmp = {.d32 = 0}; uint32_t data_per_desc; struct usb_gadget_iso_packet_descriptor *iso_packet; if(dwc_ep->proc_buf_num == 0) { /** Buffer 0 descriptors setup */ dma_ad = dwc_ep->dma_addr0; iso_packet = _ep->iso_req->iso_packet_desc0; } else { /** Buffer 1 descriptors setup */ dma_ad = dwc_ep->dma_addr1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -