示例#1
0
/***************************************************************************//**
 * @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;
}
示例#2
0
/***************************************************************************//**
 * @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;
}
示例#3
0
/***************************************************************************//**
 * @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 Initialize MSD device.
 *
 * @param[in] activityLedPort
 *   Specify a GPIO port for a LED activity indicator (i.e. enum gpioPortX)
 *   Pass -1 if no indicator LED is available.
 *
 * @param[in] activityLedPin
 *   Pin number on activityLedPort for the LED activity indicator.
 *****************************************************************************/
void MSDD_Init(int activityLedPort, uint32_t activityLedPin)
{
  if ( ( sizeof(MSDSCSI_Read10_TypeDef)           != SCSI_READ10_LEN           ) ||
       ( sizeof(MSDSCSI_Write10_TypeDef)          != SCSI_WRITE10_LEN          ) ||
       ( sizeof(MSDSCSI_Verify10_TypeDef)         != SCSI_VERIFY10_LEN         ) ||
       ( sizeof(MSDSCSI_RequestSense_TypeDef)     != SCSI_REQUESTSENSE_LEN     ) ||
       ( sizeof(InquiryData)                      != SCSI_INQUIRYDATA_LEN      ) ||
       ( sizeof(NoSenseData)                      != SCSI_REQUESTSENSEDATA_LEN ) ||
       ( sizeof(IllegalSenseData)                 != SCSI_REQUESTSENSEDATA_LEN ) ||
       ( sizeof(MSDSCSI_ReadCapacity_TypeDef)     != SCSI_READCAPACITY_LEN     ) ||
       ( sizeof(MSDSCSI_ReadCapacityData_TypeDef) != SCSI_READCAPACITYDATA_LEN ) ||
       ( sizeof(MSDSCSI_StartStopUnit_TypeDef)    != SCSI_STARTSTOPUNIT_LEN    )    )
  {
    DEBUG_USB_API_PUTS("\nMSDD_Init(), typedef size error");
    EFM_ASSERT(false);
    return;
  }

  if ( ( activityLedPort >= gpioPortA ) && ( activityLedPort <= gpioPortF ) )
    ledPort = activityLedPort;
  else
    ledPort = -1;

  ledPin     = activityLedPin;
  msdState   = MSDD_IDLE;
  pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &NoSenseData;

  if ( ledPort != -1 )
  {
    CMU_ClockEnable(cmuClock_GPIO, true);
    GPIO_PinModeSet((GPIO_Port_TypeDef)ledPort, ledPin, gpioModePushPull, 0);
  }
}
示例#5
0
/***************************************************************************//**
 * @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;
}
示例#6
0
/***************************************************************************//**
 * @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;
}
示例#7
0
/***************************************************************************//**
 * @brief
 *   MSDSCSI module initialization.
 *
 * @param[in] out
 *   Pointer to an MSD bulk OUT endpoint structure.
 *
 * @param[in] in
 *   Pointer to an MSD bulk IN endpoint structure.
 *
 * @return
 *   Returns true on success, false otherwise.
 ******************************************************************************/
bool MSDSCSI_Init(USBH_Ep_TypeDef *out, USBH_Ep_TypeDef *in)
{
  /* Check if all typedef's are properly packed. */

  if ((sizeof(MSDSCSI_Read10_TypeDef) != SCSI_READ10_LEN) ||
      (sizeof(MSDSCSI_Write10_TypeDef) != SCSI_WRITE10_LEN) ||
      (sizeof(MSDSCSI_InquiryData_TypeDef) != SCSI_INQUIRYDATA_LEN) ||
      (sizeof(MSDSCSI_RequestSenseData_TypeDef) != SCSI_REQUESTSENSEDATA_LEN) ||
      (sizeof(MSDSCSI_ReadCapacityData_TypeDef) != SCSI_READCAPACITYDATA_LEN))
  {
    DEBUG_USB_API_PUTS("\nMSDSCSI_Init(), typedef size error");
    EFM_ASSERT(false);
    return false;
  }

  /* Initialize the Bulk-Only-Transport (BOT) module. */
  if (MSDBOT_Init(out, in) != MSDBOT_STATUS_OK)
    return false;

  return true;
}
示例#8
0
/**************************************************************************//**
 * @brief Initialize MSD device.
 *
 * @param[in] activityLedPort
 *   Specify a GPIO port for a LED activity indicator (i.e. enum gpioPortX)
 *   Pass -1 if no indicator LED is available.
 *
 * @param[in] activityLedPin
 *   Pin number on activityLedPort for the LED activity indicator.
 *****************************************************************************/
