Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBDevice by
Diff: USBDevice/TARGET_Silicon_Labs/src/em_usbdep.c
- Revision:
- 59:2af474687369
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/TARGET_Silicon_Labs/src/em_usbdep.c Thu Aug 13 15:46:06 2015 +0100
@@ -0,0 +1,446 @@
+/**************************************************************************//**
+ * @file em_usbdep.c
+ * @brief USB protocol stack library, USB device endpoint handlers.
+ * @version 3.20.14
+ ******************************************************************************
+ * @section License
+ * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
+ *******************************************************************************
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "em_device.h"
+#if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
+#include "em_usb.h"
+#if defined( USB_DEVICE )
+
+#include "em_usbtypes.h"
+#include "em_usbhal.h"
+#include "em_usbd.h"
+
+#ifdef USB_USE_PRINTF
+static const char *epStatusStr[] = {
+ "IDLE","TRANS","RECV","IN_S","OUT_S"
+};
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/*
+ * USBDEP_Ep0Handler() is called each time a packet has been transmitted
+ * or recieved on the default endpoint.
+ * A state machine navigate us through the phases of a control transfer
+ * according to "chapter 9" in the USB spec.
+ */
+#if !defined( USB_DOEP0INT_STUPPKTRCVD )
+void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
+{
+ int status;
+ USBD_Ep_TypeDef *ep;
+ static bool statusIn;
+ static uint32_t xferred;
+ static USB_XferCompleteCb_TypeDef callback;
+
+ ep = &device->ep[ 0 ];
+
+#ifdef __MBED__
+
+ (void)xferred;
+ (void)statusIn;
+ (void)status;
+
+ USB_PRINTF("USBDEP: ep0 %s, rem %ld, z %d\n", epStatusStr[ep->state], ep->remaining, ep->zlp);
+
+ 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 );
+ }
+
+ USBDHAL_ReenableEp0Setup(device);
+ }
+ else
+ {
+ device->callbacks->setupCmd(device->setup);
+ }
+
+#else /* not __MBED__ */
+
+ switch ( ep->state )
+ {
+ case D_EP_IDLE:
+ ep->remaining = 0;
+ ep->zlp = 0;
+ callback = NULL;
+ statusIn = false;
+
+ status = USBDCH9_SetupCmd( device );
+
+ if ( status == USB_STATUS_REQ_ERR )
+ {
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+ USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP packet*/
+ }
+ else /* ( Status == USB_STATUS_OK ) */
+ {
+ if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
+ {
+ callback = ep->xferCompleteCb;
+ }
+
+ if ( ep->state != D_EP_RECEIVING )
+ {
+ if ( ep->remaining )
+ {
+ /* Data will be sent to host, check if a ZLP must be appended */
+ if ( ( ep->remaining < device->setup->wLength ) &&
+ ( ep->remaining % ep->packetSize == 0 ) )
+ {
+ ep->zlp = 1;
+ }
+ }
+ else
+ {
+ /* Prepare for next SETUP packet*/
+ USBDHAL_ReenableEp0Setup( device );
+
+ /* No data stage, a ZLP may have been sent. If not, send one */
+
+ xferred = 0;
+ if ( ep->zlp == 0 )
+ {
+ USBD_Write( 0, NULL, 0, NULL ); /* ACK to host */
+ ep->state = D_EP0_IN_STATUS;
+ }
+ else
+ {
+ ep->state = D_EP_IDLE;
+ ep->in = false; /* OUT for next SETUP */
+ }
+ }
+ }
+ }
+ break;
+
+ case D_EP_RECEIVING:
+ if ( ep->remaining )
+ {
+ /* There is more data to receive */
+ USBD_ReArmEp0( ep );
+ }
+ else
+ {
+ status = USB_STATUS_OK;
+ if ( callback != NULL )
+ {
+ status = callback( USB_STATUS_OK, ep->xferred, 0 );
+ callback = NULL;
+ }
+
+ if ( status != USB_STATUS_OK )
+ {
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+ USBDHAL_ReenableEp0Setup( device ); /* Prepare for next SETUP pkt. */
+ ep->state = D_EP_IDLE;
+ }
+ else /* Everything OK, send a ZLP (ACK) to host */
+ {
+ USBDHAL_ReenableEp0Setup( device );/* Prepare for next SETUP packet*/
+
+ ep->state = D_EP_IDLE; /* USBD_Write() sets state back*/
+ /* to EP_TRANSMITTING */
+ USBD_Write( 0, NULL, 0, NULL );
+ ep->state = D_EP0_IN_STATUS;
+ }
+ }
+ break;
+
+ case D_EP_TRANSMITTING:
+ if ( ep->remaining )
+ {
+ /* There is more data to transmit */
+ USBD_ReArmEp0( ep );
+ }
+ else
+ {
+ /* All data transferred, is a ZLP packet needed ? */
+ if ( ep->zlp == 1 )
+ {
+ xferred = ep->xferred;
+ ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
+ /* to EP_TRANSMITTING */
+ USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP */
+ ep->zlp = 2;
+ }
+ else
+ {
+ if ( ep->zlp == 0 )
+ {
+ xferred = ep->xferred;
+ }
+
+ ep->state = D_EP_IDLE;
+ USBD_Read( 0, NULL, 0, NULL ); /* Get ZLP packet (ACK) from host */
+ statusIn = true;
+ ep->state = D_EP0_OUT_STATUS;
+ }
+ }
+ break;
+
+ case D_EP0_IN_STATUS:
+ case D_EP0_OUT_STATUS:
+ if ( statusIn )
+ {
+ USBDHAL_ReenableEp0Setup( device );
+ }
+
+ if ( callback != NULL )
+ {
+ callback( USB_STATUS_OK, xferred, 0 );
+ }
+
+ ep->state = D_EP_IDLE;
+ ep->in = false; /* OUT for next SETUP */
+ break;
+
+ default:
+ EFM_ASSERT( false );
+ break;
+ }
+#endif /* __MBED__ */
+}
+#endif
+
+#if defined( USB_DOEP0INT_STUPPKTRCVD )
+void USBDEP_Ep0Handler( USBD_Device_TypeDef *device )
+{
+ int status;
+ USBD_Ep_TypeDef *ep;
+ static uint32_t xferred;
+ static USB_XferCompleteCb_TypeDef callback;
+
+#ifdef __MBED__
+
+ (void)xferred;
+ (void)status;
+
+ ep = &device->ep[ 0 ];
+
+ 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 );
+ }
+
+ USBDHAL_StartEp0Setup( dev );
+ }
+ else
+ {
+ device->callbacks->setupCmd(device->setup);
+ }
+
+#else
+
+ ep = &device->ep[ 0 ];
+
+ switch ( ep->state )
+ {
+ case D_EP_IDLE:
+ ep->zlp = 0;
+ ep->remaining = 0;
+ callback = NULL;
+
+ status = USBDCH9_SetupCmd( device );
+
+ if ( status == USB_STATUS_REQ_ERR )
+ {
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+ USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP packet*/
+ }
+ else /* ( Status == USB_STATUS_OK ) */
+ {
+ if ( (ep->state == D_EP_RECEIVING) || (ep->state == D_EP_TRANSMITTING) )
+ {
+ callback = ep->xferCompleteCb;
+ }
+
+ if ( ep->state != D_EP_RECEIVING )
+ {
+ if ( ep->remaining )
+ {
+ /* Data will be sent to host, check if a ZLP must be appended */
+ if ( ( ep->remaining < device->setup->wLength ) &&
+ ( ep->remaining % ep->packetSize == 0 ) )
+ {
+ ep->zlp = 1;
+ }
+ }
+ else
+ {
+ /* No data stage, a ZLP may have been sent. If not, send one */
+ xferred = 0;
+ if ( ep->zlp == 0 )
+ {
+ ep->state = D_EP_IDLE;
+ USBD_Write( 0, NULL, 0, NULL ); /* ACK to host */
+ ep->state = D_EP0_IN_STATUS;
+ }
+ }
+ }
+ }
+ break;
+
+ case D_EP_RECEIVING:
+ if ( ep->remaining )
+ {
+ ep->in = false;
+ USBD_ReArmEp0( ep );
+ }
+ else
+ {
+ status = USB_STATUS_OK;
+ if ( callback != NULL )
+ {
+ status = callback( USB_STATUS_OK, ep->xferred, 0 );
+ callback = NULL;
+ }
+
+ if ( status != USB_STATUS_OK )
+ {
+ ep->in = true;
+ USBDHAL_StallEp( ep ); /* Stall Ep0 IN */
+ ep->in = false; /* OUT for next SETUP */
+ USBDHAL_StallEp( ep ); /* Stall Ep0 OUT */
+ USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP pkt. */
+ ep->state = D_EP_IDLE;
+ }
+ else
+ {
+
+ USBDHAL_StartEp0Setup( dev ); /* Prepare for next SETUP packet*/
+ ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
+ /* to EP_TRANSMITTING */
+ USBD_Write( 0, NULL, 0, NULL );
+ ep->state = D_EP0_IN_STATUS;
+ }
+ }
+ break;
+
+ case D_EP_TRANSMITTING:
+ if ( ep->remaining )
+ {
+ ep->in = true;
+ USBD_ReArmEp0( ep );
+ }
+ else
+ {
+ if ( ep->zlp == 1 )
+ {
+ xferred = ep->xferred;
+ ep->state = D_EP_IDLE; /* USBD_Write() sets state back */
+ /* to EP_TRANSMITTING */
+ USBD_Write( 0, NULL, 0, NULL ); /* Send ZLP */
+ ep->zlp = 2;
+ }
+ else
+ {
+ if ( ep->zlp == 0 )
+ {
+ xferred = ep->xferred;
+ }
+
+ ep->state = D_EP_IDLE;
+ USBD_Read( 0, NULL, 0, NULL ); /* Get ZLP packet (ACK) from host */
+ ep->state = D_EP0_OUT_STATUS;
+ }
+ }
+ break;
+
+ case D_EP0_IN_STATUS:
+ if ( ( USB->DOEP0CTL & USB_DOEP0CTL_EPENA ) == 0 )
+ {
+ /* Prepare for more SETUP Packets */
+ USBDHAL_StartEp0Setup( dev );
+ }
+ if ( callback != NULL )
+ {
+ callback( USB_STATUS_OK, xferred, 0 );
+ }
+ ep->state = D_EP_IDLE;
+ ep->in = false; /* OUT for next SETUP */
+ break;
+
+ case D_EP0_OUT_STATUS:
+ USBDHAL_StartEp0Setup( dev ); /* Prepare for more SETUP Packets */
+ if ( callback != NULL )
+ {
+ callback( USB_STATUS_OK, xferred, 0 );
+ }
+ ep->state = D_EP_IDLE;
+ ep->in = false; /* OUT for next SETUP */
+ break;
+ }
+#endif /* __MBED__ */
+}
+#endif
+
+/*
+ * 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 );
+ }
+}
+
+/** @endcond */
+
+#endif /* defined( USB_DEVICE ) */
+#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
