Example #1
0
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;
}
Example #2
0
/***************************************************************************//**
 * @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();
  USB->IEN   = _USB_IEN_RESETVALUE;
  USB->ROUTE = _USB_ROUTE_RESETVALUE;
  USBD_SetUsbState( USBD_STATE_NONE );
}
Example #3
0
/***************************************************************************//**
 * @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);
}
Example #4
0
/***************************************************************************//**
 * @brief       Handle USB port suspend interrupt
 * @details     After receiving a USB reset, set the device state and
 *              call @ref USBD_Suspend() if configured to do so in
 *              @ref SLAB_USB_PWRSAVE_MODE
 ******************************************************************************/
static void handleUsbSuspendInt(void)
{
  if (myUsbDevice.state >= USBD_STATE_POWERED)
  {
    USBD_SetUsbState(USBD_STATE_SUSPENDED);

#if (SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONSUSPEND)
    USBD_Suspend();
#endif
  }
}
Example #5
0
/*
 * USB_IRQHandler() is the first level handler for the USB peripheral interrupt.
 */
void USB_IRQHandler( void )
{
  uint32_t status;
  bool servedVbusInterrupt = false;

  INT_Disable();

#if ( USB_PWRSAVE_MODE )
  if ( USBD_poweredDown )
  {
    /* Switch USBC clock from 32kHz to a 48MHz clock to be able to  */
    /* read USB peripheral registers.                               */
    /* If we woke up from EM2, HFCLK is now HFRCO.                  */

    /* Restore clock oscillators.*/
#if defined( CMU_OSCENCMD_USHFRCOEN )
    if ( ( CMU->STATUS & CMU_STATUS_USHFRCOENS ) == 0 )/*Wakeup from EM2 ?*/
    {
      CMU->OSCENCMD = ( cmuStatus
                        & ( CMU_STATUS_AUXHFRCOENS | CMU_STATUS_HFXOENS ) )
                      | CMU_OSCENCMD_USHFRCOEN;
    }
#else
    if ( ( CMU->STATUS & CMU_STATUS_HFXOENS ) == 0 ) /* Wakeup from EM2 ? */
    {
      CMU->OSCENCMD = cmuStatus
                      & ( CMU_STATUS_AUXHFRCOENS | CMU_STATUS_HFXOENS );
    }
#endif

    /* Select correct USBC clock.*/
#if defined( CMU_OSCENCMD_USHFRCOEN )
    CMU->CMD = CMU_CMD_USBCCLKSEL_USHFRCO;
    while ( ( CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL ) == 0 ){}
#else
    CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
    while ( ( CMU->STATUS & CMU_STATUS_USBCHFCLKSEL ) == 0 ){}
#endif
  }
#endif /* if ( USB_PWRSAVE_MODE ) */

  if ( USB->IF && ( USB->CTRL & USB_CTRL_VREGOSEN ) )
  {
    if ( USB->IF & USB_IF_VREGOSH )
    {
      USB->IFC = USB_IFC_VREGOSH;

      if ( USB->STATUS & USB_STATUS_VREGOS )
      {
        servedVbusInterrupt = true;
        DEBUG_USB_INT_LO_PUTS( "\nVboN" );

#if ( USB_PWRSAVE_MODE )
        if ( UsbPowerUp() )
        {
          USBDHAL_EnableUsbResetAndSuspendInt();
        }
        USBD_SetUsbState( USBD_STATE_POWERED );
#endif
      }
    }

    if ( USB->IF & USB_IF_VREGOSL )
    {
      USB->IFC = USB_IFC_VREGOSL;

      if ( ( USB->STATUS & USB_STATUS_VREGOS ) == 0 )
      {
        servedVbusInterrupt = true;
        DEBUG_USB_INT_LO_PUTS( "\nVboF" );

#if ( USB_PWRSAVE_MODE )
#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
        if ( !USBD_poweredDown )
        {
          USB->GINTMSK = 0;
          USB->GINTSTS = 0xFFFFFFFF;
        }

        UsbPowerDown();
#endif
        USBD_SetUsbState( USBD_STATE_NONE );
#endif
      }
    }
  }

  status = USBHAL_GetCoreInts();
  if ( status == 0 )
  {
    INT_Enable();
    if ( !servedVbusInterrupt )
    {
      DEBUG_USB_INT_LO_PUTS( "\nSinT" );
    }
    return;
  }

  HANDLE_INT( USB_GINTSTS_RESETDET   )
  HANDLE_INT( USB_GINTSTS_WKUPINT    )
  HANDLE_INT( USB_GINTSTS_USBSUSP    )
  HANDLE_INT( USB_GINTSTS_SOF        )
  HANDLE_INT( USB_GINTSTS_ENUMDONE   )
  HANDLE_INT( USB_GINTSTS_USBRST     )
  HANDLE_INT( USB_GINTSTS_IEPINT     )
  HANDLE_INT( USB_GINTSTS_OEPINT     )

  INT_Enable();

  if ( status != 0 )
  {
    DEBUG_USB_INT_LO_PUTS( "\nUinT" );
  }
}
Example #6
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;
}
Example #7
0
/*
 * USB_IRQHandler() is the first level handler for the USB peripheral interrupt.
 */