void MSDD_Init(int activityLedPort, uint32_t activityLedPin)
{
  if ((sizeof(MSDSCSI_Read10_TypeDef) != SCSI_READ10_LEN) ||
      (sizeof(MSDSCSI_Write10_TypeDef) != SCSI_WRITE10_LEN) ||
      (sizeof(MSDSCSI_RequestSense_TypeDef) != SCSI_REQUESTSENSE_LEN) ||
      (sizeof(InquiryData) != SCSI_INQUIRYDATA_LEN) ||
      (sizeof(NoSenseData) != SCSI_REQUESTSENSEDATA_LEN) ||
      (sizeof(IllegalSenseData) != SCSI_REQUESTSENSEDATA_LEN) ||
      (sizeof(MSDSCSI_ReadCapacity_TypeDef) != SCSI_READCAPACITY_LEN) ||
      (sizeof(MSDSCSI_ReadCapacityData_TypeDef) != SCSI_READCAPACITYDATA_LEN))
  {
    DEBUG_USB_API_PUTS("\nMSDD_Init(), typedef size error");
    EFM_ASSERT(false);
    return;
  }

  if ( ( activityLedPort >= gpioPortA ) && ( activityLedPort <= gpioPortF ) )
    ledPort = activityLedPort;
  else
    ledPort = -1;

  ledPin     = activityLedPin;
  msdState   = MSDD_IDLE;
  pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &NoSenseData;
  USBD_Init(&initstruct);     /* Start USB. */

  if ( ledPort != -1 )
  {
    CMU_ClockEnable(cmuClock_GPIO, true);
    GPIO_PinModeSet((GPIO_Port_TypeDef)ledPort, ledPin, gpioModePushPull, 0);
  }

  /*
   * 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(); */
}
示例#9
0
文件: msdbot.c 项目: JamesH001/SX1231
/***************************************************************************//**
 * @brief
 *   MSDBOT module initialization.
 *
 * @param[in] out
 *   Pointer to an MSD bulk OUT endpoint structure.
 *
 * @param[in] in
 *   Pointer to an MSD bulk IN endpoint structure.
 *
 * @return
 *   @ref MSDBOT_STATUS_OK on success, else @ref MSDBOT_INIT_ERROR.
 ******************************************************************************/
