text: /*
   * The Clear BSD License
   * Copyright (c) 2016, Freescale Semiconductor, Inc.
   * Copyright 2016 - 2017 NXP
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modification,
   * are permitted (subject to the limitations in the disclaimer below) provided
   * that the following conditions are met:
   *
   * o Redistributions of source code must retain the above copyright notice, this list
   *   of conditions and the following disclaimer.
   *
   * o Redistributions in binary form must reproduce the above copyright notice, this
   *   list of conditions and the following disclaimer in the documentation and/or
   *   other materials provided with the distribution.
   *
   * o Neither the name of the copyright holder nor the names of its
   *   contributors may be used to endorse or promote products derived from this
   *   software without specific prior written permission.
   *
   * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include "usb_device_config.h"
  #include "usb.h"
  #include "usb_device.h"
  #include "fsl_device_registers.h"
  
  #if (((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) || \
       ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)))
  #include "usb_device_dci.h"
  #include "usb_device_lpcip3511.h"
  
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
  
  #define USB_LPC3511IP_INTSTAT_DEV_INT_MASK USBHSD_INTSTAT_DEV_INT_MASK
  #define USB_LPC3511IP_INTSTAT_FRAME_INT_MASK USBHSD_INTSTAT_FRAME_INT_MASK
  
  #define USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK USBHSD_DEVCMDSTAT_INTONNAK_AO_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK USBHSD_DEVCMDSTAT_INTONNAK_AI_MASK
  
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_MASK USBHSD_DEVCMDSTAT_LPM_REWP_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_SHIFT USBHSD_DEVCMDSTAT_LPM_REWP_SHIFT
  
  #define USB_LPC3511IP_DEVCMDSTAT_Speed_MASK  USBHSD_DEVCMDSTAT_Speed_MASK
  
  
  #define USB_LPC3511IP_DEVCMDSTAT_DCON_MASK USBHSD_DEVCMDSTAT_DCON_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK USBHSD_DEVCMDSTAT_DEV_EN_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK USBHSD_DEVCMDSTAT_LPM_SUP_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK USBHSD_DEVCMDSTAT_FORCE_NEEDCLK_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK USBHSD_DEVCMDSTAT_LPM_SUS_MASK
  
  #define USB_LPC3511IP_USB_LPM_HIRD_SW USBHSD_LPM_HIRD_SW
  
  #define USB_LPC3511IP_DEVCMDSTAT_DEV_ADDR_MASK  USBHSD_DEVCMDSTAT_DEV_ADDR_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK  USBHSD_DEVCMDSTAT_DSUS_MASK
  #define USB_LPC3511IP_INFO_ERR_CODE_MASK USBHSD_INFO_ERR_CODE_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK USBHSD_DEVCMDSTAT_SETUP_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DRES_C_MASK USBHSD_DEVCMDSTAT_DRES_C_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DSUS_C_MASK USBHSD_DEVCMDSTAT_DSUS_C_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DCON_C_MASK USBHSD_DEVCMDSTAT_DCON_C_MASK
  #else
  #define USB_LPC3511IP_INTSTAT_DEV_INT_MASK USB_INTSTAT_DEV_INT_MASK
  #define USB_LPC3511IP_INTSTAT_FRAME_INT_MASK USB_INTSTAT_FRAME_INT_MASK
  
  #define USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK USB_DEVCMDSTAT_INTONNAK_AO_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK USB_DEVCMDSTAT_INTONNAK_AI_MASK
  
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_MASK USB_DEVCMDSTAT_LPM_REWP_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_SHIFT USB_DEVCMDSTAT_LPM_REWP_SHIFT
  
  
  #define USB_LPC3511IP_DEVCMDSTAT_DCON_MASK USB_DEVCMDSTAT_DCON_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK USB_DEVCMDSTAT_DEV_EN_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK USB_DEVCMDSTAT_LPM_SUP_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK USB_DEVCMDSTAT_FORCE_NEEDCLK_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK USB_DEVCMDSTAT_LPM_SUP_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK USB_DEVCMDSTAT_LPM_SUS_MASK
  
  #define USB_LPC3511IP_USB_LPM_HIRD_SW            USB_LPM_HIRD_SW
  
  #define USB_LPC3511IP_DEVCMDSTAT_DEV_ADDR_MASK  USB_DEVCMDSTAT_DEV_ADDR_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK  USB_DEVCMDSTAT_DSUS_MASK
  #define USB_LPC3511IP_INFO_ERR_CODE_MASK USB_INFO_ERR_CODE_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK USB_DEVCMDSTAT_SETUP_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DRES_C_MASK USB_DEVCMDSTAT_DRES_C_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DSUS_C_MASK USB_DEVCMDSTAT_DSUS_C_MASK
  #define USB_LPC3511IP_DEVCMDSTAT_DCON_C_MASK USB_DEVCMDSTAT_DCON_C_MASK
  
  #endif
  
  /*******************************************************************************
   * Definitions
   ******************************************************************************/
  
  /* on Aruba IP3511 (USB0 FS), there are 8 physical EPs, on IP3511 HS (USB1 FS), there are 10 physical EPs. */
  #define USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK (0xFFFFu)
  
  /*! @brief endpoint command status, buffer address offset */
  #define USB_LPC3511IPHS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK (0x000007FFu)
  #define USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_SHIFT (11)
  #define USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_MASK (0x03FFF800u)
  #define USB_LPC3511IPFS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK (0x0000FFFFu)
  #define USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_SHIFT (16)
  #define USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_MASK (0x03FF0000u)
  
  #define USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK (0x01U << 26)
  #define USB_LPC3511IP_ENDPOINT_RFTV_MASK (0x01U << 27)
  #define USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK (0x01U << 28)
  #define USB_LPC3511IP_ENDPOINT_STALL_MASK (0x01U << 29)
  #define USB_LPC3511IP_ENDPOINT_STALL_SHIFT (29)
  #define USB_LPC3511IP_ENDPOINT_DISABLE_MASK (0x01U << 30)
  #define USB_LPC3511IP_ENDPOINT_ACTIVE_MASK (0x01U << 31)
  #define USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT (26)
  
  #define USB_LPC3511IP_DEVCMDSTAT_INTERRUPT_WC_MASK (0x0F000000u)
  
  #define USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(lpcState, index, odd, value)                         \
      *((volatile uint32_t *)(((uint32_t)(lpcState->epCommandStatusList)) | ((uint32_t)(index) << 3) | \
                              (((uint32_t)(odd)&1U) << 2U))) &= (value)
  
  /*! @brief Set endpoint command/status value */
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
  #define USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpcState, index, odd, value, NBytes, address)                \
                                                                                                           \
      *((volatile uint32_t *)(((uint32_t)(lpcState->epCommandStatusList)) | ((uint32_t)(index) << 3) |     \
                              (((uint32_t)(odd & 1U)) << 2U))) =                                           \
          ((lpc3511IpState->controllerSpeed) ?                                                             \
                                                                                                           \
               ((uint32_t)(value) | ((uint32_t)(NBytes) << USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_SHIFT) | \
                (((uint32_t)(address) >> 6) & USB_LPC3511IPHS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK)) :      \
                                                                                                           \
               ((uint32_t)(value) | ((uint32_t)(NBytes) << USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_SHIFT) | \
                (((uint32_t)(address) >> 6) & USB_LPC3511IPFS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK)))
  #else
  #define USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpcState, index, odd, value, NBytes, address)            \
                                                                                                       \
      *((volatile uint32_t *)(((uint32_t)(lpcState->epCommandStatusList)) | ((uint32_t)(index) << 3) | \
                              (((uint32_t)(odd & 1U)) << 2U))) =                                       \
          ((uint32_t)(value) | ((uint32_t)(NBytes) << USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_SHIFT) |  \
           (((uint32_t)(address) >> 6) & USB_LPC3511IPFS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK))
  #endif
  
  #define USB_LPC3511IP_ENDPOINT_DES_INDEX(endpoint) \
      (((((uint32_t)endpoint) & 0x0F) << 1) +        \
       ((((uint32_t)endpoint) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ? (1) : (0)))
  
  #define USB_LPC3511IP_GET_MULTIPLE_OF_64(n) ((n + 63U) & 0xFFFFFFC0U)
  
  /*******************************************************************************
   * Prototypes
   ******************************************************************************/
  
  extern usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg);
  static usb_status_t USB_DeviceLpc3511IpTransaction(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                     usb_device_lpc3511ip_endpoint_state_struct_t *epState,
                                                     uint8_t endpointIndex);
  
  /*******************************************************************************
   * Variables
   ******************************************************************************/
  
  /* define the reserved buffer for endpoint max packet copy */
  #if defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)
  USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint32_t
      s_EpReservedBuffer[USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY][USB_DATA_ALIGN_SIZE_MULTIPLE(
          (USB_DEVICE_IP3511_ENDPOINT_RESERVED_BUFFER_SIZE >> 2))];
  #endif
  USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t
      s_ControlTransferData[USB_DEVICE_CONFIG_LPCIP3511FS +
                            USB_DEVICE_CONFIG_LPCIP3511HS][USB_DATA_ALIGN_SIZE_MULTIPLE(64U)];
  USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t
      s_SetupData[USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS][USB_DATA_ALIGN_SIZE_MULTIPLE(8U)];
  USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t
      s_ZeroTransactionData[USB_DEVICE_CONFIG_LPCIP3511FS +
                            USB_DEVICE_CONFIG_LPCIP3511HS][USB_DATA_ALIGN_SIZE_MULTIPLE(4)];
  static usb_device_lpc3511ip_state_struct_t
      s_UsbDeviceLpc3511IpState[USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS];
  
  /* LPC3511IP controller driver instances and endpoint command/status list, EPLISTSTART's value is the buffer pointer. */
  #if ((USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS) == 1U)
  USB_CONTROLLER_DATA USB_RAM_ADDRESS_ALIGNMENT(256) static uint32_t
      s_EpCommandStatusList1[((USB_DEVICE_IP3511_ENDPOINTS_NUM)) * 4];
  #define LPC_CONTROLLER_ENDPOINT_LIST_ARRAY \
      {                                      \
          &s_EpCommandStatusList1[0]         \
      }
  
  #elif((USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS) == 2U)
  USB_CONTROLLER_DATA USB_RAM_ADDRESS_ALIGNMENT(256) static uint32_t
      s_EpCommandStatusList1[((USB_DEVICE_IP3511_ENDPOINTS_NUM ) * 4];
  USB_CONTROLLER_DATA USB_RAM_ADDRESS_ALIGNMENT(256) static uint32_t
      s_EpCommandStatusList2[((USB_DEVICE_IP3511_ENDPOINTS_NUM ) * 4];
  #define LPC_CONTROLLER_ENDPOINT_LIST_ARRAY                     \
      {                                                          \
          &s_EpCommandStatusList1[0], &s_EpCommandStatusList2[0] \
      }
  
  #else
  #error "increase the instance count."
  #endif
  
  #if (defined USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)
  #if (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == (USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS))
  #define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 1u
  #elif((USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == USB_DEVICE_CONFIG_LPCIP3511FS) && (!USB_DEVICE_CONFIG_LPCIP3511HS))
  #define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 1u
  #elif((USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == USB_DEVICE_CONFIG_LPCIP3511HS) && (!USB_DEVICE_CONFIG_LPCIP3511FS))
  #define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 1u
  #else
  #define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 0u
  #endif
  
  #else
  #define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 0u
  
  #endif
  
  /*******************************************************************************
   * Code
   ******************************************************************************/
  #if (defined USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)
  
  static inline uint8_t USB_DeviceLpcIp3511MaxPacketNeedCopy(usb_device_lpc3511ip_state_struct_t *lpc3511IpState)
  {
  #if (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == (USB_DEVICE_CONFIG_LPCIP3511HS + USB_DEVICE_CONFIG_LPCIP3511FS))
      return 1u;
  #elif(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == USB_DEVICE_CONFIG_LPCIP3511HS)
      return (lpc3511IpState->controllerSpeed);
  #elif(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == USB_DEVICE_CONFIG_LPCIP3511FS)
  #if (defined USB_DEVICE_CONFIG_LPCIP3511HS) && (USB_DEVICE_CONFIG_LPCIP3511HS)
      if (lpc3511IpState->controllerSpeed)
      {
          return 0u;
      }
      else
      {
          return 1u;
      }
  #else
      return 1u;
  #endif
  #endif
  }
  
  static uint8_t *USB_DeviceLpcIp3511MallocMaxPacketBuffer(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                           uint32_t multile64)
  {
      uint32_t bitsIndex;
      uint8_t numIndex;
      USB_OSA_SR_ALLOC();
  
      multile64 = ((multile64 + 63) / 64);
      bitsIndex = 0;
      USB_OSA_ENTER_CRITICAL();
      do
      {
          numIndex = 0;
          for (; numIndex < multile64; ++numIndex)
          {
              if (bitsIndex >= USB_DEVICE_IP3511_BITS_FOR_RESERVED_BUFFER)
              {
                  USB_OSA_EXIT_CRITICAL();
                  return NULL; /* fail */
              }
              if (lpc3511IpState->epReservedBufferBits[(bitsIndex / 8)] &
                  (uint8_t)(0x01u << (bitsIndex & 0x00000007u))) /* has allocated */
              {
                  bitsIndex++;
                  break;
              }
              bitsIndex++;
          }
      } while (numIndex < multile64);
  
      if (numIndex >= multile64)
      {
          /* set the bits */
          for (numIndex = 0; numIndex < multile64; ++numIndex)
          {
              lpc3511IpState->epReservedBufferBits[((bitsIndex - multile64 + numIndex) / 8)] |=
                  (uint8_t)(0x01u << ((bitsIndex - multile64 + numIndex) & 0x00000007u));
          }
          USB_OSA_EXIT_CRITICAL();
          return lpc3511IpState->epReservedBuffer + ((bitsIndex - multile64) * 64);
      }
      else
      {
          USB_OSA_EXIT_CRITICAL();
          return NULL;
      }
  }
  
  static void USB_DeviceLpcIp3511ReleaseMaxPacketBuffer(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                        uint8_t *buffer,
                                                        uint32_t bufferSize)
  {
      uint32_t bitsIndex;
      uint8_t bitsNum;
      USB_OSA_SR_ALLOC();
  
      if ((buffer < lpc3511IpState->epReservedBuffer) ||
          (buffer >= (lpc3511IpState->epReservedBuffer + USB_DEVICE_IP3511_ENDPOINT_RESERVED_BUFFER_SIZE)))
      {
          return;
      }
      bitsIndex = (buffer - lpc3511IpState->epReservedBuffer) / 64;
  
      USB_OSA_ENTER_CRITICAL();
      for (bitsNum = 0; bitsNum < ((bufferSize + 63) / 64); ++bitsNum)
      {
          lpc3511IpState->epReservedBufferBits[((bitsIndex + bitsNum) / 8)] &=
              (uint8_t)(~(0x01u << ((bitsIndex + bitsNum) & 0x00000007u))); /* clear the bit */
      }
      USB_OSA_EXIT_CRITICAL();
  }
  #endif
  
  static usb_device_lpc3511ip_endpoint_state_struct_t *USB_DeviceLpc3511IpGetEndpointStateStruct(
      usb_device_lpc3511ip_state_struct_t *lpc3511IpState, uint8_t endpointIndex)
  {
      if (endpointIndex <= (USB_DEVICE_IP3511_ENDPOINTS_NUM * 2))
      {
          return &(lpc3511IpState->endpointState[endpointIndex]);
      }
  
      return NULL;
  }
  
  /*!
   * @brief Write the command/status entry to start a transfer.
   *
   * The function is used to start a transfer by writing the command/status entry.
   *
   * @param lpc3511IpState      Pointer of the controller state structure.
   * @param endpoint         Endpoint number.
   * @param direction        The direction of the endpoint, 0U - USB_OUT, 1U - USB_IN.
   * @param buffer           The memory address to save the received data, or the memory address to hold the data need to
   * be sent.
   * @param length           The length of the data.
   *
   * @return A USB error code or kStatus_USB_Success.
   */
  static usb_status_t USB_DeviceLpc3511IpEndpointPrime(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                       usb_device_lpc3511ip_endpoint_state_struct_t *epState,
                                                       uint8_t endpointIndex,
                                                       uint8_t *buffer,
                                                       uint32_t length)
  {
      uint8_t odd;
  
      USB_OSA_SR_ALLOC();
  
      /* Enter critical */
      USB_OSA_ENTER_CRITICAL();
  
      /* Flag the endpoint is busy. */
      epState->stateUnion.stateBitField.transferring = 1U;
  
      /* update the endpoint status */
      epState->transferPrimedLength += length;
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
      if ((endpointIndex >> 1U) != USB_ENDPOINT_CONTROL)
      {
          odd = epState->stateUnion.stateBitField.producerOdd;
          epState->stateUnion.stateBitField.doubleBufferBusy++;
          epState->stateUnion.stateBitField.producerOdd ^= 1;
      }
      else
  #endif
      {
          odd = 0U;
      }
      epState->epBufferStatusUnion[odd].epBufferStatusField.transactionLength = length;
  
      /* when receive the zero length packet, the controller will set 4 bytes buffer as 0x00 */
      if (buffer == NULL)
      {
          buffer = lpc3511IpState->zeroTransactionData;
      }
  
      USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(
          lpc3511IpState, endpointIndex, odd,
          (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT) |
              USB_LPC3511IP_ENDPOINT_ACTIVE_MASK,
          length, (uint32_t)buffer);
      if (epState->stateUnion.stateBitField.epControlDefault &
          ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT))
      {
          epState->stateUnion.stateBitField.epControlDefault &=
              (~((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT));
      }
      /* Exit critical */
      USB_OSA_EXIT_CRITICAL();
      return kStatus_USB_Success;
  }
  
  #if 0
  /*!
   * @brief Prime a next setup transfer.
   *
   * The function is used to prime a buffer in control out pipe to wait for receiving the host's setup packet.
   *
   * @param lpc3511IpState       Pointer of the controller state structure.
   *
   */
  static void USB_DeviceLpc3511IpPrimeNextSetup(usb_device_lpc3511ip_state_struct_t *lpc3511IpState)
  {
      USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, 0, 1, 0, 8, lpc3511IpState->setupData);
  }
  #endif
  
  /*!
   * @brief reset ip3511.
   *
   * @param lpc3511IpState       Pointer of the controller state structure.
   *
   */
  static void USB_DeviceLpc3511IpSetDefaultState(usb_device_lpc3511ip_state_struct_t *lpc3511IpState)
  {
      uint32_t index = 0;
      uint8_t usbAddress;
  
      /* zero the command/status list buffer and disable all endpoints */
      for (index = 0; index < 4; ++index)
      {
          lpc3511IpState->epCommandStatusList[index] = 0x00000000U;
      }
      for (index = 4; index < USB_DEVICE_IP3511_ENDPOINTS_NUM * 4; ++index)
      {
          lpc3511IpState->epCommandStatusList[index] = USB_LPC3511IP_ENDPOINT_DISABLE_MASK;
      }
  
      /* set address as 0 */
      usbAddress = 0U;
      USB_DeviceLpc3511IpControl(lpc3511IpState, kUSB_DeviceControlSetDeviceAddress, &usbAddress);
  
      lpc3511IpState->registerBase->EPLISTSTART = (uint32_t)lpc3511IpState->epCommandStatusList;
      /* all data buffer is in the same 4M range with this setup data buffer */
      lpc3511IpState->registerBase->DATABUFSTART = (uint32_t)lpc3511IpState->setupData;
      /* reset registers */
      lpc3511IpState->registerBase->EPINUSE = 0x0;
      lpc3511IpState->registerBase->EPSKIP = 0x0;
  /* enable all double-buffer */
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
      lpc3511IpState->registerBase->EPBUFCFG = USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK;
  #else
      lpc3511IpState->registerBase->EPBUFCFG = 0x00000000u;
  #endif
      /* clear interrupts */
      lpc3511IpState->registerBase->INTSTAT =
          (USB_LPC3511IP_INTSTAT_DEV_INT_MASK | USB_LPC3511IP_INTSTAT_FRAME_INT_MASK | USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK);
      /* enable interrupts */
      lpc3511IpState->registerBase->INTEN = USB_LPC3511IP_INTSTAT_DEV_INT_MASK | USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK;
  
      /* Clear reset flag */
      lpc3511IpState->isResetting = 0U;
  }
  
  /* Config and Enable endpoint */
  static usb_status_t USB_DeviceLpc3511IpEndpointInit(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                      usb_device_endpoint_init_struct_t *epInit)
  {
      uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(epInit->endpointAddress);
      usb_device_lpc3511ip_endpoint_state_struct_t *epState =
          USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex);
      uint16_t maxPacketSize = epInit->maxPacketSize;
  
      /* clear the endpoint status bits */
      epState->stateUnion.state = 0x00000000u;
      lpc3511IpState->registerBase->EPINUSE &= (~(0x01u << endpointIndex));
      /* Save the max packet size of the endpoint */
      epState->stateUnion.stateBitField.maxPacketSize = maxPacketSize;
      /* Set the ZLT field */
      epState->stateUnion.stateBitField.zlt = epInit->zlt;
      epState->stateUnion.stateBitField.endpointType = epInit->transferType;
  
      /* get the endpoint default control value */
      if (USB_ENDPOINT_ISOCHRONOUS == epInit->transferType)
      {
          epState->stateUnion.stateBitField.epControlDefault =
              (USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT);
      }
      else
      {
          epState->stateUnion.stateBitField.epControlDefault = 0x00U;
      }
      /* set the command/status value */
      USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(
          lpc3511IpState, endpointIndex, 0,
          (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT), 0, 0);
      if ((epInit->endpointAddress & USB_ENDPOINT_NUMBER_MASK) == USB_CONTROL_ENDPOINT)
      {
          if (!(epInit->endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK))
          {
              /* Prime setup packet when the endpoint is control out endpoint. */
              USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, 0, 1, 0, 0, (uint32_t)lpc3511IpState->setupData);
          }
      }
      else
      {
          USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(
              lpc3511IpState, endpointIndex, 1,
              (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT), 0, 0);
      }
      if ((endpointIndex >> 1) != USB_CONTROL_ENDPOINT)
      {
          /* toggle reset for the toggle */
          epState->stateUnion.stateBitField.epControlDefault |=
              ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT);
      }
  
      epState->epPacketBuffer = NULL;
      if ((endpointIndex >> 1U) == USB_CONTROL_ENDPOINT) /* control endpoint */
      {
          epState->epPacketBuffer = lpc3511IpState->controlData;
      }
  #if (defined USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)
      else
      {
          if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState))
          {
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
              uint8_t *maxPacketBuffer = USB_DeviceLpcIp3511MallocMaxPacketBuffer(
                  lpc3511IpState, USB_LPC3511IP_GET_MULTIPLE_OF_64(maxPacketSize) * 2);
  #else
              uint8_t *maxPacketBuffer = USB_DeviceLpcIp3511MallocMaxPacketBuffer(lpc3511IpState, maxPacketSize);
  #endif
              if (maxPacketBuffer == NULL)
              {
                  return kStatus_USB_AllocFail;
              }
              epState->epPacketBuffer = maxPacketBuffer;
          }
      }
  #endif
  
      return kStatus_USB_Success;
  }
  
  /*!
   * @brief De-initialize a specified endpoint.
   *
   * The function is used to de-initialize a specified endpoint.
   * Current transfer of the endpoint will be canceled and the specified endpoint will be disabled.
   *
   * @param lpc3511IpState      Pointer of the controller state structure.
   * @param ep               The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN.
   *
   * @return A USB error code or kStatus_USB_Success.
   */
  static usb_status_t USB_DeviceLpc3511IpEndpointDeinit(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, uint8_t ep)
  {
      uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(ep);
      usb_device_lpc3511ip_endpoint_state_struct_t *epState =
          USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex);
  
      /* Cancel the transfer of the endpoint */
      USB_DeviceLpc3511IpCancel(lpc3511IpState, ep);
  
  #if (defined USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)
      if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState))
      {
          if ((endpointIndex >> 1U) != USB_CONTROL_ENDPOINT) /* control endpoint */
          {
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
              USB_DeviceLpcIp3511ReleaseMaxPacketBuffer(
                  lpc3511IpState, epState->epPacketBuffer,
                  USB_LPC3511IP_GET_MULTIPLE_OF_64(epState->stateUnion.stateBitField.maxPacketSize) * 2);
  #else
              USB_DeviceLpcIp3511ReleaseMaxPacketBuffer(lpc3511IpState, epState->epPacketBuffer,
                                                        epState->stateUnion.stateBitField.maxPacketSize);
  #endif
          }
          epState->epPacketBuffer = NULL;
      }
  #endif
  
      /* reset the double buffer */
      lpc3511IpState->registerBase->EPINUSE &= ~(0x01U << endpointIndex);
      /* Disable the endpoint */
      USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, endpointIndex, 0, USB_LPC3511IP_ENDPOINT_DISABLE_MASK, 0, 0);
      /* Clear the max packet size */
      epState->stateUnion.stateBitField.maxPacketSize = 0U;
  
      return kStatus_USB_Success;
  }
  
  /*!
   * @brief Stall a specified endpoint.
   *
   * The function is used to stall a specified endpoint.
   * Current transfer of the endpoint will be canceled and the specified endpoint will be stalled.
   *
   * @param lpc3511IpState      Pointer of the controller state structure.
   * @param ep               The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN.
   *
   * @return A USB error code or kStatus_USB_Success.
   */
  static usb_status_t USB_DeviceLpc3511IpEndpointStall(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, uint8_t ep)
  {
      uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(ep);
      usb_device_lpc3511ip_endpoint_state_struct_t *epState =
          USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex);
  
      /* Set endpoint stall flag. */
      epState->stateUnion.stateBitField.stalled = 1U;
      /* lpc3511IpState->registerBase->EPINUSE &= (~(0x01u << endpointIndex)); */
      /* stall the endpoint */
      USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, endpointIndex, 0, USB_LPC3511IP_ENDPOINT_STALL_MASK, 0, 0);
      if ((ep & USB_ENDPOINT_NUMBER_MASK) != USB_CONTROL_ENDPOINT)
      {
          /* toggle reset for the toggle */
          epState->stateUnion.stateBitField.epControlDefault |=
              ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT);
          USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, endpointIndex, 1, USB_LPC3511IP_ENDPOINT_STALL_MASK, 0, 0);
      }
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
      if ((lpc3511IpState->controllerSpeed) && (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType))
      {
          lpc3511IpState->registerBase->DEVCMDSTAT |= (USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK | USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK);
          epState->stateUnion.stateBitField.epControlDefault &=
              (~((USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK | USB_LPC3511IP_ENDPOINT_RFTV_MASK) >>
                 USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT));
      }
  #endif
      
      /* cancel the transfer in the endpoint */
      USB_DeviceLpc3511IpCancel(lpc3511IpState, ep);
      return kStatus_USB_Success;
  }
  
  /*!
   * @brief Un-stall a specified endpoint.
   *
   * The function is used to un-stall a specified endpoint.
   * Current transfer of the endpoint will be canceled and the specified endpoint will be un-stalled.
   *
   * @param lpc3511IpState      Pointer of the controller state structure.
   * @param ep               The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN.
   *
   * @return A USB error code or kStatus_USB_Success.
   */
  static usb_status_t USB_DeviceLpc3511IpEndpointUnstall(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, uint8_t ep)
  {
      uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(ep);
      usb_device_lpc3511ip_endpoint_state_struct_t *epState =
          USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex);
  
      /* Clear the endpoint stall state, the hardware resets the endpoint
       * toggle to one for both directions when a setup token is received */
      epState->stateUnion.stateBitField.stalled = 0U;
  
      /* unstall the endpoint for double buffers */
      USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(lpc3511IpState, endpointIndex, 0, (~USB_LPC3511IP_ENDPOINT_STALL_MASK));
      if ((ep & USB_ENDPOINT_NUMBER_MASK) != USB_CONTROL_ENDPOINT)
      {
          USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(lpc3511IpState, endpointIndex, 1, (~USB_LPC3511IP_ENDPOINT_STALL_MASK));
  
          /* toggle reset for the toggle */
          epState->stateUnion.stateBitField.epControlDefault |=
              ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT);
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
          if ((lpc3511IpState->controllerSpeed) &&
              (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType))
          {
              epState->stateUnion.stateBitField.epControlDefault &=
                  (~((USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK | USB_LPC3511IP_ENDPOINT_RFTV_MASK) >>
                     USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT));
          }
  #endif
      }
  
      if (epState->stateUnion.stateBitField.stallPrimed)
      {
          epState->stateUnion.stateBitField.stallPrimed = 0u;
          USB_DeviceLpc3511IpTransaction(lpc3511IpState, epState, endpointIndex);
      }
      /* cancel the transfer in the endpoint */
      USB_DeviceLpc3511IpCancel(lpc3511IpState, ep);
      return kStatus_USB_Success;
  }
  
  #if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
  /*!
   * @brief Un-stall a specified endpoint.
   *
   * The function is used to un-stall a specified endpoint.
   * Current transfer of the endpoint will be canceled and the specified endpoint will be un-stalled.
   *
   * @param lpc3511IpState      Pointer of the controller state structure.
   *
   * @return A USB error code or kStatus_USB_Success.
   */
  static usb_status_t USB_DeviceLpc3511IpInterruptSuspend(usb_device_lpc3511ip_state_struct_t *lpc3511IpState)
  {
      usb_device_callback_message_struct_t message;
  
      message.buffer = (uint8_t *)NULL;
      message.code = kUSB_DeviceNotifySuspend;
      message.length = 0U;
      message.isSetup = 0U;
  
      /* Notify up layer the USB suspend signal detected. */
      USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message);
  
      return kStatus_USB_Success;
  }
  
  /*!
   * @brief Un-stall a specified endpoint.
   *
   * The function is used to un-stall a specified endpoint.
   * Current transfer of the endpoint will be canceled and the specified endpoint will be un-stalled.
   *
   * @param lpc3511IpState      Pointer of the controller state structure.
   *
   * @return A USB error code or kStatus_USB_Success.
   */
  static usb_status_t USB_DeviceLpc3511IpInterruptResume(usb_device_lpc3511ip_state_struct_t *lpc3511IpState)
  {
      usb_device_callback_message_struct_t message;
  
      message.buffer = (uint8_t *)NULL;
      message.code = kUSB_DeviceNotifyResume;
      message.length = 0U;
      message.isSetup = 0U;
  
      /* Notify up layer the USB suspend signal detected. */
      USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message);
  
      return kStatus_USB_Success;
  }
  #if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U))
  /*!
   * @brief Un-stall a specified endpoint.
   *
   * The function is used to un-stall a specified endpoint.
   * Current transfer of the endpoint will be canceled and the specified endpoint will be un-stalled.
   *
   * @param lpc3511IpState      Pointer of the controller state structure.
   *
   * @return A USB error code or kStatus_USB_Success.
   */
  static usb_status_t USB_DeviceLpc3511IpInterruptLPMSleep(usb_device_lpc3511ip_state_struct_t *lpc3511IpState)
  {
      usb_device_callback_message_struct_t message;
      uint8_t remotewakeup;
  
      message.buffer = (uint8_t *)NULL;
      message.code = kUSB_DeviceNotifyLPMSleep;
      message.length = 0U;
      message.isSetup = 0U;
  
      remotewakeup =
          (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_MASK) >> USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_SHIFT;
      USB_DeviceSetStatus(lpc3511IpState->deviceHandle, kUSB_DeviceStatusRemoteWakeup, &remotewakeup);
  
      /* Notify up layer the USB suspend signal detected. */
      USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message);
  
      return kStatus_USB_Success;
  }
  
  #endif
  #endif
  
  static uint32_t USB_DeviceLpc3511IpTokenUpdate(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                 usb_device_lpc3511ip_endpoint_state_struct_t *epState,
                                                 uint8_t endpointIndex,
                                                 uint8_t changedOdd)
  {
      uint32_t length;
      uint32_t index;
      uint8_t *destBuffer;
      uint8_t *sourceBuffer;
      uint8_t odd;
  
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
      if (changedOdd)
      {
          odd = epState->stateUnion.stateBitField.consumerOdd;
          epState->stateUnion.stateBitField.consumerOdd ^= 1;
          epState->stateUnion.stateBitField.doubleBufferBusy--;
      }
      else
  #endif
      {
          odd = 0U;
      }
  
  /* for OUT packet, compute the actual packet size. */
  #if ((defined(FSL_FEATURE_USB_VERSION) && (FSL_FEATURE_USB_VERSION >= 200U)) || \
       (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)))
  #else
      if ((endpointIndex & 0x01U) == 0x00u) /* OUT */
  #endif
      {
          /* get the transaction length */
          length = *(((uint32_t *)lpc3511IpState->registerBase->EPLISTSTART) + endpointIndex * 2 + odd);
  
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
          if (lpc3511IpState->controllerSpeed)
          {
              length =
                  (length & USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_MASK) >> USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_SHIFT;
          }
          else
  #endif
          {
              length =
                  (length & USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_MASK) >> USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_SHIFT;
          }
          length = epState->epBufferStatusUnion[odd].epBufferStatusField.transactionLength - length;
      }
  #if ((defined(FSL_FEATURE_USB_VERSION) && (FSL_FEATURE_USB_VERSION >= 200U)) || \
       (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)))
  #else
      else /* for IN packet, if there is no error, the packet lenght is the primed length. */
      {
          /* don't judge the actual packet size */
          length = epState->epBufferStatusUnion[odd].epBufferStatusField.transactionLength;
      }
  #endif
  
  #if ((defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY > 0U))
  #if USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER
      if ((epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed) && (length > 0U) &&
          ((endpointIndex & 0x01u) == 0U))
  #else
      if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState) &&
          (epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed) && (length > 0U) &&
          ((endpointIndex & 0x01u) == 0U))
  #endif
  #else
      /* control data buffer align is used */
      if (((endpointIndex >> 1U) == USB_CONTROL_ENDPOINT) &&
          (epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed) && (length > 0U) &&
          ((endpointIndex & 0x01u) == 0U))
  #endif
      {
          destBuffer = &(epState->transferBuffer[epState->transferDone]);
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
          sourceBuffer = epState->epPacketBuffer +
                         odd * USB_LPC3511IP_GET_MULTIPLE_OF_64(epState->stateUnion.stateBitField.maxPacketSize);
  #else
          sourceBuffer = epState->epPacketBuffer;
  #endif
  
          /* align with 4 bytes */
          if (!(((uint32_t)(destBuffer)) & 0x00000003U))
          {
              for (index = 0; index < (length >> 2U); ++index)
              {
                  ((uint32_t *)(destBuffer))[index] = ((uint32_t *)(sourceBuffer))[index];
              }
              for (index = index * 4; index < length; ++index)
              {
                  destBuffer[index] = sourceBuffer[index];
              }
          }
          else
          {
              for (index = 0; index < length; ++index)
              {
                  destBuffer[index] = sourceBuffer[index];
              }
          }
      }
      /* update the transferred length */
      epState->transferDone += length;
  
      return length;
  }
  
  static void USB_DeviceLpc3511IpInterruptToken(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                uint8_t endpointIndex,
                                                uint8_t isSetup,
                                                uint32_t errorStatus)
  {
      usb_device_callback_message_struct_t message;
      uint32_t length;
      uint32_t remainLength;
      usb_setup_struct_t *setupPacket;
      usb_device_lpc3511ip_endpoint_state_struct_t *epState =
          USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex);
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
  
      if ((epState->stateUnion.stateBitField.epControlDefault &
           ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)) &&
          (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType) &&
          (lpc3511IpState->controllerSpeed) &&
          (lpc3511IpState->epCommandStatusList[endpointIndex * 2 + epState->stateUnion.stateBitField.consumerOdd] &
           USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK))
      {
          if (!(lpc3511IpState->registerBase->EPTOGGLE & (0x01u << endpointIndex)))
          {
              uint32_t index;
              length = 0;
              for (index = 0; index < (USB_DEVICE_IP3511_ENDPOINTS_NUM)*4; ++index)
              {
                  if ((lpc3511IpState->epCommandStatusList[index] & USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) &&
                      (USB_ENDPOINT_INTERRUPT ==
                       lpc3511IpState->endpointState[index / 2].stateUnion.stateBitField.endpointType))
                  {
                      length++;
                  }
              }
  
              if (length <= 1)
              {
                  lpc3511IpState->registerBase->DEVCMDSTAT &=
                      ~(USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK | USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK);
              }
              epState->stateUnion.stateBitField.epControlDefault &=
                  (~((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT));
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
              /* high-speed */
              epState->stateUnion.stateBitField.epControlDefault |=
                  ((USB_LPC3511IP_ENDPOINT_RFTV_MASK | USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK) >>
                   USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT);
              USB_DeviceLpc3511IpTransaction(lpc3511IpState, epState, endpointIndex);
  #endif
          }
          return;
      }
  #endif
  
      if ((!isSetup) && (0U == epState->stateUnion.stateBitField.transferring))
      {
          return;
      }
      if (isSetup)
      {
          message.length = 8U;
          message.buffer = (lpc3511IpState->setupData);
          /* clear the primed control transactions */
          if (epState->stateUnion.stateBitField.transferring)
          {
              epState->stateUnion.stateBitField.transferring = 0U;
              if (lpc3511IpState->epCommandStatusList[0] & USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)
              {
                  USB_DeviceLpc3511IpCancel(lpc3511IpState, USB_CONTROL_ENDPOINT);
              }
          }
          if (lpc3511IpState->endpointState[1].stateUnion.stateBitField.transferring)
          {
              lpc3511IpState->endpointState[1].stateUnion.stateBitField.transferring = 0U;
              if (lpc3511IpState->epCommandStatusList[2] & USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)
              {
                  USB_DeviceLpc3511IpCancel(lpc3511IpState, (0x80u | USB_CONTROL_ENDPOINT));
              }
          }
  
          USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(
              lpc3511IpState, 0, 0, (~(USB_LPC3511IP_ENDPOINT_STALL_MASK | USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)));
          USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(
              lpc3511IpState, 1, 0, (~(USB_LPC3511IP_ENDPOINT_STALL_MASK | USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)));
  
          lpc3511IpState->registerBase->INTSTAT = 0x03u; /* clear interrupt */
          /* W1 to clear the setup flag */
          lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK;
      }
      else
      {
          length = 0;
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
          if (lpc3511IpState->epCommandStatusList[endpointIndex * 2 + epState->stateUnion.stateBitField.consumerOdd] &
              USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)
          {
              return;
          }
  #else
          if (lpc3511IpState->epCommandStatusList[endpointIndex * 2] & USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)
          {
              return;
          }
  #endif
  
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
          if ((endpointIndex >> 1U) != USB_CONTROL_ENDPOINT)
          {
              length += USB_DeviceLpc3511IpTokenUpdate(lpc3511IpState, epState, endpointIndex, 1U);
  
              if ((epState->stateUnion.stateBitField.doubleBufferBusy > 0) &&
                  (!(lpc3511IpState
                         ->epCommandStatusList[endpointIndex * 2 + epState->stateUnion.stateBitField.consumerOdd] &
                     USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)))
              {
                  length += USB_DeviceLpc3511IpTokenUpdate(lpc3511IpState, epState, endpointIndex, 1U);
              }
          }
          else
  #endif
          {
              length = USB_DeviceLpc3511IpTokenUpdate(lpc3511IpState, epState, endpointIndex, 0U);
          }
  
          /* update remaining length */
          remainLength = epState->transferLength - epState->transferDone;
  
          /* Whether the transfer is completed or not.
           * The transfer is completed when one of the following conditions meet:
           * 1. The remaining length is zero.
           * 2. The length of current transcation is not the multiple of max packet size.
           */
          if ((length > 0U) && (!(length % epState->stateUnion.stateBitField.maxPacketSize)) && (remainLength > 0U))
          {
              (void)USB_DeviceLpc3511IpTransaction(lpc3511IpState, epState, endpointIndex);
              return;
          }
          else
          {
              epState->stateUnion.stateBitField.transferring = 0U;
              message.length = epState->transferDone;
              message.buffer = epState->transferBuffer;
  
              /* process ZLT
               * 1. IN endpoint;
               * 2. transfer length is the multiple of max packet size.
              */
              if ((endpointIndex & 0x01U) && (length) && (!(length % epState->stateUnion.stateBitField.maxPacketSize)))
              {
                  if ((endpointIndex >> 1U) == USB_CONTROL_ENDPOINT)
                  {
                      setupPacket = (usb_setup_struct_t *)(&(lpc3511IpState->setupData[0]));
                      /*
                       * Send ZLT transaction if setup transfer and the required length is longer than actual length
                       */
                      if (USB_SHORT_FROM_LITTLE_ENDIAN(setupPacket->wLength) > epState->transferLength)
                      {
                          (void)USB_DeviceLpc3511IpEndpointPrime(lpc3511IpState, epState, 1U, NULL, 0U);
                          return;
                      }
                  }
                  else if ((epState->stateUnion.stateBitField.zlt))
                  {
                      (void)USB_DeviceLpc3511IpEndpointPrime(lpc3511IpState, epState, endpointIndex, NULL, 0U);
                      return;
                  }
                  else
                  {
                  }
              }
          }
      }
  
      message.isSetup = isSetup;
      message.code = ((uint8_t)(endpointIndex >> 1) | (uint8_t)(((uint32_t)(endpointIndex & 0x01U) << 0x07U)));
  
      /* Notify the up layer the controller status changed. */
      USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message);
  }
  
  /*!
   * @brief Handle the USB bus reset interrupt.
   *
   * The function is used to handle the USB bus reset interrupt.
   *
   * @param lpc3511IpState       Pointer of the controller state structure.
   *
   */
  static void USB_DeviceLpc3511IpInterruptReset(usb_device_lpc3511ip_state_struct_t *lpc3511IpState)
  {
      usb_device_callback_message_struct_t message;
  
      /* Set reset flag */
      lpc3511IpState->isResetting = 1U;
  
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
      if (lpc3511IpState->controllerSpeed)
      {
          if (((lpc3511IpState->registerBase->DEVCMDSTAT & USBHSD_DEVCMDSTAT_Speed_MASK) >>
               USBHSD_DEVCMDSTAT_Speed_SHIFT) == 0x02U)
          {
              lpc3511IpState->deviceSpeed = USB_SPEED_HIGH;
          }
          else if (((lpc3511IpState->registerBase->DEVCMDSTAT & USBHSD_DEVCMDSTAT_Speed_MASK) >>
                    USBHSD_DEVCMDSTAT_Speed_SHIFT) == 0x01U)
          {
              lpc3511IpState->deviceSpeed = USB_SPEED_FULL;
          }
          else
          {
          }
      }
      else
  #endif
      {
          lpc3511IpState->deviceSpeed = USB_SPEED_FULL;
      }
  
      message.buffer = (uint8_t *)NULL;
      message.code = kUSB_DeviceNotifyBusReset;
      message.length = 0U;
      message.isSetup = 0U;
      /* Notify up layer the USB bus reset signal detected. */
      USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message);
  }
  
  #if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE))
  /*!
   * @brief Handle detach interrupt.
   *
   * The function is used to handle the detach interrupt.
   *
   * @param lpc3511IpState       Pointer of the controller state structure.
   *
   */
  static void USB_DeviceLpc3511IpInterruptDetach(usb_device_lpc3511ip_state_struct_t *lpc3511IpState)
  {
      usb_device_callback_message_struct_t message;
  
      message.buffer = (uint8_t *)NULL;
      message.code = kUSB_DeviceNotifyDetach;
      message.length = 0U;
      message.isSetup = 0U;
  
      /* Notify up layer the USB VBUS falling signal detected. */
      USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message);
  }
  #endif
  
  usb_status_t USB_DeviceLpc3511IpInit(uint8_t controllerId,
                                       usb_device_handle handle,
                                       usb_device_controller_handle *controllerHandle)
  {
      usb_device_lpc3511ip_state_struct_t *lpc3511IpState = NULL;
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U))
      uint32_t ip3511FsBases[] = USB_BASE_ADDRS;
  #endif
      uint32_t *endpointListArray[] = LPC_CONTROLLER_ENDPOINT_LIST_ARRAY;
  
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
      uint32_t ip3511HsBases[] = USBHSD_BASE_ADDRS;
      if ((controllerId >= kUSB_ControllerLpcIp3511Hs0) && (controllerId <= kUSB_ControllerLpcIp3511Hs1))
      {
          if ((uint32_t)(controllerId - kUSB_ControllerLpcIp3511Hs0) >= (sizeof(ip3511HsBases) / sizeof(uint32_t)))
          {
              return kStatus_USB_ControllerNotFound;
          }
          lpc3511IpState =
              &s_UsbDeviceLpc3511IpState[controllerId - kUSB_ControllerLpcIp3511Hs0 + USB_DEVICE_CONFIG_LPCIP3511FS];
          lpc3511IpState->controlData =
              s_ControlTransferData[controllerId - kUSB_ControllerLpcIp3511Hs0 + USB_DEVICE_CONFIG_LPCIP3511FS];
          lpc3511IpState->setupData =
              s_SetupData[controllerId - kUSB_ControllerLpcIp3511Hs0 + USB_DEVICE_CONFIG_LPCIP3511FS];
          lpc3511IpState->zeroTransactionData =
              s_ZeroTransactionData[controllerId - kUSB_ControllerLpcIp3511Hs0 + USB_DEVICE_CONFIG_LPCIP3511FS];
          /* set the endpoint list */
          lpc3511IpState->epCommandStatusList =
              endpointListArray[controllerId - kUSB_ControllerLpcIp3511Hs0 + USB_DEVICE_CONFIG_LPCIP3511FS];
          /* get the ip base address */
          lpc3511IpState->registerBase = (USB_LPC3511IP_Type *)ip3511HsBases[controllerId - kUSB_ControllerLpcIp3511Hs0];
      }
      else
  #endif
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U))
      {
          /* get the controller instance */
          if ((controllerId < kUSB_ControllerLpcIp3511Fs0) ||
              ((controllerId - kUSB_ControllerLpcIp3511Fs0) >= (uint8_t)USB_DEVICE_CONFIG_LPCIP3511FS) ||
              ((uint32_t)(controllerId - kUSB_ControllerLpcIp3511Fs0) >= (sizeof(ip3511FsBases) / sizeof(uint32_t))))
          {
              return kStatus_USB_ControllerNotFound;
          }
          lpc3511IpState = &s_UsbDeviceLpc3511IpState[controllerId - kUSB_ControllerLpcIp3511Fs0];
          lpc3511IpState->controlData = s_ControlTransferData[controllerId - kUSB_ControllerLpcIp3511Fs0];
          lpc3511IpState->setupData = s_SetupData[controllerId - kUSB_ControllerLpcIp3511Fs0];
          lpc3511IpState->zeroTransactionData = s_ZeroTransactionData[controllerId - kUSB_ControllerLpcIp3511Fs0];
          /* set the endpoint list */
          lpc3511IpState->epCommandStatusList = endpointListArray[controllerId - kUSB_ControllerLpcIp3511Fs0];
          /* get the ip base address */
          lpc3511IpState->registerBase = (USB_LPC3511IP_Type *)ip3511FsBases[controllerId - kUSB_ControllerLpcIp3511Fs0];
      }
  #else
      {
          return kStatus_USB_ControllerNotFound;
      }
  #endif
  
      lpc3511IpState->controllerId = controllerId;
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
      if ((lpc3511IpState->controllerId >= kUSB_ControllerLpcIp3511Hs0) &&
          (lpc3511IpState->controllerId <= kUSB_ControllerLpcIp3511Hs1))
      {
          lpc3511IpState->controllerSpeed = 1U;
      }
      else
      {
          lpc3511IpState->controllerSpeed = 0U;
      }
  #endif
  
  #if ((defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY > 0U))
      /* this controller need max packet buffer copy */
      if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState))
      {
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
          if ((controllerId >= kUSB_ControllerLpcIp3511Hs0) && (controllerId <= kUSB_ControllerLpcIp3511Hs1))
          {
  #if (USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER)
              /* for allocating the max packet buffer */
              lpc3511IpState->epReservedBuffer = (uint8_t *)
                  s_EpReservedBuffer[controllerId - kUSB_ControllerLpcIp3511Hs0 + USB_DEVICE_CONFIG_LPCIP3511FS];
  #else
              lpc3511IpState->epReservedBuffer =
                  (uint8_t *)s_EpReservedBuffer[controllerId - kUSB_ControllerLpcIp3511Hs0];
  #endif
          }
          else
  #endif
          {
              lpc3511IpState->epReservedBuffer =
                  (uint8_t *)s_EpReservedBuffer[controllerId - kUSB_ControllerLpcIp3511Fs0];
          }
      }
      for (controllerId = 0; controllerId < ((USB_DEVICE_IP3511_BITS_FOR_RESERVED_BUFFER + 7) / 8); ++controllerId)
      {
          lpc3511IpState->epReservedBufferBits[controllerId] = 0u;
      }
  #endif
  
      /* disable the controller */
      lpc3511IpState->registerBase->DEVCMDSTAT &=
          (~(USB_LPC3511IP_DEVCMDSTAT_DCON_MASK | USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK | USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK));
      /* reset and enalbe the controller */
      USB_DeviceLpc3511IpSetDefaultState(lpc3511IpState);
      /* enable USB */
      lpc3511IpState->registerBase->DEVCMDSTAT |= (USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK
  #if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
  #else
                                                   | USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK
  #endif
                                                   );
  #if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U))
      lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK;
      lpc3511IpState->registerBase->LPM |= USB_LPC3511IP_USB_LPM_HIRD_SW(4);
      lpc3511IpState->registerBase->DEVCMDSTAT &= ~(USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK);
  #endif
      lpc3511IpState->deviceHandle = handle;
      *controllerHandle = lpc3511IpState;
  
      return kStatus_USB_Success;
  }
  
  usb_status_t USB_DeviceLpc3511IpDeinit(usb_device_controller_handle controllerHandle)
  {
      usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)controllerHandle;
      uint32_t usbAddress;
  
      if (controllerHandle == NULL)
      {
          return kStatus_USB_InvalidHandle;
      }
      /* Clear all interrupt flags. */
      lpc3511IpState->registerBase->INTSTAT =
          (USB_LPC3511IP_INTSTAT_DEV_INT_MASK | USB_LPC3511IP_INTSTAT_FRAME_INT_MASK | USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK);
      /* Disable all interrupts. */
      lpc3511IpState->registerBase->INTEN = 0U;
      /* Clear device address. */
      usbAddress = 0U;
      USB_DeviceLpc3511IpControl(lpc3511IpState, kUSB_DeviceControlSetDeviceAddress, &usbAddress);
  #if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U))
      lpc3511IpState->registerBase->DEVCMDSTAT &= ~USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK;
  #endif
      /* disable the controller */
      lpc3511IpState->registerBase->DEVCMDSTAT &= (~(USB_LPC3511IP_DEVCMDSTAT_DCON_MASK | USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK));
  
      return kStatus_USB_Success;
  }
  
  static usb_status_t USB_DeviceLpc3511IpGetActualBufferAndPrime(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                                 usb_device_lpc3511ip_endpoint_state_struct_t *epState,
                                                                 uint8_t endpointIndex,
                                                                 uint8_t changedOdd)
  {
      uint32_t index;
      uint8_t *destBuffer;
      uint8_t *actualBuffer;
      uint32_t length;
      uint8_t odd;
  
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
      if (changedOdd)
      {
          odd = epState->stateUnion.stateBitField.producerOdd;
      }
      else
  #endif
      {
          odd = 0;
      }
      actualBuffer = epState->transferBuffer + epState->transferPrimedLength;
      length = epState->transferLength - epState->transferPrimedLength;
      /* Data length needs to less than max packet size. */
      if (length > epState->stateUnion.stateBitField.maxPacketSize)
      {
          length = epState->stateUnion.stateBitField.maxPacketSize;
      }
  
      epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed = 0;
  
      index = (endpointIndex & 0x01u); /* index mean IN endpoint here */
      if (length > 0U)
      {
  #if ((defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY > 0U))
  /* if all the enabled IP support the reserved buffer, then don't need the judgement. */
  #if (!USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER)
  #define USB_DEVICE_IP3511_NEED_CHECK_BUFFER (1u)
          /* lengt > 0 && ((buffer not align with 64) || (buffer is not in the deticated ram))) */
          if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState))
  #endif
  #else
  #define USB_DEVICE_IP3511_NEED_CHECK_BUFFER (1u)
          /* align the buffer for control transfer */
          if (((endpointIndex >> 1U) == USB_CONTROL_ENDPOINT))
  #endif
          {
              /* not 64 bytes align || not in the dedicated ram || ( OUT && not mutiple of 4 ) */
              if ((((uint32_t)actualBuffer & 0x0000003FU) != 0U) ||
                  (((uint32_t)actualBuffer & 0xFFC00000U) != (lpc3511IpState->registerBase->DATABUFSTART & 0xFFC00000U))
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
                  || ((lpc3511IpState->controllerSpeed) && (!index) &&
                      (length != epState->stateUnion.stateBitField.maxPacketSize)))
  #else
                      )
  #endif
              {
                  epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed = 1U;
  /* usb copy buffer for this packet */
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
                  destBuffer =
                      (uint8_t *)(epState->epPacketBuffer + (odd * USB_LPC3511IP_GET_MULTIPLE_OF_64(
                                                                       epState->stateUnion.stateBitField.maxPacketSize)));
  #else
                  destBuffer = (uint8_t *)(epState->epPacketBuffer);
  #endif
                  if (index) /* USB_IN */
                  {
                      /* align with 4 bytes */
                      if (!(((uint32_t)actualBuffer) & 0x00000003U))
                      {
                          for (index = 0; index < ((length + 0x03U) >> 2U); ++index)
                          {
                              ((uint32_t *)(destBuffer))[index] = ((uint32_t *)actualBuffer)[index];
                          }
                      }
                      else
                      {
                          for (index = 0; index < length; ++index)
                          {
                              destBuffer[index] = actualBuffer[index];
                          }
                      }
                  }
                  else
                  {
  #if ((defined(FSL_FEATURE_USB_VERSION) && (FSL_FEATURE_USB_VERSION >= 200U)) || \
       (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)))
  #else
                      length = epState->stateUnion.stateBitField.maxPacketSize;
  #endif
                  }
                  actualBuffer = destBuffer;
              }
          }
  #if (defined USB_DEVICE_IP3511_NEED_CHECK_BUFFER) && (USB_DEVICE_IP3511_NEED_CHECK_BUFFER)
          else /* cannot do memory copy */
          {
              /* not 64 bytes align || not in the dedicated ram || ( OUT && HS && not mutiple of 4 ) */
              if ((((uint32_t)actualBuffer & 0x0000003FU) != 0U) ||
                  (((uint32_t)actualBuffer & 0xFFC00000U) != (lpc3511IpState->registerBase->DATABUFSTART & 0xFFC00000U))
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
                  || ((lpc3511IpState->controllerSpeed) && (!index) && ((length & 0x00000003u) != 0u)))
  #else
                      )
  #endif
              {
                  return kStatus_USB_Error;
              }
          }
  #endif
      }
  
      /* Send/Receive data when the device is not resetting. */
      if (0U == lpc3511IpState->isResetting)
      {
          return USB_DeviceLpc3511IpEndpointPrime(lpc3511IpState, epState, endpointIndex, actualBuffer, length);
      }
      else
      {
          return kStatus_USB_Error;
      }
  }
  static usb_status_t USB_DeviceLpc3511IpTransaction(usb_device_lpc3511ip_state_struct_t *lpc3511IpState,
                                                     usb_device_lpc3511ip_endpoint_state_struct_t *epState,
                                                     uint8_t endpointIndex)
  {
      usb_status_t status = kStatus_USB_Error;
      USB_OSA_SR_ALLOC();
  
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
      /* high-speed */
      if ((epState->stateUnion.stateBitField.epControlDefault &
           ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)) &&
          (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType) && (lpc3511IpState->controllerSpeed))
      {
          /* users can use NVIC to disable/enable the USB interrupt to improve the system performance */
          USB_OSA_ENTER_CRITICAL();
  
          lpc3511IpState->registerBase->DEVCMDSTAT |= (USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK | USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK);
  
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
          USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(
              lpc3511IpState, endpointIndex, epState->stateUnion.stateBitField.producerOdd,
              (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT) | (epState->stateUnion.stateBitField.stalled << USB_LPC3511IP_ENDPOINT_STALL_SHIFT),
              0U, (uint32_t)lpc3511IpState->zeroTransactionData);
  #else
          USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(
              lpc3511IpState, endpointIndex, 0,
              (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT) | (epState->stateUnion.stateBitField.stalled << USB_LPC3511IP_ENDPOINT_STALL_SHIFT),
              0U, (uint32_t)lpc3511IpState->zeroTransactionData);
  #endif
          /* users can use NVIC to disable/enable the USB interrupt to improve the system performance */
          USB_OSA_EXIT_CRITICAL();
          return kStatus_USB_Success;
      }
  #endif
  
      /* Enter critical */
      USB_OSA_ENTER_CRITICAL();
      if (epState->stateUnion.stateBitField.stalled)
      {
          if ((endpointIndex >> 1U) != USB_ENDPOINT_CONTROL)
          {
              epState->stateUnion.stateBitField.stallPrimed = 1u;
              status = kStatus_USB_Success;
          }
          status = kStatus_USB_Error;
          USB_OSA_EXIT_CRITICAL();
          return status;
      }
      USB_OSA_EXIT_CRITICAL();
  
      /* 1. transfer size is 0; 2. All are primed */
      if ((epState->transferLength <= epState->transferPrimedLength) && (epState->transferLength != 0))
      {
          return kStatus_USB_Success;
      }
  
  #if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE)
      if ((endpointIndex >> 1U) != USB_CONTROL_ENDPOINT)
      {
          /* disable endpoint interrupts, users can use NVIC to disable/enable the USB interrupt to improve the system performance */
          USB_OSA_ENTER_CRITICAL();
          /* lpc3511IpState->registerBase->INTEN &= (uint32_t)(~(USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK)); */
  
          do
          {
              status = USB_DeviceLpc3511IpGetActualBufferAndPrime(lpc3511IpState, epState, endpointIndex, 1U);
              if (status != kStatus_USB_Success)
              {
                  break;
              }
          } while ((epState->transferLength > epState->transferPrimedLength) &&
                   (epState->stateUnion.stateBitField.doubleBufferBusy < 2));
  
          /* enable endpoint interrupt again, users can use NVIC to disable/enable the USB interrupt to improve the system performance */
          USB_OSA_EXIT_CRITICAL();
      }
      else
  #endif
      {
          status = USB_DeviceLpc3511IpGetActualBufferAndPrime(lpc3511IpState, epState, endpointIndex, 0U);
      }
      return status;
  }
  
  usb_status_t USB_DeviceLpc3511IpSend(usb_device_controller_handle controllerHandle,
                                       uint8_t endpointAddress,
                                       uint8_t *buffer,
                                       uint32_t length)
  {
      usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)controllerHandle;
      uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(endpointAddress);
      usb_device_lpc3511ip_endpoint_state_struct_t *epState =
          USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex);
  
      if (1U == epState->stateUnion.stateBitField.transferring)
      {
          return kStatus_USB_Error;
      }
  
      /* Save the tansfer information */
      epState->transferDone = 0U;
      epState->transferBuffer = buffer;
      epState->transferLength = length;
      epState->transferPrimedLength = 0U;
  
      return USB_DeviceLpc3511IpTransaction(lpc3511IpState, epState, endpointIndex);
  
  /* prime the control setup transfer if it is control in endpoint and data length is zero
   * For IP3511 there is no need to prime, the buffer is always in the command/status list
  */
  #if 0
      if ((0U == length) && (USB_CONTROL_ENDPOINT == (endpointAddress & USB_ENDPOINT_NUMBER_MASK)))
      {
          USB_DeviceLpc3511IpPrimeNextSetup(lpc3511IpState);
      }
  #endif
  }
  
  usb_status_t USB_DeviceLpc3511IpRecv(usb_device_controller_handle controllerHandle,
                                       uint8_t endpointAddress,
                                       uint8_t *buffer,
                                       uint32_t length)
  {
      return USB_DeviceLpc3511IpSend(controllerHandle, endpointAddress, buffer, length);
  }
  
  usb_status_t USB_DeviceLpc3511IpCancel(usb_device_controller_handle controllerHandle, uint8_t ep)
  {
      /* users can use NVIC to disable/enable the USB interrupt to improve the system performance */
      USB_OSA_SR_ALLOC();
  
      usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)controllerHandle;
      usb_device_callback_message_struct_t message;
      uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(ep);
      usb_device_lpc3511ip_endpoint_state_struct_t *epState =
          USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex);
  
      /* Cancel the transfer and notify the up layer when the endpoint is busy. */
      if (epState->stateUnion.stateBitField.transferring)
      {
          /* disable endpoint interrupts, users can use NVIC to disable/enable the USB interrupt to improve the system performance */
          USB_OSA_ENTER_CRITICAL();
  
          do
          {
              if (epState->stateUnion.stateBitField.doubleBufferBusy == 2)
              {
                  epState->stateUnion.stateBitField.doubleBufferBusy = 1;
              }
              else
              {
                  epState->stateUnion.stateBitField.doubleBufferBusy = 0;
              }
              /* cancel the transfer in the endpoint command/status */
              lpc3511IpState->registerBase->EPSKIP |= (0x01U << endpointIndex);
              while (lpc3511IpState->registerBase->EPSKIP & (0x01U << endpointIndex))
              {
              }
              if (epState->stateUnion.stateBitField.doubleBufferBusy)
              {
                  epState->stateUnion.stateBitField.producerOdd =
                      ((lpc3511IpState->registerBase->EPINUSE & ((uint32_t)(0x01 << endpointIndex))) >> endpointIndex);
                  epState->stateUnion.stateBitField.producerOdd ^= 1;
                  lpc3511IpState->registerBase->EPINUSE |=
                      (uint32_t)(epState->stateUnion.stateBitField.producerOdd << endpointIndex);
              }
          } while (epState->stateUnion.stateBitField.doubleBufferBusy);
  
          /* clear interrupt status, enable endpoint interrupt again */
          lpc3511IpState->registerBase->INTSTAT = (0x01U << endpointIndex);
          
          /* users can use NVIC to disable/enable the USB interrupt to improve the system performance */
          USB_OSA_EXIT_CRITICAL();
  
          message.length = USB_UNINITIALIZED_VAL_32;
          message.buffer = epState->transferBuffer;
          message.code = ep;
          message.isSetup = 0U;
          epState->stateUnion.stateBitField.transferring = 0U;
          epState->stateUnion.stateBitField.producerOdd =
              ((lpc3511IpState->registerBase->EPINUSE & ((uint32_t)(0x01 << endpointIndex))) >> endpointIndex);
          epState->stateUnion.stateBitField.consumerOdd =
              ((lpc3511IpState->registerBase->EPINUSE & ((uint32_t)(0x01 << endpointIndex))) >> endpointIndex);
          USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message);
      }
      return kStatus_USB_Success;
  }
  
  usb_status_t USB_DeviceLpc3511IpControl(usb_device_controller_handle controllerHandle,
                                          usb_device_control_type_t type,
                                          void *param)
  {
      usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)controllerHandle;
      usb_status_t error = kStatus_USB_Error;
      uint32_t tmp32Value;
      uint8_t tmp8Value;
  #if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))
      usb_device_struct_t *deviceHandle;
  #endif
      usb_device_lpc3511ip_endpoint_state_struct_t *epState;
  
      if (controllerHandle == NULL)
      {
          return kStatus_USB_InvalidHandle;
      }
  
  #if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))
      deviceHandle = (usb_device_struct_t *)lpc3511IpState->deviceHandle;
  #endif
  
      switch (type)
      {
          case kUSB_DeviceControlRun:
              lpc3511IpState->registerBase->DEVCMDSTAT |= (USB_LPC3511IP_DEVCMDSTAT_DCON_MASK);
              break;
  
          case kUSB_DeviceControlStop:
              lpc3511IpState->registerBase->DEVCMDSTAT &= (~USB_LPC3511IP_DEVCMDSTAT_DCON_MASK);
              break;
  
          case kUSB_DeviceControlEndpointInit:
              if (param)
              {
                  error = USB_DeviceLpc3511IpEndpointInit(lpc3511IpState, (usb_device_endpoint_init_struct_t *)param);
              }
              break;
  
          case kUSB_DeviceControlEndpointDeinit:
              if (param)
              {
                  tmp8Value = *((uint8_t *)param);
                  error = USB_DeviceLpc3511IpEndpointDeinit(lpc3511IpState, tmp8Value);
              }
              break;
  
          case kUSB_DeviceControlEndpointStall:
              if (param)
              {
                  tmp8Value = *((uint8_t *)param);
                  error = USB_DeviceLpc3511IpEndpointStall(lpc3511IpState, tmp8Value);
              }
              break;
  
          case kUSB_DeviceControlEndpointUnstall:
              if (param)
              {
                  tmp8Value = *((uint8_t *)param);
                  error = USB_DeviceLpc3511IpEndpointUnstall(lpc3511IpState, tmp8Value);
              }
              break;
  
          case kUSB_DeviceControlGetDeviceStatus:
              if (param)
              {
                  *((uint16_t *)param) =
                      (USB_DEVICE_CONFIG_SELF_POWER << (USB_REQUEST_STANDARD_GET_STATUS_DEVICE_SELF_POWERED_SHIFT))
  #if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U))
                      | ((uint16_t)(((uint32_t)deviceHandle->remotewakeup)
                                    << (USB_REQUEST_STANDARD_GET_STATUS_DEVICE_REMOTE_WARKUP_SHIFT)))
  #endif
                      ;
                  error = kStatus_USB_Success;
              }
              break;
  
          case kUSB_DeviceControlGetEndpointStatus:
              if (param)
              {
                  usb_device_endpoint_status_struct_t *endpointStatus = (usb_device_endpoint_status_struct_t *)param;
  
                  if (((endpointStatus->endpointAddress) & USB_ENDPOINT_NUMBER_MASK) < USB_DEVICE_IP3511_ENDPOINTS_NUM)
                  {
                      epState = USB_DeviceLpc3511IpGetEndpointStateStruct(
                          lpc3511IpState, USB_LPC3511IP_ENDPOINT_DES_INDEX(endpointStatus->endpointAddress));
                      endpointStatus->endpointStatus = (uint16_t)(epState->stateUnion.stateBitField.stalled == 1U) ?
                                                           kUSB_DeviceEndpointStateStalled :
                                                           kUSB_DeviceEndpointStateIdle;
                      error = kStatus_USB_Success;
                  }
              }
              break;
  
          case kUSB_DeviceControlSetDeviceAddress:
              if (param)
              {
                  tmp8Value = *((uint8_t *)param);
                  tmp32Value = lpc3511IpState->registerBase->DEVCMDSTAT;
                  tmp32Value &= (~USB_LPC3511IP_DEVCMDSTAT_DEV_ADDR_MASK);
                  tmp32Value |= (tmp8Value & USB_LPC3511IP_DEVCMDSTAT_DEV_ADDR_MASK);
                  lpc3511IpState->registerBase->DEVCMDSTAT = tmp32Value;
                  error = kStatus_USB_Success;
              }
              break;
  
          case kUSB_DeviceControlGetSynchFrame:
              break;
  
  #if defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)
          case kUSB_DeviceControlResume:
              /* todo: turn on USB clock and enable the USB clock source */
              lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK;
              lpc3511IpState->registerBase->DEVCMDSTAT &= ~USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK;
              while (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK)
              {
              }
              /* the W1C bits */
              lpc3511IpState->registerBase->DEVCMDSTAT &=
                  ~(USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK | USB_LPC3511IP_DEVCMDSTAT_INTERRUPT_WC_MASK);
              error = kStatus_USB_Success;
              break;
  #if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U))
          case kUSB_DeviceControlSleepResume:
              /* todo: turn on USB clock and enable the USB clock source */
              lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK;
              lpc3511IpState->registerBase->DEVCMDSTAT &= ~USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK;
              while (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK)
              {
                  __NOP();
              }
              /* the W1C bits */
              lpc3511IpState->registerBase->DEVCMDSTAT &=
                  ~(USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK | USB_LPC3511IP_DEVCMDSTAT_INTERRUPT_WC_MASK);
              error = kStatus_USB_Success;
              break;
  #endif
          case kUSB_DeviceControlGetRemoteWakeUp:
              *((uint8_t *)param) = !!(lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_MASK);
              break;
  #endif /* USB_DEVICE_CONFIG_REMOTE_WAKEUP */
  
          case kUSB_DeviceControlSetDefaultStatus:
              for (tmp32Value = 0U; tmp32Value < USB_DEVICE_IP3511_ENDPOINTS_NUM; tmp32Value++)
              {
                  USB_DeviceLpc3511IpEndpointDeinit(lpc3511IpState, (tmp32Value | (USB_IN << 0x07U)));
                  USB_DeviceLpc3511IpEndpointDeinit(lpc3511IpState, (tmp32Value | (USB_OUT << 0x07U)));
              }
              USB_DeviceLpc3511IpSetDefaultState(lpc3511IpState);
              error = kStatus_USB_Success;
              break;
  
          case kUSB_DeviceControlGetSpeed:
              if (param)
              {
                  *((uint8_t *)param) = lpc3511IpState->deviceSpeed;
                  error = kStatus_USB_Success;
              }
              break;
          case kUSB_DeviceControlGetOtgStatus:
              break;
          case kUSB_DeviceControlSetOtgStatus:
              break;
  #if (defined(USB_DEVICE_CONFIG_USB20_TEST_MODE) && (USB_DEVICE_CONFIG_USB20_TEST_MODE > 0U))
          case kUSB_DeviceControlSetTestMode:
              if (param)
              {
                  tmp8Value = *((uint8_t *)param);
  #if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
                  lpc3511IpState->registerBase->DEVCMDSTAT |=
                      ((uint32_t)(tmp8Value) << USBHSD_DEVCMDSTAT_PHY_TEST_MODE_SHIFT);
  #endif
                  error = kStatus_USB_Success;
              }
              break;
  #endif
          default:
              break;
      }
  
      return error;
  }
  
  void USB_DeviceLpcIp3511IsrFunction(void *deviceHandle)
  {
      usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle;
      usb_device_lpc3511ip_state_struct_t *lpc3511IpState;
      uint32_t interruptStatus;
      uint32_t usbErrorCode;
      uint32_t devState;
  
      if (NULL == deviceHandle)
      {
          return;
      }
  
      lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)(handle->controllerHandle);
      /* get and clear interrupt status */
      interruptStatus = lpc3511IpState->registerBase->INTSTAT;
      lpc3511IpState->registerBase->INTSTAT = interruptStatus;
      interruptStatus &= lpc3511IpState->registerBase->INTEN;
  
      usbErrorCode = (lpc3511IpState->registerBase->INFO & USB_LPC3511IP_INFO_ERR_CODE_MASK);
  
      /* device status change interrupt */
      if (interruptStatus & USB_LPC3511IP_INTSTAT_DEV_INT_MASK)
      {
          /* get and clear device state change status */
          devState = lpc3511IpState->registerBase->DEVCMDSTAT;
          devState &= ~(USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK);
          lpc3511IpState->registerBase->DEVCMDSTAT = (devState | USB_LPC3511IP_DEVCMDSTAT_INTERRUPT_WC_MASK);
  
          /* reset change */
          if (devState & USB_LPC3511IP_DEVCMDSTAT_DRES_C_MASK)
          {
              USB_DeviceLpc3511IpInterruptReset(lpc3511IpState);
          }
  
  #if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE))
          /* dis-connect change */
          if (devState & USB_LPC3511IP_DEVCMDSTAT_DCON_C_MASK)
          {
              USB_DeviceLpc3511IpInterruptDetach(lpc3511IpState);
          }
  #endif
  
  /* Suspend/Resume */
  #if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
          if (devState & USB_LPC3511IP_DEVCMDSTAT_DSUS_C_MASK)
          {
              if (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK)
              {
                  USB_DeviceLpc3511IpInterruptSuspend(lpc3511IpState);
              }
  #if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U))
              else if (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK)
              {
                  USB_DeviceLpc3511IpInterruptLPMSleep(lpc3511IpState);
              }
  #endif
              else
              {
                  USB_DeviceLpc3511IpInterruptResume(lpc3511IpState);
              }
          }
  
  #endif
  
  #if 0U /* some soc don't support this bit, need check according to the feature macro */
          /* OTG Status change */
          if (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_OTG_C_MASK)
          {
          }
  #endif
      }
  
      /* endpoint transfers interrupt */
      if (interruptStatus & USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK)
      {
          devState = 0;                /* devState means index here */
          if (interruptStatus & 0x01u) /* control OUT */
          {
              if (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK)
              {
                  devState = 2;
                  if ((lpc3511IpState->endpointState[0].stateUnion.stateBitField.stalled == 1U) ||
                      (lpc3511IpState->endpointState[1].stateUnion.stateBitField.stalled == 1U))
                  {
                      USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(
                          lpc3511IpState, 0, 0,
                          (~(USB_LPC3511IP_ENDPOINT_STALL_MASK | USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)));
                      USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(
                          lpc3511IpState, 1, 0,
                          (~(USB_LPC3511IP_ENDPOINT_STALL_MASK | USB_LPC3511IP_ENDPOINT_ACTIVE_MASK)));
                      lpc3511IpState->endpointState[0].stateUnion.stateBitField.stalled = 0U;
                      lpc3511IpState->endpointState[1].stateUnion.stateBitField.stalled = 0U;
                  }
  
                  /* todo: setup token interrupt */
                  USB_DeviceLpc3511IpInterruptToken(lpc3511IpState, 0U, 1, usbErrorCode);
              }
          }
  
          for (; devState < (USB_DEVICE_IP3511_ENDPOINTS_NUM * 2); ++devState)
          {
              /* check the endpoint interrupt */
              if (interruptStatus & (0x01U << devState))
              {
                  USB_DeviceLpc3511IpInterruptToken(lpc3511IpState, devState, 0, usbErrorCode);
              }
          }
      }
  
  #if 0U
      if (interruptStatus & USB_LPC3511IP_INTSTAT_FRAME_INT_MASK)
      {
      }
  #endif
  }
  
  #endif
  