void USB_IRQHandler( void )
{
	uint32_t status;
	bool servedVbusInterrupt = false;

	INT_Disable();

#if ( USB_PWRSAVE_MODE )
	if ( USBD_poweredDown )
	{
		/* Switch USBC clock from 32kHz to HFCLK to be able to read USB */
		/* peripheral registers.                                        */
		/* If we woke up from EM2, HFCLK is now HFRCO.                  */

		CMU_OscillatorEnable( cmuOsc_HFXO, true, false);  /* Prepare HFXO. */
		CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
		while ( !( CMU->STATUS & CMU_STATUS_USBCHFCLKSEL ) ) { }
	}
#endif /* if ( USB_PWRSAVE_MODE ) */

	if ( USB->IF && ( USB->CTRL & USB_CTRL_VREGOSEN ) )
	{
		if ( USB->IF & USB_IF_VREGOSH )
		{
			USB->IFC = USB_IFC_VREGOSH;

			if ( USB->STATUS & USB_STATUS_VREGOS )
			{
				servedVbusInterrupt = true;
				DEBUG_USB_INT_LO_PUTS( "\nVboN" );

#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
				if ( UsbPowerUp() )
#endif
				{
					USBDHAL_EnableUsbResetInt();
				}

				USBD_SetUsbState( USBD_STATE_POWERED );
			}
		}

		if ( USB->IF & USB_IF_VREGOSL )
		{
			USB->IFC = USB_IFC_VREGOSL;

			if ( !( USB->STATUS & USB_STATUS_VREGOS ) )
			{
				servedVbusInterrupt = true;
				DEBUG_USB_INT_LO_PUTS( "\nVboF" );

				USB->GINTMSK = 0;
				USB->GINTSTS = 0xFFFFFFFF;

#if ( USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF )
				UsbPowerDown();
#endif
				USBD_SetUsbState( USBD_STATE_NONE );
			}
		}
	}

	status = USBHAL_GetCoreInts();
	if ( status == 0 )
	{
		INT_Enable();
		if ( !servedVbusInterrupt )
		{
			DEBUG_USB_INT_LO_PUTS( "\nSinT" );
		}
		return;
	}

	HANDLE_INT( USB_GINTSTS_RESETDET   )
	HANDLE_INT( USB_GINTSTS_WKUPINT    )
	HANDLE_INT( USB_GINTSTS_USBSUSP    )
	HANDLE_INT( USB_GINTSTS_SOF        )
	HANDLE_INT( USB_GINTSTS_ENUMDONE   )
	HANDLE_INT( USB_GINTSTS_USBRST     )
	HANDLE_INT( USB_GINTSTS_IEPINT     )
	HANDLE_INT( USB_GINTSTS_OEPINT     )

	INT_Enable();

	if ( status != 0 )
	{
		DEBUG_USB_INT_LO_PUTS( "\nUinT" );
	}
}
Example #8
0
/***************************************************************************//**
 * @brief       Handles USB port resume interrupt
 * @details     Restore the device state to its previous value.
 ******************************************************************************/
static void handleUsbResumeInt(void)
{
  USBD_SetUsbState(myUsbDevice.savedState);
}
Example #9
0
/***************************************************************************//**
 * @brief       Handles USB port reset interrupt
 * @details     After receiving a USB reset, halt all endpoints except for
 *              Endpoint 0, set the device state, and configure USB hardware.
 ******************************************************************************/
static void handleUsbResetInt(void)
{
  // Setup EP0 to receive SETUP packets
  myUsbDevice.ep0.state = D_EP_IDLE;

  // Halt all other endpoints
#if SLAB_USB_EP1IN_USED
  myUsbDevice.ep1in.state = D_EP_HALT;
#endif
#if SLAB_USB_EP2IN_USED
  myUsbDevice.ep2in.state = D_EP_HALT;
#endif
#if SLAB_USB_EP3IN_USED
  myUsbDevice.ep3in.state = D_EP_HALT;
#endif
#if SLAB_USB_EP1OUT_USED
  myUsbDevice.ep1out.state = D_EP_HALT;
#endif
#if SLAB_USB_EP2OUT_USED
  myUsbDevice.ep2out.state = D_EP_HALT;
#endif
#if SLAB_USB_EP3OUT_USED
  myUsbDevice.ep3out.state = D_EP_HALT;
#endif

  // After a USB reset, some USB hardware configurations will be reset and must
  // be reconfigured.

  // Re-enable clock recovery
#if SLAB_USB_CLOCK_RECOVERY_ENABLED
#if SLAB_USB_FULL_SPEED
  USB_EnableFullSpeedClockRecovery();
#else
  USB_EnableLowSpeedClockRecovery();
#endif
#endif

  // Re-enable USB interrupts
  USB_EnableSuspendDetection();
  USB_EnableDeviceInts();

  // If VBUS is preset, put the device in the Default state.
  // Otherwise, put it in the Attached state.
//#if (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF))

  // If VBUS is preset, put the device in the Default state.
    // Otherwise, put it in the Attached state.
    // If the device is bus-powered, always put it in the Default state
  #if (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF) && !SLAB_USB_BUS_POWERED)

  if (USB_IsVbusOn())
  {
    USBD_SetUsbState(USBD_STATE_DEFAULT);
  }
  else
  {
    USBD_SetUsbState(USBD_STATE_ATTACHED);
  }
#else
  USBD_SetUsbState(USBD_STATE_DEFAULT);
#endif  // (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF))

#if SLAB_USB_RESET_CB
  // Make the USB Reset Callback
  USBD_ResetCb();
#endif
}
Example #10
0
void USBD_Stop(void)
{
  USB_DisableInts();
  USBD_Disconnect();
  USBD_SetUsbState(USBD_STATE_NONE);
}
Example #11
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;
}
Example #12
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;
}