int MSDBOT_Init(USBH_Ep_TypeDef *out, USBH_Ep_TypeDef *in)
{
  /* Check if typedef's are properly packed. */

  if ((sizeof(MSDBOT_CBW_TypeDef) != CBW_LEN) ||
      (sizeof(MSDBOT_CSW_TypeDef) != CSW_LEN))
  {
    DEBUG_USB_API_PUTS("\nMSDBOT_Init(), typedef size error");
    EFM_ASSERT(false);
    return MSDBOT_INIT_ERROR;
  }

  /* Keep a local copy of bulk IN/OUT endpoint handles. */
  epOut = out;
  epIn  = in;

  /* Transfer timeouts are scaled according to device bus speed. */
  if (epIn->parentDevice->speed == PORT_FULL_SPEED)
    timeoutFactor = 512;
  else
    timeoutFactor = 64;

  return MSDBOT_STATUS_OK;
}
示例#10
0
/***************************************************************************//**
 * @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 )
{
  CORE_DECLARE_IRQ_STATE;
  CORE_ENTER_CRITICAL();

  if ( ( dev->state != USBD_STATE_SUSPENDED ) ||
       ( dev->remoteWakeupEnabled == false  )    )
  {
    CORE_EXIT_CRITICAL();
    DEBUG_USB_API_PUTS( "\nUSBD_RemoteWakeup(), Illegal remote wakeup" );
    return USB_STATUS_ILLEGAL;
  }

  USBDHAL_SetRemoteWakeup();
  CORE_EXIT_CRITICAL();

  USBTIMER_DelayMs( 10 );

  CORE_ENTER_CRITICAL();
  USBDHAL_ClearRemoteWakeup();
  CORE_EXIT_CRITICAL();

  return USB_STATUS_OK;
}
示例#11
0
/***************************************************************************//**
 * @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)
{
  CORE_DECLARE_IRQ_STATE;
  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);

  CORE_ENTER_CRITICAL();
#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);
  CORE_EXIT_CRITICAL();

  if( ret != USB_STATUS_OK ) {
    return ret;
  }

  USBDHAL_ActivateEp(ep, false);

  return USB_STATUS_OK;
}
示例#12
0
/***************************************************************************//**
 * @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;
}
示例#13
0
/***************************************************************************//**
 * @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;
  CORE_DECLARE_IRQ_STATE;

#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) );

  CORE_ENTER_CRITICAL();

  /* 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
  {
    CORE_EXIT_CRITICAL();
    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 );
  }

  CORE_EXIT_CRITICAL();
  return USB_STATUS_OK;
}
示例#14
0
/***************************************************************************//**
 * @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;
}
示例#15
0
/***************************************************************************//**
 * @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 )
{
  int numEps;
  USBD_Ep_TypeDef *ep;
  uint8_t txFifoNum;
  uint8_t *conf, *confEnd;
  USB_EndpointDescriptor_TypeDef *epd;
  uint32_t totalRxFifoSize, totalTxFifoSize, numInEps, numOutEps;

  CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
#if ( USB_USBC_32kHz_CLK == USB_USBC_32kHz_CLK_LFXO )
  CMU_OscillatorEnable( cmuOsc_LFXO, true, false );
#else
  CMU_OscillatorEnable( cmuOsc_LFRCO, true, false );
#endif
  USBTIMER_Init();

  memset( dev, 0, sizeof( USBD_Device_TypeDef ) );

  dev->setup                = dev->setupPkt;
  dev->deviceDescriptor     = p->deviceDescriptor;
  dev->configDescriptor     = (USB_ConfigurationDescriptor_TypeDef*)
                              p->configDescriptor;
  dev->stringDescriptors    = p->stringDescriptors;
  dev->numberOfStrings      = p->numberOfStrings;
  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;
  ep->packetSize     = USB_EP0_SIZE;
  ep->remaining      = 0;
  ep->xferred        = 0;
  ep->state          = D_EP_IDLE;
  ep->xferCompleteCb = NULL;
  ep->fifoSize       = USB_EP0_SIZE / 4;

  totalTxFifoSize = ep->fifoSize * p->bufferingMultiplier[ 0 ];
  totalRxFifoSize = (ep->fifoSize + 1) * p->bufferingMultiplier[ 0 ];

#if defined( DEBUG_USB_API )
  /* Do a sanity check on the configuration descriptor */
  {
    int i;

    /* Check if bLength's adds up exactly to wTotalLength */
    i = 0;
    conf = (uint8_t*)dev->configDescriptor;
    confEnd = conf + dev->configDescriptor->wTotalLength;

    while ( conf < confEnd )
    {
      if ( *conf == 0 )
        break;

      i += *conf;
      conf += *conf;
    }

    if ( ( conf != confEnd                          ) ||
         ( i != dev->configDescriptor->wTotalLength )    )
    {
      DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal configuration descriptor" );
      EFM_ASSERT( false );
      return USB_STATUS_ILLEGAL;
    }
  }
