/** * @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; }