/***************************************************************************//** * @brief * Reset stall state on a stalled (halted) endpoint. * * @param[in] epAddr * The address of the endpoint to un-stall. * * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ int USBD_UnStallEp( int epAddr ) { USB_Status_TypeDef retVal; CORE_DECLARE_IRQ_STATE; USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); if ( ep == NULL ) { DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal request" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( ep->num == 0 ) { DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } CORE_ENTER_CRITICAL(); retVal = USBDHAL_UnStallEp( ep ); CORE_EXIT_CRITICAL(); if ( retVal != USB_STATUS_OK ) { retVal = USB_STATUS_ILLEGAL; } return retVal; }
/***************************************************************************//** * @brief * Reset stall state on a stalled (halted) endpoint. * * @param[in] epAddr * The address of the endpoint to un-stall. * * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ int USBD_UnStallEp( int epAddr ) { USB_Status_TypeDef retVal; USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); if ( ep == NULL ) { DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal request" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( ep->num == 0 ) { DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } INT_Disable(); retVal = USBDHAL_UnStallEp( ep ); INT_Enable(); if ( retVal != USB_STATUS_OK ) { retVal = USB_STATUS_ILLEGAL; } return retVal; }
/* * Handle IN endpoint transfer interrupt. */ static void Handle_USB_GINTSTS_IEPINT( void ) { int epnum; uint16_t epint; uint16_t epmask; uint32_t status; USBD_Ep_TypeDef *ep; DEBUG_USB_INT_HI_PUTCHAR( 'i' ); epint = USBDHAL_GetAllInEpInts(); for ( epnum = 0, epmask = 1; epnum <= MAX_NUM_IN_EPS; epnum++, epmask <<= 1 ) { if ( epint & epmask ) { ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | epnum ); status = USBDHAL_GetInEpInts( ep ); if ( status & USB_DIEP_INT_XFERCOMPL ) { USB_DINEPS[ epnum ].INT = USB_DIEP_INT_XFERCOMPL; DEBUG_USB_INT_HI_PUTCHAR( 'c' ); if ( epnum == 0 ) { if ( ep->remaining > ep->packetSize ) { ep->remaining -= ep->packetSize; ep->xferred += ep->packetSize; } else { ep->xferred += ep->remaining; ep->remaining = 0; } USBDEP_Ep0Handler( dev ); } else { ep->xferred = ep->remaining - ( ( USB_DINEPS[ epnum ].TSIZ & _USB_DIEP_TSIZ_XFERSIZE_MASK ) >> _USB_DIEP_TSIZ_XFERSIZE_SHIFT ); ep->remaining -= ep->xferred; USBDEP_EpHandler( ep->addr ); #if defined( USB_DOEP0INT_STUPPKTRCVD ) if ( USB_DINEPS[ ep->num ].INT & USB_DIEP_INT_NAKINTRPT ) { USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_NAKINTRPT; } #endif } } }
/***************************************************************************//** * @brief * Query the stall state of an endpoint * * @param[in] epAddr * The address of the endpoint to query. * * @return * True if endpoint is stalled, false otherwise ******************************************************************************/ int USBD_EpIsStalled(int epAddr) { USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); if( !ep ) { return false; } return USBDHAL_EpIsStalled(ep); }
/***************************************************************************//** * @brief * Set an endpoint0 in the stalled (halted) state. * * @details * Temporarily stalls endpoint 0. Used to signal a failure to respond to * the host's setup packet. ******************************************************************************/ void USBD_StallEp0() { int const epAddr = 0; USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); ep->in = true; USBDHAL_StallEp( ep ); /* Stall Ep0 IN */ ep->in = false; /* OUT for next SETUP */ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */ #if !defined( USB_DOEP0INT_STUPPKTRCVD ) USBDHAL_ReenableEp0Setup( dev ); /* Prepare for next SETUP pkt. */ #else USBDHAL_StartEp0Setup( dev ); #endif ep->state = D_EP_IDLE; }
/***************************************************************************//** * @brief * Abort a pending transfer on a specific endpoint. * * @param[in] epAddr * The address of the endpoint to abort. ******************************************************************************/ int USBD_AbortTransfer( int epAddr ) { USB_XferCompleteCb_TypeDef callback; USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); CORE_DECLARE_IRQ_STATE; if ( ep == NULL ) { DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( ep->num == 0 ) { DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } CORE_ENTER_CRITICAL(); if ( ep->state == D_EP_IDLE ) { CORE_EXIT_CRITICAL(); return USB_STATUS_OK; } USBD_AbortEp( ep ); ep->state = D_EP_IDLE; if ( ep->xferCompleteCb ) { callback = ep->xferCompleteCb; ep->xferCompleteCb = NULL; if ( ( dev->lastState == USBD_STATE_CONFIGURED ) && ( dev->state == USBD_STATE_ADDRESSED ) ) { USBDHAL_DeactivateEp( ep ); } DEBUG_TRACE_ABORT( USB_STATUS_EP_ABORTED ); callback( USB_STATUS_EP_ABORTED, ep->xferred, ep->remaining ); } CORE_EXIT_CRITICAL(); return USB_STATUS_OK; }
/***************************************************************************//** * @brief * Check if an endpoint is busy doing a transfer. * * @param[in] epAddr * The address of the endpoint to check. * * @return * True if endpoint is busy, false otherwise. ******************************************************************************/ bool USBD_EpIsBusy( int epAddr ) { USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); if ( ep == NULL ) { DEBUG_USB_API_PUTS( "\nUSBD_EpIsBusy(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( ep->state == D_EP_IDLE ) return false; return true; }
/* * USBDEP_EpHandler() is called each time a packet has been transmitted * or recieved on an endpoint other than the default endpoint. */ void USBDEP_EpHandler( uint8_t epAddr ) { USB_XferCompleteCb_TypeDef callback; USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); if ( ( ep->state == D_EP_TRANSMITTING ) || ( ep->state == D_EP_RECEIVING ) ) { ep->state = D_EP_IDLE; if ( ep->xferCompleteCb ) { callback = ep->xferCompleteCb; ep->xferCompleteCb = NULL; callback( USB_STATUS_OK, ep->xferred, ep->remaining ); } } else { EFM_ASSERT( false ); } }
/***************************************************************************//** * @brief * Start a write (IN) transfer on an endpoint. * * @param[in] epAddr * Endpoint address. * * @param[in] data * Pointer to transfer data buffer. This buffer must be WORD (4 byte) aligned. * * @param[in] byteCount * Transfer length. * * @param[in] callback * Function to be called on transfer completion. Supply NULL if no callback * is needed. See @ref USB_XferCompleteCb_TypeDef. * * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ int USBD_Write( int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback ) { USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); CORE_DECLARE_IRQ_STATE; USB_PRINTF("USBD: Write addr %x, data %p, size %d, cb 0x%lx\n", epAddr, data, byteCount, (uint32_t)callback); if ( ep == NULL ) { DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( ( byteCount > MAX_XFER_LEN ) || ( ( byteCount / ep->packetSize ) > MAX_PACKETS_PR_XFER ) ) { DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal transfer size" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( (uint32_t)data & 3 ) { DEBUG_USB_API_PUTS( "\nUSBD_Write(), Misaligned data buffer" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } CORE_ENTER_CRITICAL(); if ( USBDHAL_EpIsStalled( ep ) ) { CORE_EXIT_CRITICAL(); DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is halted" ); return USB_STATUS_EP_STALLED; } if ( ep->state != D_EP_IDLE ) { CORE_EXIT_CRITICAL(); DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is busy" ); return USB_STATUS_EP_BUSY; } if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) ) { CORE_EXIT_CRITICAL(); DEBUG_USB_API_PUTS( "\nUSBD_Write(), Device not configured" ); return USB_STATUS_DEVICE_UNCONFIGURED; } ep->buf = (uint8_t*)data; ep->remaining = byteCount; ep->xferred = 0; if ( ep->num == 0 ) { ep->in = true; } else if ( ep->in != true ) { CORE_EXIT_CRITICAL(); DEBUG_USB_API_PUTS( "\nUSBD_Write(), Illegal EP direction" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } ep->state = D_EP_TRANSMITTING; ep->xferCompleteCb = callback; USBD_ArmEp( ep ); CORE_EXIT_CRITICAL(); return USB_STATUS_OK; }
/***************************************************************************//** * @brief * Start a read (OUT) transfer on an endpoint. * * @note * The transfer buffer length must be a multiple of 4 bytes in length and * WORD (4 byte) aligned. When allocating the buffer, round buffer length up. * If it is possible that the host will send more data than your device * expects, round buffer size up to the next multiple of maxpacket size. * * @param[in] epAddr * Endpoint address. * * @param[in] data * Pointer to transfer data buffer. * * @param[in] byteCount * Transfer length. * * @param[in] callback * Function to be called on transfer completion. Supply NULL if no callback * is needed. See @ref USB_XferCompleteCb_TypeDef. * * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ int USBD_Read( int epAddr, void *data, int byteCount, USB_XferCompleteCb_TypeDef callback ) { USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); if ( ep == NULL ) { DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( ( byteCount > MAX_XFER_LEN ) || ( ( byteCount / ep->packetSize ) > MAX_PACKETS_PR_XFER ) ) { DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal transfer size" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } #if !defined( USB_SLAVEMODE ) if ( (uint32_t)data & 3 ) { DEBUG_USB_API_PUTS( "\nUSBD_Read(), Misaligned data buffer" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } #endif INT_Disable(); if ( USBDHAL_EpIsStalled( ep ) ) { INT_Enable(); DEBUG_USB_API_PUTS( "\nUSBD_Read(), Endpoint is halted" ); return USB_STATUS_EP_STALLED; } if ( ep->state != D_EP_IDLE ) { INT_Enable(); DEBUG_USB_API_PUTS( "\nUSBD_Read(), Endpoint is busy" ); return USB_STATUS_EP_BUSY; } if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) ) { INT_Enable(); DEBUG_USB_API_PUTS( "\nUSBD_Read(), Device not configured" ); return USB_STATUS_DEVICE_UNCONFIGURED; } ep->buf = (uint8_t*)data; ep->remaining = byteCount; ep->xferred = 0; if ( ep->num == 0 ) { ep->in = false; } else if ( ep->in != false ) { INT_Enable(); DEBUG_USB_API_PUTS( "\nUSBD_Read(), Illegal EP direction" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } ep->state = D_EP_RECEIVING; ep->xferCompleteCb = callback; USBD_ArmEp( ep ); INT_Enable(); return USB_STATUS_OK; }