#endif /* defined( DEBUG_USB_API ) */

  /* Parse configuration decriptor */
  numEps = 0;
  numInEps  = 0;
  numOutEps = 0;
  conf = (uint8_t*)dev->configDescriptor;
  confEnd = conf + dev->configDescriptor->wTotalLength;

  txFifoNum = 1;
  while ( conf < confEnd )
  {
    if ( *conf == 0 )
    {
      DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal configuration descriptor" );
      EFM_ASSERT( false );
      return USB_STATUS_ILLEGAL;
    }

    if ( *(conf + 1) == USB_ENDPOINT_DESCRIPTOR )
    {
      numEps++;
      epd = (USB_EndpointDescriptor_TypeDef*)conf;

      ep                 = &dev->ep[ numEps ];
      ep->in             = ( epd->bEndpointAddress & USB_SETUP_DIR_MASK ) != 0;
      ep->buf            = NULL;
      ep->addr           = epd->bEndpointAddress;
      ep->num            = ep->addr & USB_EPNUM_MASK;
      ep->mask           = 1 << ep->num;
      ep->type           = epd->bmAttributes & CONFIG_DESC_BM_TRANSFERTYPE;
      ep->packetSize     = epd->wMaxPacketSize;
      ep->remaining      = 0;
      ep->xferred        = 0;
      ep->state          = D_EP_IDLE;
      ep->xferCompleteCb = NULL;
      if ( ep->in )
      {
        numInEps++;
        ep->txFifoNum = txFifoNum++;
        ep->fifoSize = (ep->packetSize/4) * p->bufferingMultiplier[ numEps ];
        dev->inEpAddr2EpIndex[ ep->num ] = numEps;
        totalTxFifoSize += ep->fifoSize;
        if ( ep->num > MAX_NUM_IN_EPS )
        {
          DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal IN EP address" );
          EFM_ASSERT( false );
          return USB_STATUS_ILLEGAL;
        }
      }
      else
      {
        numOutEps++;
        ep->fifoSize = (ep->packetSize/4 + 1) * p->bufferingMultiplier[ numEps ];
        dev->outEpAddr2EpIndex[ ep->num ] = numEps;
        totalRxFifoSize += ep->fifoSize;
        if ( ep->num > MAX_NUM_OUT_EPS )
        {
          DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal OUT EP address" );
          EFM_ASSERT( false );
          return USB_STATUS_ILLEGAL;
        }
      }
    }
    conf += *conf;
  }

  /* 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) );

  if ( numEps != NUM_EP_USED )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  if ( numInEps > MAX_NUM_IN_EPS )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal IN EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  if ( numOutEps > MAX_NUM_OUT_EPS )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal OUT EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  INT_Disable();

  /* Enable USB clock */
  CMU->HFCORECLKEN0 |= CMU_HFCORECLKEN0_USB | CMU_HFCORECLKEN0_USBC;
  CMU_ClockSelectSet( cmuClock_USBC, cmuSelect_HFCLK );

  USBHAL_DisableGlobalInt();

  if ( USBDHAL_CoreInit( totalRxFifoSize, totalTxFifoSize ) == USB_STATUS_OK )
  {
    USBDHAL_EnableUsbResetInt();
    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;
}
示例#16
0
/***************************************************************************//**
 * @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 )
{
  int numEps;
  USBD_Ep_TypeDef *ep;
  uint8_t txFifoNum;
  uint8_t *conf, *confEnd;
  USB_EndpointDescriptor_TypeDef *epd;
  USB_InterfaceDescriptor_TypeDef *id;
  uint32_t totalRxFifoSize, totalTxFifoSize, numInEps, numOutEps;

#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->deviceDescriptor     = p->deviceDescriptor;
  dev->configDescriptor     = (USB_ConfigurationDescriptor_TypeDef*)
                              p->configDescriptor;
  dev->stringDescriptors    = p->stringDescriptors;
  dev->numberOfStrings      = p->numberOfStrings;
  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;
  ep->packetSize     = p->deviceDescriptor->bMaxPacketSize0;

  if ( ep->packetSize == 32 )
  {
    dev->ep0MpsCode = _USB_DOEP0CTL_MPS_32B;
  }
  else if ( ep->packetSize == 64 )
  {
    dev->ep0MpsCode = _USB_DOEP0CTL_MPS_64B;
  }
  else
  {
    return USB_STATUS_ILLEGAL;
  }

  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 ];

#if defined( DEBUG_USB_API )
  /* Do a sanity check on the configuration descriptor */
  {
    int i;

    /* Check if bLength's adds up exactly to wTotalLength */
    i = 0;
    conf = (uint8_t*)dev->configDescriptor;
    confEnd = conf + dev->configDescriptor->wTotalLength;

    while ( conf < confEnd )
    {
      if ( *conf == 0 )
        break;

      i += *conf;
      conf += *conf;
    }

    if ( ( conf != confEnd                          ) ||
         ( i != dev->configDescriptor->wTotalLength )    )
    {
      DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal configuration descriptor" );
      EFM_ASSERT( false );
      return USB_STATUS_ILLEGAL;
    }
  }
