text: /***************************************************************************//**
   * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved.
   *
   * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt
   ******************************************************************************/
  
  #ifndef __SILICON_LABS_EFM8_USB_H__
  #define __SILICON_LABS_EFM8_USB_H__
  
  #include "si_toolchain.h"
  #include "usbconfig.h"
  #include <string.h>
  #include <stddef.h>
  #include <stdbool.h>
  #include <stdint.h>
  
  /***************************************************************************//**
   * @addtogroup Efm8_usb
   * @brief USB Device Protocol Stack for EFM8 devices
   * @{
   *
   *   @section usb_device_contents Contents
   *
   *   @li @ref usb_device_library_revision
   *   @li @ref usb_device_intro
   *   @li @ref usb_device_api
   *   @li @ref usb_device_conf
   *   @li @ref usb_device_powersave
   *   @li @ref usb_device_transfers
   *   @li @ref usb_device_pitfalls
   *
   *   @n @section usb_device_library_revision EFM8 USB Library Revision
   *   Library Revision: 1.0.3
   *
   *   @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, Interrupt, and Isochronous transfers.
   *
   *   The stack is highly configurable to suit various needs and includes
   *   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_library_architecture_diagram Library Architecture Diagram
   *
   *   @image html USB_Library_Architecture.png
   *
   *   @n @section usb_device_api The EFM8 USB Library 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 hyper-linked 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 efm8_usb.h.
   *
   *   All functions defined in the API can be called from within interrupt handlers.
   *
   *  @subsection usb_device_api_functions API Functions
   *
   *   @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. 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 call to the @ref USBD_XferCompleteCb() callback
   *    function (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 with @htmlonly
   *    USBD_Read() or USBD_Write() @endhtmlonly but that have not completed yet.
   *    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 turn the data-line (D+ or D-) pull-up on or off. They can
   *    be used to force re-enumeration. 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
   *    Checks if an endpoint is busy.
   *
   *   @ref USBD_StallEp(), @ref USBD_UnStallEp() @n
   *    These functions stall or un-stall an endpoint. This functionality may not
   *    be needed by your application. They may be useful when implementing some
   *    USB classes, e.g. a mass storage devices use them extensively.
   *
   *   @ref USBD_Stop() @n
   *    Removes the data-line (D+ or D-) pull-up and disables the USB block. The
   *    application should call @htmlonly USBD_Init() after calling
   *    USBD_Stop() @endhtmlonly to restart USB operation.
   *
   *   @ref USBD_Suspend() @n
   *    Puts the device in its low-power suspend mode. This function will not exit
   *    until a wakeup event (resume signaling, VBUS attachment/removal, or remote
   *    wakeup source interrupt) occurs. The USB Library can be configured to
   *    automatically call this function by configuring @ref SLAB_USB_PWRSAVE_MODE.
   *
   *   @ref USBD_RemoteWakeup() @n
   *    Used in SUSPENDED state (see @ref USB_Status_TypeDef) to signal resume to
   *    host. The function will be called automatically by the library if the
   *    @ref USBD_RemoteWakeupCb() function returns true. The function will
   *    also check that the host has sent a SET_FEATURE request to enable Remote
   *    Wakeup before issuing the 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_Run() @n
   *    When @ref SLAB_USB_POLLED_MODE is set to 1, the USB interrupt is disabled
   *    and the application must periodically call @htmlonly USBD_Run()
   *    @endhtmlonly to handle USB events.
   *
   *  @n @subsection usb_device_api_callback Callback Functions
   *
   *  @subsubsection usb_device_api_mandatory_callbacks Mandatory Callback Functions
   *
   *    @n @anchor TransferCallback
   *    @ref USBD_XferCompleteCb() is called each time a packet is sent or
   *    received. It is called with three parameters, the status of the transfer,
   *    the number of bytes transferred and the number of bytes remaining. The
   *    transfer complete callback can be enabled or disabled by setting the
   *    <em>callback</em> parameters of @ref USBD_Write() and @ref USBD_Read() to
   *    true or false.
   *    @note This callback is called from within the USB interrupt handler if
   *        @ref SLAB_USB_POLLED_MODE is set to 1. Otherwise, it is called from
   *        @ref USBD_Run().
   *
   *  @n
   *  @subsubsection usb_device_api_optional_callbacks Optional Callback Functions
   *
   *    @n These callbacks are all optional, and it is up to the application
   *    programmer to decide if the application needs the functionality they
   *    provide. Each callback is enabled or disabled by setting a constant in
   *    <em>usbconfig.h</em>.
   *    @note These callbacks are called from within the USB interrupt handler if
   *          @ref SLAB_USB_POLLED_MODE is set to 1. Otherwise, they are called
   *          from @ref USBD_Run().
   *
   *   @n USBD_ResetCb() is called each time reset signaling is sensed on the USB
   *    wire.
   *
   *   @n USBD_SofCb() is called with the frame number as a parameter on each SOF
   *    interrupt.
   *
   *   @n USBD_DeviceStateChangeCb() is called whenever the device state changes.
   *    Some uses of this include detecting that a USB suspend has been issued
   *    in order to reduce current consumption or calling USBD_Read() after
   *    entering the Configured state. The USB HID keyboard example
   *    project has a good example on how to use this callback.
   *
   *   @n USBD_IsSelfPoweredCb() is called by the device stack when host
   *    queries the device with a GET_STATUS command to check if the device is
   *    currently self-powered or bus-powered. This feature is only applicable on
   *    self-powered devices which can also operate when only bus power is
   *    available.
   *
   *   @n USBD_SetupCmdCb() is called each time a setup command is received from
   *    the 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 of how
   *    to use this callback.
   *
   *   @n @section usb_device_conf Configuring the Library
   *
   *   Your application must provide a header file named @em usbconfig.h. This file
   *   must contain the following \#define's. See @ref usb_config for
   *   documentation of these constants.@n @n
   *   @code
   * // -----------------------------------------------------------------------------
   * // Specify bus- or self-powered
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_BUS_POWERED              0
   *
   * // -----------------------------------------------------------------------------
   * // Specify USB speed
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_FULL_SPEED               1
   *
   * // -----------------------------------------------------------------------------
   * // Enable or disable the clock recovery
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_CLOCK_RECOVERY_ENABLED   1
   *
   * // -----------------------------------------------------------------------------
   * // Enable or disable remote wakeup
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_REMOTE_WAKEUP_ENABLED    0
   *
   * // -----------------------------------------------------------------------------
   * // Specify number of interfaces and whether any interfaces support alternate
   * // settings
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_NUM_INTERFACES           1
   * #define SLAB_USB_SUPPORT_ALT_INTERFACES   0
   *
   * // -----------------------------------------------------------------------------
   * // Enable or disable each endpoint
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_EP1IN_USED               1
   * #define SLAB_USB_EP1OUT_USED              0
   * #define SLAB_USB_EP2IN_USED               0
   * #define SLAB_USB_EP2OUT_USED              0
   * #define SLAB_USB_EP3IN_USED               0
   * #define SLAB_USB_EP3OUT_USED              0
   *
   * // -----------------------------------------------------------------------------
   * // Specify the maximum packet size for each endpoint
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_EP1IN_MAX_PACKET_SIZE    64
   * #define SLAB_USB_EP1OUT_MAX_PACKET_SIZE   0
   * #define SLAB_USB_EP2IN_MAX_PACKET_SIZE    0
   * #define SLAB_USB_EP2OUT_MAX_PACKET_SIZE   0
   * #define SLAB_USB_EP3IN_MAX_PACKET_SIZE    0
   * #define SLAB_USB_EP3OUT_MAX_PACKET_SIZE   0
   *
   * // -----------------------------------------------------------------------------
   * // Specify transfer type of each endpoint
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_EP1IN_TRANSFER_TYPE      USB_EPTYPE_INTR
   * #define SLAB_USB_EP1OUT_TRANSFER_TYPE     USB_EPTYPE_BULK
   * #define SLAB_USB_EP2IN_TRANSFER_TYPE      USB_EPTYPE_INTR
   * #define SLAB_USB_EP2OUT_TRANSFER_TYPE     USB_EPTYPE_BULK
   * #define SLAB_USB_EP3IN_TRANSFER_TYPE      USB_EPTYPE_ISOC
   * #define SLAB_USB_EP3OUT_TRANSFER_TYPE     USB_EPTYPE_ISOC
   *
   * // -----------------------------------------------------------------------------
   * // Enable or disable callback functions
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_RESET_CB                 1
   * #define SLAB_USB_SOF_CB                   1
   * #define SLAB_USB_STATE_CHANGE_CB          1
   * #define SLAB_USB_IS_SELF_POWERED_CB       1
   * #define SLAB_USB_SETUP_CMD_CB             1
   * #define SLAB_USB_HANDLER_CB               0
   *
   * // -----------------------------------------------------------------------------
   * // Specify number of languages supported by string descriptors
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_NUM_LANGUAGES            1
   *
   * // -----------------------------------------------------------------------------
   * // If only one descriptor language is supported, specify that language here.
   * // If multiple descriptor languages are supported, this value is ignored and
   * // the supported languages must listed in the
   * // myUsbStringTableLanguageIDsDescriptor structure.
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_LANGUAGE                 USB_LANGID_ENUS
   *
   * // -----------------------------------------------------------------------------
   * // Enable use of UTF-8 strings for string descriptors.
   * // If this option is enabled then packed string descriptors that are created
   * // with UTF8_PACKED_STATIC_CONST_STRING_DESC() can be UTF-8 encoded and they
   * // will be decoded into UCS-2 16-bit wide character format used for USB string
   * // descriptors.  If this feature is not needed then it can be disabled to save
   * // some code memory space. 
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_UTF8_STRINGS             1
   *
   * // -----------------------------------------------------------------------------
   * // Set the power saving mode
   * //
   * // SLAB_USB_PWRSAVE_MODE configures when the device will automatically enter
   * // the USB power-save mode. It is a bitmask constant with bit values:
   * //
   * //   USB_PWRSAVE_MODE_OFF       - No energy saving mode selected
   * //   USB_PWRSAVE_MODE_ONSUSPEND - Enter USB power-save mode on USB suspend
   * //   USB_PWRSAVE_MODE_ONVBUSOFF - Enter USB power-save mode when not attached
   * //                                to the USB host.
   * //   USB_PWRSAVE_MODE_FASTWAKE  - Exit USB power-save mode more quickly, but
   * //                                consume more power while in USB power-save
   * //                                mode.
   * //                                While the device is in USB power-save mode
   * //                                (typically during USB suspend), the
   * //                                internal voltage regulator stays in normal
   * //                                power mode instead of entering suspend
   * //                                power mode.
   * //                                This is an advanced feature that may be
   * //                                useful in certain applications that support
   * //                                remote wakeup.
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_PWRSAVE_MODE             (USB_PWRSAVE_MODE_ONVBUSOFF \
   *                                            | USB_PWRSAVE_MODE_ONSUSPEND)
   *
   * // -----------------------------------------------------------------------------
   * // Enable or disable polled mode
   * //
   * // When enabled, the application must call USBD_Run() periodically to process
   * // USB events.
   * // When disabled, USB events will be handled automatically by an interrupt
   * // handler.
   * // -----------------------------------------------------------------------------
   * #define SLAB_USB_POLLED_MODE              0
   * @endcode
   *
   *   @n @section usb_device_powersave Energy-saving options
   *
   *   The device stack provides built-in energy saving options.These options
   *   are configured by setting flags in @ref SLAB_USB_PWRSAVE_MODE in @em
   *   usbconfig.h. These flags are bitmasks and can be or'd together.@n@n
   *
   *   <b>Energy-Saving Option Flags:</b>
   *
   *   @ref USB_PWRSAVE_MODE_OFF@n The device will not automatically enter its
   *   low-power suspned mode after detecting a USB suspend. The application
   *   firmware may still call @ref USBD_Suspend() to manually enter suspend mode.
   *
   *   @ref USB_PWRSAVE_MODE_ONSUSPEND@n Enter a low-power suspend mode
   *   when a USB suspend is detected. When resume signaling is detected,
   *   the stack will exit the low-power mode.
   *
   *   @ref USB_PWRSAVE_MODE_ONVBUSOFF@n Enter the low-power suspend
   *   mode any time the device detects that VBUS is not present. When VBUS is
   *   attached, the stack will exit the low-power mode. The USB Specification
   *   does not define the state of the device when VBUS is not present, but it
   *   may be desirable for some applications to enter suspend mode when in this
   *   undefined state.
   *
   *   @ref USB_PWRSAVE_MODE_FASTWAKE@n Keep the internal regulator at
   *   its normal operating state while in the low-power suspend state. This
   *   allows the device to wake from suspend more quickly than it would from its
   *   suspend state. This option can be useful in applications that support
   *   remote wakeup and need to exit suspend in time to recognize some external
   *   signal (i.e. a byte received on the UART). The device will still consume
   *   low enough power to meet the USB Suspend Current Specification, but it will
   *   be slightly higher than it would otherwise be.
   *
   *   The USB HID Keyboard device example project demonstrates some of these
   *   energy-saving options.
   *
   *   <b>Example:</b>
   *   Leave all energy saving to the stack, the device enters low-power mode on
   *   suspend and when detached from host. @n
   *   In usbconfig.h:
   *   @code
   *   #define SLAB_USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF)
   *   @endcode
   *
   *   @n @section usb_device_transfers Transfer Operation
   *
   *   @subsection usb_device_transfers_overview Overview
   *
   *   A USB transfer consists of one or more packets. For an IN transfer, the
   *   packets are sent from the device to the host. For an OUT transfer, the
   *   packets are sent from the host to the device.  @ref USBD_Write() initiates
   *   an IN transfer, while @ref USBD_Read() initiates an OUT transfer.
   *
   *   @subsection usb_device_transfers_types Transfer Types
   *
   *   There are four USB transfer types: @ref usb_device_transfer_types_control,
   *   @ref usb_device_transfer_types_bulk, @ref usb_device_transfer_types_interrupt,
   *   and @ref usb_device_transfer_types_isochronous.
   *
   *   @subsubsection usb_device_transfer_types_control Control
   *
   *   Control transfers are used to send configuration and status
   *   information, and also to send vendor-defined data. The USB Library only
   *   supports control transfers on Endpoint 0. @n @n
   *   The application firmware can handle control requests by looking at the
   *   contents of the setup packet in @ref USBD_SetupCmdCb(). If the application
   *   supports a particular request, it can call @ref USBD_Read() or @ref
   *   USBD_Write() with <em>epAddr</em> set to <em>EP0</em> and return @ref
   *   USB_STATUS_OK. If it does not need to handle the request, it should return
   *   @ref USB_STATUS_REQ_UNHANDLED. This will notify the library that it should
   *   try to handle the setup command. The library will automatically service
   *   Standard (i.e. Chapter 9) requests, so @ref USBD_SetupCmdCb() should return
   *   @ref USB_STATUS_REQ_UNHANDLED unless it is a class- or vendor-specific
   *   request. If neither the library nor the application supports a setup
   *   request, the library will issue a stall.
   *
   *   @subsubsection usb_device_transfer_types_bulk Bulk
   *
   *   Bulk transfers are used to send large, non-periodic data. Examples include
   *   sending a file to a Mass Storage Device or a print-job to a printer. A bulk
   *   transfer may consist of one or more packets.
   *
   *   Endpoints are configured for bulk mode in <em>usbconfig.h</em>. As an
   *   example: @code
   *   #define SLAB_USB_EP1OUT_TRANSFER_TYPE     USB_EPTYPE_BULK@endcode
   *   configures Endpout 1 OUT transfers for bulk mode.
   *
   *   The @ref byteCount parameter of @ref USBD_Write() and @ref USBD_Read()
   *   configures the maximum length for a given bulk transfer. The transfer will
   *   complete when the device sends or receives either:
   *     1. A packet less than its maximum packet size
   *     2. Exactly the number of bytes specified in @ref byteCount
   *   Note that @ref USBD_XferCompleteCb() will be called for each packet sent or
   *   received for the duration of a transfer.
   *
   *   @subsubsection usb_device_transfer_types_interrupt Interrupt
   *
   *   Interrupt transfers are used to send low-bandwidth, hight-latency data at
   *   a non-periodic rate. Examples include input devices, such as mice,
   *   keyboards, and joysticks. An interrupt transfer may consist of one or more
   *   packets.
   *
   *   Endpoints are configured for interrupt mode in <em>usbconfig.h</em>. As an
   *   example: @code
   *   #define SLAB_USB_EP1OUT_TRANSFER_TYPE     USB_EPTYPE_INTR@endcode
   *   configures Endpout 1 OUT transfers for interrupt mode.
   *
   *   Interrupt transfers work identically to bulk transfer in the USB Library.
   *   Refer to @ref usb_device_transfer_types_bulk for more information.
   *
   *   @subsubsection usb_device_transfer_types_isochronous Isochronous
   *
   *   Isochronous transfers are used to send periodic, continuous data. Automatic
   *   error-checking is not included with isochronous transfers as it is with all
   *   other transfer types. Examples include streaming audio and video. As
   *   isochronous data is sent at a continuous rate, it typically consists of
   *   one IN and/or OUT packet per frame.
   *
   *   Endpoint 3 is the only endpoint in the USB Library that supports
   *   isochronous transfers. Endpoints are configured for isochronous mode in
   *   <em>usbconfig.h</em>. As an example: @code
   *   #define SLAB_USB_EP3OUT_TRANSFER_TYPE     USB_EPTYPE_ISOC@endcode
   *   configures Endpout 3 OUT transfers for isochronous mode.
   *
   *   The library works differently for isochronous transfers. The application
   *   must define a circular buffer to hold isochronous data. When calling
   *   USBD_Read() or USBD_Write(), <em>dat</em> is the first address of this
   *   buffer and <em>byteCount</em> is its length. The library will read from or
   *   write to this buffer as soon as the host issues a request, so it is the
   *   responsibility of the application firmware to ensure that this buffer is
   *   fed or consumed at the correct rate to prevent an underrun/overrun
   *   condition.
   *
   *   The parameters of @ref USBD_XferCompleteCb() take on a different meaning in
   *   isochronous mode. For OUT transfers, <em>xferred</em> is the number of
   *   bute received in the last packet and <em>remaining</em> is the current
   *   index into the circular buffer. For IN transfers, <em>xferred</em> is
   *   ignored, <em>remaining</em> is the current index into the circular buffer,
   *   and the return value is the number of bytes to transmit in the next
   *   packet.
   *
   *   @n @section usb_device_pitfalls Pitfalls
   *
   *   @subsection usb_device_pitfalls_nonreentrancy Non-Reentrancy
   *
   *    Due to the non-reentrant architecture of the 8051, it is recommended
   *    that all calls to a particular API function be made from functions of the
   *    same interrupt priority (main loop, low priority, or high priority).
   *
   *    The interrupt priority of the USB callback functions is determined by the
   *    constant @ref SLAB_USB_POLLED_MODE. When 0, the callbacks are called from
   *    the USB Interrupt Handler. When 1, the callbacks are called from
   *    USBD_Run(), which is typically called from the main loop.
   *    If an API function must be called from functions of differing interrupt
   *    priorities, there are a number of ways to ensure that the calls are made
   *    safely:
   *
   *      1. Disable the interrupt source of the higher-priority function before
   *         making the call. Restore the interrupt enable setting after the call
   *         returns:
   *
   *         (Assuming @htmlonly USBD_Write() is called from main() and
   *         USBD_XferCompleteCb() @endhtmlonly, the call from main() should
   *         disable and restore the USB interrupt):
   *         @code
   *         bool usbIntsEnabled = USB_GetIntsEnabled();
   *
   *         USB_DisableInts();
   *
   *         USBD_Write(EP1IN, myBuf, 1, true);
   *
   *         if (usbIntsEnabled)
   *         {
   *           USB_EnableInts();
   *         }
   *         @endcode
   *
   *      2. Add the compiler-specific reentrant keyword to the function
   *         definition(s) in efm8_usbd.c:
   *         @code
   *         int8_t USBD_AbortTransfer(uint8_t epAddr) reentrant
   *         @endcode
   *         and to the function prototype definition(s) in efm8_usb.h:
   *         @code
   *         int8_t USBD_AbortTransfer(uint8_t epAddr) reentrant;
   *         @endcode
   *         Using the reentrant keyword may require the application to provide
   *         a heap for local variable allocation. Additionally, it will reduce
   *         the performance and increase the code size of the modified function.
   *      3. Make a copy of the function(s) and rename it. Call the original
   *         function in once context, and the renamed version in another.
   *
   *    @subsection usb_device_pitfalls_buffer_allocation Buffer Allocation
   *
   *    Dynamically allocated buffers passed to @ref USBD_Write() and @ref
   *    USBD_Read() must not be freed until the transfer completes.
   *
   ******************************************************************************/
  
  /***************************************************************************//**
   *  @addtogroup efm8_usb_constants Constants
   *  @{
   ******************************************************************************/
  
  // -----------------------------------------------------------------------------
  // Global Constants
  
  // SETUP request, direction of data stage
  #define USB_SETUP_DIR_OUT       0               ///< Setup request data stage OUT direction value.
  #define USB_SETUP_DIR_IN        1               ///< Setup request data stage IN direction value.
  #define USB_SETUP_DIR_MASK      0x80            ///< Setup request data stage direction mask.
  #define USB_SETUP_DIR_D2H       0x80            ///< Setup request data stage IN direction mask.
  #define USB_SETUP_DIR_H2D       0x00            ///< Setup request data stage OUT direction mask.
  
  // SETUP request type
  #define USB_SETUP_TYPE_STANDARD       0         ///< Standard setup request value.
  #define USB_SETUP_TYPE_CLASS          1         ///< Class setup request value.
  #define USB_SETUP_TYPE_VENDOR         2         ///< Vendor setup request value.
  #define USB_SETUP_TYPE_STANDARD_MASK  0x00      ///< Standard setup request mask.
  #define USB_SETUP_TYPE_CLASS_MASK     0x20      ///< Class setup request mask.
  #define USB_SETUP_TYPE_VENDOR_MASK    0x40      ///< Vendor setup request mask.
  
  // SETUP request recipient
  #define USB_SETUP_RECIPIENT_DEVICE    0         ///< Setup request device recipient value.
  #define USB_SETUP_RECIPIENT_INTERFACE 1         ///< Setup request interface recipient value.
  #define USB_SETUP_RECIPIENT_ENDPOINT  2         ///< Setup request endpoint recipient value.
  #define USB_SETUP_RECIPIENT_OTHER     3         ///< Setup request other recipient value.
  
  // bmRequestType bitmasks
  #define USB_BMREQUESTTYPE_RECIPIENT     0x1F    ///< Recipient is bmRequestType[4:0]
  #define USB_BMREQUESTTYPE_TYPE          0x60    ///< Type is bmRequestType[6:5]
  #define USB_BMREQUESTTYPE_DIRECTION     0x80    ///< Recipient is bmRequestType[7]
  
  // SETUP standard request codes for Full Speed devices
  #define GET_STATUS                0             ///< Standard setup request GET_STATUS.
  #define CLEAR_FEATURE             1             ///< Standard setup request CLEAR_FEATURE.
  #define SET_FEATURE               3             ///< Standard setup request SET_FEATURE.
  #define SET_ADDRESS               5             ///< Standard setup request SET_ADDRESS.
  #define GET_DESCRIPTOR            6             ///< Standard setup request GET_DESCRIPTOR.
  #define SET_DESCRIPTOR            7             ///< Standard setup request SET_DESCRIPTOR.
  #define GET_CONFIGURATION         8             ///< Standard setup request GET_CONFIGURATION.
  #define SET_CONFIGURATION         9             ///< Standard setup request SET_CONFIGURATION.
  #define GET_INTERFACE             10            ///< Standard setup request GET_INTERFACE.
  #define SET_INTERFACE             11            ///< Standard setup request SET_INTERFACE.
  #define SYNCH_FRAME               12            ///< Standard setup request SYNCH_FRAME.
  
  // SETUP class request codes
  #define USB_HID_GET_REPORT        0x01          ///< HID class setup request GET_REPORT.
  #define USB_HID_GET_IDLE          0x02          ///< HID class setup request GET_IDLE.
  #define USB_HID_SET_REPORT        0x09          ///< HID class setup request SET_REPORT.
  #define USB_HID_SET_IDLE          0x0A          ///< HID class setup request SET_IDLE.
  #define USB_HID_SET_PROTOCOL      0x0B          ///< HID class setup request SET_PROTOCOL.
  #define USB_CDC_SETLINECODING     0x20          ///< CDC class setup request SET_LINE_CODING.
  #define USB_CDC_GETLINECODING     0x21          ///< CDC class setup request GET_LINE_CODING.
  #define USB_CDC_SETCTRLLINESTATE  0x22          ///< CDC class setup request SET_CONTROL_LINE_STATE.
  #define USB_MSD_BOTRESET          0xFF          ///< MSD class setup request Bulk only transfer reset.
  #define USB_MSD_GETMAXLUN         0xFE          ///< MSD class setup request Get Max LUN.
  
  // SETUP command GET/SET_DESCRIPTOR descriptor types
  #define USB_DEVICE_DESCRIPTOR             1     ///< DEVICE descriptor value.
  #define USB_CONFIG_DESCRIPTOR             2     ///< CONFIGURATION descriptor value.
  #define USB_STRING_DESCRIPTOR             3     ///< STRING descriptor value.
  #define USB_INTERFACE_DESCRIPTOR          4     ///< INTERFACE descriptor value.
  #define USB_ENDPOINT_DESCRIPTOR           5     ///< ENDPOINT descriptor value.
  #define USB_DEVICE_QUALIFIER_DESCRIPTOR   6     ///< DEVICE_QUALIFIER descriptor value.
  #define USB_OTHER_SPEED_CONFIG_DESCRIPTOR 7     ///< OTHER_SPEED_CONFIGURATION descriptor value.
  #define USB_INTERFACE_POWER_DESCRIPTOR    8     ///< INTERFACE_POWER descriptor value.
  #define USB_HUB_DESCRIPTOR                0x29  ///< HUB descriptor value.
  #define USB_HID_DESCRIPTOR                0x21  ///< HID descriptor value.
  #define USB_HID_REPORT_DESCRIPTOR         0x22  ///< HID REPORT descriptor value.
  #define USB_CS_INTERFACE_DESCRIPTOR       0x24  ///< Audio Class-specific Descriptor Type.
  
  #define USB_DEVICE_DESCSIZE               18    ///< Device descriptor size.
  #define USB_CONFIG_DESCSIZE               9     ///< Configuration descriptor size.
  #define USB_INTERFACE_DESCSIZE            9     ///< Interface descriptor size.
  #define USB_ENDPOINT_DESCSIZE             7     ///< Endpoint descriptor size.
  #define USB_DEVICE_QUALIFIER_DESCSIZE     10    ///< Device qualifier descriptor size.
  #define USB_OTHER_SPEED_CONFIG_DESCSIZE   9     ///< Device other speed configuration descriptor size.
  #define USB_HID_DESCSIZE                  9     ///< HID descriptor size.
  #define USB_CDC_HEADER_FND_DESCSIZE       5     ///< CDC Header functional descriptor size.
  #define USB_CDC_CALLMNG_FND_DESCSIZE      5     ///< CDC Call Management functional descriptor size.
  #define USB_CDC_ACM_FND_DESCSIZE          4     ///< CDC Abstract Control Management functional descriptor size.
  
  // String descriptor locations
  #define USB_STRING_DESCRIPTOR_ENCODING    0     ///< Denotes whether string descriptor is UTF-8 or binary
  #define USB_STRING_DESCRIPTOR_LENGTH      1     ///< Length of string descriptor
  #define USB_STRING_DESCRIPTOR_TYPE        2     ///< Type of string descriptor (USB_STRING_DESCRIPTOR)
  #define USB_STRING_DESCRIPTOR_NAME        3     ///< The string encoded as per USB_STRING_DESCRIPTOR_PACKED
  
  // String descriptor encoding types
  #define USB_STRING_DESCRIPTOR_UTF16LE        0  ///< The string is in UTF-16LE encoding
  #define USB_STRING_DESCRIPTOR_UTF16LE_PACKED 1  ///< The string is in packed UTF-16LE encoding (the 0x00
                                                  ///  characters between ASCII characters are omitted)
  #define USB_STRING_DESCRIPTOR_UTF8           2  ///< The string is in UTF-8 encoding
  
  // Misc. USB definitions
  #define USB_FULL_EP0_SIZE                 64      ///< The size of endpoint 0 at full speed.
  #define USB_FULL_INT_BULK_MAX_EP_SIZE     64      ///< The max size of any full speed bulk/interrupt endpoint.
  #define USB_FULL_ISOC_MAX_EP_SIZE         1023    ///< The max size of any full speed isochronous endpoint.
  #define USB_LOW_EP0_SIZE                  8       ///< The size of endpoint 0 at low speed.
  #define USB_LOW_INT_BULK_MAX_EP_SIZE      8       ///< The max size of any low speed bulk/interrupt endpoint.
  #define USB_LOW_ISOC_MAX_EP_SIZE          0       ///< The max size of any low speed isochronous endpoint.
  #define USB_EPTYPE_CTRL                   0       ///< Endpoint type control.
  #define USB_EPTYPE_ISOC                   1       ///< Endpoint type isochronous.
  #define USB_EPTYPE_BULK                   2       ///< Endpoint type bulk.
  #define USB_EPTYPE_INTR                   3       ///< Endpoint type interrupt.
  #define USB_EP_DIR_IN                     0x80    ///< Endpoint IN direction mask.
  #define USB_EP_DIR_OUT                    0x00    ///< Endponit OUT direction mask.
  #define USB_SETUP_PKT_SIZE                8       ///< Setup request packet size.
  #define USB_EPNUM_MASK                    0x0F    ///< Endpoint number mask.
  #define USB_LANGID_ENUS                   0x0409  ///< English-United States language id.
  #define USB_LANGID_NOBO                   0x0414  ///< Norwegian-Bokmal language id.
  #define USB_MAX_DEVICE_ADDRESS            127     ///< Maximum allowable device address.
  #define MAX_USB_EP_NUM                    15      ///< Limit imposed by the USB standard
  #define USB_VENDOR_ID_SILICON_LABS        0x10C4  ///< Silicon Labs VID
  
  #define CONFIG_DESC_BM_REMOTEWAKEUP 0x20        ///< Configuration descriptor attribute macro.
  #define CONFIG_DESC_BM_SELFPOWERED  0x40        ///< Configuration descriptor attribute macro.
  #define CONFIG_DESC_BM_RESERVED_D7  0x80        ///< Configuration descriptor attribute macro.
  #define CONFIG_DESC_BM_TRANSFERTYPE 0x03        ///< Configuration descriptor transfer type bitmask.
  #define CONFIG_DESC_MAXPOWER_mA(x)  (((x)+1)/2) ///< Configuration descriptor power macro.
  
  #define DEVICE_IS_SELFPOWERED       0x0001      ///< Standard request GET_STATUS bitmask.
  #define REMOTE_WAKEUP_ENABLED       0x0002      ///< Standard request GET_STATUS bitmask.
  #define USB_FEATURE_ENDPOINT_HALT         0     ///< Standard request CLEAR/SET_FEATURE bitmask.
  #define USB_FEATURE_DEVICE_REMOTE_WAKEUP  1     ///< Standard request CLEAR/SET_FEATURE bitmask.
  
  #define HUB_FEATURE_PORT_RESET            4     ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector.
  #define HUB_FEATURE_PORT_POWER            8     ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector.
  #define HUB_FEATURE_C_PORT_CONNECTION     16    ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector.
  #define HUB_FEATURE_C_PORT_RESET          20    ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector.
  #define HUB_FEATURE_PORT_INDICATOR        22    ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector.
  
  #define USB_CLASS_CDC                     2     ///< CDC device/interface class code.
  #define USB_CLASS_CDC_DATA                0x0A  ///< CDC Data interface class code.
  #define USB_CLASS_CDC_ACM                 2     ///< CDC Abstract Control Model interface subclass code.
  #define USB_CLASS_CDC_HFN                 0     ///< CDC class Header Functional Descriptor subtype.
  #define USB_CLASS_CDC_CMNGFN              1     ///< CDC class Call Management Functional Descriptor subtype.
  #define USB_CLASS_CDC_ACMFN               2     ///< CDC class Abstract Control Management Functional Descriptor subtype.
  #define USB_CLASS_CDC_UNIONFN             6     ///< CDC class Union Functional Descriptor subtype.
  
  #define USB_CLASS_HID                     3     ///< HID device/interface class code.
  #define USB_CLASS_HID_KEYBOARD            1     ///< HID keyboard interface protocol code.
  #define USB_CLASS_HID_MOUSE               2     ///< HID mouse interface protocol code.
  
  #define USB_CLASS_HUB                     9     ///< HUB device/interface class code.
  
  #define USB_CLASS_MSD                     8     ///< MSD device/interface class code.
  #define USB_CLASS_MSD_BOT_TRANSPORT       0x50  ///< MSD Bulk Only Transport protocol.
  #define USB_CLASS_MSD_SCSI_CMDSET         6     ///< MSD Subclass SCSI transparent command set.
  #define USB_CLASS_MSD_CSW_CMDPASSED       0     ///< MSD BOT Command status wrapper command passed code.
  #define USB_CLASS_MSD_CSW_CMDFAILED       1     ///< MSD BOT Command status wrapper command failed code.
  #define USB_CLASS_MSD_CSW_PHASEERROR      2     ///< MSD BOT Command status wrapper cmd phase error code.
  
  #define USB_CLASS_VENDOR_SPECIFIC         0xFF  ///< Vendor Specific class
  #define USB_SUBCLASS_VENDOR_SPECIFIC      0xFF  ///< Vendor Specific sub-class
  
  /// @brief USB power save modes
  #define USB_PWRSAVE_MODE_OFF       0            ///< No energy saving option selected.
  #define USB_PWRSAVE_MODE_ONSUSPEND 1            ///< Enter USB power-save mode on suspend.
  #define USB_PWRSAVE_MODE_ONVBUSOFF 2            ///< Enter USB power-save mode when not attached to the USB host.
  #define USB_PWRSAVE_MODE_FASTWAKE  4            ///< Exit USB power-save mode more quickly. This is useful for
                                                  ///< some applications that support remote wakeup.
  
  /// @brief Endpoint 0 packet size
  #if SLAB_USB_FULL_SPEED
  #define USB_EP0_SIZE    USB_FULL_EP0_SIZE
  #else
  #define USB_EP0_SIZE    USB_LOW_EP0_SIZE
  #endif // SLABS_USB_FULL_SPEED
  
  /// @brief Total number of USB endpoints used by the device
  #define SLAB_USB_NUM_EPS_USED    (SLAB_USB_EP1IN_USED   \
                                    + SLAB_USB_EP1OUT_USED \
                                    + SLAB_USB_EP2IN_USED  \
                                    + SLAB_USB_EP2OUT_USED \
                                    + SLAB_USB_EP3IN_USED  \
                                    + SLAB_USB_EP3OUT_USED \
                                    + 1)
  /**  @} (end addtogroup efm8_usb_constants Constants) */
  
  /***************************************************************************//**
   *  @addtogroup efm8_usb_macros Macros
   *  @{
   ******************************************************************************/
  
  // -----------------------------------------------------------------------------
  // Global Macros
  
  /// Macro for getting minimum value.
  #ifndef EFM8_MIN
  #define EFM8_MIN(a, b)    ((a) < (b) ? (a) : (b))
  #endif
  
  /// Macro for getting maximum value.
  #ifndef EFM8_MAX
  #define EFM8_MAX(a, b)    ((a) > (b) ? (a) : (b))
  #endif
  
  #ifndef UNREFERENCED_ARGUMENT
  #if defined __C51__
  /// Macro for removing unreferenced arguments from compiler warnings
  #define UNREFERENCED_ARGUMENT(arg) (0, arg)
  #elif defined __ICC8051__
  /// Macro for removing unreferenced arguments from compiler warnings
  #define UNREFERENCED_ARGUMENT(arg) ((void)arg)
  #endif
  #endif
  
  /***************************************************************************//**
   * @brief       Macro for creating USB-compliant UTF-16LE UNICODE string
   *              descriptor from a C string.
   * @details     This macro should be used for ASCII strings in which all
   *              characters are represented by a single ASCII byte (i.e.
   *              U.S. English strings).
   *              The USB Library will expand variables created with this macro
   *              by inserting a 0x00 between each character. This allows the
   *              string to be stored in a "packed", or compressed, format.
   * @n@n         This example sends "Silicon Labs" as the Manufacturer String:
   *
   *              #define MFR_STRING    "Silicon Labs"
   *
   *              UTF16LE_PACKED_STATIC_CONST_STRING_DESC(manufacturer[], \
   *                                                      MFR_STRING);
   * @param       __name
   *              The name of the variable that holds the string descriptor
   * @param       __val
   *              The value of the string descriptor
   ******************************************************************************/
  #define UTF16LE_PACKED_STATIC_CONST_STRING_DESC(__name, __val, __size) \
    SI_SEGMENT_VARIABLE(__name,  static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \
      { USB_STRING_DESCRIPTOR_UTF16LE_PACKED, __size * 2, USB_STRING_DESCRIPTOR, __val }
  
  /***************************************************************************//**
   * @brief       Macro for creating USB-compliant UTF-16LE UNICODE string
   *              descriptor from a UTF-8 string.
   * @details     This macro should be used for UTF-8 strings in which all
   *              characters are represented by a valid UTF-8 byte sequence
   *              of 1-3 bytes per character.  The USB library will expand
   *              variables created with this macro by decoding the UTF-8
   *              sequence into 16-bit wide UCS-2 characters required for USB
   *              string descriptors.
   * @n@n         This example set an array named _manufacturer[]_ to a
   *              series of symbols: an anchor, a lightning bolt, and a
   *              fußball as the Manufacturer String:
   *
   *              #define MFR_STRING    "⚓⚡⚽"
   *
   *              // This string has 3 Unicode characters so the __len
   *              // parameter is 3, even though it will take 3 bytes to
   *              // represent each character
   *              UTF8_PACKED_STATIC_CONST_STRING_DESC(manufacturer[], 3, \
   *                                                   MFR_STRING);
   * @param       __name
   *              The name of the variable that holds the string descriptor
   * @param       __len
   *              Number of Unicode characters (or codepoints) in the string
   * @param       __val
   *              The value of the string descriptor
   ******************************************************************************/
  #define UTF8_PACKED_STATIC_CONST_STRING_DESC(__name, __len, __val) \
    SI_SEGMENT_VARIABLE(__name,  static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \
      { USB_STRING_DESCRIPTOR_UTF8, (__len) * 2, USB_STRING_DESCRIPTOR, __val }
  
  /***************************************************************************//**
   * @brief       Macro for creating USB-compliant UTF-16LE UNICODE string
   *              descriptor from a UTF-8 string.
   * @details     This macro should be used for UTF-8 strings in which all
   *              characters are represented by a valid UTF-8 byte sequence
   *              of 1-3 bytes per character.  The USB library will expand
   *              variables created with this macro by decoding the UTF-8
   *              sequence into 16-bit wide UCS-2 characters required for USB
   *              string descriptors.
   * @n@n         This example set an array named _manufacturer[]_ to a
   *              series of symbols: an anchor, a lightning bolt, and a
   *              fußball as the Manufacturer String:
   *
   *              #define MFR_STRING    "⚓⚡⚽"
   *
   *              // This string has 3 Unicode characters so the __len
   *              // parameter is 3, even though it will take 3 bytes to
   *              // represent each character
   *              UTF8_PACKED_STATIC_CONST_STRING_DESC(manufacturer[], 3, \
   *                                                   MFR_STRING);
   * @param       __name
   *              The name of the variable that holds the string descriptor
   * @param       __len
   *              Number of Unicode characters (or codepoints) in the string
   * @param       __val
   *              The value of the string descriptor
   ******************************************************************************/
  #define UTF8_PACKED_STATIC_CONST_STRING_DESC(__name, __len, __val) \
    SI_SEGMENT_VARIABLE(__name,  static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \
      { USB_STRING_DESCRIPTOR_UTF8, (__len) * 2, USB_STRING_DESCRIPTOR, __val }
  
  /***************************************************************************//**
   * @brief       Macro for creating USB-compliant UTF-16LE UNICODE string
   *              descriptor from a C array initializer.
   * @details     This macro should be used for converting an array initializer
   *              into a string descriptor. Unlike @ref
   *              UTF16LE_PACKED_STATIC_CONST_STRING_DESC(), the library will not
   *              attempt to unpack variables created with this macro, so the
   *              array will be sent exactly as it is defined.
   * @n@n         This example sends "Mouse" as the Product String:
   *
   *              #define PROD_STRING   'M',0,'o',0,'u',0,'s',0,'e',0
   *
   *              ARRAY_STATIC_CONST_STRING_DESC(product[], \
   *                                             10, \
   *                                             PROD_STRING);
   * @param       __name
   *              The name of the variable that holds the string descriptor
   * @param       __len
   *              Number of characters (including nulls) in the string to send
   * @param       __val
   *              The array initializer.
   ******************************************************************************/
  #define ARRAY_STATIC_CONST_STRING_DESC(__name, __len, __val) \
    SI_SEGMENT_VARIABLE(__name,  static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \
      { USB_STRING_DESCRIPTOR_UTF16LE, __len + 2, USB_STRING_DESCRIPTOR, __val }
  
  /***************************************************************************//**
   * @brief       Macro for creating USB-compliant UTF-16LE UNICODE string
   *              descriptor from a UTF-16 C string.
   * @details     This macro should be used for strings which are already
   *              represented in UTF-16. This is an advanced option that should
   *              only be used for some foreign languages.
   * @param       __name
   *              The name of the variable that holds the string descriptor
   * @param       __val
   *              The value of the string descriptor
   ******************************************************************************/
  #define UTF16LE_STATIC_CONST_STRING_DESC(__name, __val) \
    SI_SEGMENT_VARIABLE(__name,  static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \
      { USB_STRING_DESCRIPTOR_UTF16LE, sizeof(__val) + 2, USB_STRING_DESCRIPTOR, __val }
  
  /***************************************************************************//**
   * @brief       Macro for creating Language ID's String Descriptor (String
   *              Descriptor 0)
   * @details     This macro should be used to create the Language ID String
   *              Descriptor.
   * @n@n         This example USB device only support U.S. English:
   *
   *              #define LANG_STRING   htole16(SLAB_USB_LANGUAGE)
   *
   *              LANGID_STATIC_CONST_STRING_DESC(langDesc[], LANG_STRING);
   *
   *              This example USB device support Norwegian U.S. English:
   *
   *              #define LANG_STRING   htole16(USB_LANGID_NOBO), \
   *                                    htole16(USB_LANGID_ENUS)
   *
   *              LANGID_STATIC_CONST_STRING_DESC(langDesc[], LANG_STRING);
   *
   * @param       __name
   *              The name of the variable that holds the string descriptor
   * @param       __val
   *              The value of the string descriptor
   ******************************************************************************/
  #define LANGID_STATIC_CONST_STRING_DESC(__name, __val) \
    SI_SEGMENT_VARIABLE(__name,  static const USB_LangId_StringDescriptor_Typedef, SI_SEG_CODE) = \
      { htole16(((SLAB_USB_NUM_LANGUAGES * 2) + 2) + (USB_STRING_DESCRIPTOR << 8)), __val }
  
  /**  @} (end addtogroup efm8_usb_macros Macros) */
  
  /***************************************************************************//**
   *  @addtogroup efm8_usb_typedefs Typedefs
   *  @{
   ******************************************************************************/
  
  // -----------------------------------------------------------------------------
  // Typedefs
  
  /// @brief USB transfer status enumerator.
  typedef enum
  {
    USB_STATUS_OK = 0,                            ///< No errors detected.
    USB_STATUS_REQ_ERR = -1,                      ///< Setup request error.
    USB_STATUS_EP_BUSY = -2,                      ///< Endpoint is busy.
    USB_STATUS_REQ_UNHANDLED = -3,                ///< Setup request not handled.
    USB_STATUS_ILLEGAL = -4,                      ///< Illegal operation attempted.
    USB_STATUS_EP_STALLED = -5,                   ///< Endpoint is stalled.
    USB_STATUS_EP_ABORTED = -6,                   ///< Endpoint transfer was aborted.
    USB_STATUS_EP_ERROR = -7,                     ///< Endpoint transfer error.
    USB_STATUS_EP_NAK = -8,                       ///< Endpoint NAK'ed transfer request.
    USB_STATUS_DEVICE_UNCONFIGURED = -9,          ///< Device is unconfigured.
    USB_STATUS_DEVICE_SUSPENDED = -10,            ///< Device is suspended.
    USB_STATUS_DEVICE_RESET = -11,                ///< Device is/was reset.
    USB_STATUS_TIMEOUT = -12,                     ///< Transfer timeout.
    USB_STATUS_DEVICE_REMOVED = -13,              ///< Device was removed.
    USB_STATUS_EP_RX_BUFFER_OVERRUN = -14,        ///< Not enough data in the Rx buffer to hold the
    USB_STATUS_DATA_ERROR = -15,                  ///< OUT packet had CRC or bit-stuffing error
                                                  ///< last received packet
  } USB_Status_TypeDef;
  
  /// @brief USB device state enumerator.
  typedef enum
  {
    USBD_STATE_NONE = 0,               ///< Device state is undefined/unknown.
    USBD_STATE_ATTACHED = 1,           ///< Device state is ATTACHED.
    USBD_STATE_POWERED = 2,            ///< Device state is POWERED.
    USBD_STATE_DEFAULT = 3,            ///< Device state is DEFAULT.
    USBD_STATE_ADDRESSED = 4,          ///< Device state is ADDRESSED.
    USBD_STATE_SUSPENDED = 5,          ///< Device state is SUSPENDED.
    USBD_STATE_CONFIGURED = 6,         ///< Device state is CONFIGURED.
    USBD_STATE_LASTMARKER = 7,         ///< Device state enum end marker.
  } USBD_State_TypeDef;
  
  /// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
  /// @brief Endpoint states
  typedef enum
  {
    D_EP_DISABLED = 0,                 ///< Endpoint is disabled
    D_EP_IDLE = 1,                     ///< Endpoint is idle
    D_EP_TRANSMITTING = 2,             ///< Endpoint is transmitting data
    D_EP_RECEIVING = 3,                ///< Endpoint is receiving data
    D_EP_STATUS = 4,                   ///< Endpoint is in status stage
    D_EP_STALL = 5,                    ///< Endpoint is stalling
    D_EP_HALT = 6,                     ///< Endpoint is halted
    D_EP_LASTMARKER = 7                ///< End of EpState enum
  } USBD_EpState_TypeDef;
  /// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN
  
  /// @brief Endpoint access address
  typedef enum
  {
    EP0,
  #if (SLAB_USB_EP1IN_USED)
    EP1IN,
  #endif
  #if (SLAB_USB_EP2IN_USED)
    EP2IN,
  #endif
  #if (SLAB_USB_EP3IN_USED)
    EP3IN,
  #endif
  #if (SLAB_USB_EP1OUT_USED)
    EP1OUT,
  #endif
  #if (SLAB_USB_EP2OUT_USED)
    EP2OUT,
  #endif
  #if (SLAB_USB_EP3OUT_USED)
    EP3OUT,
  #endif
  } USB_EP_Index_TypeDef;
  
  /// @brief USB Setup type.
  typedef struct
  {
    struct
    {
      uint8_t Recipient : 5;           ///< Request recipient (device, interface, endpoint, other)
      uint8_t Type : 2;                ///< Request type (standard, class or vendor).
      uint8_t Direction : 1;           ///< Transfer direction of SETUP data phase.
    } bmRequestType;
  
    uint8_t bRequest;
    uint16_t wValue;
    uint16_t wIndex;
    uint16_t wLength;
  } USB_Setup_TypeDef;
  
  /// @brief USB Setup Union type.
  typedef union
  {
    USB_Setup_TypeDef setup;
    uint8_t c[8];
    uint16_t i[4];
  } USB_Setup_UnionDef;
  
  /// @brief USB Device Descriptor.
  typedef struct
  {
    uint8_t bLength;                   ///< Size of this descriptor in bytes
    uint8_t bDescriptorType;           ///< Constant DEVICE Descriptor Type
    uint16_t bcdUSB;                   ///< USB Specification Release Number in BCD
    uint8_t bDeviceClass;              ///< Class code (assigned by the USB-IF)
    uint8_t bDeviceSubClass;           ///< Subclass code (assigned by the USB-IF)
    uint8_t bDeviceProtocol;           ///< Protocol code (assigned by the USB-IF)
    uint8_t bMaxPacketSize0;           ///< Maximum packet size for endpoint zero
    uint16_t idVendor;                 ///< Vendor ID (assigned by the USB-IF)
    uint16_t idProduct;                ///< Product ID (assigned by the manufacturer)
    uint16_t bcdDevice;                ///< Device release number in binary-coded decimal
    uint8_t iManufacturer;             ///< Index of string descriptor describing manufacturer
    uint8_t iProduct;                  ///< Index of string descriptor describing product
    uint8_t iSerialNumber;             ///< Index of string descriptor describing the serial number
    uint8_t bNumConfigurations;        ///< Number of possible configurations
  } USB_DeviceDescriptor_TypeDef;
  
  
  /// @brief USB Configuration Descriptor.
  typedef struct
  {
    uint8_t bLength;                   ///< Size of this descriptor in bytes
    uint8_t bDescriptorType;           ///< Constant CONFIGURATION Descriptor Type
    uint16_t wTotalLength;             ///< Total length of data returned for this
                                       ///< configuration. Includes the combined length of all
                                       ///< descriptors (configuration, interface, endpoint,
                                       ///< and class- or vendor-specific) returned for this
                                       ///< configuration.
    uint8_t bNumInterfaces;            ///< Number of interfaces supported by this
                                       ///< configuration
    uint8_t bConfigurationValue;       ///< Value to use as an argument to the
                                       ///< SetConfiguration request to select this
                                       ///< configuration.
    uint8_t iConfiguration;            ///< Index of string descriptor describing this
                                       ///< configuration.
    uint8_t bmAttributes;              ///< Configuration characteristics.
                                       ///< @n D7: Reserved (set to one)
                                       ///< @n D6: Self-powered
                                       ///< @n D5: Remote Wakeup
                                       ///< @n D4...0: Reserved (reset to zero)
    uint8_t bMaxPower;                 ///< Maximum power consumption of the USB device, unit
                                       ///< is 2mA per LSB
  } USB_ConfigurationDescriptor_TypeDef;
  
  
  /// @brief USB Interface Descriptor.
  typedef struct
  {
    uint8_t bLength;                   ///< Size of this descriptor in bytes.
    uint8_t bDescriptorType;           ///< Constant INTERFACE Descriptor Type.
    uint8_t bInterfaceNumber;          ///< Number of this interface. Zero-based value
                                       ///< identifying the index in the array of concurrent
                                       ///< interfaces supported by this configuration.
    uint8_t bAlternateSetting;         ///< Value used to select this alternate setting for
                                       ///< the interface identified in the prior field.
    uint8_t bNumEndpoints;             ///< Number of endpoints used by this interface
                                       ///< (excluding endpoint zero). If this value is zero,
                                       ///< this interface only uses the Default Control Pipe.
    uint8_t bInterfaceClass;           ///< Class code (assigned by the USB-IF). A value
                                       ///< of zero is reserved for future standardization. If
                                       ///< this field is set to FFH, the interface class is
                                       ///< vendor-specific. All other values are reserved for
                                       ///< assignment by the USB-IF.
    uint8_t bInterfaceSubClass;        ///< Subclass code (assigned by the USB-IF). These codes
                                       ///< are qualified by the value of the bInterfaceClass
                                       ///< field. If the bInterfaceClass field is reset to
                                       ///< zero, this field must also be reset to zero. If
                                       ///< the bInterfaceClass field is not set to FFH, all
                                       ///< values are reserved for assignment by the USB-IF.
    uint8_t bInterfaceProtocol;        ///< Protocol code (assigned by the USB). These codes
                                       ///< are qualified by the value of the bInterfaceClass
                                       ///< and the bInterfaceSubClass fields. If an interface
                                       ///< supports class-specific requests, this code
                                       ///< identifies the protocols that the device uses as
                                       ///< defined by the specification of the device class.
                                       ///< If this field is reset to zero, the device does
                                       ///< not use a class-specific protocol on this
                                       ///< interface. If this field is set to FFH, the device
                                       ///< uses a vendor-specific protocol for this interface
    uint8_t iInterface;                ///< Index of string descriptor describing this
                                       ///< interface.
  } USB_InterfaceDescriptor_TypeDef;
  
  
  /// @brief USB Endpoint Descriptor.
  typedef struct
  {
    uint8_t bLength;                   ///< Size of this descriptor in bytes
    uint8_t bDescriptorType;           ///< Constant ENDPOINT Descriptor Type
    uint8_t bEndpointAddress;          ///< The address of the endpoint
    uint8_t bmAttributes;              ///< This field describes the endpoint attributes
    uint16_t wMaxPacketSize;           ///< Maximum packet size for the endpoint
    uint8_t bInterval;                 ///< Interval for polling EP for data transfers
  } USB_EndpointDescriptor_TypeDef;
  
  /// @brief USB String Descriptor.
  typedef uint8_t USB_StringDescriptor_TypeDef;         ///< The string descriptor
  
  /// @brief USB Language ID String Descriptor.
  typedef uint16_t USB_LangId_StringDescriptor_Typedef; ///< The language ID string descriptor
  
  #if (SLAB_USB_NUM_LANGUAGES == 1)
  /// @brief USB String Table Structure.
  typedef SI_VARIABLE_SEGMENT_POINTER(, USB_StringDescriptor_TypeDef, SI_SEG_GENERIC) USB_StringTable_TypeDef;
  #elif (SLAB_USB_NUM_LANGUAGES > 1)
  typedef struct
  {
    uint16_t *languageIDs;
    USB_StringDescriptor_TypeDef * * *languageArray;
  } USB_StringTable_TypeDef;
  #endif // ( SLAB_USB_NUM_LANGUAGES == 1 )
  
  /// @brief USB Device stack initialization structure.
  ///  @details This structure is passed to @ref USBD_Init() when starting up
  ///  the device.
  typedef struct
  {
    SI_VARIABLE_SEGMENT_POINTER(deviceDescriptor, USB_DeviceDescriptor_TypeDef, SI_SEG_GENERIC);          ///< Pointer to the device descriptor
    SI_VARIABLE_SEGMENT_POINTER(configDescriptor, USB_ConfigurationDescriptor_TypeDef, SI_SEG_GENERIC);   ///< Pointer to the configuration descriptor
    SI_VARIABLE_SEGMENT_POINTER(stringDescriptors, USB_StringTable_TypeDef, SI_SEG_GENERIC);              ///< Pointer to an array of string descriptor pointers
    uint8_t numberOfStrings;                                                                              ///< Number of strings in string descriptor array
  } USBD_Init_TypeDef;
  
  /// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
  // Endpoint structure
  typedef struct
  {
    SI_VARIABLE_SEGMENT_POINTER(buf, uint8_t, SI_SEG_GENERIC);
    uint16_t remaining;
    USBD_EpState_TypeDef state;
    union
    {
      struct
      {
        uint8_t callback         : 1;
        uint8_t outPacketPending : 1;
        uint8_t inPacketPending  : 1;
        uint8_t waitForRead      : 1;
      } bits;
      uint8_t c;
    } misc;
  } USBD_Ep_TypeDef;
  
  // USB Device structure
  typedef struct
  {
    uint8_t configurationValue;
  #if SLAB_USB_REMOTE_WAKEUP_ENABLED
    uint8_t remoteWakeupEnabled;
  #endif
    uint8_t numberOfStrings;
    USBD_State_TypeDef state;
    USBD_State_TypeDef savedState;
    USB_Setup_TypeDef setup;
    union
    {
      struct
      {
        uint8_t type : 7;
        uint8_t init : 1;
      } encoding;
      uint8_t c;
    } ep0String;
    USBD_Ep_TypeDef ep0;
  #if SLAB_USB_EP1IN_USED
    USBD_Ep_TypeDef ep1in;
  #endif
  #if SLAB_USB_EP2IN_USED
    USBD_Ep_TypeDef ep2in;
  #endif
  #if SLAB_USB_EP3IN_USED
    USBD_Ep_TypeDef ep3in;
  #endif
  #if SLAB_USB_EP1OUT_USED
    USBD_Ep_TypeDef ep1out;
  #endif
  #if SLAB_USB_EP2OUT_USED
    USBD_Ep_TypeDef ep2out;
  #endif
  #if SLAB_USB_EP3OUT_USED
    USBD_Ep_TypeDef ep3out;
  #endif
  #if ((SLAB_USB_EP3IN_USED) && (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC))
    uint16_t ep3inIsoIdx;
  #endif
  #if ((SLAB_USB_EP3OUT_USED) && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC))
    uint16_t ep3outIsoIdx;
  #endif
  #if SLAB_USB_SUPPORT_ALT_INTERFACES
    uint8_t interfaceAltSetting[SLAB_USB_NUM_INTERFACES];
  #endif
    SI_VARIABLE_SEGMENT_POINTER(deviceDescriptor, USB_DeviceDescriptor_TypeDef, SI_SEG_GENERIC);
    SI_VARIABLE_SEGMENT_POINTER(configDescriptor, USB_ConfigurationDescriptor_TypeDef, SI_SEG_GENERIC);
    SI_VARIABLE_SEGMENT_POINTER(stringDescriptors, USB_StringTable_TypeDef, SI_SEG_GENERIC);
  } USBD_Device_TypeDef;
  /// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN
  
  /**  @} (end addtogroup efm8_usb_typedefs Typedefs) */
  
  /***************************************************************************//**
   *  @addtogroup efm8_usb_constants Constants
   *  @{
   ******************************************************************************/
  
  // -----------------------------------------------------------------------------
  // Compiler-specific memory segment definitions
  
  #ifndef MEM_MODEL_SEG
  
  // -----------------------------------------------------------------------------
  //  Memory Model-Specific Location
  //
  //  MEM_MODEL_SEG is the default memory segment used for a given
  //  memory model. Some variables use this symbol in order to reduce the amount
  //  of code space and number of cycles it takes to access them.
  //  The user can override this value by defining it in his usbconfig.h file.
  //  For example:
  //
  //  #define MEM_MODEL_LOC    SI_SEG_XDATA
  //
  //  will place these variables in XRAM regardless of the memory model used to
  //  build the project.
  // -----------------------------------------------------------------------------
  
  #if (defined SDCC) || (defined __SDCC)
  
  #if (__SDCC_MODEL_SMALL)
  #define MEM_MODEL_SEG  SI_SEG_IDATA
  #elif defined __SDCC_MODEL_MEDIUM
  #define MEM_MODEL_SEG  SI_SEG_PDATA
  #elif (defined __SDCC_MODEL_LARGE) || (defined __SDCC_MODEL_HUGE)
  #define MEM_MODEL_SEG  SI_SEG_XDATA
  #else
  #error "Illegal memory model setting."
  #endif
  
  #elif defined __RC51__
  
  #if (__MEMORY_MODEL__ == 0)     // TINY
  #define MEM_MODEL_SEG  SI_SEG_IDATA
  #elif (__MEMORY_MODEL__ == 1)   // SMALL
  #define MEM_MODEL_SEG  SI_SEG_IDATA
  #elif (__MEMORY_MODEL__ == 2)   // COMPACT
  #define MEM_MODEL_SEG  SI_SEG_PDATA
  #elif (__MEMORY_MODEL__ == 3)   // LARGE
  #define MEM_MODEL_SEG  SI_SEG_XDATA
  #elif (__MEMORY_MODEL__ == 4)   // HUGE
  #define MEM_MODEL_SEG  SI_SEG_PDATA
  #else
  #error "Illegal memory model setting."
  #endif
  
  #elif defined __C51__
  
  #if (__MODEL__ == 0)     // SMALL
  #define MEM_MODEL_SEG  SI_SEG_IDATA
  #elif (__MODEL__ == 1)   // COMPACT
  #define MEM_MODEL_SEG  SI_SEG_PDATA
  #elif (__MODEL__ == 2)   // LARGE
  #define MEM_MODEL_SEG  SI_SEG_XDATA
  #else
  #error "Illegal memory model setting."
  #endif
  
  #elif defined _CC51
  
  #if (_MODEL == 's')     // SMALL
  #define MEM_MODEL_SEG  SI_SEG_IDATA
  #elif (_MODEL == 'a')   // AUXPAGE
  #define MEM_MODEL_SEG  SI_SEG_PDATA
  #elif (_MODEL == 'l')   // LARGE
  #define MEM_MODEL_SEG  SI_SEG_XDATA
  #elif (_MODEL == 'r')   // REENTRANT
  #define MEM_MODEL_SEG  SI_SEG_XDATA
  #else
  #error "Illegal memory model setting."
  #endif
  
  #elif defined __ICC8051__
  #if (__DATA_MODEL__ == 0)     // TINY
  #define MEM_MODEL_SEG  SI_SEG_IDATA
  #elif (__DATA_MODEL__ == 1)   // SMALL
  #define MEM_MODEL_SEG  SI_SEG_IDATA
  #elif (__DATA_MODEL__ == 2)   // LARGE
  #define MEM_MODEL_SEG  SI_SEG_XDATA
  #elif (__DATA_MODEL__ == 3)   // GENERIC
  #define MEM_MODEL_SEG  SI_SEG_XDATA
  #elif (__DATA_MODEL__ == 4)   // FAR
  #define MEM_MODEL_SEG  SI_SEG_XDATA
  #else
  #error "Illegal memory model setting."
  #endif
  
  #endif
  #endif  // #ifndef MEM_MODEL_SEG
  
  /**  @} (end addtogroup efm8_usb_constants Constants) */
  
  /// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
  void USBD_SetUsbState(USBD_State_TypeDef newState);
  USB_Status_TypeDef USBDCH9_SetupCmd(void);
  /// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN
  
  // -----------------------------------------------------------------------------
  // Library Configuration Definitions
  
  /**************************************************************************//**
   * @addtogroup efm8_usb_config Library Configuration
   * @{
   *
   * @details Library configuration constants read from usbconfig.h.
   *
   *  This library will look for configuration constants in **usbconfig.h**.
   *  This file is provided/written by the user and should be
   *  located in a directory that is part of the include path.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_BUS_POWERED
   * @brief Configures the USB device for bus-powered or self-powered mode.
   * @details
   * When '1' the USB device is bus-powered.
   * When '0' the USB device is self-powered.
   *
   * Default setting is '1' and may be overridden by defining in 'usbconfig.h'.
   *
   * @note The EFM8UB1, EFM8UB3, and EFM8UB4 devices can be configured to ignore
   *       the voltage on the VBUS pin and to instead use that pin as GPIO. If
   *       this feature is used, SLAB_USB_BUS_POWERED should be set to '1' even if
   *       the device is not drawing its power from the VBUS line.
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_FULL_SPEED
   * @brief Configures the USB device for full-speed or low-speed operation.
   * @details
   * When '1' the USB device is full-speed
   * When '0' the USB device is low-speed
   *
   * Default setting is '1' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_CLOCK_RECOVERY_ENABLED
   * @brief Enables/disables the USB Clock Recovery
   * @details USB Clock Recovery uses the incoming USB dat stream to adjust the
   *  internal oscillator. This allows the internal oscillator to meet the
   *  requirements for USB clock tolerance.
   *
   * When '1' the USB clock recovery is enabled
   * When '0' the USB clock recovery is disabled
   *
   * Default setting is '1' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_REMOTE_WAKEUP_ENABLED
   * @brief Enables/disables remote wakeup capability
   * @details Remote wakeup allow the USB device to wake the host from suspend.
   *   When enabled, the library will call @ref USBD_RemoteWakeupCb() to determine
   *   if the remote wakeup source caused the device to wake up. If it did, the
   *   library will exit suspend mode and call @ref USBD_RemoteWakeup() to wake
   *   up the host.
   *
   * When '1' remote wakeup is enabled
   * When '0' remote wakeup is disabled
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_NUM_INTERFACES
   * @brief The number of interfaces available in the configuration
   * @details
   * Default setting is '1' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_SUPPORT_ALT_INTERFACES
   * @brief Enables/disables alternate interface settings
   * @details If any of the interfaces support alternate settings, this should be
   *  set to '1'. Upon receiveing a SET_INTERFACE request, the library will call
   *  @ref USBD_SetInterfaceCb(), which should return @ref USB_STATUS_OK if the
   *  alternate setting is valid or @ref USB_STATUS_REQ_ERR if it is not.
   *
   * When '1' alternate inteface settings are supported
   * When '0' alternate interface settings are not supported, and the library will
   *  respond to any SET_INTERFACE request with a procedural stall
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP1IN_USED
   * @brief Enables/disables Endpoint 1 IN
   * @details
   * When '1' Endpoint 1 IN is enabled
   * When '0' Endpoint 1 IN is disabled
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP1OUT_USED
   * @brief Enables/disables Endpoint 1 OUT
   * @details
   * When '1' Endpoint 1 OUT is enabled
   * When '0' Endpoint 1 OUT is disabled
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP2IN_USED
   * @brief Enables/disables Endpoint 2 IN
   * @details
   * When '1' Endpoint 2 IN is enabled
   * When '0' Endpoint 2 IN is disabled
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP2OUT_USED
   * @brief Enables/disables Endpoint 2 OUT
   * @details
   * When '1' Endpoint 2 OUT is enabled
   * When '0' Endpoint 2 OUT is disabled
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP3IN_USED
   * @brief Enables/disables Endpoint 3 IN
   * @details
   * When '1' Endpoint 3 IN is enabled
   * When '0' Endpoint 3 IN is disabled
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP3OUT_USED
   * @brief Enables/disables Endpoint 3 OUT
   * @details
   * When '1' Endpoint 3 OUT is enabled
   * When '0' Endpoint 3 OUT is disabled
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP1IN_MAX_PACKET_SIZE
   * @brief The maximum packet size that can be received on Endpoint 1 IN
   * @details
   * Default setting is '64' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP1OUT_MAX_PACKET_SIZE
   * @brief The maximum packet size that can be transmitted on Endpoint 1 OUT
   * @details
   * Default setting is '64' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP2IN_MAX_PACKET_SIZE
   * @brief The maximum packet size that can be received on Endpoint 2 IN
   * @details
   * Default setting is '64' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP2OUT_MAX_PACKET_SIZE
   * @brief The maximum packet size that can be transmitted on Endpoint 2 OUT
   * @details
   * Default setting is '64' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP3IN_MAX_PACKET_SIZE
   * @brief The maximum packet size that can be received on Endpoint 3 IN
   * @details
   * Default setting is '64' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP3OUT_MAX_PACKET_SIZE
   * @brief The maximum packet size that can be transmitted on Endpoint 3 OUT
   * @details
   * Default setting is '64' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP1IN_TRANSFER_TYPE
   * @brief Transfer type on Endpoint 1 IN
   * @details
   * May take one of the following values:
   *  USB_EPTYPE_INTR - Interrupt
   *  USB_EPTYPE_BULK - Bulk
   *
   * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in
   * 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP1OUT_TRANSFER_TYPE
   * @brief Transfer type on Endpoint 1 OUT
   * @details
   * May take one of the following values:
   *  USB_EPTYPE_INTR - Interrupt
   *  USB_EPTYPE_BULK - Bulk
   *
   * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in
   * 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP2IN_TRANSFER_TYPE
   * @brief Transfer type on Endpoint 2 IN
   * @details
   * May take one of the following values:
   *  USB_EPTYPE_INTR - Interrupt
   *  USB_EPTYPE_BULK - Bulk
   *
   * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in
   * 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP2OUT_TRANSFER_TYPE
   * @brief Transfer type on Endpoint 2 OUT
   * @details
   * May take one of the following values:
   *  USB_EPTYPE_INTR - Interrupt
   *  USB_EPTYPE_BULK - Bulk
   *
   * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in
   * 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP3IN_TRANSFER_TYPE
   * @brief Transfer type on Endpoint 3 IN
   * @details
   * May take one of the following values:
   *  USB_EPTYPE_INTR - Interrupt
   *  USB_EPTYPE_BULK - Bulk
   *  USB_EPTYPE_ISOC - Isochronous
   *
   * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in
   * 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_EP3OUT_TRANSFER_TYPE
   * @brief Transfer type on Endpoint 3 OUT
   * @details
   * May take one of the following values:
   *  USB_EPTYPE_INTR - Interrupt
   *  USB_EPTYPE_BULK - Bulk
   *  USB_EPTYPE_ISOC - Isochronous
   *
   * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in
   * 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_RESET_CB
   * @brief Enables/disables the USB Reset callback function
   * @details
   * When '1' @ref USBD_ResetCb() is called upon reception of a USB Reset
   * When '0' @ref USBD_ResetCb() is not called upon reception of a USB Reset
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_SOF_CB
   * @brief Enables/disables the USB Start-Of-Frame callback function
   * @details
   * When '1' @ref USBD_SofCb() is called upon reception of a Start-of-Frame
   *  packet
   * When '0' @ref USBD_SofCb() is not called upon reception of a Start-of-Frame
   *  packet
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_STATE_CHANGE_CB
   * @brief Enables/disables the USB State Change callback function
   * @details
   * When '1' @ref USBD_DeviceStateChangeCb() is called when the USB device state
   *  changes
   * When '0' @ref USBD_DeviceStateChangeCb() is not called when the USB device
   *  state changes
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_IS_SELF_POWERED_CB
   * @brief Enables/disables the USB Self-Powered callback function
   * @details
   * When '1' @ref USBD_IsSelfPoweredCb() is called upon reception of a
   *  GET_STATUS (Self-Powered) request
   * When '0' @ref USBD_IsSelfPoweredCb() is not called upon reception of a
   *  GET_STATUS (Self-Powered) request
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_SETUP_CMD_CB
   * @brief Enables/disables the USB Setup Command callback function
   * @details
   * When '1' @ref USBD_SetupCmdCb() is called upon reception of a Setup Request
   * When '0' @ref USBD_SetupCmdCb() is not called upon reception of a Setup
   *  Request
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_HANDLER_CB
   * @brief Enables/disables the USB Handler Entry and Exit callback functions
   * @details
   * When '1' @ref USBD_EnterHandler() will be called before the USB handler
   *  executes and @ref USBD_ExitHandler() will be called after the USB handler
   *  completes
   * When '0' @ref USBD_EnterHandler() and @ref USBD_ExitHandler() will not be
   *  called
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_NUM_LANGUAGES
   * @brief Number of languages supported by the USB string descriptors
   * @details
   * Default setting is '1' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_LANGUAGE
   * @brief
   *  Defines the language of the USB string descriptors when
   *  @ref SLAB_USB_NUM_LANGUAGES is '1'.
   *
   * @details
   * When @ref SLAB_USB_NUM_LANGUAGES is greater than '1', the supported languages
   *  must be defined in a separate table, and a structure of type
   *  @ref USB_StringDescriptor_TypeDef must be defined for each supported
   *  language
   *
   * Default setting is @ref USB_LANGID_ENUS and may be overridden by defining in
   *  'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_UTF8_STRINGS
   * @brief
   *  Enables UTF-8 string decoding for USB string descriptors that are created
   *  using @ref UTF8_PACKED_STATIC_CONST_STRING_DESC.
   *
   * @details
   * If this option is enabled, USB descriptor strings that are created using
   * @ref UTF8_PACKED_STATIC_CONST_STRING_DESC can be encoded as UTF-8 which
   * allows for Unicode characters (up to 16-bits wide) to be used for USB
   * string descriptors.  The UTF-8 strings will be decoded into UCS-2 16-bit
   * wide character format required by USB.  If this feature is not needed then
   * this option can be disabled to save code memory space.  If this option is
   * disabled, then @ref UTF8_PACKED_STATIC_CONST_STRING_DESC should not be used.
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_PWRSAVE_MODE
   * @brief Configures the power-saving options supported by the device
   *
   * @details
   * Default setting is @ref USB_PWRSAVE_MODE_ONSUSPEND and may be overridden by
   *  defining in 'usbconfig.h'.
   *
   *  SLAB_USB_PWRSAVE_MODE configures when the device will automatically enter
   *  the USB power-save mode. It is a bitmask constant with bit values:
   *
   *   @ref USB_PWRSAVE_MODE_OFF       - No energy saving option selected
   *   @ref USB_PWRSAVE_MODE_ONSUSPEND - Enter USB power-save mode on USB suspend
   *   @ref USB_PWRSAVE_MODE_ONVBUSOFF - Enter USB power-save mode when not
   *                                     attached to the USB host.
   *   @ref USB_PWRSAVE_MODE_FASTWAKE  - Exit USB power-save mode more quickly.
   *                                     This is useful for some applications that
   *                                     support remote wakeup.
   *****************************************************************************/
  
  /**************************************************************************//**
   * @def SLAB_USB_POLLED_MODE
   * @brief Enables/disables USB library polled mode
   * @details
   * When '1' the library will run in polled mode
   * When '0' the library will run in interrupt mode
   *
   * Default setting is '0' and may be overridden by defining in 'usbconfig.h'.
   *
   *****************************************************************************/
  
  /**  @} (end addtogroup efm8_usb_config Library Configuration) */
  
  // Set default USB library configurations if the value is not configured in
  // usbconfig.h
  
  #ifndef SLAB_USB_BUS_POWERED
  #define SLAB_USB_BUS_POWERED              1
  #endif
  
  #ifndef SLAB_USB_FULL_SPEED
  #define SLAB_USB_FULL_SPEED               1
  #endif
  
  #ifndef SLAB_USB_CLOCK_RECOVERY_ENABLED
  #define SLAB_USB_CLOCK_RECOVERY_ENABLED   1
  #endif
  
  #ifndef SLAB_USB_REMOTE_WAKEUP_ENABLED
  #define SLAB_USB_REMOTE_WAKEUP_ENABLED    0
  #endif
  
  #ifndef SLAB_USB_NUM_INTERFACES
  #define SLAB_USB_NUM_INTERFACES           1
  #endif
  
  #ifndef SLAB_USB_SUPPORT_ALT_INTERFACES
  #define SLAB_USB_SUPPORT_ALT_INTERFACES   0
  #endif
  
  #ifndef SLAB_USB_EP1IN_USED
  #define SLAB_USB_EP1IN_USED               0
  #endif
  
  #ifndef SLAB_USB_EP1OUT_USED
  #define SLAB_USB_EP1OUT_USED              0
  #endif
  
  #ifndef SLAB_USB_EP2IN_USED
  #define SLAB_USB_EP2IN_USED               0
  #endif
  
  #ifndef SLAB_USB_EP2OUT_USED
  #define SLAB_USB_EP2OUT_USED              0
  #endif
  
  #ifndef SLAB_USB_EP3IN_USED
  #define SLAB_USB_EP3IN_USED               0
  #endif
  
  #ifndef SLAB_USB_EP3OUT_USED
  #define SLAB_USB_EP3OUT_USED              0
  #endif
  
  #ifndef SLAB_USB_EP1IN_MAX_PACKET_SIZE
  #define SLAB_USB_EP1IN_MAX_PACKET_SIZE    64
  #endif
  
  #ifndef SLAB_USB_EP1OUT_MAX_PACKET_SIZE
  #define SLAB_USB_EP1OUT_MAX_PACKET_SIZE   64
  #endif
  
  #ifndef SLAB_USB_EP2IN_MAX_PACKET_SIZE
  #define SLAB_USB_EP2IN_MAX_PACKET_SIZE    64
  #endif
  
  #ifndef SLAB_USB_EP2OUT_MAX_PACKET_SIZE
  #define SLAB_USB_EP2OUT_MAX_PACKET_SIZE   64
  #endif
  
  #ifndef SLAB_USB_EP3IN_MAX_PACKET_SIZE
  #define SLAB_USB_EP3IN_MAX_PACKET_SIZE    64
  #endif
  
  #ifndef SLAB_USB_EP3OUT_MAX_PACKET_SIZE
  #define SLAB_USB_EP3OUT_MAX_PACKET_SIZE   64
  #endif
  
  #ifndef SLAB_USB_EP1IN_TRANSFER_TYPE
  #define SLAB_USB_EP1IN_TRANSFER_TYPE      USB_EPTYPE_INTR
  #endif
  
  #ifndef SLAB_USB_EP1OUT_TRANSFER_TYPE
  #define SLAB_USB_EP1OUT_TRANSFER_TYPE     USB_EPTYPE_INTR
  #endif
  
  #ifndef SLAB_USB_EP2IN_TRANSFER_TYPE
  #define SLAB_USB_EP2IN_TRANSFER_TYPE      USB_EPTYPE_INTR
  #endif
  
  #ifndef SLAB_USB_EP2OUT_TRANSFER_TYPE
  #define SLAB_USB_EP2OUT_TRANSFER_TYPE     USB_EPTYPE_INTR
  #endif
  
  #ifndef SLAB_USB_EP3IN_TRANSFER_TYPE
  #define SLAB_USB_EP3IN_TRANSFER_TYPE      USB_EPTYPE_INTR
  #endif
  
  #ifndef SLAB_USB_EP3OUT_TRANSFER_TYPE
  #define SLAB_USB_EP3OUT_TRANSFER_TYPE     USB_EPTYPE_INTR
  #endif
  
  #ifndef SLAB_USB_RESET_CB
  #define SLAB_USB_RESET_CB                 0
  #endif
  
  #ifndef SLAB_USB_SOF_CB
  #define SLAB_USB_SOF_CB                   0
  #endif
  
  #ifndef SLAB_USB_STATE_CHANGE_CB
  #define SLAB_USB_STATE_CHANGE_CB          0
  #endif
  
  #ifndef SLAB_USB_IS_SELF_POWERED_CB
  #define SLAB_USB_IS_SELF_POWERED_CB       0
  #endif
  
  #ifndef SLAB_USB_SETUP_CMD_CB
  #define SLAB_USB_SETUP_CMD_CB             0
  #endif
  
  #ifndef SLAB_USB_HANDLER_CB
  #define SLAB_USB_HANDLER_CB               0
  #endif
  
  #ifndef SLAB_USB_NUM_LANGUAGES
  #define SLAB_USB_NUM_LANGUAGES            1
  #endif
  
  #ifndef SLAB_USB_LANGUAGE
  #define SLAB_USB_LANGUAGE                 USB_LANGID_ENUS
  #endif
  
  #ifndef SLAB_USB_UTF8_STRINGS
  #define SLAB_USB_UTF8_STRINGS             0
  #endif
  
  #ifndef SLAB_USB_PWRSAVE_MODE
  #define SLAB_USB_PWRSAVE_MODE             USB_PWRSAVE_MODE_ONSUSPEND
  #endif
  
  #ifndef SLAB_USB_POLLED_MODE
  #define SLAB_USB_POLLED_MODE  0
  #endif
  
  #if SLAB_USB_POLLED_MODE
  void usbIrqHandler(void);
  #endif
  
  /***************************************************************************//**
   *  @addtogroup efm8_api API Functions
   *  @{
   ******************************************************************************/
  
  /***************************************************************************//**
   * @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);
  
  /***************************************************************************//**
   * @brief
   *   Abort a pending transfer on a specific endpoint.
   *
   * @param epAddr
   *   The address of the endpoint to abort.
   * @return
   *   @ref USB_STATUS_OK is the transfer aborted, @ref USB_STATUS_ILLEGAL
   *   otherwise
   ******************************************************************************/
  int8_t USBD_AbortTransfer(uint8_t epAddr);
  
  /***************************************************************************//**
   * @brief
   *   Start USB device operation.
   *
   * @details
   *   Device operation is started by connecting a pull-up resistor on the
   *   appropriate USB data line.
   ******************************************************************************/
  void USBD_Connect(void);
  
  /***************************************************************************//**
   * @brief
   *   Stop USB device operation.
   *
   * @details
   *   Device operation is stopped by disconnecting the pull-up resistor from the
   *   appropriate USB data line. Often referred to as a "soft" disconnect.
   ******************************************************************************/
  void USBD_Disconnect(void);
  
  /***************************************************************************//**
   * @brief
   *   Check if an endpoint is busy doing a transfer.
   *
   * @param epAddr
   *   The address of the endpoint to check.
   *
   * @return
   *   True if endpoint is busy, false otherwise.
   ******************************************************************************/
  bool USBD_EpIsBusy(uint8_t epAddr);
  
  /***************************************************************************//**
   * @brief
   *   Get current USB device state.
   *
   * @return
   *   Device USB state. See @ref USBD_State_TypeDef.
   ******************************************************************************/
  USBD_State_TypeDef USBD_GetUsbState(void);
  
  /***************************************************************************//**
   * @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 p
   *   Pointer to device initialization struct. See @ref USBD_Init_TypeDef.
   *
   * @return
   *   @ref USB_STATUS_OK on success, else an appropriate error code.
   ******************************************************************************/
  int8_t USBD_Init(SI_VARIABLE_SEGMENT_POINTER(p, const USBD_Init_TypeDef, SI_SEG_GENERIC));
  
  /***************************************************************************//**
   * @brief
   *   Start a read (OUT) transfer on an endpoint.
   *
   * @note
   *   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 epAddr
   *   Endpoint address.
   *
   * @param dat
   *   Pointer to transfer data buffer.
   *
   * @param byteCount
   *   Transfer length.
   *
   * @param callback
   *   Boolean to determine if USB_XferCompleteCb should be called for this
   *   transfer.
   *
   * @return
   *   @ref USB_STATUS_OK on success, else an appropriate error code.
   ******************************************************************************/
  int8_t USBD_Read(uint8_t epAddr, 
                   SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC),
                   uint16_t byteCount,
                   bool callback);
  
  /***************************************************************************//**
   * @brief
   *   Perform a remote wakeup signaling sequence.
   *
   * @note
   *   This function is typically called by the library if @ref
   *   USBD_RemoteWakeupCb() returns true, so it does not need to be called by
   *   application code.
   *
   * @return
   *   @ref USB_STATUS_OK on success, else an appropriate error code.
   ******************************************************************************/
  int8_t USBD_RemoteWakeup(void);
  
  /***************************************************************************//**
   * @brief
   *  Processes USB events when the library is configured for polled mode
   *
   * @details
   *  The USB library can be configured for interrupt (SLAB_USB_POLLED_MODE == 0)
   *  or polled (SLAB_USB_POLLED_MODE == 1) mode.
   *
   *  When in interrupt mode, the USB interrupt handler will trigger
   *  when a USB event occurs. Callback functions will be called as needed.
   *
   *  When in polled mode, the application must call USBD_Run() periodically to
   *  check for and process USB events. This may be useful in complex systems or
   *  when using an RTOS to perform all USB processing in the main loop instead
   *  of in the interrupt context.
   *
   ******************************************************************************/
  void USBD_Run(void);
  
  /***************************************************************************//**
   * @brief
   *   Set an endpoint in the stalled (halted) state.
   *
   * @param epAddr
   *   The address of the endpoint to stall.
   *
   * @return
   *   @ref USB_STATUS_OK on success, else an appropriate error code.
   ******************************************************************************/
  int8_t USBD_StallEp(uint8_t epAddr);
  
  /***************************************************************************//**
   * @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);
  
  /***************************************************************************//**
   * @brief
   *   Enters USB suspend mode
   *
   * @details
   *   Disables USB transceiver, VDD Monitor, and prefetch engine. Suspends the
   *   internal regulator and internal oscillator.
   *   This function will not exit until the device recognizes resume signaling,
   *   VBUS attachment/removal, or a remote wakeup source interrupt.
   *   Before exiting, restores the states of the USB transceiver,
   *   VDD Monitor, prefetch engine, and internal regulator.
   ******************************************************************************/
  void USBD_Suspend(void);
  
  /***************************************************************************//**
   * @brief
   *   Reset stall state on a stalled (halted) endpoint.
   *
   * @param epAddr
   *   The address of the endpoint to un-stall.
   *
   * @return
   *   @ref USB_STATUS_OK on success, else an appropriate error code.
   ******************************************************************************/
  int8_t USBD_UnStallEp(uint8_t epAddr);
  
  /***************************************************************************//**
   * @brief
   *   Start a write (IN) transfer on an endpoint.
   *
   * @param epAddr
   *   Endpoint address.
   *
   * @param dat
   *   Pointer to transfer data buffer. This buffer must be WORD (4 byte) aligned.
   *
   * @param byteCount
   *   Transfer length.
   *
   * @param callback
   *   Boolean to determine if USB_XferCompleteCb should be called for this
   *   transfer.
   *
   * @return
   *   @ref USB_STATUS_OK on success, else an appropriate error code.
   ******************************************************************************/
  int8_t USBD_Write(uint8_t epAddr,
                    SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC),
                    uint16_t byteCount,
                    bool callback);
  
  /**  @} (end addtogroup efm8_api API Functions) */
  
  /***************************************************************************//**
   *  @addtogroup efm8_callbacks Callback Functions
   *  @{
   ******************************************************************************/
  
  /***************************************************************************//**
   * @brief
   *  USB Handler Entry callback function.
   * @details
   *  Some systems may wish to be in a low-power state when between USB events.
   *  This low-power state may configure the system clock to a very low
   *  frequency. In order to reduce the execution time of the USB handler, this
   *  function is called before the handler executes to allow the system to switch
   *  to a higher clock source. When all USB processing is complete,
   *  @ref USBD_ExitHandler() will be called to allow the system to return
   *  to the low-power state.
   *  This callback function is optionally enabled by setting
   *  @ref SLAB_USB_HANDLER_CB to 1.
   ******************************************************************************/
  void USBD_EnterHandler(void);
  
  /***************************************************************************//**
   * @brief
   *  USB Handler Exit callback function.
   * @details
   *  Some systems may wish to be in a low-power state when between USB events.
   *  This low-power state may configure the system clock to a very low
   *  frequency. This function is called after all USB processing is finished
   *  to allow  a system that was previously configured by
   *  @ref USBD_EnterHandler() for high power to return to a low power state.
   *  This callback function is optionally enabled by setting
   *  @ref SLAB_USB_HANDLER_CB to 1.
   ******************************************************************************/
  void USBD_ExitHandler(void);
  
  /***************************************************************************//**
   * @brief
   *  USB Reset callback function.
   * @details
   *  Called whenever USB reset signaling is detected on the USB port.
   ******************************************************************************/
  void USBD_ResetCb(void);
  
  /***************************************************************************//**
   * @brief
   *  USB Start Of Frame (SOF) interrupt callback function.
   *
   * @details
   *  Called at each SOF interrupt (if enabled),
   *
   * @param sofNr
   *   Current frame number. The value rolls over to 0 after 16383 (0x3FFF).
   ******************************************************************************/
  void USBD_SofCb(uint16_t sofNr);
  
  /***************************************************************************//**
   * @brief
   *  USB State change callback function.
   *
   * @details
   *  Called whenever the USB state of the device changes
   *
   * @param oldState
   *   The device USB state just left. See @ref USBD_State_TypeDef.
   *
   * @param newState
   *   New (the current) USB device state. See @ref USBD_State_TypeDef.
   ******************************************************************************/
  void USBD_DeviceStateChangeCb(USBD_State_TypeDef oldState,
                                USBD_State_TypeDef newState);
  
  /***************************************************************************//**
   * @brief
   *  USB power mode callback function.
   *
   * @details
   *  Called whenever the device stack needs to know if the device is currently
   *  self- or bus-powered. Typically when host has issued a @ref GET_STATUS
   *  setup command.
   *
   * @return
   *  True if self-powered, false otherwise.
   ******************************************************************************/
  bool USBD_IsSelfPoweredCb(void);
  
  /***************************************************************************//**
   * @brief
   *  USB setup request callback function.
   *
   * @details
   *  Called on each setup request received from host. This gives the system a
   *  possibility to extend or override standard requests, and to implement class
   *  or vendor specific requests. Return @ref USB_STATUS_OK if the request is
   *  handled, return @ref USB_STATUS_REQ_ERR if it is an illegal request or
   *  return @ref USB_STATUS_REQ_UNHANDLED to pass the request on to the default
   *  request handler.
   *
   * @param setup
   *  Pointer to a USB setup packet. See @ref USB_Setup_TypeDef.
   *
   * @return
   *  An appropriate status/error code. See @ref USB_Status_TypeDef.
   ******************************************************************************/
  USB_Status_TypeDef USBD_SetupCmdCb(SI_VARIABLE_SEGMENT_POINTER(setup,
                                                                 USB_Setup_TypeDef,
                                                                 MEM_MODEL_SEG));
  
  /***************************************************************************//**
   * @brief
   *  USB set interface callback function.
   *
   * @details
   *  Called each time the SET_INTERFACE request is made.
   *
   * @param interface
   *  Number of the interface to set.
   *
   * @param altSetting
   *  Alternate setting for the interface
   *
   * @return
   *  @ref USB_STATUS_OK if the alternate interface is valid and can be set,
   *  @ref USB_STATUS_REQ_ERR otherwise
   ******************************************************************************/
  USB_Status_TypeDef USBD_SetInterfaceCb(uint8_t interface, uint8_t altSetting);
  
  /***************************************************************************//**
   * @brief
   *  Queries the application to see if a remote wakeup occurred.
   * @details
   *  If remote wakeup is enabled via @ref SLAB_USB_REMOTE_WAKEUP_ENABLED, the
   *  USB library will query the application after waking from suspend to see if
   *  the remote wakeup source was the reason for the wakeup. If this function
   *  returns True, the library will call @ref USBD_RemoteWakeup() to wake up the
   *  host and exit suspend mode.
   * @return
   *  True if the remote wakeup source was the reason the device woke from
   *  suspend, false otherwise.
   *
   ******************************************************************************/
  bool USBD_RemoteWakeupCb(void);
  
  /***************************************************************************//**
   * @brief
   *  Delays 10 - 15 ms while resume signaling is active during a remote
   *  wakeup event
   *
   ******************************************************************************/
  void USBD_RemoteWakeupDelay(void);
  
  /***************************************************************************//**
   * @brief
   *  Processes USB events when the library is configured for polled mode
   *
   * @ details
   *  The USB library can be configured for interrupt
   *  (@ref SLAB_USB_POLLED_MODE == 0) or polled (@ref SLAB_USB_POLLED_MODE == 1)
   *  mode.
   *
   *  When in interrupt mode, the USB interrupt handler will trigger
   *  when a USB event occurs. Callback functions will be called as needed.
   *
   *  When in polled mode, the application must call USBD_Run() periodically to
   *  check for and process USB events. This may be useful in complex systems or
   *  when using an RTOS to perform all USB processing in the main loop instead
   *  of in the interrupt context.
   *
   ******************************************************************************/
  void USBD_Run(void);
  
  /***************************************************************************//**
   * @brief
   *  USB transfer complete callback function.
   *
   * @details
   *  Called each time a packet is sent on an IN endpoint or received on an
   *  OUT endpoint.
   *
   * @param epAddr
   *  Endpoint on which the transfer occurred
   *
   *  @param status
   *    Status of the endpoint
   *
   *  @param xferred
   *    For bulk, interrupt, and control transfers:
   *      Number of bytes transferred since the last USBD_Write() or USBD_Read()
   *      call.
   *    For isochronous IN transfers:
   *      This parameter is not used
   *    For isochronous OUT transfers:
   *      the number of bytes received in the last packet
   *
   *  @param remaining
   *    For bulk, interrupt, and control transfers:
   *      Number of bytes left to send or receive on the endpoint
   *    For isochronous transfers:
   *      The current index into the circular buffer holding isochronous data
   *
   * @return
   *    For bulk, interrupt, and control transfers:
   *      '0'
   *    For isochronous IN transfers:
   *      the number of bytes to transmit in the next packet
   *    For isochronous OUT ransfers:
   *      '0'
   ******************************************************************************/
  uint16_t USBD_XferCompleteCb(uint8_t epAddr, \
                               USB_Status_TypeDef status, \
                               uint16_t xferred, \
                               uint16_t remaining);
  
  /**  @} (end addtogroup efm8_callbacks Callback Functions) */
  
  /// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
  // -------------------- FIFO Access Functions  ---------------------------------
  void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC));
  void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), bool txPacket);
  /// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN
  
  // -------------------- Include Files ------------------------------------------
  
   // Error if peripheral driver not in use
   #include "usb_0.h"
  
  /** @} (end addtogroup Efm8_usb) */
  
  #endif // __SILICON_LABS_EFM8_USB_H__
  