//-------------------------------------------------------------- USBD_Status USBD_CtlReceiveStatus(USB_OTG_CORE_HANDLE * pdev) { USBD_Status ret = USBD_OK; pdev->dev.device_state = USB_OTG_EP0_STATUS_OUT; DCD_EP_PrepareRx(pdev, 0, NULL, 0); USB_OTG_EP0_OutStart(pdev); return ret; }
//-------------------------------------------------------------- USBD_Status USBD_CtlSendStatus(USB_OTG_CORE_HANDLE * pdev) { USBD_Status ret = USBD_OK; pdev->dev.device_state = USB_OTG_EP0_STATUS_IN; DCD_EP_Tx(pdev, 0, NULL, 0); USB_OTG_EP0_OutStart(pdev); return ret; }
/** * @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; }
/** * @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; }
/** * @brief DCD_HandleInEP_ISR * Indicates that an IN EP has a pending Interrupt * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleInEP_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_DIEPINTn_TypeDef diepint; uint32_t ep_intr; uint32_t epnum = 0; uint32_t fifoemptymsk; diepint.d32 = 0; ep_intr = USB_OTG_ReadDevAllInEPItr(pdev); while ( ep_intr ) { if (ep_intr&0x1) /* In ITR */ { diepint.d32 = DCD_ReadDevInEP(pdev , epnum); /* Get In ITR status */ if ( diepint.b.xfercompl ) { fifoemptymsk = 0x1 << epnum; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); CLEAR_IN_EP_INTR(epnum, xfercompl); /* TX COMPLETE */ USBD_DCD_INT_fops->DataInStage(pdev , epnum); if (pdev->cfg.dma_enable == 1) { if((epnum == 0) && (pdev->dev.device_state == USB_OTG_EP0_STATUS_IN)) { /* prepare to rx more setup packets */ USB_OTG_EP0_OutStart(pdev); } } } if ( diepint.b.timeout ) { CLEAR_IN_EP_INTR(epnum, timeout); } if (diepint.b.intktxfemp) { CLEAR_IN_EP_INTR(epnum, intktxfemp); } if (diepint.b.inepnakeff) { CLEAR_IN_EP_INTR(epnum, inepnakeff); } if ( diepint.b.epdisabled ) { CLEAR_IN_EP_INTR(epnum, epdisabled); } if (diepint.b.emptyintr) { DCD_WriteEmptyTxFifo(pdev , epnum); CLEAR_IN_EP_INTR(epnum, emptyintr); } } epnum++; ep_intr >>= 1; } return 1; }
/** * @brief DCD_HandleInEP_ISR * Indicates that an IN EP has a pending Interrupt * @param pdev: device instance * @retval status */ static uint32_t DCD_HandleInEP_ISR(USB_OTG_CORE_HANDLE *pdev) { USB_OTG_DIEPINTn_TypeDef diepint; uint32_t ep_intr; uint32_t epnum = 0; uint32_t fifoemptymsk; diepint.d32 = 0; ep_intr = USB_OTG_ReadDevAllInEPItr(pdev); while ( ep_intr ) { if (ep_intr&0x1) /* In ITR */ { diepint.d32 = DCD_ReadDevInEP(pdev , epnum); /* Get In ITR status */ if ( diepint.b.xfercompl ) { fifoemptymsk = 0x1 << epnum; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); CLEAR_IN_EP_INTR(epnum, xfercompl); /* TX COMPLETE */ USBD_DCD_INT_fops->DataInStage(pdev , epnum); if (pdev->cfg.dma_enable == 1) { if((epnum == 0) && (pdev->dev.device_state == USB_OTG_EP0_STATUS_IN)) { /* prepare to rx more setup packets */ USB_OTG_EP0_OutStart(pdev); } } } if ( diepint.b.timeout ) { CLEAR_IN_EP_INTR(epnum, timeout); } if (diepint.b.intktxfemp) { CLEAR_IN_EP_INTR(epnum, intktxfemp); } if (diepint.b.inepnakeff) { CLEAR_IN_EP_INTR(epnum, inepnakeff); } if ( diepint.b.epdisabled ) { CLEAR_IN_EP_INTR(epnum, epdisabled); } if (diepint.b.emptyintr) { /*===============ADDED SECTION ==============================*/ /* This only applies to INTERRUPT transfer mode. diepint.b.emptyintr interrupt can't be reset by writing 1 to DIEPINT register. According to reference manual, this bit is read-only. The CLEAR_IN_EP_INTR(epnum, emptyintr) does not work! The only way to stop this interrupt is to disable it using mask register DIEPEMPMSK. Original code gets here, is unsuccessful at interrupt flag reset and when interrupt handler returns, another one is fired again, robbing CPU time, which is then spent only in interrupt handlers (this one and all other that have higher priority) This only happens in HID mode (when interrupt in endpoint is used) and when host is not actively polling device (us) for update. This is situation on Linux when no program is using joystick. The kernel/joystick driver stops polling device. */ if ( pdev->dev.in_ep[epnum].type == USB_OTG_EP_INT ) { fifoemptymsk = 0x1 << epnum; USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); } /*===============END OF ADDED SECTION ==============================*/ DCD_WriteEmptyTxFifo(pdev , epnum); CLEAR_IN_EP_INTR(epnum, emptyintr); } } epnum++; ep_intr >>= 1; } return 1; }