#endif /* defined( DEBUG_USB_API ) */

  /* Parse configuration decriptor */
  numEps = 0;
  numInEps  = 0;
  numOutEps = 0;
  conf = (uint8_t*)dev->configDescriptor;
  confEnd = conf + dev->configDescriptor->wTotalLength;

  txFifoNum = 1;
  while ( conf < confEnd )
  {
    if ( *conf == 0 )
    {
      DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal configuration descriptor" );
      EFM_ASSERT( false );
      return USB_STATUS_ILLEGAL;
    }

    if ( *(conf + 1) == USB_ENDPOINT_DESCRIPTOR )
    {
      numEps++;
      epd = (USB_EndpointDescriptor_TypeDef*)conf;

#if defined( __GNUC__ )
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
      ep                 = &dev->ep[ numEps ];
#if defined( __GNUC__ )
#pragma GCC diagnostic pop
#endif

      ep->in             = ( epd->bEndpointAddress & USB_SETUP_DIR_MASK ) != 0;
      ep->buf            = NULL;
      ep->addr           = epd->bEndpointAddress;
      ep->num            = ep->addr & USB_EPNUM_MASK;
      ep->mask           = 1 << ep->num;
      ep->type           = epd->bmAttributes & CONFIG_DESC_BM_TRANSFERTYPE;
      ep->packetSize     = epd->wMaxPacketSize;
      ep->remaining      = 0;
      ep->xferred        = 0;
      ep->state          = D_EP_IDLE;
      ep->xferCompleteCb = NULL;

      if ( p->bufferingMultiplier[ numEps ] == 0 )
      {
        DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal EP fifo buffer configuration" );
        EFM_ASSERT( false );
        return USB_STATUS_ILLEGAL;
      }

      if ( ep->in )
      {
        numInEps++;
        ep->txFifoNum = txFifoNum++;
        ep->fifoSize = ( ( ep->packetSize + 3 ) / 4 )
                       * p->bufferingMultiplier[ numEps ];
        dev->inEpAddr2EpIndex[ ep->num ] = numEps;
        totalTxFifoSize += ep->fifoSize;
        if ( ep->num > MAX_NUM_IN_EPS )
        {
          DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal IN EP address" );
          EFM_ASSERT( false );
          return USB_STATUS_ILLEGAL;
        }
      }
      else
      {
        numOutEps++;
        ep->fifoSize = ( ( ( ep->packetSize + 3 ) / 4 ) + 1 )
                       * p->bufferingMultiplier[ numEps ];
        dev->outEpAddr2EpIndex[ ep->num ] = numEps;
        totalRxFifoSize += ep->fifoSize;
        if ( ep->num > MAX_NUM_OUT_EPS )
        {
          DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal OUT EP address" );
          EFM_ASSERT( false );
          return USB_STATUS_ILLEGAL;
        }
      }
    }
    else if ( *(conf + 1) == USB_INTERFACE_DESCRIPTOR )
    {
      id = (USB_InterfaceDescriptor_TypeDef*)conf;

      if ( id->bAlternateSetting == 0 )     // Only check default interfaces
      {
        if ( dev->numberOfInterfaces != id->bInterfaceNumber )
        {
          DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal interface number" );
          EFM_ASSERT( false );
          return USB_STATUS_ILLEGAL;
        }
      dev->numberOfInterfaces++;
      }
    }

    conf += *conf;
  }

  /* 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) );

  if ( dev->configDescriptor->bNumInterfaces != dev->numberOfInterfaces )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal interface count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  if ( numEps != NUM_EP_USED )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  if ( numInEps > MAX_NUM_IN_EPS )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal IN EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  if ( numOutEps > MAX_NUM_OUT_EPS )
  {
    DEBUG_USB_API_PUTS( "\nUSBD_Init(), Illegal OUT EP count" );
    EFM_ASSERT( false );
    return USB_STATUS_ILLEGAL;
  }

  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;
}