/** * @brief DCD_HandleRxStatusQueueLevel_ISR * Handles the Rx Status Queue Level Interrupt * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleRxStatusQueueLevel_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTMSK_TypeDef int_mask; USB_OTG_DRXSTS_TypeDef status; USB_OTG_EP *ep; /* Disable the Rx Status Queue Level interrupt */ int_mask.d32 = 0; int_mask.b.rxstsqlvl = 1; USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, int_mask.d32, 0); /* Get the Status from the top of the FIFO */ status.d32 = USB_OTG_READ_REG32( &pdev->regs.GREGS->GRXSTSP ); ep = &pdev->dev.out_ep[status.b.epnum]; switch (status.b.pktsts) { case STS_GOUT_NAK: break; case STS_DATA_UPDT: if (status.b.bcnt) { USB_OTG_ReadPacket(pdev,ep->xfer_buff, status.b.bcnt); ep->xfer_buff += status.b.bcnt; ep->xfer_count += status.b.bcnt; } break; case STS_XFER_COMP: break; case STS_SETUP_COMP: break; case STS_SETUP_UPDT: /* Copy the setup packet received in FIFO into the setup buffer in RAM */ USB_OTG_ReadPacket(pdev , pdev->dev.setup_packet, 8); ep->xfer_count += status.b.bcnt; break; default: break; } /* Enable the Rx Status Queue Level interrupt */ USB_OTG_MODIFY_REG32( &pdev->regs.GREGS->GINTMSK, 0, int_mask.d32); return 1; }
/** * @brief USBD_SetFeature * Handle Set device feature request * @param pdev: device instance * @param req: usb request * @retval status */ static void USBD_SetFeature(USB_OTG_CORE_HANDLE *pdev, USB_SETUP_REQ *req) { USB_OTG_DCTL_TypeDef dctl; uint8_t test_mode = 0; if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) { pdev->dev.DevRemoteWakeup = 1; pdev->dev.class_cb->Setup (pdev, req); USBD_CtlSendStatus(pdev); } else if ((req->wValue == USB_FEATURE_TEST_MODE) && ((req->wIndex & 0xFF) == 0)) { dctl.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DCTL); test_mode = req->wIndex >> 8; switch (test_mode) { case 1: // TEST_J dctl.b.tstctl = 1; break; case 2: // TEST_K dctl.b.tstctl = 2; break; case 3: // TEST_SE0_NAK dctl.b.tstctl = 3; break; case 4: // TEST_PACKET dctl.b.tstctl = 4; break; case 5: // TEST_FORCE_ENABLE dctl.b.tstctl = 5; break; } SET_TEST_MODE = dctl; pdev->dev.test_mode = 1; USBD_CtlSendStatus(pdev); }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_HC_DoPing(USB_OTG_CORE_HANDLE *pdev , uint8_t hc_num) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_HCCHAR_TypeDef hcchar; USB_OTG_HCTSIZn_TypeDef hctsiz; hctsiz.d32 = 0; hctsiz.b.dopng = 1; hctsiz.b.pktcnt = 1; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCTSIZ, hctsiz.d32); hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR); hcchar.b.chen = 1; hcchar.b.chdis = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCCHAR, hcchar.d32); return status; }
/******************************************************************************* * Function Name : OTGD_FS_ReadPacket * Description : Reads a packet from the Rx FIFO * Input : None * Output : None * Return : status *******************************************************************************/ void* OTGD_FS_ReadPacket(uint8_t *dest, uint16_t bytes) { uint32_t i = 0; uint32_t word_count = (bytes + 3) / 4; __IO uint32_t *fifo = USB_OTG_FS_regs.FIFO[0]; uint32_t *data_buff = (uint32_t *)dest; for (i = 0; i < word_count; i++, data_buff++) { *data_buff = USB_OTG_READ_REG32(fifo); } /* Return the buffer pointer because if the transfer is composed of several packets, the data of the next packet must be stored following the previous packet's data */ return ((void *)data_buff); }
/******************************************************************************* * Function Name : OTGD_FS_SetDeviceMode * Description : Set device mode * Input : None * Output : None * Return : Status *******************************************************************************/ USB_OTG_Status OTGD_FS_SetDeviceMode(void) { USB_OTG_Status status = USB_OTG_OK; USB_OTG_GUSBCFG_TypeDef usbcfg ; usbcfg.d32 = 0; usbcfg.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.GREGS->GUSBCFG); usbcfg.b.force_dev = 1; USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.GREGS->GUSBCFG, usbcfg.d32); mDELAY(50); return status; }
/******************************************************************************* * Function Name : OTGD_FS_EP0Activate * Description : enables EP0 OUT to receive SETUP packets and configures EP0 IN for transmitting packets * Input : None * Output : None * Return : status *******************************************************************************/ USB_OTG_Status OTGD_FS_EP0Activate(void) { USB_OTG_Status status = USB_OTG_OK; USB_OTG_DEPCTLx_TypeDef diepctl; USB_OTG_DCTL_TypeDef dctl; diepctl.d32 = 0; dctl.d32 = 0; diepctl.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.DINEPS[0]->DIEPCTLx); diepctl.b.mps = DEP0CTL_MPS_64; USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DINEPS[0]->DIEPCTLx, diepctl.d32); dctl.b.cgnpinnak = 1; USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.DEV->DCTL, dctl.d32, dctl.d32); return status; }
static uint32_t USB_OTG_USBH_handle_ptxfempty_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_HPTXSTS_TypeDef hptxsts; uint32_t write_len; char *write_buff; hptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HPTXSTS); write_len = (pdev->host.hc[hptxsts.b.chnum].xfer_len + 3) / 4; if (hptxsts.b.ptxfspcavail <= write_len) { write_len = hptxsts.b.ptxfspcavail * 4; write_buff = (char*)pdev->host.hc[hptxsts.b.chnum].xfer_buff; pdev->host.hc[hptxsts.b.chnum].xfer_len -= write_len; pdev->host.hc[hptxsts.b.chnum].xfer_buff += write_len; } else { USB_OTG_GINTMSK_TypeDef intmsk; intmsk.d32 = 0; intmsk.b.ptxfempty = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, 0); write_buff = (char*)pdev->host.hc[hptxsts.b.chnum].xfer_buff; write_len = pdev->host.hc[hptxsts.b.chnum].xfer_len; pdev->host.hc[hptxsts.b.chnum].xfer_len = 0; pdev->host.hc[hptxsts.b.chnum].xfer_buff += write_len; } USB_OTG_WritePacket(pdev, (uint8_t*)write_buff, hptxsts.b.chnum, write_len); if (pdev->host.hc[hptxsts.b.chnum].xfer_len < 0) { pdev->host.hc[hptxsts.b.chnum].xfer_len = 0; } return 1; }
// Handles the incomplete Periodic transfer Interrupt static void USB_OTG_USBH_handle_IncompletePeriodicXfer_ISR (USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTSTS_TypeDef gintsts; USB_OTG_HCCHAR_TypeDef hcchar; hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[0]->HCCHAR); hcchar.b.chen = 1; hcchar.b.chdis = 1; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[0]->HCCHAR, hcchar.d32); gintsts.d32 = 0; /* Clear interrupt */ gintsts.b.incomplisoout = 1; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32); }
/******************************************************************************* * Function Name : OTGD_FS_GetEPStatus * Description : returns the EP Status * Input : - ep: pointer to the EP structure * Output : None * Return : status: DEV_EP_TX_STALL, DEV_EP_TX_VALID, DEV_EP_TX_NAK, * DEV_EP_RX_STALL, DEV_EP_RX_VALID or DEV_EP_RX_NAK, *******************************************************************************/ uint32_t OTGD_FS_GetEPStatus(USB_OTG_EP *ep) { USB_OTG_DEPCTLx_TypeDef depctl; __IO uint32_t *depctl_addr; uint32_t Status = 0; depctl.d32 = 0; if (ep->is_in == 1) { depctl_addr = &(USB_OTG_FS_regs.DINEPS[ep->num]->DIEPCTLx); } else { depctl_addr = &(USB_OTG_FS_regs.DOUTEPS[ep->num]->DOEPCTLx); } depctl.d32 = USB_OTG_READ_REG32(depctl_addr); /* Process for IN endpoint */ if (ep->is_in == 1) { if (depctl.b.stall == 1) Status = DEV_EP_TX_STALL; else if (depctl.b.naksts == 1) Status = DEV_EP_TX_NAK; else Status = DEV_EP_TX_VALID; } /* Process for OUT endpoint */ else { if (depctl.b.stall == 1) Status = DEV_EP_RX_STALL; else if (depctl.b.naksts == 1) Status = DEV_EP_RX_NAK; else Status = DEV_EP_RX_VALID; } /* Return the current status */ return Status; }
static uint32_t USB_OTG_USBH_handle_nptxfempty_ISR(USB_OTG_CORE_HANDLE*pdev) { int free_space; USB_OTG_HNPTXSTS_TypeDef hnptxsts; uint32_t write_len; char *write_buff; hnptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS); hnptxsts.b.chnum = pdev->cur_bulk_out_ch; write_len = (pdev->host.hc[hnptxsts.b.chnum].xfer_len + 3) / 4; free_space = hnptxsts.b.nptxfspcavail - 16; if (free_space < write_len) { write_len = free_space * 4; write_buff = (char*)pdev->host.hc[hnptxsts.b.chnum].xfer_buff; pdev->host.hc[hnptxsts.b.chnum].xfer_len -= write_len; pdev->host.hc[hnptxsts.b.chnum].xfer_buff += write_len; } else { USB_OTG_GINTMSK_TypeDef intmsk; intmsk.d32 = 0; intmsk.b.nptxfempty = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, 0); write_buff = (char*)pdev->host.hc[hnptxsts.b.chnum].xfer_buff; write_len = write_len * 4; pdev->host.hc[hnptxsts.b.chnum].xfer_len = 0; pdev->bulk_out_irq_pending = 0; } USB_OTG_WritePacket(pdev, (uint8_t*)write_buff, hnptxsts.b.chnum, write_len); if (pdev->host.hc[hnptxsts.b.chnum].xfer_len < 0) { pdev->host.hc[hnptxsts.b.chnum].xfer_len = 0; } return 1; }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_FlushRxFifo(USB_OTG_CORE_HANDLE * pdev) { USB_OTG_STS status = USB_OTG_OK; __IO USB_OTG_GRSTCTL_TypeDef greset; uint32_t count = 0; greset.d32 = 0; greset.b.rxfflsh = 1; USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GRSTCTL, greset.d32); do { greset.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GRSTCTL); if (++count > 200000) { break; } } while (greset.b.rxfflsh == 1); /* Wait for 3 PHY Clocks */ USB_OTG_BSP_uDelay(3); return status; }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_SetCurrentMode(USB_OTG_CORE_HANDLE * pdev, uint8_t mode) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_GUSBCFG_TypeDef usbcfg; usbcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG); usbcfg.b.force_host = 0; usbcfg.b.force_dev = 0; if (mode == HOST_MODE) { usbcfg.b.force_host = 1; } else if (mode == DEVICE_MODE) { usbcfg.b.force_dev = 1; } USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GUSBCFG, usbcfg.d32); USB_OTG_BSP_mDelay(50); return status; }
/******************************************************************************* * Function Name : OTGD_FS_EPActivate * Description : Activates an EP * Input : ep * Output : None * Return : num_in_ep *******************************************************************************/ USB_OTG_Status OTGD_FS_EPActivate(USB_OTG_EP *ep) { USB_OTG_Status status = USB_OTG_OK; USB_OTG_DEPCTLx_TypeDef depctl; USB_OTG_DAINT_TypeDef daintmsk; __IO uint32_t *addr; depctl.d32 = 0; daintmsk.d32 = 0; /* Read DEPCTLn register */ if (ep->is_in == 1) { addr = &USB_OTG_FS_regs.DINEPS[ep->num]->DIEPCTLx; daintmsk.ep.in = 1 << ep->num; } else { addr = &USB_OTG_FS_regs.DOUTEPS[ep->num]->DOEPCTLx; daintmsk.ep.out = 1 << ep->num; } /* If the EP is already active don't change the EP Control * register. */ depctl.d32 = USB_OTG_READ_REG32(addr); if (!depctl.b.usbactep) { depctl.b.mps = ep->maxpacket; depctl.b.eptype = ep->type; depctl.b.txfnum = ep->tx_fifo_num; depctl.b.setd0pid = 1; depctl.b.usbactep = 1; USB_OTG_WRITE_REG32(addr, depctl.d32); } /* Enable the Interrupt for this EP */ USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.DEV->DAINTMSK, 0, daintmsk.d32); return status; }
//-------------------------------------------------------------- void USB_OTG_EP0_OutStart(USB_OTG_CORE_HANDLE * pdev) { USB_OTG_DEP0XFRSIZ_TypeDef doeptsize0; doeptsize0.d32 = 0; doeptsize0.b.supcnt = 3; doeptsize0.b.pktcnt = 1; doeptsize0.b.xfersize = 8 * 3; USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[0]->DOEPTSIZ, doeptsize0.d32); if (pdev->cfg.dma_enable == 1) { USB_OTG_DEPCTL_TypeDef doepctl; doepctl.d32 = 0; USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[0]->DOEPDMA, (uint32_t) & pdev->dev.setup_packet); /* EP enable */ doepctl.d32 = USB_OTG_READ_REG32(&pdev->regs.OUTEP_REGS[0]->DOEPCTL); doepctl.b.epena = 1; doepctl.d32 = 0x80008000; USB_OTG_WRITE_REG32(&pdev->regs.OUTEP_REGS[0]->DOEPCTL, doepctl.d32); } }
//-------------------------------------------------------------- USB_OTG_STS USB_OTG_EPClearStall(USB_OTG_CORE_HANDLE * pdev, USB_OTG_EP * ep) { USB_OTG_STS status = USB_OTG_OK; USB_OTG_DEPCTL_TypeDef depctl; __IO uint32_t *depctl_addr; depctl.d32 = 0; if (ep->is_in == 1) { depctl_addr = &(pdev->regs.INEP_REGS[ep->num]->DIEPCTL); } else { depctl_addr = &(pdev->regs.OUTEP_REGS[ep->num]->DOEPCTL); } depctl.d32 = USB_OTG_READ_REG32(depctl_addr); /* clear the stall bits */ depctl.b.stall = 0; if (ep->type == EP_TYPE_INTR || ep->type == EP_TYPE_BULK) { depctl.b.setd0pid = 1; /* DATA0 */ } USB_OTG_WRITE_REG32(depctl_addr, depctl.d32); return status; }
/******************************************************************************* * Function Name : OTGD_FS_Handle_EnumDone_ISR * Description : Reads the device status register and set the device speed * Input : None * Output : None * Return : status *******************************************************************************/ uint32_t OTGD_FS_Handle_EnumDone_ISR(void) { USB_OTG_GINTSTS_TypeDef gintsts; USB_OTG_GUSBCFG_TypeDef gusbcfg; gintsts.d32 = 0; gusbcfg.d32 = 0; OTGD_FS_EP0Activate(); /* Set USB turnaround time */ gusbcfg.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.GREGS->GUSBCFG); gusbcfg.b.usbtrdtim = 9; USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.GREGS->GUSBCFG, gusbcfg.d32); /* Call user function */ INTR_ENUMDONE_Callback(); /* Clear interrupt */ gintsts.b.enumdone = 1; USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.GREGS->GINTSTS, gintsts.d32); return 1; }
//-------------------------------------------------------------- void USB_OTG_StopHost(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_HCCHAR_TypeDef hcchar; uint32_t i; USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HAINTMSK , 0); USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HAINT, 0xFFFFFFFF); /* Flush out any leftover queued requests. */ for (i = 0; i < pdev->cfg.host_channels; i++) { hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[i]->HCCHAR); hcchar.b.chen = 0; hcchar.b.chdis = 1; hcchar.b.epdir = 0; USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[i]->HCCHAR, hcchar.d32); } /* Flush the FIFO */ USB_OTG_FlushRxFifo(pdev); USB_OTG_FlushTxFifo(pdev , 0x10 ); }
/** * @brief USB_OTG_HandleConnectorIDStatusChange_ISR * handles the Connector ID Status Change Interrupt * @param None * @retval : status */ static uint32_t USB_OTG_HandleConnectorIDStatusChange_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTMSK_TypeDef gintmsk; USB_OTG_GOTGCTL_TypeDef gotgctl; USB_OTG_GINTSTS_TypeDef gintsts; gintsts.d32 = 0 ; gintmsk.d32 = 0 ; gotgctl.d32 = 0 ; gintmsk.b.sofintr = 1; USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, gintmsk.d32, 0); gotgctl.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GOTGCTL); /* B-Device connector (Device Mode) */ if (gotgctl.b.conidsts) { USB_OTG_DisableGlobalInt(pdev); USB_OTG_CoreInitDev(pdev); USB_OTG_EnableGlobalInt(pdev); #ifdef USE_OTG_MODE pdev->otg.OTG_State = B_PERIPHERAL; #endif } else { USB_OTG_DisableGlobalInt(pdev); USB_OTG_CoreInitHost(pdev); USB_OTG_EnableGlobalInt(pdev); #ifdef USE_OTG_MODE pdev->otg.OTG_State = A_HOST; #endif } /* Set flag and clear interrupt */ gintsts.b.conidstschng = 1; USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); return 1; }
/** * @brief USB_OTG_HandleSessionRequest_ISR * Initiating the Session Request Protocol * @param None * @retval : status */ static uint32_t USB_OTG_HandleSessionRequest_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTSTS_TypeDef gintsts; USB_OTG_GOTGCTL_TypeDef gotgctl; gotgctl.d32 = 0; gintsts.d32 = 0; gotgctl.d32 = USB_OTG_READ_REG32( &pdev->regs.GREGS->GOTGCTL ); if (USB_OTG_IsDeviceMode(pdev) && (gotgctl.b.bsesvld)) { } else if (gotgctl.b.asesvld) { } /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.sessreqintr = 1; USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); return 1; }
//-------------------------------------------------------------- enum USB_OTG_SPEED USB_OTG_GetDeviceSpeed(USB_OTG_CORE_HANDLE * pdev) { USB_OTG_DSTS_TypeDef dsts; enum USB_OTG_SPEED speed = USB_SPEED_UNKNOWN; dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS); switch (dsts.b.enumspd) { case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: speed = USB_SPEED_HIGH; break; case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: case DSTS_ENUMSPD_FS_PHY_48MHZ: speed = USB_SPEED_FULL; break; case DSTS_ENUMSPD_LS_PHY_6MHZ: speed = USB_SPEED_LOW; break; } return speed; }
/** * @brief DCD_HandleResume_ISR * Indicates that the USB_OTG controller has detected a resume or * remote Wake-up sequence * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleResume_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_GINTSTS_TypeDef gintsts; USB_OTG_DCTL_TypeDef devctl; USB_OTG_PCGCCTL_TypeDef power; if(pdev->cfg.low_power) { /* un-gate USB Core clock */ #pragma GCC diagnostic push // HJI #pragma GCC diagnostic ignored "-Wstrict-aliasing" // HJI power.d32 = USB_OTG_READ_REG32(&pdev->regs.PCGCCTL); #pragma GCC diagnostic pop // HJI power.b.gatehclk = 0; power.b.stoppclk = 0; USB_OTG_WRITE_REG32(pdev->regs.PCGCCTL, power.d32); } /* Clear the Remote Wake-up Signaling */ devctl.d32 = 0; devctl.b.rmtwkupsig = 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, devctl.d32, 0); /* Inform upper layer by the Resume Event */ USBD_DCD_INT_fops->Resume (pdev); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.wkupintr = 1; USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); return 1; }
/******************************************************************************* * Function Name : OTGD_FS_Handle_UsbReset_ISR * Description : This interrupt occurs when a USB Reset is detected. * Input : None * Output : None * Return : status *******************************************************************************/ uint32_t OTGD_FS_Handle_UsbReset_ISR(void) { USB_OTG_DAINT_TypeDef daintmsk; USB_OTG_DOEPMSKx_TypeDef doepmsk; USB_OTG_DIEPMSKx_TypeDef diepmsk; USB_OTG_DCFG_TypeDef dcfg; USB_OTG_DCTL_TypeDef dctl; USB_OTG_GINTSTS_TypeDef gintsts; uint32_t i = 0; daintmsk.d32 = 0; doepmsk.d32 = 0; diepmsk.d32 = 0; dcfg.d32 =0; dctl.d32 = 0; gintsts.d32 = 0; /* Clear the Remote Wakeup Signalling */ dctl.b.rmtwkupsig = 1; USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.DEV->DCTL, dctl.d32, 0 ); /* Flush the NP Tx FIFO */ OTGD_FS_FlushTxFifo( 0 ); /* clear pending interrupts */ for (i = 0; i < NUM_TX_FIFOS ; i++) { USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DINEPS[i]->DIEPINTx, 0xFF); USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DOUTEPS[i]->DOEPINTx, 0xFF); } USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DEV->DAINT, 0xFFFFFFFF ); daintmsk.ep.in = 1; daintmsk.ep.out = 1; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DAINTMSK, daintmsk.d32 ); doepmsk.b.setup = 1; doepmsk.b.b2bsetup = 1; doepmsk.b.xfercompl = 1; doepmsk.b.epdis = 1; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DOEPMSK, doepmsk.d32 ); diepmsk.b.xfercompl = 1; diepmsk.b.timeout = 1; diepmsk.b.epdis = 1; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DIEPMSK, diepmsk.d32 ); /* Reset Device Address */ dcfg.d32 = USB_OTG_READ_REG32( &USB_OTG_FS_regs.DEV->DCFG); dcfg.b.devaddr = 0; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DCFG, dcfg.d32); /* setup EP0 to receive SETUP packets */ PCD_EP0_OutStart(); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.usbreset = 1; USB_OTG_WRITE_REG32 (&USB_OTG_FS_regs.GREGS->GINTSTS, gintsts.d32); /* Call the user reset function */ OTGD_FS_DEVICE_RESET; /* Call user function */ INTR_USBRESET_Callback(); return 1; }
/******************************************************************************* * Function Name : OTGD_FS_Handle_RxStatusQueueLevel_ISR * Description : Handles the Rx Status Queue Level Interrupt. * Input : None * Output : None * Return : status *******************************************************************************/ uint32_t OTGD_FS_Handle_RxStatusQueueLevel_ISR(void) { USB_OTG_GINTMSK_TypeDef int_mask; USB_OTG_GRXSTSP_TypeDef status; USB_OTG_EP *ep; int_mask.d32 = 0; status.d32 = 0; /* Disable the Rx Status Queue Level interrupt */ int_mask.b.rxstsqlvl = 1; USB_OTG_MODIFY_REG32( &USB_OTG_FS_regs.GREGS->GINTMSK, int_mask.d32, 0); /* Get the Status from the top of the FIFO */ status.d32 = USB_OTG_READ_REG32( &USB_OTG_FS_regs.GREGS->GRXSTSP ); /* Get the related endpoint structure */ ep = PCD_GetOutEP(status.b.epnum); switch (status.b.pktsts) { case STS_GOUT_NAK: break; case STS_DATA_UPDT: if (status.b.bcnt) { if (ep->type == EP_TYPE_ISOC) { /* Call user function */ INTR_RXSTSQLVL_ISODU_Callback(); /* Copy the received buffer to the RAM */ OTGD_FS_ReadPacket((uint8_t*)(IsocBuff + (ISOC_BUFFER_SZE * IsocBufferIdx)), status.b.bcnt); ep->xfer_buff = (uint8_t*)(IsocBuff + (ISOC_BUFFER_SZE * IsocBufferIdx)); /* Check if the end of the global buffer has been reached */ if (IsocBufferIdx == (NUM_SUB_BUFFERS - 1)) { /* Reset the buffer index */ IsocBufferIdx = 0; } else { /* Increment the buffer index */ IsocBufferIdx ++; } } else { /* Copy the received buffer to the RAM */ OTGD_FS_ReadPacket(USBD_Data_Buffer, status.b.bcnt); ep->xfer_buff = USBD_Data_Buffer; } /* Update the endpoint structure */ ep->xfer_len = status.b.bcnt; ep->xfer_count += status.b.bcnt; } else { ep->xfer_len = status.b.bcnt; } break; case STS_XFER_COMP: break; case STS_SETUP_COMP: break; case STS_SETUP_UPDT: /* Copy the setup packet received in Fifo into the setup buffer in RAM */ OTGD_FS_ReadPacket(USBD_Data_Buffer, 8); ep->xfer_buff = USBD_Data_Buffer; ep->xfer_count += status.b.bcnt; ep->xfer_len = status.b.bcnt; break; default: break; } /* Call the user function */ INTR_RXSTSQLVL_Callback(); /* Enable the Rx Status Queue Level interrupt */ USB_OTG_MODIFY_REG32( &USB_OTG_FS_regs.GREGS->GINTMSK, 0, int_mask.d32); /* Clear interrupt: this is a read only bit, it cannot be cleared by register access */ return 1; }
/******************************************************************************* * Function Name : OTGD_FS_EP0StartXfer * Description : Handle the setup for a data xfer for EP0 and starts the xfer * Input : None * Output : None * Return : status *******************************************************************************/ USB_OTG_Status OTGD_FS_EP0StartXfer(USB_OTG_EP *ep) { USB_OTG_Status status = USB_OTG_OK; uint32_t fifoemptymsk = 0; USB_OTG_DEPCTLx_TypeDef depctl; OTG_FS_DEPTSIZx_TypeDef deptsiz; USB_OTG_DINEPS *in_regs ; depctl.d32 = 0; deptsiz.d32 = 0; /* IN endpoint */ if (ep->is_in == 1) { in_regs = USB_OTG_FS_regs.DINEPS[0]; depctl.d32 = USB_OTG_READ_REG32(&in_regs->DIEPCTLx); deptsiz.d32 = USB_OTG_READ_REG32(&in_regs->DIEPTSIZx); /* Zero Length Packet? */ if (ep->xfer_len == 0) { deptsiz.b.xfersize = 0; deptsiz.b.pktcnt = 1; } else { if (ep->xfer_len > ep->maxpacket) { ep->xfer_len = ep->maxpacket; deptsiz.b.xfersize = ep->maxpacket; } else { deptsiz.b.xfersize = ep->xfer_len; } deptsiz.b.pktcnt = 1; } USB_OTG_WRITE_REG32(&in_regs->DIEPTSIZx, deptsiz.d32); /* EP enable, IN data in FIFO */ depctl.b.cnak = 1; depctl.b.epena = 1; USB_OTG_WRITE_REG32(&in_regs->DIEPCTLx, depctl.d32); /* Enable the Tx FIFO Empty Interrupt for this EP */ if (ep->xfer_len > 0) { fifoemptymsk |= 1 << ep->num; USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.DEV->DIEPEMPMSK, 0, fifoemptymsk); } } else { /* OUT endpoint */ depctl.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.DOUTEPS[0]->DOEPCTLx); deptsiz.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.DOUTEPS[0]->DOEPTSIZx); /* Program the transfer size and packet count as follows: * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) * pktcnt = N */ if (ep->xfer_len == 0) { deptsiz.b.xfersize = ep->maxpacket; deptsiz.b.pktcnt = 1; } else { deptsiz.b.pktcnt = (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket; deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; } USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DOUTEPS[0]->DOEPTSIZx, deptsiz.d32); /* EP enable */ depctl.b.cnak = 1; depctl.b.epena = 1; USB_OTG_WRITE_REG32 (&(USB_OTG_FS_regs.DOUTEPS[0]->DOEPCTLx), depctl.d32); } return status; }
/******************************************************************************* * Function Name : OTGD_FS_EPStartXfer * Description : Handle the setup for data xfer for an EP and starts the xfer * Input : None * Output : None * Return : status *******************************************************************************/ USB_OTG_Status OTGD_FS_EPStartXfer(USB_OTG_EP *ep) { USB_OTG_DSTS_TypeDef dsts; USB_OTG_Status status = USB_OTG_OK; __IO USB_OTG_DEPCTLx_TypeDef depctl; OTG_FS_DEPTSIZx_TypeDef deptsiz; depctl.d32 = 0; deptsiz.d32 = 0; /* IN endpoint */ if (ep->is_in == 1) { depctl.d32 = USB_OTG_READ_REG32(&(USB_OTG_FS_regs.DINEPS[ep->num]->DIEPCTLx)); deptsiz.d32 = USB_OTG_READ_REG32(&(USB_OTG_FS_regs.DINEPS[ep->num]->DIEPTSIZx)); /* Zero Length Packet? */ if (ep->xfer_len == 0) { deptsiz.b.xfersize = 0; deptsiz.b.pktcnt = 1; } else { /* Program the transfer size and packet count * as follows: xfersize = N * maxpacket + * short_packet pktcnt = N + (short_packet * exist ? 1 : 0) */ deptsiz.b.xfersize = ep->xfer_len; deptsiz.b.pktcnt = (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; if (ep->type == EP_TYPE_ISOC) { deptsiz.b.mcount = 1; } } USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DINEPS[ep->num]->DIEPTSIZx, deptsiz.d32); if (ep->type != EP_TYPE_ISOC) { /* Enable the Tx FIFO Empty Interrupt for this EP */ uint32_t fifoemptymsk = 0; fifoemptymsk = 1 << ep->num; USB_OTG_MODIFY_REG32(&USB_OTG_FS_regs.DEV->DIEPEMPMSK, 0, fifoemptymsk); } /* EP enable, IN data in FIFO */ depctl.b.cnak = 1; depctl.b.epena = 1; if (ep->type == EP_TYPE_ISOC) { dsts.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.DEV->DSTS); if (((dsts.b.soffn)&0x1)==0) { depctl.b.setoddfrm=1; } else { depctl.b.setd0pid=1; } } USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DINEPS[ep->num]->DIEPCTLx, depctl.d32); if (ep->type == EP_TYPE_ISOC) { /*write buffer in TXFIFO*/ /* user should ensure that ep->xfer_len <= ep->maxpacket */ OTGD_FS_WritePacket(ep->xfer_buff, ep->num, ep->xfer_len); } } else { /* OUT endpoint */ depctl.d32 = USB_OTG_READ_REG32(&(USB_OTG_FS_regs.DOUTEPS[ep->num]->DOEPCTLx)); deptsiz.d32 = USB_OTG_READ_REG32(&(USB_OTG_FS_regs.DOUTEPS[ep->num]->DOEPTSIZx)); /* Program the transfer size and packet count as follows: * pktcnt = N * xfersize = N * maxpacket */ if (ep->xfer_len == 0) { deptsiz.b.xfersize = ep->maxpacket; deptsiz.b.pktcnt = 1; } else { deptsiz.b.pktcnt = (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket; deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; } USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DOUTEPS[ep->num]->DOEPTSIZx, deptsiz.d32); if (ep->type == EP_TYPE_ISOC) { if (ep->even_odd_frame) { depctl.b.setoddfrm = 1; } else { depctl.b.setd0pid = 1; } } /* EP enable */ depctl.b.cnak = 1; depctl.b.epena = 1; USB_OTG_WRITE_REG32(&USB_OTG_FS_regs.DOUTEPS[ep->num]->DOEPCTLx, depctl.d32); } return status; }
/** * @brief DCD_HandleOutEP_ISR * Indicates that an OUT EP has a pending Interrupt * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleOutEP_ISR(USB_OTG_CORE_HANDLE *pdev) { uint32_t ep_intr; USB_OTG_DOEPINTn_TypeDef doepint; USB_OTG_DEPXFRSIZ_TypeDef deptsiz; uint32_t epnum = 0; doepint.d32 = 0; /* Read in the device interrupt bits */ ep_intr = USB_OTG_ReadDevAllOutEp_itr(pdev); while ( ep_intr ) { if (ep_intr&0x1) { doepint.d32 = USB_OTG_ReadDevOutEP_itr(pdev, epnum); /* Transfer complete */ if ( doepint.b.xfercompl ) { /* Clear the bit in DOEPINTn for this interrupt */ CLEAR_OUT_EP_INTR(epnum, xfercompl); if (pdev->cfg.dma_enable == 1) { deptsiz.d32 = USB_OTG_READ_REG32(&(pdev->regs.OUTEP_REGS[epnum]->DOEPTSIZ)); /*ToDo : handle more than one single MPS size packet */ pdev->dev.out_ep[epnum].xfer_count = pdev->dev.out_ep[epnum].maxpacket - \ deptsiz.b.xfersize; } /* Inform upper layer: data ready */ /* RX COMPLETE */ USBD_DCD_INT_fops->DataOutStage(pdev , epnum); if (pdev->cfg.dma_enable == 1) { if((epnum == 0) && (pdev->dev.device_state == USB_OTG_EP0_STATUS_OUT)) { /* prepare to rx more setup packets */ USB_OTG_EP0_OutStart(pdev); } } } /* Endpoint disable */ if ( doepint.b.epdisabled ) { /* Clear the bit in DOEPINTn for this interrupt */ CLEAR_OUT_EP_INTR(epnum, epdisabled); } /* Setup Phase Done (control EPs) */ if ( doepint.b.setup ) { /* inform the upper layer that a setup packet is available */ /* SETUP COMPLETE */ USBD_DCD_INT_fops->SetupStage(pdev); CLEAR_OUT_EP_INTR(epnum, setup); } } epnum++; ep_intr >>= 1; } return 1; }
/******************************************************************************* * Function Name : OTGD_FS_ReadOtgItr * Description : returns the USB_OTG Interrupt register * Input : None * Output : None * Return : None *******************************************************************************/ uint32_t OTGD_FS_ReadOtgItr (void) { return (USB_OTG_READ_REG32 (&USB_OTG_FS_regs.GREGS->GOTGINT)); }
/******************************************************************************* * Function Name : OTGD_FS_CoreInitDev * Description : Initialize the USB_OTG controller registers for device mode * Input : None * Output : None * Return : Status *******************************************************************************/ USB_OTG_Status OTGD_FS_CoreInitDev (void) { USB_OTG_Status status = USB_OTG_OK; USB_OTG_DEPCTLx_TypeDef depctl; USB_OTG_DCFG_TypeDef dcfg; USB_OTG_FIFOSIZ_TypeDef txfifosize0; USB_OTG_FIFOSIZ_TypeDef txfifosize; uint32_t i = 0; depctl.d32 = 0; dcfg.d32 = 0; txfifosize0.d32 = 0; txfifosize.d32 = 0; /* Set device speed */ InitDevSpeed (); /* Restart the Phy Clock */ USB_OTG_WRITE_REG32(USB_OTG_FS_regs.PCGCCTL, 0); /* Device configuration register */ dcfg.d32 = USB_OTG_READ_REG32( &USB_OTG_FS_regs.DEV->DCFG); dcfg.b.perfrint = DCFG_FRAME_INTERVAL_80; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DCFG, dcfg.d32 ); /* set Rx FIFO size */ USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.GREGS->GRXFSIZ, RX_FIFO_SIZE); /* EP0 TX*/ txfifosize0.b.depth = TX0_FIFO_SIZE; txfifosize0.b.startaddr = RX_FIFO_SIZE; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.GREGS->DIEPTXF0, txfifosize0.d32 ); /* EP1 TX*/ txfifosize.b.startaddr = txfifosize0.b.startaddr + txfifosize0.b.depth; txfifosize.b.depth = TX1_FIFO_SIZE; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.GREGS->DIEPTXFx[0], txfifosize.d32 ); /* EP2 TX*/ txfifosize.b.startaddr += txfifosize.b.depth; txfifosize.b.depth = TX2_FIFO_SIZE; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.GREGS->DIEPTXFx[1], txfifosize.d32 ); /* EP3 TX*/ txfifosize.b.startaddr += txfifosize.b.depth; txfifosize.b.depth = TX3_FIFO_SIZE; USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.GREGS->DIEPTXFx[2], txfifosize.d32 ); /* Flush the FIFOs */ OTGD_FS_FlushTxFifo(0x10); /* all Tx FIFOs */ OTGD_FS_FlushRxFifo(); /* Clear all pending Device Interrupts */ USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DIEPMSK, 0 ); USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DOEPMSK, 0 ); USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DAINT, 0xFFFFFFFF ); USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DEV->DAINTMSK, 0 ); for (i = 0; i < NUM_TX_FIFOS; i++) { depctl.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.DINEPS[i]->DIEPCTLx); if (depctl.b.epena) { depctl.d32 = 0; depctl.b.epdis = 1; depctl.b.snak = 1; } else { depctl.d32 = 0; } USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DINEPS[i]->DIEPCTLx, depctl.d32); USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DINEPS[i]->DIEPTSIZx, 0); USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DINEPS[i]->DIEPINTx, 0xFF); } for (i = 0; i < 1/* NUM_OUT_EPS*/; i++) { depctl.d32 = USB_OTG_READ_REG32(&USB_OTG_FS_regs.DOUTEPS[i]->DOEPCTLx); if (depctl.b.epena) { depctl.d32 = 0; depctl.b.epdis = 1; depctl.b.snak = 1; } else { depctl.d32 = 0; } USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DOUTEPS[i]->DOEPCTLx, depctl.d32); USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DOUTEPS[i]->DOEPTSIZx, 0); USB_OTG_WRITE_REG32( &USB_OTG_FS_regs.DOUTEPS[i]->DOEPINTx, 0xFF); } OTGD_FS_EnableDevInt(); return status; }
/** * @brief DCD_HandleUsbReset_ISR * This interrupt occurs when a USB Reset is detected * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleUsbReset_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_DAINT_TypeDef daintmsk; USB_OTG_DOEPMSK_TypeDef doepmsk; USB_OTG_DIEPMSK_TypeDef diepmsk; USB_OTG_DCFG_TypeDef dcfg; USB_OTG_DCTL_TypeDef dctl; USB_OTG_GINTSTS_TypeDef gintsts; uint32_t i; dctl.d32 = 0; daintmsk.d32 = 0; doepmsk.d32 = 0; diepmsk.d32 = 0; dcfg.d32 = 0; gintsts.d32 = 0; /* Clear the Remote Wake-up Signaling */ dctl.b.rmtwkupsig = 1; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, dctl.d32, 0 ); /* Flush the Tx FIFO */ USB_OTG_FlushTxFifo(pdev , 0 ); for (i = 0; i < pdev->cfg.dev_endpoints ; i++) { USB_OTG_WRITE_REG32( &pdev->regs.INEP_REGS[i]->DIEPINT, 0xFF); USB_OTG_WRITE_REG32( &pdev->regs.OUTEP_REGS[i]->DOEPINT, 0xFF); } USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINT, 0xFFFFFFFF ); daintmsk.ep.in = 1; daintmsk.ep.out = 1; USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DAINTMSK, daintmsk.d32 ); doepmsk.b.setup = 1; doepmsk.b.xfercompl = 1; doepmsk.b.epdisabled = 1; USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DOEPMSK, doepmsk.d32 ); #ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DOUTEP1MSK, doepmsk.d32 ); #endif diepmsk.b.xfercompl = 1; diepmsk.b.timeout = 1; diepmsk.b.epdisabled = 1; USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DIEPMSK, diepmsk.d32 ); #ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DINEP1MSK, diepmsk.d32 ); #endif /* Reset Device Address */ dcfg.d32 = USB_OTG_READ_REG32( &pdev->regs.DREGS->DCFG); dcfg.b.devaddr = 0; USB_OTG_WRITE_REG32( &pdev->regs.DREGS->DCFG, dcfg.d32); /* setup EP0 to receive SETUP packets */ USB_OTG_EP0_OutStart(pdev); /* Clear interrupt */ gintsts.d32 = 0; gintsts.b.usbreset = 1; USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32); /*Reset internal state machine */ USBD_DCD_INT_fops->Reset(pdev); return 1; }
/******************************************************************************* * Function Name : IsDeviceMode * Description : check device mode * Input : None * Output : None * Return : current mode *******************************************************************************/ uint32_t USBD_FS_IsDeviceMode(void) { return ((USB_OTG_READ_REG32(&USB_OTG_FS_regs.GREGS->GINTSTS ) & 0x1) == 0 ); }