/******************************************************************************* * Function Name : CTR_LP. * Description : Low priority Endpoint Correct Transfer interrupt's service * routine. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CTR_LP(void) { uint32_t wEPVal = 0; /* stay in loop while pending ints */ while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) { _SetISTR((uint16_t)CLR_CTR); /* clear CTR flag */ /* extract highest priority endpoint number */ EPindex = (uint8_t)(wIstr & ISTR_EP_ID); if (EPindex == 0) { /* Decode and service control endpoint interrupt */ /* calling related service routine */ /* (Setup0_Process, In0_Process, Out0_Process) */ /* save RX & TX status */ /* and set both to NAK */ SaveRState = _GetEPRxStatus(ENDP0); SaveTState = _GetEPTxStatus(ENDP0); _SetEPRxStatus(ENDP0, EP_RX_NAK); _SetEPTxStatus(ENDP0, EP_TX_NAK); /* DIR bit = origin of the interrupt */ if ((wIstr & ISTR_DIR) == 0) { /* DIR = 0 */ /* DIR = 0 => IN int */ /* DIR = 0 implies that (EP_CTR_TX = 1) always */ _ClearEP_CTR_TX(ENDP0); In0_Process(); /* before terminate set Tx & Rx status */ _SetEPRxStatus(ENDP0, SaveRState); _SetEPTxStatus(ENDP0, SaveTState); return; } else { /* DIR = 1 */ /* DIR = 1 & CTR_RX => SETUP or OUT int */ /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */ wEPVal = _GetENDPOINT(ENDP0); if ((wEPVal & EP_CTR_TX) != 0) { _ClearEP_CTR_TX(ENDP0); In0_Process(); /* before terminate set Tx & Rx status */ _SetEPRxStatus(ENDP0, SaveRState); _SetEPTxStatus(ENDP0, SaveTState); return; } else if ((wEPVal &EP_SETUP) != 0) { _ClearEP_CTR_RX(ENDP0); /* SETUP bit kept frozen while CTR_RX = 1 */ Setup0_Process(); /* before terminate set Tx & Rx status */ _SetEPRxStatus(ENDP0, SaveRState); _SetEPTxStatus(ENDP0, SaveTState); return; } else if ((wEPVal & EP_CTR_RX) != 0) { _ClearEP_CTR_RX(ENDP0); Out0_Process(); /* before terminate set Tx & Rx status */ _SetEPRxStatus(ENDP0, SaveRState); _SetEPTxStatus(ENDP0, SaveTState); return; } } }/* if(EPindex == 0) */ else { /* Decode and service non control endpoints interrupt */ /* process related endpoint register */ wEPVal = _GetENDPOINT(EPindex); if ((wEPVal & EP_CTR_RX) != 0) { /* clear int flag */ _ClearEP_CTR_RX(EPindex); /* call OUT service function */ (*pEpInt_OUT[EPindex-1])(); } /* if((wEPVal & EP_CTR_RX) */ if ((wEPVal & EP_CTR_TX) != 0) { /* clear int flag */ _ClearEP_CTR_TX(EPindex); /* call IN service function */ (*pEpInt_IN[EPindex-1])(); } /* if((wEPVal & EP_CTR_TX) != 0) */ }/* if(EPindex == 0) else */ }/* while(...) */ }
/******************************************************************************* * Function Name : Suspend * Description : sets suspend mode operating conditions * Input : None. * Output : None. * Return : USB_SUCCESS. *******************************************************************************/ void Suspend(void) { uint32_t i =0; uint16_t wCNTR; uint32_t tmpreg = 0; __IO uint32_t savePWR_CR=0; /* suspend preparation */ /* ... */ /*Store CNTR value */ wCNTR = _GetCNTR(); /* This a sequence to apply a force RESET to handle a robustness case */ /*Store endpoints registers status */ for (i=0; i<8; i++) EP[i] = _GetENDPOINT(i); /* unmask RESET flag */ wCNTR|=CNTR_RESETM; _SetCNTR(wCNTR); /*apply FRES */ wCNTR|=CNTR_FRES; _SetCNTR(wCNTR); /*clear FRES*/ wCNTR&=~CNTR_FRES; _SetCNTR(wCNTR); /*poll for RESET flag in ISTR*/ while((_GetISTR()&ISTR_RESET) == 0); /* clear RESET flag in ISTR */ _SetISTR((uint16_t)CLR_RESET); /*restore Enpoints*/ for (i=0; i<8; i++) _SetENDPOINT(i, EP[i]); /* Now it is safe to enter macrocell in suspend mode */ wCNTR |= CNTR_FSUSP; _SetCNTR(wCNTR); /* force low-power mode in the macrocell */ wCNTR = _GetCNTR(); wCNTR |= CNTR_LPMODE; _SetCNTR(wCNTR); /*prepare entry in low power mode (STOP mode)*/ /* Select the regulator state in STOP mode*/ savePWR_CR = PWR->CR; tmpreg = PWR->CR; /* Clear PDDS and LPDS bits */ tmpreg &= ((uint32_t)0xFFFFFFFC); /* Set LPDS bit according to PWR_Regulator value */ tmpreg |= PWR_Regulator_LowPower; /* Store the new value */ PWR->CR = tmpreg; /* Set SLEEPDEEP bit of Cortex System Control Register */ #if defined (STM32F30X) || defined (STM32F37X) SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; #else SCB->SCR |= SCB_SCR_SLEEPDEEP; #endif /* enter system in STOP mode, only when wakeup flag in not set */ if((_GetISTR()&ISTR_WKUP)==0) { __WFI(); /* Reset SLEEPDEEP bit of Cortex System Control Register */ #if defined (STM32F30X) || defined (STM32F37X) SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); #else SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP); #endif } else { /* Clear Wakeup flag */ _SetISTR(CLR_WKUP); /* clear FSUSP to abort entry in suspend mode */ wCNTR = _GetCNTR(); wCNTR&=~CNTR_FSUSP; _SetCNTR(wCNTR); /*restore sleep mode configuration */ /* restore Power regulator config in sleep mode*/ PWR->CR = savePWR_CR; /* Reset SLEEPDEEP bit of Cortex System Control Register */ #if defined (STM32F30X) || defined (STM32F37X) SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); #else SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP); #endif } }
/******************************************************************************* * Function Name : SetEPType * Description : sets the type in the endpoint register. * Input : bEpNum: Endpoint Number. * wType: type definition. * Output : None. * Return : None. *******************************************************************************/ void SetEPType(uint8_t bEpNum, uint16_t wType) { _SetENDPOINT(bEpNum,(_GetENDPOINT(bEpNum) & EP_T_MASK) | wType); }
/******************************************************************************* * Function Name : GetEPType * Description : Returns the endpoint type. * Input : bEpNum: Endpoint Number. * Output : None. * Return : Endpoint Type *******************************************************************************/ uint16_t GetEPType(uint8_t bEpNum) { return _GetENDPOINT(bEpNum) & EP_T_FIELD; }
/******************************************************************************* * Function Name : SetEPAddress * Description : Set the endpoint address. * Input : bEpNum: Endpoint Number. * bAddr: New endpoint address. * Output : None. * Return : None. *******************************************************************************/ void SetEPAddress(uint8_t bEpNum, uint8_t bAddr) { _SetENDPOINT(bEpNum,EP_CTR_RX | EP_CTR_TX | (_GetENDPOINT(bEpNum) & EPREG_MASK) | bAddr); }
/******************************************************************************* * Function Name : GetEPAddress * Description : Get the endpoint address. * Input : bEpNum: Endpoint Number. * Output : None. * Return : Endpoint address. *******************************************************************************/ uint8_t GetEPAddress(uint8_t bEpNum) { return (uint8_t)(_GetENDPOINT(bEpNum) & EPADDR_FIELD); }
/******************************************************************************* * Function Name : ToggleDTOG_TX * Description : Toggle the DTOG_TX bit. * Input : bEpNum: Endpoint Number. * Output : None. * Return : None. *******************************************************************************/ void ToggleDTOG_TX(uint8_t bEpNum) { _SetENDPOINT(bEpNum,EP_CTR_RX | EP_CTR_TX | EP_DTOG_TX | (_GetENDPOINT(bEpNum) & EPREG_MASK)); }
/******************************************************************************* * Function Name : ClearDTOG_TX. * Description : Clear the DTOG_TX bit. * Input : bEpNum: Endpoint Number. * Output : None. * Return : None. *******************************************************************************/ void ClearDTOG_TX(uint8_t bEpNum) { if ((_GetENDPOINT(bEpNum) & EP_DTOG_TX) != 0) ToggleDTOG_TX(bEpNum); }
/******************************************************************************* * Function Name : ClearEP_KIND * Description : set the EP_KIND bit. * Input : bEpNum: Endpoint Number. * Output : None. * Return : None. *******************************************************************************/ void ClearEP_KIND(uint8_t bEpNum) { _SetENDPOINT(bEpNum,EP_CTR_RX | EP_CTR_TX | (_GetENDPOINT(bEpNum) & EPKIND_MASK)); }
/******************************************************************************* * Function Name : ClearEP_CTR_TX * Description : Clear the CTR_TX bit. * Input : bEpNum: Endpoint Number. * Output : None. * Return : None. *******************************************************************************/ void ClearEP_CTR_TX(uint8_t bEpNum) { _SetENDPOINT(bEpNum,_GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK); }
/******************************************************************************* * Function Name : SetEP_KIND * Description : Clear the EP_KIND bit. * Input : bEpNum: Endpoint Number. * Output : None. * Return : None. *******************************************************************************/ void SetEP_KIND(uint8_t bEpNum) { _SetENDPOINT(bEpNum,EP_CTR_RX | EP_CTR_TX | ((_GetENDPOINT(bEpNum) | EP_KIND) & EPREG_MASK)); }
/******************************************************************************* * Function Name : GetEPRxStatus * Description : Returns the endpoint Rx status. * Input : bEpNum: Endpoint Number. * Output : None. * Return : Endpoint RX Status *******************************************************************************/ uint16_t GetEPRxStatus(uint8_t bEpNum) { return (uint16_t)_GetENDPOINT(bEpNum) & EPRX_STAT; }
/******************************************************************************* * Function Name : USB_Istr * Description : ISTR events interrupt service routine * Input : None. * Output : None. * Return : None. *******************************************************************************/ void USB_Istr(void) { uint32_t i=0; __IO uint32_t EP[8]; wIstr = _GetISTR(); DBG_USB_PRINT("USB Isr\r\n"); #if (IMR_MSK & ISTR_SOF) if (wIstr & ISTR_SOF & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_SOF); bIntPackSOF++; #ifdef SOF_CALLBACK SOF_Callback(); #endif } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ DBG_USB_PRINT("USB Isr 1\r\n"); #if (IMR_MSK & ISTR_CTR) if (wIstr & ISTR_CTR & wInterrupt_Mask) { /* servicing of the endpoint correct transfer interrupt */ /* clear of the CTR flag into the sub */ CTR_LP(); #ifdef CTR_CALLBACK CTR_Callback(); #endif } #endif DBG_USB_PRINT("USB Isr 2\r\n"); /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_RESET) if (wIstr & ISTR_RESET & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_RESET); Device_Property.Reset(); #ifdef RESET_CALLBACK RESET_Callback(); #endif } #endif DBG_USB_PRINT("USB Isr 3\r\n"); /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_DOVR) if (wIstr & ISTR_DOVR & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_DOVR); #ifdef DOVR_CALLBACK DOVR_Callback(); #endif } #endif DBG_USB_PRINT("USB Isr 4\r\n"); /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_ERR) if (wIstr & ISTR_ERR & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_ERR); #ifdef ERR_CALLBACK ERR_Callback(); #endif } #endif DBG_USB_PRINT("USB Isr 5\r\n"); /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_WKUP) if (wIstr & ISTR_WKUP & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_WKUP); Resume(RESUME_EXTERNAL); #ifdef WKUP_CALLBACK WKUP_Callback(); #endif } #endif DBG_USB_PRINT("USB Isr 6\r\n"); /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_SUSP) if (wIstr & ISTR_SUSP & wInterrupt_Mask) { /* check if SUSPEND is possible */ if (fSuspendEnabled) { DBG_USB_PRINT("Suspend\r\n"); Suspend(); } else { /* if not possible then resume after xx ms */ DBG_USB_PRINT("Resume\r\n"); Resume(RESUME_LATER); } /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ _SetISTR((uint16_t)CLR_SUSP); #ifdef SUSP_CALLBACK DBG_USB_PRINT("SUSP_Callback in\r\n"); SUSP_Callback(); DBG_USB_PRINT("SUSP_Callback out\r\n"); #endif } #endif DBG_USB_PRINT("USB Isr 7\r\n"); /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (IMR_MSK & ISTR_ESOF) if (wIstr & ISTR_ESOF & wInterrupt_Mask) { /* clear ESOF flag in ISTR */ _SetISTR((uint16_t)CLR_ESOF); if ((_GetFNR()&FNR_RXDP)!=0) { /* increment ESOF counter */ esof_counter ++; /* test if we enter in ESOF more than 3 times with FSUSP =0 and RXDP =1=>> possible missing SUSP flag*/ if ((esof_counter >3)&&((_GetCNTR()&CNTR_FSUSP)==0)) { /* this a sequence to apply a force RESET*/ /*Store CNTR value */ wCNTR = _GetCNTR(); /*Store endpoints registers status */ for (i=0;i<8;i++) EP[i] = _GetENDPOINT(i); /*apply FRES */ wCNTR|=CNTR_FRES; _SetCNTR(wCNTR); /*clear FRES*/ wCNTR&=~CNTR_FRES; _SetCNTR(wCNTR); /*poll for RESET flag in ISTR*/ while((_GetISTR()&ISTR_RESET) == 0); /* clear RESET flag in ISTR */ _SetISTR((uint16_t)CLR_RESET); /*restore Enpoints*/ for (i=0;i<8;i++) _SetENDPOINT(i, EP[i]); esof_counter = 0; } } else { esof_counter = 0; } DBG_USB_PRINT("USB Isr 8_1\r\n"); /* resume handling timing is made with ESOFs */ Resume(RESUME_ESOF); /* request without change of the machine state */ DBG_USB_PRINT("USB Isr 8_2\r\n"); #ifdef ESOF_CALLBACK ESOF_Callback(); #endif } #endif DBG_USB_PRINT("USB Isr 8\r\n"); } /* USB_Istr */
/** * @brief Correct Transfer interrupt's service * @param None * @retval None */ void CTR(void) { USB_EP *ep; uint16_t count=0; uint8_t EPindex; __IO uint16_t wIstr; __IO uint16_t wEPVal = 0; /* stay in loop while pending interrupts */ while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) { /* extract highest priority endpoint number */ EPindex = (uint8_t)(wIstr & ISTR_EP_ID); if (EPindex == 0) { /* Decode and service control endpoint interrupt */ /* DIR bit = origin of the interrupt */ if ((wIstr & ISTR_DIR) == 0) { /* DIR = 0 */ /* DIR = 0 => IN int */ /* DIR = 0 implies that (EP_CTR_TX = 1) always */ _ClearEP_CTR_TX(ENDP0); ep = &((&USB_Device_dev)->dev.in_ep[0]); ep->xfer_count = GetEPTxCount(ep->num); ep->xfer_buff += ep->xfer_count; /* TX COMPLETE */ USBD_DCD_INT_fops->DataInStage(&USB_Device_dev, 0x00); } else { /* DIR = 1 */ /* DIR = 1 & CTR_RX => SETUP or OUT int */ /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */ ep = &((&USB_Device_dev)->dev.out_ep[0]); wEPVal = _GetENDPOINT(ENDP0); if ((wEPVal &EP_SETUP) != 0) { /* Get SETUP Packet*/ ep->xfer_count = GetEPRxCount(ep->num); PMAToUserBufferCopy(&((&USB_Device_dev)->dev.setup_packet[0]),ep->pmaadress , ep->xfer_count); /* SETUP bit kept frozen while CTR_RX = 1*/ _ClearEP_CTR_RX(ENDP0); /* Process SETUP Packet*/ USBD_DCD_INT_fops->SetupStage(&USB_Device_dev); } else if ((wEPVal & EP_CTR_RX) != 0) { _ClearEP_CTR_RX(ENDP0); /* Get Control Data OUT Packet*/ ep->xfer_count = GetEPRxCount(ep->num); if (ep->xfer_count != 0) { PMAToUserBufferCopy(ep->xfer_buff, ep->pmaadress, ep->xfer_count); ep->xfer_buff+=ep->xfer_count; } /* Process Control Data OUT Packet*/ USBD_DCD_INT_fops->DataOutStage(&USB_Device_dev, 0x00); _SetEPRxCount(ENDP0, ep->maxpacket); _SetEPRxStatus(ENDP0,EP_RX_VALID); } } }/* if(EPindex == 0) */ else { /* Decode and service non control endpoints interrupt */ /* process related endpoint register */ wEPVal = _GetENDPOINT(EPindex); if ((wEPVal & EP_CTR_RX) != 0) { /* clear int flag */ _ClearEP_CTR_RX(EPindex); ep = &((&USB_Device_dev)->dev.out_ep[EPindex]); /* OUT double Buffering*/ if (ep->doublebuffer == 0) { count = GetEPRxCount(ep->num); if (count != 0) { PMAToUserBufferCopy(ep->xfer_buff, ep->pmaadress, count); } } else { if (GetENDPOINT(ep->num) & EP_DTOG_RX) { /*read from endpoint BUF0Addr buffer*/ count = GetEPDblBuf0Count(ep->num); if (count != 0) { PMAToUserBufferCopy(ep->xfer_buff, ep->pmaaddr0, count); } } else { /*read from endpoint BUF1Addr buffer*/ count = GetEPDblBuf1Count(ep->num); if (count != 0) { PMAToUserBufferCopy(ep->xfer_buff, ep->pmaaddr1, count); } } FreeUserBuffer(ep->num, EP_DBUF_OUT); } /*multi-packet on the NON control OUT endpoint*/ ep->xfer_count+=count; ep->xfer_buff+=count; if ((ep->xfer_len == 0) || (count < ep->maxpacket)) { /* RX COMPLETE */ USBD_DCD_INT_fops->DataOutStage(&USB_Device_dev, ep->num); } else { DCD_EP_PrepareRx (&USB_Device_dev,ep->num, ep->xfer_buff, ep->xfer_len); } } /* if((wEPVal & EP_CTR_RX) */ if ((wEPVal & EP_CTR_TX) != 0) { ep = &((&USB_Device_dev)->dev.in_ep[EPindex]); /* clear int flag */ _ClearEP_CTR_TX(EPindex); /* IN double Buffering*/ if (ep->doublebuffer == 0) { ep->xfer_count = GetEPTxCount(ep->num); if (ep->xfer_count != 0) { UserToPMABufferCopy(ep->xfer_buff, ep->pmaadress, ep->xfer_count); } } else { if (GetENDPOINT(ep->num) & EP_DTOG_TX) { /*read from endpoint BUF0Addr buffer*/ ep->xfer_count = GetEPDblBuf0Count(ep->num); if (ep->xfer_count != 0) { UserToPMABufferCopy(ep->xfer_buff, ep->pmaaddr0, ep->xfer_count); } } else { /*read from endpoint BUF1Addr buffer*/ ep->xfer_count = GetEPDblBuf1Count(ep->num); if (ep->xfer_count != 0) { UserToPMABufferCopy(ep->xfer_buff, ep->pmaaddr1, ep->xfer_count); } } FreeUserBuffer(ep->num, EP_DBUF_IN); } /*multi-packet on the NON control IN endpoint*/ ep->xfer_count =GetEPTxCount(ep->num); ep->xfer_buff+=ep->xfer_count; /* Zero Length Packet? */ if (ep->xfer_len == 0) { /* TX COMPLETE */ USBD_DCD_INT_fops->DataInStage(&USB_Device_dev, ep->num); } else { DCD_EP_Tx (&USB_Device_dev,ep->num, ep->xfer_buff, ep->xfer_len); } } /* if((wEPVal & EP_CTR_TX) != 0) */ }/* if(EPindex == 0) else */ }/* while(...) */ }
/******************************************************************************* * Function Name : CTR_LP. * Description : Low priority Endpoint Correct Transfer interrupt's service * routine. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CTR_LP(void) { __IO uint16_t wEPVal = 0; // stay in loop while pending interrupts while ((wIstr = *ISTR) & ISTR_CTR) { // extract highest priority endpoint number EPindex = (uint8_t)(wIstr & ISTR_EP_ID); if (EPindex == 0) { // Decode and service control endpoint interrupt // calling related service routine // (Setup0_Process, In0_Process, Out0_Process) // save RX & TX status and set both to NAK SaveRState = _GetENDPOINT(ENDP0); SaveTState = SaveRState & EPTX_STAT; SaveRState &= EPRX_STAT; SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK); // DIR bit = origin of the interrupt if ((wIstr & ISTR_DIR) == 0) { // DIR = 0 => IN int // DIR = 0 implies that (EP_CTR_TX = 1) always ClearEP_CTR_TX(ENDP0); In0_Process(); // before terminate set Tx & Rx status SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); return; } else { // DIR = 1 & CTR_RX => SETUP or OUT int // DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending wEPVal = _GetENDPOINT(ENDP0); if ((wEPVal &EP_SETUP) != 0) { ClearEP_CTR_RX(ENDP0); // SETUP bit kept frozen while CTR_RX = 1 Setup0_Process(); // before terminate set Tx & Rx status SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); return; } else if ((wEPVal & EP_CTR_RX) != 0) { ClearEP_CTR_RX(ENDP0); Out0_Process(); // before terminate set Tx & Rx status SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); return; } } } else { // Decode and service non control endpoints interrupt // process related endpoint register wEPVal = _GetENDPOINT(EPindex); if ((wEPVal & EP_CTR_RX) != 0) { // clear int flag ClearEP_CTR_RX(EPindex); // call OUT service function (*pEpInt_OUT[EPindex-1])(); } if ((wEPVal & EP_CTR_TX) != 0) { // clear int flag ClearEP_CTR_TX(EPindex); // call IN service function (*pEpInt_IN[EPindex-1])(); } } } }