a
Fork of USBDevice by
Diff: USBDevice/TARGET_Silicon_Labs/src/em_usbd.c
- Revision:
- 71:53949e6131f6
- Parent:
- 70:2c525a50f1b6
--- a/USBDevice/TARGET_Silicon_Labs/src/em_usbd.c Thu Jul 20 10:14:36 2017 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1438 +0,0 @@
-/**************************************************************************//**
- * @file em_usbd.c
- * @brief USB protocol stack library, device API.
- * @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_cmu.h"
-#include "em_usbtypes.h"
-#include "em_usbhal.h"
-#include "em_usbd.h"
-
-/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
-
-static USBD_Device_TypeDef device;
-USBD_Device_TypeDef *dev = &device;
-
-static uint32_t totalRxFifoSize = 0, totalTxFifoSize = 0;
-static int numEps = 0;
-static int txFifoNum = 1;
-
-static void USBD_ResetEndpoints(void);
-extern USB_Status_TypeDef USBDHAL_ReconfigureFifos( uint32_t totalRxFifoSize,
- uint32_t totalTxFifoSize );
-#ifndef __MBED__
-static const char *stateNames[] =
-{
- [ USBD_STATE_NONE ] = "NONE ",
- [ USBD_STATE_ATTACHED ] = "ATTACHED ",
- [ USBD_STATE_POWERED ] = "POWERED ",
- [ USBD_STATE_DEFAULT ] = "DEFAULT ",
- [ USBD_STATE_ADDRESSED ] = "ADDRESSED ",
- [ USBD_STATE_CONFIGURED ] = "CONFIGURED",
- [ USBD_STATE_SUSPENDED ] = "SUSPENDED ",
- [ USBD_STATE_LASTMARKER ] = "UNDEFINED "
-};
-#endif
-
-/** @endcond */
-
-/***************************************************************************//**
- * @brief
- * Abort all pending transfers.
- *
- * @details
- * Aborts transfers for all endpoints currently in use. Pending
- * transfers on the default endpoint (EP0) are not aborted.
- ******************************************************************************/
-void USBD_AbortAllTransfers( void )
-{
- INT_Disable();
- USBDHAL_AbortAllTransfers( USB_STATUS_EP_ABORTED );
- INT_Enable();
-}
-
-/***************************************************************************//**
- * @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 );
-
- 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;
- }
-
- INT_Disable();
- if ( ep->state == D_EP_IDLE )
- {
- INT_Enable();
- 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 );
- }
-
- INT_Enable();
- return USB_STATUS_OK;
-}
-
-/***************************************************************************//**
- * @brief
- * Start USB device operation.
- *
- * @details
- * Device operation is started by connecting a pullup resistor on the
- * appropriate USB data line.
- ******************************************************************************/
-void USBD_Connect( void )
-{
- INT_Disable();
- USBDHAL_Connect();
- INT_Enable();
-}
-
-/***************************************************************************//**
- * @brief
- * Stop USB device operation.
- *
- * @details
- * Device operation is stopped by disconnecting the pullup resistor from the
- * appropriate USB data line. Often referred to as a "soft" disconnect.
- ******************************************************************************/
-void USBD_Disconnect( void )
-{
- INT_Disable();
- USBDHAL_Disconnect();
- INT_Enable();
-}
-
-/***************************************************************************//**
- * @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;
-}
-
-/***************************************************************************//**
- * @brief
- * Get current USB device state.
- *
- * @return
- * Device USB state. See @ref USBD_State_TypeDef.
- ******************************************************************************/
-USBD_State_TypeDef USBD_GetUsbState( void )
-{
- return dev->state;
-}
-
-/***************************************************************************//**
- * @brief
- * Get a string naming a device USB state.
- *
- * @param[in] state
- * Device USB state. See @ref USBD_State_TypeDef.
- *
- * @return
- * State name string pointer.
- ******************************************************************************/
-const char *USBD_GetUsbStateName( USBD_State_TypeDef state )
-{
- if ( state > USBD_STATE_LASTMARKER )
- state = USBD_STATE_LASTMARKER;
-
-#ifndef __MBED__
- return stateNames[ state ];
-#else
- return NULL;
-#endif
-}
-
-/***************************************************************************//**
- * @brief
- * Initializes USB device hardware and internal protocol stack data structures,
- * then connects the data-line (D+ or D-) pullup resistor to signal host that
- * enumeration can begin.
- *
- * @note
- * You may later use @ref USBD_Disconnect() and @ref USBD_Connect() to force
- * reenumeration.
- *
- * @param[in] p
- * Pointer to device initialization struct. See @ref USBD_Init_TypeDef.
- *
- * @return
- * @ref USB_STATUS_OK on success, else an appropriate error code.
- ******************************************************************************/
-int USBD_Init( const USBD_Init_TypeDef *p )
-{
- USBD_Ep_TypeDef *ep;
-
-#if !defined( USB_CORECLK_HFRCO ) || !defined( CMU_OSCENCMD_USHFRCOEN )
- /* Devices supporting crystal-less USB can use HFRCO or HFXO as core clock. */
- /* All other devices must use HFXO as core clock. */
- if ( CMU_ClockSelectGet( cmuClock_HF ) != cmuSelect_HFXO )
- {
- CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
- }
-#endif
-
-#if !defined( CMU_OSCENCMD_USHFRCOEN )
-#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
- CMU_OscillatorEnable(cmuOsc_LFXO, true, false);
-#else
- CMU_OscillatorEnable(cmuOsc_LFRCO, true, false);
-#endif
-
-#else
- CMU_ClockEnable(cmuClock_CORELE, true);
- /* LFC clock is needed to detect USB suspend when LEMIDLE is activated. */
-#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
- CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFXO);
-#else
- CMU_ClockSelectSet(cmuClock_LFC, cmuSelect_LFRCO);
-#endif
- CMU_ClockEnable(cmuClock_USBLE, true);
-#endif
-
- USBTIMER_Init();
-
- memset( dev, 0, sizeof( USBD_Device_TypeDef ) );
-
- dev->setup = dev->setupPkt;
- dev->state = USBD_STATE_LASTMARKER;
- dev->savedState = USBD_STATE_NONE;
- dev->lastState = USBD_STATE_NONE;
- dev->callbacks = p->callbacks;
- dev->remoteWakeupEnabled = false;
-
- /* Initialize EP0 */
-
- ep = &dev->ep[ 0 ];
- ep->in = false;
- ep->buf = NULL;
- ep->num = 0;
- ep->mask = 1;
- ep->addr = 0;
- ep->type = USB_EPTYPE_CTRL;
- ep->txFifoNum = 0;
-
- /* FIXME! */
- ep->packetSize = 64;
- dev->ep0MpsCode = _USB_DOEP0CTL_MPS_64B;
-
- ep->remaining = 0;
- ep->xferred = 0;
- ep->state = D_EP_IDLE;
- ep->xferCompleteCb = NULL;
- ep->fifoSize = ep->packetSize / 4;
-
- totalTxFifoSize = ep->fifoSize * p->bufferingMultiplier[ 0 ];
- totalRxFifoSize = (ep->fifoSize + 1) * p->bufferingMultiplier[ 0 ];
-
- /* Rx-FIFO size: SETUP packets : 4*n + 6 n=#CTRL EP's
- * GOTNAK : 1
- * Status info : 2*n n=#OUT EP's (EP0 included) in HW
- */
- totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) );
-
- INT_Disable();
-
- /* Enable USB clock */
- CMU->HFCORECLKEN0 |= CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC;
-
-#if defined( CMU_OSCENCMD_USHFRCOEN )
- CMU->USHFRCOCONF = CMU_USHFRCOCONF_BAND_48MHZ;
- CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_USHFRCO );
-
- /* Enable USHFRCO Clock Recovery mode. */
- CMU->USBCRCTRL |= CMU_USBCRCTRL_EN;
-
- /* Turn on Low Energy Mode (LEM) features. */
- USB->CTRL = USB_CTRL_LEMOSCCTRL_GATE
- | USB_CTRL_LEMIDLEEN
- | USB_CTRL_LEMPHYCTRL;
-#else
- CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_HFCLK );
-#endif
-
- USBHAL_DisableGlobalInt();
-
- if ( USBDHAL_CoreInit( totalRxFifoSize, totalTxFifoSize ) == USB_STATUS_OK )
- {
- USBDHAL_EnableUsbResetAndSuspendInt();
- USBHAL_EnableGlobalInt();
- NVIC_ClearPendingIRQ( USB_IRQn );
- NVIC_EnableIRQ( USB_IRQn );
- }
- else
- {
- INT_Enable();
- DEBUG_USB_API_PUTS( "\nUSBD_Init(), FIFO setup error" );
- EFM_ASSERT( false );
- return USB_STATUS_ILLEGAL;
- }
-
-#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
- if ( USBHAL_VbusIsOn() )
- {
- USBD_SetUsbState( USBD_STATE_POWERED );
- }
- else
-#endif
- {
- USBD_SetUsbState( USBD_STATE_NONE );
- }
-
- INT_Enable();
- 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 );
-
- USB_PRINTF("USBD: Read addr %x, data %p, size %d, cb 0x%lx\n",
- epAddr, data, byteCount, (uint32_t)callback);
-
- 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 ( (uint32_t)data & 3 )
- {
- DEBUG_USB_API_PUTS( "\nUSBD_Read(), Misaligned data buffer" );
- EFM_ASSERT( false );
- return USB_STATUS_ILLEGAL;
- }
-
- 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;
-}
-
-/***************************************************************************//**
- * @brief
- * Perform a remote wakeup signalling sequence.
- *
- * @note
- * It is the responsibility of the application to ensure that remote wakeup
- * is not attempted before the device has been suspended for at least 5
- * miliseconds. This function should not be called from within an interrupt
- * handler.
- *
- * @return
- * @ref USB_STATUS_OK on success, else an appropriate error code.
- ******************************************************************************/
-int USBD_RemoteWakeup( void )
-{
- INT_Disable();
-
- if ( ( dev->state != USBD_STATE_SUSPENDED ) ||
- ( dev->remoteWakeupEnabled == false ) )
- {
- INT_Enable();
- DEBUG_USB_API_PUTS( "\nUSBD_RemoteWakeup(), Illegal remote wakeup" );
- return USB_STATUS_ILLEGAL;
- }
-
- USBDHAL_SetRemoteWakeup();
- INT_Enable();
- USBTIMER_DelayMs( 10 );
- INT_Disable();
- USBDHAL_ClearRemoteWakeup();
- INT_Enable();
- return USB_STATUS_OK;
-}
-
-/***************************************************************************//**
- * @brief
- * Check if it is ok to enter energy mode EM2.
- *
- * @note
- * Before entering EM2 both the USB hardware and the USB stack must be in a
- * certain state, this function checks if all conditions for entering EM2
- * is met.
- * Refer to the @ref usb_device_powersave section for more information.
- *
- * @return
- * True if ok to enter EM2, false otherwise.
- ******************************************************************************/
-bool USBD_SafeToEnterEM2( void )
-{
-#if ( USB_PWRSAVE_MODE )
- return USBD_poweredDown ? true : false;
-#else
- return false;
-#endif
-}
-
-/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
-
-void USBD_SetUsbState( USBD_State_TypeDef newState )
-{
- USBD_State_TypeDef currentState;
-
- currentState = dev->state;
- if ( newState == USBD_STATE_SUSPENDED )
- {
- dev->savedState = currentState;
- }
-
- dev->lastState = dev->state;
- dev->state = newState;
-
- if ( ( dev->callbacks->usbStateChange ) &&
- ( currentState != newState ) )
- {
- /* When we transition to a state "lower" than CONFIGURED
- * we must reset the endpoint data
- */
- if ( (dev->lastState == USBD_STATE_CONFIGURED ||
- dev->lastState == USBD_STATE_SUSPENDED ) &&
- dev->state < USBD_STATE_CONFIGURED )
- {
- USBD_ResetEndpoints();
- }
-
- dev->callbacks->usbStateChange( currentState, newState );
- }
-}
-
-/** @endcond */
-
-/***************************************************************************//**
- * @brief
- * Set an endpoint in the stalled (halted) state.
- *
- * @param[in] epAddr
- * The address of the endpoint to stall.
- *
- * @return
- * @ref USB_STATUS_OK on success, else an appropriate error code.
- ******************************************************************************/
-int USBD_StallEp( int epAddr )
-{
- USB_Status_TypeDef retVal;
- USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr );
-
- if ( ep == NULL )
- {
- DEBUG_USB_API_PUTS( "\nUSBD_StallEp(), Illegal request" );
- EFM_ASSERT( false );
- return USB_STATUS_ILLEGAL;
- }
-
- if ( ep->num == 0 )
- {
- DEBUG_USB_API_PUTS( "\nUSBD_StallEp(), Illegal endpoint" );
- EFM_ASSERT( false );
- return USB_STATUS_ILLEGAL;
- }
-
- INT_Disable();
- retVal = USBDHAL_StallEp( ep );
- INT_Enable();
-
- if ( retVal != USB_STATUS_OK )
- {
- retVal = USB_STATUS_ILLEGAL;
- }
-
- return retVal;
-}
-
-/***************************************************************************//**
- * @brief
- * Stop USB device stack operation.
- *
- * @details
- * The data-line pullup resistor is turned off, USB interrupts are disabled,
- * and finally the USB pins are disabled.
- ******************************************************************************/
-void USBD_Stop( void )
-{
- USBD_Disconnect();
- NVIC_DisableIRQ( USB_IRQn );
- USBHAL_DisableGlobalInt();
- USBHAL_DisableUsbInt();
- USBHAL_DisablePhyPins();
- USBD_SetUsbState( USBD_STATE_NONE );
- /* Turn off USB clocks. */
- CMU->HFCORECLKEN0 &= ~(CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC);
-}
-
-/***************************************************************************//**
- * @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;
-}
-
-/***************************************************************************//**
- * @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 );
-
- 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;
- }
-
- INT_Disable();
- if ( USBDHAL_EpIsStalled( ep ) )
- {
- INT_Enable();
- DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is halted" );
- return USB_STATUS_EP_STALLED;
- }
-
- if ( ep->state != D_EP_IDLE )
- {
- INT_Enable();
- DEBUG_USB_API_PUTS( "\nUSBD_Write(), Endpoint is busy" );
- return USB_STATUS_EP_BUSY;
- }
-
- if ( ( ep->num > 0 ) && ( USBD_GetUsbState() != USBD_STATE_CONFIGURED ) )
- {
- INT_Enable();
- 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 )
- {
- INT_Enable();
- 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 );
- INT_Enable();
- return USB_STATUS_OK;
-}
-
-int USBD_SetAddress(uint8_t addr)
-{
- int retVal = USB_STATUS_REQ_ERR;
-
- if ( dev->state == USBD_STATE_DEFAULT )
- {
- if ( addr != 0 )
- {
- USBD_SetUsbState( USBD_STATE_ADDRESSED );
- }
- USBDHAL_SetAddr( addr );
- retVal = USB_STATUS_OK;
- }
- else if ( dev->state == USBD_STATE_ADDRESSED )
- {
- if ( addr == 0 )
- {
- USBD_SetUsbState( USBD_STATE_DEFAULT );
- }
- USBDHAL_SetAddr( addr );
- retVal = USB_STATUS_OK;
- }
-
- return retVal;
-}
-
-/***************************************************************************//**
- * @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
- * Reset (remove) all client endpoints
- *
- * @details
- * Removes client endpoints, and resets the RX/TX fifos. No endpoints
- * other than EP0 can be used until added with @ref USBD_AddEndpoint.
- ******************************************************************************/
-static void USBD_ResetEndpoints(void)
-{
- USBD_Ep_TypeDef *ep = &dev->ep[0];
-
- numEps = 0;
- txFifoNum = 1;
-
- totalTxFifoSize = ep->fifoSize * 1;
- totalRxFifoSize = (ep->fifoSize + 1) * 1;
- totalRxFifoSize += 10 + 1 + ( 2 * (MAX_NUM_OUT_EPS + 1) );
-}
-
-/***************************************************************************//**
- * @brief
- * Add a new endpoint
- *
- * @param[in] epAddr
- * Endpoint address
- *
- * @param[in] transferType
- * Endpoint type, one of @ref USB_EPTYPE_BULK, @ref USB_EPTYPE_INTR or
- * @ref USB_EPTYPE_ISOC.
- *
- * @param[in] maxPacketSize
- * Maximum packet size of the new endpoint, in bytes
- *
- * @param[in] bufferMult
- * FIFO buffer size multiplier
- *
- * @return
- * @ref USB_STATUS_OK on success, else an appropriate error code.
- ******************************************************************************/
-int USBD_AddEndpoint(int epAddr, int transferType,
- int maxPacketSize, int bufferMult)
-{
- USBD_Ep_TypeDef *ep;
-
- numEps++;
-
- ep = &dev->ep[ numEps ];
- ep->in = ( epAddr & USB_SETUP_DIR_MASK ) != 0;
- ep->buf = NULL;
- ep->addr = epAddr;
- ep->num = ep->addr & USB_EPNUM_MASK;
- ep->mask = 1 << ep->num;
- ep->type = transferType;
- ep->packetSize = maxPacketSize;
- ep->remaining = 0;
- ep->xferred = 0;
- ep->state = D_EP_IDLE;
- ep->xferCompleteCb = NULL;
-
- if ( ep->in )
- {
- ep->txFifoNum = txFifoNum++;
- ep->fifoSize = ( ( ep->packetSize + 3 ) / 4 ) * bufferMult;
- dev->inEpAddr2EpIndex[ ep->num ] = numEps;
- totalTxFifoSize += ep->fifoSize;
-
- if ( ep->num > MAX_NUM_IN_EPS )
- {
- DEBUG_USB_API_PUTS( "\nUSBD_AddEndpoint(), Illegal IN EP address" );
- EFM_ASSERT( false );
- return USB_STATUS_ILLEGAL;
- }
- }
- else
- {
- ep->fifoSize = ( ( ( ep->packetSize + 3 ) / 4 ) + 1 ) * bufferMult;
- dev->outEpAddr2EpIndex[ ep->num ] = numEps;
- totalRxFifoSize += ep->fifoSize;
-
- if ( ep->num > MAX_NUM_OUT_EPS )
- {
- DEBUG_USB_API_PUTS( "\nUSBD_AddEndpoint(), Illegal OUT EP address" );
- EFM_ASSERT( false );
- return USB_STATUS_ILLEGAL;
- }
- }
-
- USB_PRINTF("USBD: Added endpoint %d to slot %d, in %d, addr 0x%x, type %d, ps %d, fifo %ld (total tx %ld, rx %ld)\n",
- ep->num, numEps, ep->in, ep->addr, ep->type, ep->packetSize, ep->fifoSize,
- totalTxFifoSize, totalRxFifoSize);
-
- INT_Disable();
-#if defined( CMU_OSCENCMD_USHFRCOEN )
- /* Happy Gecko workaround: disable LEM GATE mode if using ISOC endpoints. */
- if ( transferType == USB_EPTYPE_ISOC )
- {
- USB->CTRL = (USB->CTRL & ~_USB_CTRL_LEMOSCCTRL_MASK) | USB_CTRL_LEMOSCCTRL_NONE;
- }
-#endif
-
- int ret = USBDHAL_ReconfigureFifos(totalRxFifoSize, totalTxFifoSize);
- INT_Enable();
-
- if( ret != USB_STATUS_OK ) {
- return ret;
- }
-
- USBDHAL_ActivateEp(ep, false);
-
- return USB_STATUS_OK;
-}
-
-
-/***************************************************************************//**
- * @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;
-}
-
-/******** THE REST OF THE FILE IS DOCUMENTATION ONLY !**********************//**
- * @{
-
-@page usb_device USB device stack library
-
- The source files for the USB device stack resides in the usb directory
- and follows the naming convention: em_usbd<em>nnn</em>.c/h.
-
- @li @ref usb_device_intro
- @li @ref usb_device_api
- @li @ref usb_device_conf
- @li @ref usb_device_powersave
- @li @ref usb_device_example1
-
-
-@n @section usb_device_intro Introduction
-
- The USB device protocol stack provides an API which makes it possible to
- create USB devices with a minimum of effort. The device stack supports control,
- bulk and interrupt transfers.
-
- The stack is highly configurable to suit various needs, it does also contain
- useful debugging features together with several demonstration projects to
- get you started fast.
-
- We recommend that you read through this documentation, then proceed to build
- and test a few example projects before you start designing your own device.
-
-@n @section usb_device_api The device stack API
-
- This section contains brief descriptions of the functions in the API. You will
- find detailed information on input and output parameters and return values by
- clicking on the hyperlinked function names. It is also a good idea to study
- the code in the USB demonstration projects.
-
- Your application code must include one header file: @em em_usb.h.
-
- All functions defined in the API can be called from within interrupt handlers.
-
- The USB stack use a hardware timer to keep track of time. TIMER0 is the
- default choice, refer to @ref usb_device_conf for other possibilities.
- Your application must not use the selected timer.
-
- <b>Pitfalls:</b>@n
- The USB peripheral will fill your receive buffers in quantities of WORD's
- (4 bytes). Transmit and receive buffers must be WORD aligned, in
- addition when allocating storage for receive buffers, round size up to
- next WORD boundary. 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 for the relevant endpoint to avoid data corruption.
-
- Transmit buffers passed to @htmlonly USBD_Write() @endhtmlonly must be
- statically allocated because @htmlonly USBD_Write() @endhtmlonly only
- initiates the transfer. When the host decide to actually perform the
- transfer, your data must be available.
-
- @n @ref USBD_Init() @n
- This function is called to register your device and all its properties with
- the device stack. The application must fill in a @ref USBD_Init_TypeDef
- structure prior to calling. Refer to @ref DeviceInitCallbacks for the
- optional callback functions defined within this structure. When this
- function has been called your device is ready to be enumerated by the USB
- host.
-
- @ref USBD_Read(), @ref USBD_Write() @n
- These functions initiate data transfers.
- @n @htmlonly USBD_Read() @endhtmlonly initiate a transfer of data @em
- from host @em to device (an @em OUT transfer in USB terminology).
- @n @htmlonly USBD_Write() @endhtmlonly initiate a transfer of data @em from
- device @em to host (an @em IN transfer).
-
- When the USB host actually performs the transfer, your application will be
- notified by means of a callback function which you provide (optionally).
- Refer to @ref TransferCallback for details of the callback functionality.
-
- @ref USBD_AbortTransfer(), @ref USBD_AbortAllTransfers() @n
- These functions terminate transfers that are initiated, but has not yet
- taken place. If a transfer is initiated with @htmlonly USBD_Read()
- or USBD_Write(), @endhtmlonly but the USB host never actually peform
- the transfers, these functions will deactivate the transfer setup to make
- the USB device endpoint hardware ready for new (and potentially) different
- transfers.
-
- @ref USBD_Connect(), @ref USBD_Disconnect() @n
- These functions turns the data-line (D+ or D-) pullup on or off. They can be
- used to force reenumeration. It's good practice to delay at least one second
- between @htmlonly USBD_Disconnect() and USBD_Connect() @endhtmlonly
- to allow the USB host to unload the currently active device driver.
-
- @ref USBD_EpIsBusy() @n
- Check if an endpoint is busy.
-
- @ref USBD_StallEp(), @ref USBD_UnStallEp() @n
- These functions stalls or un-stalls an endpoint. This functionality may not
- be needed by your application, but the USB device stack use them in response
- to standard setup commands SET_FEATURE and CLEAR_FEATURE. They may be useful
- when implementing some USB classes, e.g. a mass storage device use them
- extensively.
-
- @ref USBD_RemoteWakeup() @n
- Used in SUSPENDED state (see @ref USB_Status_TypeDef) to signal resume to
- host. It's the applications responsibility to adhere to the USB standard
- which states that a device can not signal resume before it has been
- SUSPENDED for at least 5 ms. The function will also check the configuration
- descriptor defined by the application to see if it is legal for the device
- to signal resume.
-
- @ref USBD_GetUsbState() @n
- Returns the device USB state (see @ref USBD_State_TypeDef). Refer to
- Figure 9-1. "Device State Diagram" in the USB revision 2.0 specification.
-
- @ref USBD_GetUsbStateName() @n
- Returns a text string naming a given USB device state.
-
- @ref USBD_SafeToEnterEM2() @n
- Check if it is ok to enter energy mode EM2. Refer to the
- @ref usb_device_powersave section for more information.
-
- @n @anchor TransferCallback <b>The transfer complete callback function:</b> @n
- @n USB_XferCompleteCb_TypeDef() is called when a transfer completes. It is
- called with three parameters, the status of the transfer, the number of
- bytes transferred and the number of bytes remaining. It may not always be
- needed to have a callback on transfer completion, but you should keep in
- mind that a transfer may be aborted when you least expect it. A transfer
- will be aborted if host stalls the endpoint, if host resets your device, if
- host unconfigures your device or if you unplug your device cable and the
- device is selfpowered.
- @htmlonly USB_XferCompleteCb_TypeDef() @endhtmlonly is also called if your
- application use @htmlonly USBD_AbortTransfer() or USBD_AbortAllTransfers()
- @endhtmlonly calls.
- @note This callback is called from within an interrupt handler with
- interrupts disabled.
-
- @n @anchor DeviceInitCallbacks <b>Optional callbacks passed to the stack via
- the @ref USBD_Init() function:</b> @n
- @n These callbacks are all optional, and it is up to the application
- programmer to decide if the application needs the functionality they
- provide.
- @note These callbacks are all called from within an interrupt handler
- with interrupts disabled.
-
- USBD_UsbResetCb_TypeDef() is called each time reset signalling is sensed on
- the USB wire.
-
- @n USBD_SofIntCb_TypeDef() is called with framenumber as a parameter on
- each SOF interrupt.
-
- @n USBD_DeviceStateChangeCb_TypeDef() is called whenever the device state
- change. Useful for detecting e.g. SUSPENDED state change in order to reduce
- current consumption of buspowered devices. The USB HID keyboard example
- project has a good example on how to use this callback.
-
- @n USBD_IsSelfPoweredCb_TypeDef() is called by the device stack when host
- queries the device with a standard setup GET_STATUS command to check if the
- device is currently selfpowered or buspowered. This feature is only
- applicable on selfpowered devices which also works when only buspower is
- available.
-
- @n USBD_SetupCmdCb_TypeDef() is called each time a setup command is
- received from host. Use this callback to override or extend the default
- handling of standard setup commands, and to implement class or vendor
- specific setup commands. The USB HID keyboard example project has a good
- example on how to use this callback.
-
- @n <b>Utility functions:</b> @n
- @n USB_PUTCHAR() Transmit a single char on the debug serial port.
- @n @n USB_PUTS() Transmit a zero terminated string on the debug serial port.
- @n @n USB_PRINTF() Transmit "printf" formated data on the debug serial port.
- @n @n USB_GetErrorMsgString() Return an error message string for a given
- error code.
- @n @n USB_PrintErrorMsgString() Format and print a text string given an
- error code, prepends an optional user supplied leader string.
- @n @n USBTIMER_DelayMs() Active wait millisecond delay function. Can also be
- used inside interrupt handlers.
- @n @n USBTIMER_DelayUs() Active wait microsecond delay function. Can also be
- used inside interrupt handlers.
- @n @n USBTIMER_Init() Initialize the timer system. Called by @htmlonly
- USBD_Init(), @endhtmlonly but your application must call it again to
- reinitialize whenever you change the HFPERCLK frequency.
- @n @n USBTIMER_Start() Start a timer. You can configure the USB device stack
- to provide any number of timers. The timers have 1 ms resolution, your
- application is notified of timeout by means of a callback.
- @n @n USBTIMER_Stop() Stop a timer.
-
-@n @section usb_device_conf Configuring the device stack
-
- Your application must provide a header file named @em usbconfig.h. This file
- must contain the following \#define's:@n @n
- @verbatim
-#define USB_DEVICE // Compile the stack for device mode.
-#define NUM_EP_USED n // Your application use 'n' endpoints in
- // addition to endpoint 0. @endverbatim
-
- @n @em usbconfig.h may define the following items: @n @n
- @verbatim
-#define NUM_APP_TIMERS n // Your application needs 'n' timers
-
-#define DEBUG_USB_API // Turn on API debug diagnostics.
-
-// Some utility functions in the API needs printf. These
-// functions have "print" in their name. This macro enables
-// these functions.
-#define USB_USE_PRINTF // Enable utility print functions.
-
-// Define a function for transmitting a single char on the serial port.
-extern int RETARGET_WriteChar(char c);
-#define USER_PUTCHAR RETARGET_WriteChar
-
-#define USB_TIMER USB_TIMERn // Select which hardware timer the USB stack
- // is allowed to use. Valid values are n=0,1,2...
- // corresponding to TIMER0, TIMER1, ...
- // If not specified, TIMER0 is used
-
-#define USB_VBUS_SWITCH_NOT_PRESENT // Hardware does not have a VBUS switch
-
-#define USB_CORECLK_HFRCO // Devices supporting crystal-less USB can use
- // HFRCO as core clock, default is HFXO
-@endverbatim
-
- @n You are strongly encouraged to start application development with DEBUG_USB_API
- turned on. When DEBUG_USB_API is turned on and USER_PUTCHAR is defined, useful
- debugging information will be output on the development kit serial port.
- Compiling with the DEBUG_EFM_USER flag will also enable all asserts
- in both @em emlib and in the USB stack. If asserts are enabled and
- USER_PUTCHAR defined, assert texts will be output on the serial port.
-
- You application must include @em retargetserial.c if DEBUG_USB_API is defined
- and @em retargetio.c if USB_USE_PRINTF is defined.
- These files reside in the @em drivers
- directory in the software package for your development board. Refer to
- @ref usb_device_powersave for energy-saving mode configurations.
-
-@n @section usb_device_powersave Energy-saving modes
-
- The device stack provides two energy saving levels. The first level is to
- set the USB peripheral in energy saving mode, the next level is to enter
- Energy Mode 2 (EM2). These energy saving modes can be applied when the device
- is suspended by the USB host, or when when the device is not connected to a
- USB host.
- In addition to this an application can use energy modes EM1 and EM2. There
- are no restrictions on when EM1 can be entered, EM2 can only be entered
- when the USB device is suspended or detached from host.
-
- Energy-saving modes are selected with a \#define in @em usbconfig.h, default
- selection is to not use any energy saving modes.@n @n
- @verbatim
-#define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ENTEREM2)@endverbatim
-
- There are three flags available, the flags can be or'ed together as shown above.
-
- <b>\#define USB_PWRSAVE_MODE_ONSUSPEND</b>@n Set USB peripheral in low power
- mode on suspend.
-
- <b>\#define USB_PWRSAVE_MODE_ONVBUSOFF</b>@n Set USB peripheral in low power
- mode when not attached to a host. This mode assumes that the internal voltage
- regulator is used and that the VREGI pin of the chip is connected to VBUS.
- This option can not be used with bus-powered devices.
-
- <b>\#define USB_PWRSAVE_MODE_ENTEREM2</b>@n Enter EM2 when USB peripheral is
- in low power mode.
-
- When the USB peripheral is set in low power mode, it must be clocked by a 32kHz
- clock. Both LFXO and LFRCO can be used, but only LFXO guarantee USB specification
- compliance. Selection is done with a \#define in @em usbconfig.h.@n @n
- @verbatim
-#define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO @endverbatim
- Two flags are available, <b>USB_USBC_32kHz_CLK_LFXO</b> and
- <b>USB_USBC_32kHz_CLK_LFRCO</b>. <b>USB_USBC_32kHz_CLK_LFXO</b> is selected
- by default.
-
- The USB HID keyboard and Mass Storage device example projects demonstrate
- different energy-saving modes.
-
- <b>Example 1:</b>
- Leave all energy saving to the stack, the device enters EM2 on suspend and
- when detached from host. @n
- @verbatim
-In usbconfig.h:
-
-#define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF | USB_PWRSAVE_MODE_ENTEREM2)
- @endverbatim
-
- @n <b>Example 2:</b>
- Let the stack control energy saving in the USB periheral but let your
- application control energy modes EM1 and EM2. @n
- @verbatim
-In usbconfig.h:
-
-#define USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF)
-
-In application code:
-
-if ( USBD_SafeToEnterEM2() )
- EMU_EnterEM2(true);
-else
- EMU_EnterEM1(); @endverbatim
-
-@n @section usb_device_example1 Vendor unique device example application
-
- This example represents the most simple USB device imaginable. It's purpose
- is to turn user LED's on or off under control of vendor unique setup commands.
- The device will rely on @em libusb device driver on the host, a host
- application @em EFM32-LedApp.exe is bundled with the example.
-
- The main() is really simple ! @n @n
- @verbatim
-#include "em_usb.h"
-
-#include "descriptors.h"
-
-int main( void )
-{
- BSP_Init(BSP_INIT_DEFAULT); // Initialize DK board register access
- CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
- BSP_LedsSet(0); // Turn off all LED's
-
- ConsoleDebugInit(); // Initialize UART for debug diagnostics
-
- USB_PUTS( "\nEFM32 USB LED Vendor Unique Device example\n" );
-
- USBD_Init( &initstruct ); // GO !
-
- //When using a debugger it is pratical to uncomment the following three
- //lines to force host to re-enumerate the device.
-
- //USBD_Disconnect();
- //USBTIMER_DelayMs( 1000 );
- //USBD_Connect();
-
- for (;;) {}
-} @endverbatim
-
- @n Configure the device stack in <em>usbconfig.h</em>: @n @n
- @verbatim
-#define USB_DEVICE // Compile stack for device mode.
-
-// **************************************************************************
-** **
-** Specify number of endpoints used (in addition to EP0). **
-** **
-*****************************************************************************
-#define NUM_EP_USED 0 // EP0 is the only endpoint used.
-
-// **************************************************************************
-** **
-** Configure serial port debug output. **
-** **
-*****************************************************************************
-// Prototype a function for transmitting a single char on the serial port.
-extern int RETARGET_WriteChar(char c);
-#define USER_PUTCHAR RETARGET_WriteChar
-
-// Enable debug diagnostics from API functions (illegal input params etc.)
-#define DEBUG_USB_API @endverbatim
-
- @n Define device properties and fill in USB initstruct in
- <em>descriptors.h</em>: @n @n
- @verbatim
-EFM32_ALIGN(4)
-static const USB_DeviceDescriptor_TypeDef deviceDesc __attribute__ ((aligned(4))) =
-{
- .bLength = USB_DEVICE_DESCSIZE,
- .bDescriptorType = USB_DEVICE_DESCRIPTOR,
- .bcdUSB = 0x0200,
- .bDeviceClass = 0xFF,
- .bDeviceSubClass = 0,
- .bDeviceProtocol = 0,
- .bMaxPacketSize0 = USB_FS_CTRL_EP_MAXSIZE,
- .idVendor = 0x10C4,
- .idProduct = 0x0001,
- .bcdDevice = 0x0000,
- .iManufacturer = 1,
- .iProduct = 2,
- .iSerialNumber = 3,
- .bNumConfigurations = 1
-};
-
-EFM32_ALIGN(4)
-static const uint8_t configDesc[] __attribute__ ((aligned(4)))=
-{
- // *** Configuration descriptor ***
- USB_CONFIG_DESCSIZE, // bLength
- USB_CONFIG_DESCRIPTOR, // bDescriptorType
- USB_CONFIG_DESCSIZE + // wTotalLength (LSB)
- USB_INTERFACE_DESCSIZE,
- (USB_CONFIG_DESCSIZE + // wTotalLength (MSB)
- USB_INTERFACE_DESCSIZE)>>8,
- 1, // bNumInterfaces
- 1, // bConfigurationValue
- 0, // iConfiguration
- CONFIG_DESC_BM_RESERVED_D7 | // bmAttrib: Self powered
- CONFIG_DESC_BM_SELFPOWERED,
- CONFIG_DESC_MAXPOWER_mA( 100 ), // bMaxPower: 100 mA
-
- // *** Interface descriptor ***
- USB_INTERFACE_DESCSIZE, // bLength
- USB_INTERFACE_DESCRIPTOR, // bDescriptorType
- 0, // bInterfaceNumber
- 0, // bAlternateSetting
- NUM_EP_USED, // bNumEndpoints
- 0xFF, // bInterfaceClass
- 0, // bInterfaceSubClass
- 0, // bInterfaceProtocol
- 0, // iInterface
-};
-
-STATIC_CONST_STRING_DESC_LANGID( langID, 0x04, 0x09 );
-STATIC_CONST_STRING_DESC( iManufacturer, 'E','n','e','r','g','y',' ', \
- 'M','i','c','r','o',' ','A','S' );
-STATIC_CONST_STRING_DESC( iProduct , 'V','e','n','d','o','r',' ', \
- 'U','n','i','q','u','e',' ', \
- 'L','E','D',' ', \
- 'D','e','v','i','c','e' );
-STATIC_CONST_STRING_DESC( iSerialNumber, '0','0','0','0','0','0', \
- '0','0','1','2','3','4' );
-
-static const void * const strings[] =
-{
- &langID,
- &iManufacturer,
- &iProduct,
- &iSerialNumber
-};
-
-// Endpoint buffer sizes
-// 1 = single buffer, 2 = double buffering, 3 = tripple buffering ...
-static const uint8_t bufferingMultiplier[ NUM_EP_USED + 1 ] = { 1 };
-
-static const USBD_Callbacks_TypeDef callbacks =
-{
- .usbReset = NULL,
- .usbStateChange = NULL,
- .setupCmd = SetupCmd,
- .isSelfPowered = NULL,
- .sofInt = NULL
-};
-
-static const USBD_Init_TypeDef initstruct =
-{
- .deviceDescriptor = &deviceDesc,
- .configDescriptor = configDesc,
- .stringDescriptors = strings,
- .numberOfStrings = sizeof(strings)/sizeof(void*),
- .callbacks = &callbacks,
- .bufferingMultiplier = bufferingMultiplier
-}; @endverbatim
-
- @n Now we have to implement vendor unique USB setup commands to control the
- LED's (see callbacks variable above). Notice that the buffer variable below is
- statically allocated because @htmlonly USBD_Write() @endhtmlonly only
- initiates the transfer. When the host actually performs the transfer, the
- SetupCmd() function will have returned ! @n @n
-
- @verbatim
-#define VND_GET_LEDS 0x10
-#define VND_SET_LED 0x11
-
-static int SetupCmd( const USB_Setup_TypeDef *setup )
-{
- int retVal;
- uint16_t leds;
- static uint32_t buffer;
- uint8_t *pBuffer = (uint8_t*)&buffer;
-
- retVal = USB_STATUS_REQ_UNHANDLED;
-
- if ( setup->Type == USB_SETUP_TYPE_VENDOR )
- {
- switch ( setup->bRequest )
- {
- case VND_GET_LEDS:
- // ********************
- *pBuffer = BSP_LedsGet() & 0x1F;
- retVal = USBD_Write( 0, pBuffer, setup->wLength, NULL );
- break;
-
- case VND_SET_LED:
- // ********************
- leds = DVK_getLEDs() & 0x1F;
- if ( setup->wValue )
- {
- leds |= LED0 << setup->wIndex;
- }
- else
- {
- leds &= ~( LED0 << setup->wIndex );
- }
- BSP_LedsSet( leds );
- retVal = USB_STATUS_OK;
- break;
- }
- }
-
- return retVal;
-}@endverbatim
-
- * @}**************************************************************************/
-
-#endif /* defined( USB_DEVICE ) */
-#endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
