/*
 * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
 * Copyright 2016,2019 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "usb_host_config.h"
#if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI > 0U))
#include "usb_host.h"
#include "usb_host_hci.h"
#include "usb_host_devices.h"
#include "fsl_device_registers.h"
#include "usb_host_ehci.h"
#include "usb_phy.h"
#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST))
#include "usb_host.h"
#endif

/*******************************************************************************
 * Definitions
 ******************************************************************************/

#if defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM > 0U)

#error The SOC does not suppoort dedicated RAM case.

#endif

#define USB_HOST_EHCI_BANDWIDTH_DELAY (3500U)
#define USB_HOST_EHCI_BANDWIDTH_HUB_LS_SETUP (333U)
#define USB_HOST_EHCI_BANDWIDTH_FRAME_TOTOAL_TIME (900U)

#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST))
#define USB_HOST_EHCI_TEST_DESCRIPTOR_LENGTH (18U)
#define USB_HOST_EHCI_PORTSC_PTC_J_STATE (0x01U)
#define USB_HOST_EHCI_PORTSC_PTC_K_STATE (0x02U)
#define USB_HOST_EHCI_PORTSC_PTC_SE0_NAK (0x03U)
#define USB_HOST_EHCI_PORTSC_PTC_PACKET (0x04U)
#define USB_HOST_EHCI_PORTSC_PTC_FORCE_ENABLE_HS (0x05U)
#define USB_HOST_EHCI_PORTSC_PTC_FORCE_ENABLE_FS (0x06U)
#define USB_HOST_EHCI_PORTSC_PTC_FORCE_ENABLE_LS (0x07U)
#endif

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
/*!
 * @brief compute data bandwidth time.
 *
 * @param speed       data speed.
 * @param pipeType    data type.
 * @param direction   data direction.
 * @param dataLength  data length.
 *
 *@return time value.
 */
static uint32_t USB_HostBandwidthComputeTime(uint8_t speed, uint8_t pipeType, uint8_t direction, uint32_t dataLength);

/*!
 * @brief compute current allocated bandwidth when ehci work as full-speed or low-speed host.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param frameIndex      frame index.
 * @param frameBandwidths return frame bandwidth data.
 */
static void USB_HostBandwidthFslsHostComputeCurrent(usb_host_ehci_instance_t *ehciInstance,
                                                    uint16_t frameIndex,
                                                    uint16_t *frameBandwidth);

/*!
 * @brief compute current hub's allocated FS/LS bandwidth when ehci work as hi-speed host.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param hubNumber       hub address.
 * @param frameIndex      frame index.
 * @param frameBandwidths return frame bandwidth data.
 */
static void USB_HostBandwidthHsHostComputeCurrentFsls(usb_host_ehci_instance_t *ehciInstance,
                                                      uint32_t hubNumber,
                                                      uint16_t frameIndex,
                                                      uint8_t frameBandwidths[8]);

/*!
 * @brief compute current allocated HS bandwidth when ehci work as hi-speed host.
 *
 * @param ehciInstance         ehci instance pointer.
 * @param frameIndex      frame index.
 * @param frameBandwidths return frame bandwidth data.
 */
static void USB_HostBandwidthHsHostComputeCurrentHsAll(usb_host_ehci_instance_t *ehciInstance,
                                                       uint16_t frameIndex,
                                                       uint8_t frameBandwidths[8]);

/*!
 * @brief allocate HS bandwidth when host work as high-speed host.
 *
 * @param ehciInstance         ehci instance pointer.
 * @param uframeInterval  micro-frame interval.
 * @param timeData        time for allocating.
 * @param uframe_index_out return start uframe index.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostBandwidthHsHostAllocateHsCommon(usb_host_ehci_instance_t *ehciInstance,
                                                            uint16_t uframeInterval,
                                                            uint16_t timeData,
                                                            uint16_t *uframeIndexOut);

/*!
 * @brief allocate HS interrupt bandwidth when host work as high-speed host.
 *
 * @param ehciInstance         ehci instance pointer.
 * @param ehciPipePointer    ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostBandwidthHsHostAllocateInterrupt(usb_host_ehci_instance_t *ehciInstance,
                                                             usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief allocate bandwidth when host work as full-speed or low-speed host.
 *
 * @param ehciInstance         ehci instance pointer.
 * @param ehciPipePointer    ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostBandwidthFslsHostAllocate(usb_host_ehci_instance_t *ehciInstance,
                                                      usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief get the 2 power value of uint8_t.
 *
 * @param value     input uint8_t value.
 */
static uint8_t USB_HostEhciGet2PowerValue(uint8_t value);

/*!
 * @brief memory zero.
 *
 * @param buffer     buffer pointer.
 * @param length     buffer length.
 */
static void USB_HostEhciZeroMem(uint32_t *buffer, uint32_t length);

/*!
 * @brief host ehci delay.
 *
 * @param ehciIpBase     ehci ip base address.
 * @param ms          millisecond.
 */
static void USB_HostEhciDelay(USBHS_Type *ehciIpBase, uint32_t ms);

/*!
 * @brief host ehci start async schedule.
 *
 * @param ehciInstance    ehci instance pointer.
 */
static void USB_HostEhciStartAsync(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief host ehci stop async schedule.
 *
 * @param ehciInstance    ehci instance pointer.
 */
static void USB_HostEhciStopAsync(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief host ehci start periodic schedule.
 *
 * @param ehciInstance    ehci instance pointer.
 */
static void USB_HostEhciStartPeriodic(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief host ehci stop periodic schedule.
 *
 * @param ehciInstance    ehci instance pointer.
 */
static void USB_HostEhciStopPeriodic(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief initialize the qtd for one transfer.
 *
 * @param ehciInstance      ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 * @param transfer      transfer information.
 *
 *@return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciQhQtdListInit(usb_host_ehci_instance_t *ehciInstance,
                                              usb_host_ehci_pipe_t *ehciPipePointer,
                                              usb_host_transfer_t *transfer);

/*!
 * @brief release the qtd list.
 *
 * @param ehciInstance   ehci instance pointer.
 * @param ehciQtdStart   qtd list start pointer.
 * @param ehciQtdEnd     qtd list end pointer.
 *
 *@return the transfer's length.
 */
static uint32_t USB_HostEhciQtdListRelease(usb_host_ehci_instance_t *ehciInstance,
                                           usb_host_ehci_qtd_t *ehciQtdStart,
                                           usb_host_ehci_qtd_t *ehciQtdEnd);

/*!
 * @brief de-initialize qh's linking qtd list.
 * 1. remove qtd from qh; 2. remove transfer from qh; 3. release qtd; 4. transfer callback.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe.
 *
 *@return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciQhQtdListDeinit(usb_host_ehci_instance_t *ehciInstance,
                                                usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief de-initialize transfer's linking qtd list.
 * 1. stop this qh schedule; 2. remove qtd from qh; 3. remove transfer from qh; 4. release qtd; 5. transfer callback; 6.
 *start this qh schedule.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 * @param transfer        transfer information.
 *
 *@return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciTransferQtdListDeinit(usb_host_ehci_instance_t *ehciInstance,
                                                      usb_host_ehci_pipe_t *ehciPipePointer,
                                                      usb_host_transfer_t *transfer);

/*!
 * @brief initialize QH when opening one control, bulk or interrupt pipe.
 *
 * @param ehciInstance       ehci instance pointer.
 * @param ehciPipePointer    ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciQhInit(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief de-initialize QH when closing one control, bulk or interrupt pipe.
 *
 * @param ehciInstance       ehci instance pointer.
 * @param ehciPipePointer    ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciQhDeinit(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief add qh to one frame entry.
 *
 * @param ehciInstance      ehci instance pointer.
 * @param entryPointerValue entry pointer value.
 * @param framePos          frame index.
 * @param uframeInterval    micro-frame interval.
 */
static void USB_HostEhciAddQhToFrame(usb_host_ehci_instance_t *ehciInstance,
                                     uint32_t entryPointerValue,
                                     uint16_t framePos,
                                     uint16_t uframeInterval);

/*!
 * @brief remove entry from frame list.
 *
 * @param ehciInstance      ehci instance pointer.
 * @param entryPointerValue entry pointer value.
 * @param framePos          frame index.
 */
static void USB_HostEhciRemoveFromFrame(usb_host_ehci_instance_t *ehciInstance,
                                        uint32_t entryPointerValue,
                                        uint16_t framePos);

#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))
/*!
 * @brief add sitd array to the frame list.
 *
 * @param ehciInstance      ehci instance pointer.
 * @param entryPointerValue entry pointer value.
 * @param startEntryPointer sitd entry pointer.
 */
static void USB_HostEhciLinkSitd(usb_host_ehci_instance_t *ehciInstance,
                                 usb_host_ehci_pipe_t *ehciPipePointer,
                                 void *startEntryPointer);

/*!
 * @brief initialize sitd array for one transfer.
 *
 * @param ehciInstance      ehci instance pointer.
 * @param ehciPipePointer   ehci pipe pointer.
 * @param transfer          transfer information.
 */
static usb_status_t USB_HostEhciSitdArrayInit(usb_host_ehci_instance_t *ehciInstance,
                                              usb_host_ehci_pipe_t *ehciPipePointer,
                                              usb_host_transfer_t *transfer);

/*!
 * @brief release sitd list.
 *
 * @param ehciInstance     ehci instance pointer.
 * @param startSitdPointer start sitd pointer.
 * @param endSitdPointer   end sitd pointer.
 *
 * @return transfer's result length.
 */
static uint32_t USB_HostEhciSitdArrayRelease(usb_host_ehci_instance_t *ehciInstance,
                                             usb_host_ehci_sitd_t *startSitdPointer,
                                             usb_host_ehci_sitd_t *endSitdPointer);

/*!
 * @brief de-initialize sitd list.
 * 1. remove transfer; 2. remove sitd from frame list and release sitd; 3. transfer callback
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciSitdArrayDeinit(usb_host_ehci_instance_t *ehciInstance,
                                                usb_host_ehci_pipe_t *ehciPipePointer);
#endif /* USB_HOST_CONFIG_EHCI_MAX_SITD */

#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
/*!
 * @brief compute the frame index when inserting itd.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param lastLinkUframe  last inserted micro-frame.
 * @param startUframe     start micro-frame.
 * @param uframeInterval  micro-frame interval.
 *
 * @return frame index
 */
static uint32_t USB_HostEhciGetItdLinkFrame(usb_host_ehci_instance_t *ehciInstance,
                                            uint32_t lastLinkUframe,
                                            uint16_t startUframe,
                                            uint16_t uframeInterval);

/*!
 * @brief initialize itd list for one transfer.
 * 1. initialize itd list; 2. insert itd to frame list.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 * @param transfer        transfer information.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciItdArrayInit(usb_host_ehci_instance_t *ehciInstance,
                                             usb_host_ehci_pipe_t *ehciPipePointer,
                                             usb_host_transfer_t *transfer);

/*!
 * @brief release itd list.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param startItdPointer start itd pointer.
 * @param endItdPointer   end itd pointer.
 *
 * @return transfer's result length.
 */
static uint32_t USB_HostEhciItdArrayRelease(usb_host_ehci_instance_t *ehciInstance,
                                            usb_host_ehci_itd_t *startItdPointer,
                                            usb_host_ehci_itd_t *endItdPointer);

/*!
 * @brief de-initialize itd list.
 * 1. remove transfer; 2. remove itd from frame list and release itd; 3. transfer callback
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciItdArrayDeinit(usb_host_ehci_instance_t *ehciInstance,
                                               usb_host_ehci_pipe_t *ehciPipePointer);
#endif /* USB_HOST_CONFIG_EHCI_MAX_ITD */

/*!
 * @brief open control or bulk pipe.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciOpenControlBulk(usb_host_ehci_instance_t *ehciInstance,
                                                usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief close control or bulk pipe.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciCloseControlBulk(usb_host_ehci_instance_t *ehciInstance,
                                                 usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief open interrupt pipe.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciOpenInterrupt(usb_host_ehci_instance_t *ehciInstance,
                                              usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief close interrupt pipe.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciCloseInterrupt(usb_host_ehci_instance_t *ehciInstance,
                                               usb_host_ehci_pipe_t *ehciPipePointer);

#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
/*!
 * @brief open iso pipe.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciOpenIso(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief close iso pipe.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciCloseIso(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer);

/*!
 * @brief allocate HS iso bandwidth when host work as high-speed host.
 *
 * @param ehciInstance         ehci instance pointer.
 * @param ehciPipePointer    ehci pipe pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostBandwidthHsHostAllocateIso(usb_host_ehci_instance_t *ehciInstance,
                                                       usb_host_ehci_pipe_t *ehciPipePointer);

#endif

/*!
 * @brief reset ehci ip.
 *
 * @param ehciInstance      ehci instance pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciResetIP(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief start ehci ip.
 *
 * @param ehciInstance      ehci instance pointer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciStartIP(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief cancel pipe's transfers.
 *
 * @param ehciInstance    ehci instance pointer.
 * @param ehciPipePointer ehci pipe pointer.
 * @param transfer        the canceling transfer.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciCancelPipe(usb_host_ehci_instance_t *ehciInstance,
                                           usb_host_ehci_pipe_t *ehciPipePointer,
                                           usb_host_transfer_t *transfer);

/*!
 * @brief control ehci bus.
 *
 * @param ehciInstance  ehci instance pointer.
 * @param bus_control   control code.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint8_t busControl);

/*!
 * @brief ehci transaction done process function.
 *
 * @param ehciInstance      ehci instance pointer.
 */
void USB_HostEhciTransactionDone(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief ehci port change interrupt process function.
 *
 * @param ehciInstance      ehci instance pointer.
 */
static void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief ehci timer0 interrupt process function.
 * cancel control/bulk transfer that time out.
 *
 * @param ehciInstance      ehci instance pointer.
 */
static void USB_HostEhciTimer0(usb_host_ehci_instance_t *ehciInstance);

#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
/*!
 * @brief ehci timer1 interrupt process function.
 * cancel control/bulk transfer that time out.
 *
 * @param ehciInstance      ehci instance pointer.
 */
static void USB_HostEhciTimer1(usb_host_ehci_instance_t *ehciInstance);
#endif

#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST))
/*!
 * @brief suspend bus.
 *
 * @param ehciInstance      ehci instance pointer.
 */
static void USB_HostEhciSuspendBus(usb_host_ehci_instance_t *ehciInstance);

/*!
 * @brief resume bus.
 *
 * @param ehciInstance      ehci instance pointer.
 */
static void USB_HostEhciResumeBus(usb_host_ehci_instance_t *ehciInstance);

extern usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance,
                                                     usb_host_transfer_t *transfer,
                                                     void *param);
#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */

/*******************************************************************************
 * Variables
 ******************************************************************************/

/* EHCI controller driver instances. */
#if (USB_HOST_CONFIG_EHCI == 1U)
USB_RAM_ADDRESS_ALIGNMENT(4096)
USB_CONTROLLER_DATA static uint8_t s_UsbHostEhciFrameList1[USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 4];

static uint8_t usbHostEhciFramListStatus[1] = {0};

USB_RAM_ADDRESS_ALIGNMENT(64) USB_CONTROLLER_DATA static usb_host_ehci_data_t s_UsbHostEhciData1;
#define USB_HOST_EHCI_DATA_ARRAY \
    {                            \
        &s_UsbHostEhciData1      \
    }
#elif (USB_HOST_CONFIG_EHCI == 2U)
USB_RAM_ADDRESS_ALIGNMENT(4096)
USB_CONTROLLER_DATA static uint8_t s_UsbHostEhciFrameList1[USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 4];
USB_RAM_ADDRESS_ALIGNMENT(4096)
USB_CONTROLLER_DATA static uint8_t s_UsbHostEhciFrameList2[USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 4];
static uint8_t usbHostEhciFramListStatus[2] = {0, 0};

USB_RAM_ADDRESS_ALIGNMENT(64) USB_CONTROLLER_DATA static usb_host_ehci_data_t s_UsbHostEhciData1;
USB_RAM_ADDRESS_ALIGNMENT(64) USB_CONTROLLER_DATA static usb_host_ehci_data_t s_UsbHostEhciData2;
#define USB_HOST_EHCI_DATA_ARRAY                 \
    {                                            \
        &s_UsbHostEhciData1, &s_UsbHostEhciData2 \
    }
#else
#error "Please increase the instance count."
#endif

#define USB_HOST_EHCI_MAX_MICRFRAME_VALUE ((USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE << 3U) - 1)

static uint8_t s_SlotMaxBandwidth[8]   = {125, 125, 125, 125, 125, 125, 50, 0};
static uint8_t s_SlotMaxBandwidthHs[8] = {100, 100, 100, 100, 100, 100, 100, 100};

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief EHCI NC get USB NC bass address.
 *
 * This function is used to get USB NC bass address.
 *
 * @param[in] controllerId    EHCI controller ID; See the #usb_controller_index_t.
 *
 * @retval USB NC bass address.
 */
#if (defined(USB_HOST_CONFIG_LOW_POWER_MODE) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
void *USB_EhciNCGetBase(uint8_t controllerId)
{
    void *usbNCBase = NULL;
#if ((defined FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
    uint32_t instance;
    uint32_t newinstance       = 0;
    uint32_t usbnc_base_temp[] = USBNC_BASE_ADDRS;
    uint32_t usbnc_base[]      = USBNC_BASE_ADDRS;

    if (controllerId < kUSB_ControllerEhci0)
    {
        return NULL;
    }

    controllerId = controllerId - kUSB_ControllerEhci0;

    for (instance = 0; instance < (sizeof(usbnc_base_temp) / sizeof(usbnc_base_temp[0])); instance++)
    {
        if (usbnc_base_temp[instance])
        {
            usbnc_base[newinstance++] = usbnc_base_temp[instance];
        }
    }
    if (controllerId > newinstance)
    {
        return NULL;
    }

    usbNCBase = (void *)usbnc_base[controllerId];
#endif
    return usbNCBase;
}
#endif
#endif

#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST))

usb_status_t USB_HostEhciTestSetMode(usb_host_ehci_instance_t *ehciInstance, uint32_t testMode)
{
    uint32_t ehciPortSC;

    ehciPortSC = ehciInstance->ehciIpBase->PORTSC1;
    ehciPortSC &= ~((uint32_t)USBHS_PORTSC1_PTC_MASK);   /* clear test mode bits */
    ehciPortSC |= (testMode << USBHS_PORTSC1_PTC_SHIFT); /* set test mode bits */
    ehciInstance->ehciIpBase->PORTSC1 = ehciPortSC;
    return kStatus_USB_Success;
}

static void USB_HostEhciTestSuspendResume(usb_host_ehci_instance_t *ehciInstance)
{
    uint8_t timeCount;
    timeCount = 15; /* 15s */
    while (timeCount--)
    {
        USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U);
    }
    USB_HostEhciSuspendBus(ehciInstance);
    timeCount = 15; /* 15s */
    while (timeCount--)
    {
        USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U);
    }

    USB_HostEhciResumeBus(ehciInstance);
}

static void USB_HostEhciTestCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
    USB_HostFreeTransfer(param, transfer);
}

static void USB_HostEhciTestSingleStepGetDeviceDesc(usb_host_ehci_instance_t *ehciInstance,
                                                    usb_device_handle deviceHandle)
{
    usb_host_process_descriptor_param_t getDescriptorParam;
    usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
    usb_host_transfer_t *transfer;
    uint8_t timeCount;

    /* disable periodic shedule */
    USB_HostEhciStopPeriodic(ehciInstance);

    timeCount = 15; /* 15s */
    while (timeCount--)
    {
        USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U);
    }

    /* malloc one transfer */
    if (USB_HostMallocTransfer(ehciInstance->hostHandle, &transfer) != kStatus_USB_Success)
    {
#ifdef HOST_ECHO
        usb_echo("allocate transfer error\r\n");
#endif
        return;
    }

    getDescriptorParam.descriptorLength  = sizeof(usb_descriptor_device_t);
    getDescriptorParam.descriptorLength  = 18;
    getDescriptorParam.descriptorBuffer  = (uint8_t *)&deviceInstance->deviceDescriptor;
    getDescriptorParam.descriptorType    = USB_DESCRIPTOR_TYPE_DEVICE;
    getDescriptorParam.descriptorIndex   = 0;
    getDescriptorParam.languageId        = 0;
    transfer->callbackFn                 = USB_HostEhciTestCallback;
    transfer->callbackParam              = ehciInstance->hostHandle;
    transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_DIR_IN;
    transfer->setupPacket->bRequest      = USB_REQUEST_STANDARD_GET_DESCRIPTOR;
    transfer->setupPacket->wIndex        = 0;
    transfer->setupPacket->wLength       = 0;
    transfer->setupPacket->wValue        = 0;
    USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam);
}

static usb_status_t USB_HostEhciSingleStepQtdListInit(usb_host_ehci_instance_t *ehciInstance,
                                                      usb_host_ehci_pipe_t *ehciPipePointer,
                                                      usb_host_transfer_t *transfer,
                                                      uint8_t setupPhase)
{
    volatile usb_host_ehci_qh_t *vltQhPointer;
    usb_host_ehci_qtd_t *qtdPointer = NULL;
    volatile uint32_t *entryPointer;
    uint32_t qtdNumber;
    uint32_t dataLength;
    uint32_t dataAddress;
    uint8_t index;

    /* compute the qtd number */
    qtdNumber = 1;

    vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;
    /* get qtd list */
    USB_HostEhciLock();
    if (qtdNumber <= ehciInstance->ehciQtdNumber)
    {
        ehciInstance->ehciQtdNumber -= qtdNumber;
        qtdPointer = NULL;
        do
        {
            if (qtdPointer != NULL)
            {
                qtdPointer->nextQtdPointer = (uint32_t)ehciInstance->ehciQtdHead;
            }
            qtdPointer                 = ehciInstance->ehciQtdHead;
            ehciInstance->ehciQtdHead  = (usb_host_ehci_qtd_t *)qtdPointer->nextQtdPointer;
            qtdPointer->nextQtdPointer = 0;
        } while (--qtdNumber);
    }
    else
    {
        USB_HostEhciUnlock();
        return kStatus_USB_Error;
    }
    USB_HostEhciUnlock();

    /* int qTD */
    if (setupPhase == 1) /* setup transaction qtd init */
    {
        qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
        /* dt: need set; ioc: 0; C_Page: 0; PID Code: SETUP; Status: Active */
        qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0;
        qtdPointer->transferResults[0] =
            ((0x00000000 << EHCI_HOST_QTD_DT_SHIFT) | (8 << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) |
             (EHCI_HOST_PID_SETUP << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));
        dataAddress                    = (uint32_t)(transfer->setupPacket);
        qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */
        /* set buffer pointer no matter data length */
        for (index = 0; index < 4; ++index)
        {
            qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000);
        }
    }
    else if (setupPhase == 2) /* data transaction qtd */
    {
        dataLength = transfer->transferLength;
        if (dataLength != 0)
        {
            qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
            /* dt: need set; ioc: 0; C_Page: 0; PID Code: IN/OUT; Status: Active */
            qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0;

            qtdPointer->transferResults[0] =
                ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (dataLength << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) |
                 (EHCI_HOST_PID_IN << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));

            dataAddress                    = (uint32_t)(transfer->transferBuffer);
            qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */
            /* set buffer pointer no matter data length */
            for (index = 0; index < 4; ++index)
            {
                qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000);
            }
        }
    }
    else if (setupPhase == 3)
    {
        /* status transaction qtd */
        qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
        /* dt: dont care; ioc: 1; C_Page: 0; PID Code: IN/OUT; Status: Active */
        qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0;

        qtdPointer->transferResults[0] =
            ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (EHCI_HOST_PID_OUT << EHCI_HOST_QTD_PID_CODE_SHIFT) |
             (EHCI_HOST_QTD_IOC_MASK) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));

        qtdPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE;
    }
    qtdPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE;
    qtdPointer->transferResults[0] |= EHCI_HOST_QTD_IOC_MASK; /* set IOC */

    /* save qtd to transfer */
    transfer->union1.unitHead = (uint32_t)qtdPointer;
    transfer->union2.unitTail = (uint32_t)qtdPointer;
    /* link transfer to qh */
    transfer->next = NULL;
    if (vltQhPointer->ehciTransferHead == NULL)
    {
        transfer->next                 = NULL;
        vltQhPointer->ehciTransferHead = vltQhPointer->ehciTransferTail = transfer;
    }
    else
    {
        transfer->next                       = NULL;
        vltQhPointer->ehciTransferTail->next = transfer;
        vltQhPointer->ehciTransferTail       = transfer;
    }

    USB_HostEhciLock();
    /* link qtd to qh (link to end) */
    entryPointer = &(vltQhPointer->nextQtdPointer);
    dataAddress  = *entryPointer; /* dataAddress variable means entry value here */
    while ((dataAddress) && (!(dataAddress & EHCI_HOST_T_INVALID_VALUE)))
    {
        entryPointer = (volatile uint32_t *)dataAddress;
        dataAddress  = *entryPointer;
    }
    *entryPointer = (uint32_t)qtdPointer;
    USB_HostEhciUnlock();
    USB_HostEhciStartAsync(ehciInstance);

    return kStatus_USB_Success;
}

static void USB_HostEhciTestSingleStepGetDeviceDescData(usb_host_ehci_instance_t *ehciInstance,
                                                        usb_device_handle deviceHandle)
{
    static uint8_t buffer[USB_HOST_EHCI_TEST_DESCRIPTOR_LENGTH];
    usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
    usb_host_transfer_t *transfer;
    uint8_t timeCount;

    USB_HostEhciStopPeriodic(ehciInstance);

    if (USB_HostMallocTransfer(ehciInstance->hostHandle, &transfer) != kStatus_USB_Success)
    {
        return;
    }
    transfer->callbackFn                 = USB_HostEhciTestCallback;
    transfer->callbackParam              = ehciInstance->hostHandle;
    transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_DIR_IN;
    transfer->setupPacket->bRequest      = USB_REQUEST_STANDARD_GET_DESCRIPTOR;
    transfer->setupPacket->wLength       = USB_SHORT_TO_LITTLE_ENDIAN(USB_HOST_EHCI_TEST_DESCRIPTOR_LENGTH);
    transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN((uint16_t)((uint16_t)USB_DESCRIPTOR_TYPE_DEVICE << 8));
    transfer->setupPacket->wIndex = 0;
    USB_HostEhciSingleStepQtdListInit(ehciInstance, (usb_host_ehci_pipe_t *)(deviceInstance->controlPipe), transfer, 1);

    timeCount = 15; /* 15s */
    while (timeCount--)
    {
        USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U);
    }

    if (USB_HostMallocTransfer(ehciInstance->hostHandle, &transfer) != kStatus_USB_Success)
    {
        return;
    }
    transfer->callbackFn     = USB_HostEhciTestCallback;
    transfer->callbackParam  = ehciInstance->hostHandle;
    transfer->transferBuffer = buffer;
    transfer->transferLength = USB_HOST_EHCI_TEST_DESCRIPTOR_LENGTH;
    USB_HostEhciSingleStepQtdListInit(ehciInstance, (usb_host_ehci_pipe_t *)(deviceInstance->controlPipe), transfer, 2);

    if (USB_HostMallocTransfer(ehciInstance->hostHandle, &transfer) != kStatus_USB_Success)
    {
        return;
    }
    transfer->callbackFn     = USB_HostEhciTestCallback;
    transfer->callbackParam  = ehciInstance->hostHandle;
    transfer->transferBuffer = NULL;
    transfer->transferLength = 0;
    USB_HostEhciSingleStepQtdListInit(ehciInstance, (usb_host_ehci_pipe_t *)(deviceInstance->controlPipe), transfer, 3);

    timeCount = 15; /* 15s */
    while (timeCount--)
    {
        USB_HostEhciDelay(ehciInstance->ehciIpBase, 1000U);
    }

    usb_echo("test_single_step_get_dev_desc_data finished\r\n");

    return;
}

void USB_HostEhciTestModeInit(usb_device_handle deviceHandle)
{
    uint32_t productId;
    usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
    usb_host_ehci_instance_t *ehciInstance =
        (usb_host_ehci_instance_t *)(((usb_host_instance_t *)(deviceInstance->hostHandle))->controllerHandle);

    USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDevicePID, &productId);

    usb_echo("usb host ehci test mode init  product id:0x%x\r\n", productId);

    switch (productId)
    {
        case 0x0101U:
            USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_SE0_NAK);
            break;
        case 0x0102U:
            USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_J_STATE);
            break;
        case 0x0103U:
            USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_K_STATE);
            break;
        case 0x0104U:
            USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_PACKET);
            break;
        case 0x0105U:
            usb_echo("set test mode FORCE_ENALBE_HS\r\n");
            USB_HostEhciTestSetMode(ehciInstance, USB_HOST_EHCI_PORTSC_PTC_FORCE_ENABLE_HS);
            break;
        case 0x0106U:
            USB_HostEhciTestSuspendResume(ehciInstance);
            break;
        case 0x0107U:
            usb_echo("start test SINGLE_STEP_GET_DEV_DESC\r\n");
            USB_HostEhciTestSingleStepGetDeviceDesc(ehciInstance, deviceHandle);
            break;
        case 0x0108U:
            usb_echo("start test SINGLE_STEP_GET_DEV_DESC_DATA\r\n");
            USB_HostEhciTestSingleStepGetDeviceDescData(ehciInstance, deviceHandle);
            break;
        default:
            break;
    }

    return;
}

static void USB_HostEhciSuspendBus(usb_host_ehci_instance_t *ehciInstance)
{
    uint32_t ehciPortSC;

    USB_HostEhciLock();
    ehciPortSC = ehciInstance->ehciIpBase->PORTSC1;
    if (ehciPortSC & USBHS_PORTSC1_PE_MASK)
    {
        ehciPortSC = ehciInstance->ehciIpBase->PORTSC1;
        ehciPortSC &= (uint32_t)(~EHCI_PORTSC1_W1_BITS);
        ehciInstance->ehciIpBase->PORTSC1 = (ehciPortSC | USBHS_PORTSC1_SUSP_MASK);
    }
    USB_HostEhciUnlock();
}

static void USB_HostEhciResumeBus(usb_host_ehci_instance_t *ehciInstance)
{
    uint32_t ehciPortSC;

    USB_HostEhciLock();
    /* Resume port */
    ehciPortSC = ehciInstance->ehciIpBase->PORTSC1;
    if (ehciPortSC & USBHS_PORTSC1_PE_MASK)
    {
        ehciPortSC &= (uint32_t)(~EHCI_PORTSC1_W1_BITS);
        ehciInstance->ehciIpBase->PORTSC1 = (ehciPortSC | USBHS_PORTSC1_FPR_MASK);
    }
    USB_HostEhciUnlock();
}
#endif

static uint32_t USB_HostBandwidthComputeTime(uint8_t speed, uint8_t pipeType, uint8_t direction, uint32_t dataLength)
{
    uint32_t result = (3167 + ((1000 * dataLength) * 7U * 8U / 6U)) / 1000;

    if (pipeType == USB_ENDPOINT_ISOCHRONOUS) /* iso */
    {
        if (speed == USB_SPEED_HIGH)
        {
            result = 38 * 8 * 2083 + 2083 * result + USB_HOST_EHCI_BANDWIDTH_DELAY;
        }
        else if (speed == USB_SPEED_FULL)
        {
            if (direction == USB_IN)
            {
                result = 7268000 + 83540 * result + USB_HOST_EHCI_BANDWIDTH_DELAY;
            }
            else
            {
                result = 6265000 + 83540 * result + USB_HOST_EHCI_BANDWIDTH_DELAY;
            }
        }
        else
        {
        }
    }
    else /* interrupt */
    {
        if (speed == USB_SPEED_HIGH)
        {
            result = 55 * 8 * 2083 + 2083 * result + USB_HOST_EHCI_BANDWIDTH_DELAY;
        }
        else if (speed == USB_SPEED_FULL)
        {
            result = 9107000 + 83540 * result + USB_HOST_EHCI_BANDWIDTH_DELAY;
        }
        else if (speed == USB_SPEED_LOW)
        {
            if (direction == USB_IN)
            {
                result = 64060000 + 2000 * USB_HOST_EHCI_BANDWIDTH_HUB_LS_SETUP + 676670 * result +
                         USB_HOST_EHCI_BANDWIDTH_DELAY;
            }
            else
            {
                result = 6265000 + 83540 * result + USB_HOST_EHCI_BANDWIDTH_DELAY;
            }
        }
        else
        {
        }
    }

    result /= 1000000;
    if (result == 0)
    {
        result = 1;
    }

    return result;
}

static void USB_HostBandwidthFslsHostComputeCurrent(usb_host_ehci_instance_t *ehciInstance,
                                                    uint16_t frameIndex,
                                                    uint16_t *frameBandwidth)
{
    usb_host_ehci_pipe_t *ehciPipePointer;

    /* clear the bandwidth */
    *frameBandwidth = 0;

    ehciPipePointer = ehciInstance->ehciRunningPipeList;
    while (ehciPipePointer != NULL)
    {
        /* only compute iso and interrupt pipe */
        if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS) ||
            (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT))
        {
            /* does pipe allocate bandwidth in frameIndex frame? note: interval is power of 2. */
            if ((frameIndex >= ehciPipePointer->startFrame) &&
                (!((uint32_t)(frameIndex - ehciPipePointer->startFrame) &
                   (uint32_t)(ehciPipePointer->pipeCommon.interval - 1))))
            {
                *frameBandwidth += ehciPipePointer->dataTime;
            }
        }
        ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next;
    }
}

static void USB_HostBandwidthHsHostComputeCurrentFsls(usb_host_ehci_instance_t *ehciInstance,
                                                      uint32_t hubNumber,
                                                      uint16_t frameIndex,
                                                      uint8_t frameBandwidths[8])
{
    usb_host_ehci_pipe_t *ehciPipePointer;
    uint8_t index;
    uint32_t deviceInfo;

    for (index = 0; index < 8; ++index)
    {
        frameBandwidths[index] = 0;
    }

    ehciPipePointer = ehciInstance->ehciRunningPipeList;
    while (ehciPipePointer != NULL)
    {
        /* only compute iso and interrupt pipe */
        if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS) ||
            (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT))
        {
            /* compute FS/LS bandwidth that blong to same high-speed hub, because FS/LS bandwidth is allocated from
             * first parent high-speed hub */
            USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle,
                                                   kUSB_HostGetDeviceHSHubNumber, &deviceInfo);
            if (deviceInfo != hubNumber)
            {
                ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next;
                continue;
            }
            USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed,
                                                   &deviceInfo);
            if (deviceInfo == USB_SPEED_HIGH)
            {
                ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next;
                continue;
            }

            /* does pipe allocate bandwidth in frameIndex frame? note: interval is power of 2. */
            if ((frameIndex >= ehciPipePointer->startFrame) &&
                (!((uint32_t)(frameIndex - ehciPipePointer->startFrame) &
                   (uint32_t)(ehciPipePointer->pipeCommon.interval - 1))))
            {
                if (ehciPipePointer->pipeCommon.pipeType ==
                    USB_ENDPOINT_ISOCHRONOUS) /* iso bandwidth is allocated once */
                {
                    frameBandwidths[ehciPipePointer->startUframe + 1] += ehciPipePointer->dataTime;
                }
                else /* iso bandwidth is allocated three times */
                {
                    frameBandwidths[ehciPipePointer->startUframe + 1] += ehciPipePointer->dataTime;
                    frameBandwidths[ehciPipePointer->startUframe + 2] += ehciPipePointer->dataTime;
                    frameBandwidths[ehciPipePointer->startUframe + 3] += ehciPipePointer->dataTime;
                }
            }
        }
        ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next;
    }

    for (index = 0; index < 7; ++index) /*  */
    {
        if (frameBandwidths[index] > s_SlotMaxBandwidth[index])
        {
            frameBandwidths[index + 1] += (frameBandwidths[index] - s_SlotMaxBandwidth[index]);
            frameBandwidths[index] = s_SlotMaxBandwidth[index];
        }
    }
}

static void USB_HostBandwidthHsHostComputeCurrentHsAll(usb_host_ehci_instance_t *ehciInstance,
                                                       uint16_t frameIndex,
                                                       uint8_t frameBandwidths[8])
{
    usb_host_ehci_pipe_t *ehciPipePointer;
    uint8_t index;
    uint32_t deviceInfo;
    uint16_t frameInterval;

    for (index = 0; index < 8; ++index)
    {
        frameBandwidths[index] = 0;
    }

    ehciPipePointer = ehciInstance->ehciRunningPipeList;
    while (ehciPipePointer != NULL)
    {
        /* only compute iso and interrupt pipe */
        if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS) ||
            (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT))
        {
            frameInterval = ehciPipePointer->pipeCommon.interval;
            USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed,
                                                   &deviceInfo);
            if (deviceInfo == USB_SPEED_HIGH) /* high-speed data bandwidth */
            {
                /* frameInterval means micro-frame here */
                if (frameIndex >= ehciPipePointer->startFrame)
                {
                    if ((frameInterval > 8) &&
                        (frameIndex * 8 - ehciPipePointer->startFrame * 8 >= ehciPipePointer->startUframe))
                    {
                        if (!((uint32_t)(frameIndex * 8 - ehciPipePointer->startFrame * 8 -
                                         ehciPipePointer->startUframe) &
                              (uint32_t)(frameInterval - 1)))
                        {
                            frameBandwidths[ehciPipePointer->startUframe] += ehciPipePointer->dataTime;
                        }
                    }
                    else
                    {
                        for (index = ehciPipePointer->startUframe; index < 8; index += frameInterval)
                        {
                            frameBandwidths[index] += ehciPipePointer->dataTime;
                        }
                    }
                }
            }
            else /* full-speed split bandwidth */
            {
                if ((frameIndex >= ehciPipePointer->startFrame) &&
                    (!((uint32_t)(frameIndex - ehciPipePointer->startFrame) & (uint32_t)(frameInterval - 1))))
                {
                    for (index = 0; index < 8; ++index)
                    {
                        if ((uint32_t)(ehciPipePointer->uframeSmask) &
                            (uint32_t)(0x01 << index)) /* start-split micro-frames */
                        {
                            frameBandwidths[index] += ehciPipePointer->startSplitTime;
                        }
                        if ((uint32_t)(ehciPipePointer->uframeCmask) &
                            (uint32_t)(0x01 << index)) /* complete-split micro-frames */
                        {
                            frameBandwidths[index] += ehciPipePointer->completeSplitTime;
                        }
                    }
                }
            }
        }
        ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next;
    }

#if 0
    for (index = 0; index < 7; ++index) /*  */
    {
        if (frameBandwidths[index] > s_SlotMaxBandwidthHs[index])
        {
            frameBandwidths[index + 1] += (frameBandwidths[index] - s_SlotMaxBandwidthHs[index]);
            frameBandwidths[index] = s_SlotMaxBandwidthHs[index];
        }
    }
#endif
}

/*!
 * @brief allocate HS bandwidth when host work as high-speed host.
 *
 * @param ehciInstance         ehci instance pointer.
 * @param uframeInterval  micro-frame interval.
 * @param timeData        time for allocating.
 * @param uframeIndexOut return start uframe index.
 *
 * @return kStatus_USB_Success or error codes.
 */
static usb_status_t USB_HostBandwidthHsHostAllocateHsCommon(usb_host_ehci_instance_t *ehciInstance,
                                                            uint16_t uframeInterval,
                                                            uint16_t timeData,
                                                            uint16_t *uframeIndexOut)
{
    uint16_t uframeIntervalIndex;
    uint16_t uframeIndex;
    uint16_t frameIndex;
    uint8_t frameTimes[8];

    frameIndex = 0;
    USB_HostBandwidthHsHostComputeCurrentHsAll(
        ehciInstance, frameIndex, frameTimes); /* compute the allocated bandwidths in the frameIndex frame */
    for (uframeIntervalIndex = 0; (uframeIntervalIndex < uframeInterval); ++uframeIntervalIndex) /* start micro-frame */
    {
        /* for all the micro-frame in interval uframeInterval */
        for (uframeIndex = uframeIntervalIndex; uframeIndex < (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 8);
             uframeIndex += uframeInterval)
        {
            if (frameIndex != (uframeIndex >> 3))
            {
                frameIndex = (uframeIndex >> 3);
                USB_HostBandwidthHsHostComputeCurrentHsAll(
                    ehciInstance, frameIndex,
                    frameTimes); /* compute the allocated bandwidths in the new frameIndex frame */
            }
            if (frameTimes[uframeIndex & 0x0007] + timeData >
                s_SlotMaxBandwidthHs[(uframeIndex & 0x0007)]) /* micro-frame has enough idle bandwidth? */
            {
                break; /* fail */
            }
        }
        if (uframeIndex >= (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE * 8)) /* success? */
        {
            break;
        }
    }

    if (uframeIntervalIndex < uframeInterval)
    {
        *uframeIndexOut = (uframeIntervalIndex);
        return kStatus_USB_Success;
    }
    else
    {
        return kStatus_USB_Error;
    }
}

#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))

static usb_status_t USB_HostBandwidthHsHostAllocateIso(usb_host_ehci_instance_t *ehciInstance,
                                                       usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_status_t status;
    uint32_t deviceInfo;
    uint32_t hubNumber;
    uint16_t uframeIntervalIndex = 0;
    uint16_t frameIntervalIndex  = 0;
    uint16_t frameIndex;
    uint16_t timeCompleteSplit;
    uint16_t timeStartSplit;
    uint32_t timeData;
    uint8_t SsCsNumber = 0;
    uint16_t frameInterval;
    uint8_t frameTimes[8];
    uint8_t allocateOk = 1;
    uint8_t index;

    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed,
                                           &deviceInfo);

    timeData = USB_HostBandwidthComputeTime(
        deviceInfo, USB_ENDPOINT_ISOCHRONOUS, ehciPipePointer->pipeCommon.direction,
        ehciPipePointer->pipeCommon.maxPacketSize * ehciPipePointer->pipeCommon.numberPerUframe);
    /* pipe is high-speed */
    if (deviceInfo == USB_SPEED_HIGH)
    {
        uframeIntervalIndex = 0;
        status = USB_HostBandwidthHsHostAllocateHsCommon(ehciInstance, ehciPipePointer->uframeInterval, timeData,
                                                         &uframeIntervalIndex);
        if (status == kStatus_USB_Success)
        {
            ehciPipePointer->startFrame  = (uframeIntervalIndex / 8);
            ehciPipePointer->startUframe = (uframeIntervalIndex & 0x0007);
            ehciPipePointer->dataTime    = timeData;

            return kStatus_USB_Success;
        }
    }
    else /* pipe is full-speed or low-speed */
    {
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetHubThinkTime,
                                               &deviceInfo); /* deviceInfo variable means hub think time */
        timeData += (deviceInfo * 7 / (6 * 12));
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHSHubNumber,
                                               &hubNumber);
        frameInterval = ehciPipePointer->pipeCommon.interval;

        /* compute start-split and complete-split bandwidth */
        if (ehciPipePointer->pipeCommon.direction == USB_OUT)
        {
            timeStartSplit    = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_ISOCHRONOUS, USB_OUT,
                                                          ehciPipePointer->pipeCommon.maxPacketSize);
            timeCompleteSplit = 0;
        }
        else
        {
            timeStartSplit    = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_ISOCHRONOUS, USB_IN, 1);
            timeCompleteSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_ISOCHRONOUS, USB_IN,
                                                             ehciPipePointer->pipeCommon.maxPacketSize);
        }
        /* note: bandwidth must put in one frame */
        for (uframeIntervalIndex = 0; uframeIntervalIndex <= 5; ++uframeIntervalIndex) /* uframe interval */
        {
            for (frameIntervalIndex = 0; frameIntervalIndex < frameInterval; ++frameIntervalIndex) /* frame interval */
            {
                allocateOk = 1;
                for (frameIndex = frameIntervalIndex; frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE;
                     frameIndex += frameInterval) /* check all the frames */
                {
                    /* compute start-split and complete-split number */
                    SsCsNumber = (ehciPipePointer->pipeCommon.maxPacketSize + 187) /
                                 188; /* ss number for iso out; cs number for iso in */
                    if (ehciPipePointer->pipeCommon.direction == USB_OUT) /* ISO OUT */
                    {
                        if (uframeIntervalIndex + SsCsNumber > 8)
                        {
                            allocateOk = 0;
                        }
                    }
                    else
                    {
                        if (uframeIntervalIndex + 2 + SsCsNumber >
                            8) /* ISO IN: there are two micro-frame interval between start-split and complete-split */
                        {
                            allocateOk = 0;
                        }
                    }
                    if (allocateOk)
                    {
                        /* allocate start-split and complete-split bandwidth */
                        USB_HostBandwidthHsHostComputeCurrentHsAll(ehciInstance, frameIndex, frameTimes);
                        if (ehciPipePointer->pipeCommon.direction == USB_OUT) /* ISO OUT */
                        {
                            index = uframeIntervalIndex;
                            for (; index < (uframeIntervalIndex + SsCsNumber); ++index)
                            {
                                if (frameTimes[index] + timeStartSplit > s_SlotMaxBandwidthHs[index])
                                {
                                    allocateOk = 0;
                                    break;
                                }
                            }
                        }
                        else /* ISO IN */
                        {
                            index = uframeIntervalIndex;
                            if (frameTimes[index] + timeStartSplit > s_SlotMaxBandwidthHs[index])
                            {
                                allocateOk = 0;
                            }
                            if (allocateOk)
                            {
                                index =
                                    uframeIntervalIndex +
                                    2; /* there are two micro-frames interval between start-split and complete-split */
                                for (; index < (uframeIntervalIndex + 2 + SsCsNumber); ++index)
                                {
                                    if (frameTimes[index] + timeCompleteSplit > s_SlotMaxBandwidthHs[index])
                                    {
                                        allocateOk = 0;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    /* allocate data bandwidth */
                    if (allocateOk)
                    {
                        USB_HostBandwidthHsHostComputeCurrentFsls(ehciInstance, hubNumber, frameIndex, frameTimes);
                        index = uframeIntervalIndex + 1; /* timeData bandwidth start position */
                        /* iso must occupy all the uframe bandwidth */
                        {
                            deviceInfo = timeData; /* note: deviceInfo variable means bandwidth here */
                            while ((index < 8) && (deviceInfo > s_SlotMaxBandwidth[index]))
                            {
                                if (frameTimes[index] > 0)
                                {
                                    allocateOk = 0;
                                    break;
                                }
                                else
                                {
                                    deviceInfo -= s_SlotMaxBandwidth[index];
                                }
                                ++index;
                            }
                        }
                    }
                    if (allocateOk)
                    {
                        /* data bandwidth can be put in the frame? */
                        index = uframeIntervalIndex + 1; /* timeData bandwidth start position */
                        frameTimes[index] += timeData;
                        for (; index < 7; ++index)
                        {
                            if (frameTimes[index] > s_SlotMaxBandwidth[index])
                            {
                                frameTimes[index + 1] += (frameTimes[index] - s_SlotMaxBandwidth[index]);
                                frameTimes[index] = s_SlotMaxBandwidth[index];
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (frameTimes[index] > s_SlotMaxBandwidth[index])
                        {
                            allocateOk = 0;
                        }
                    }

                    if (allocateOk)
                    {
                        break;
                    }
                }
                if (allocateOk)
                {
                    break;
                }
            }
            if (allocateOk)
            {
                break;
            }
        }

        if (allocateOk)
        {
            ehciPipePointer->startFrame        = frameIntervalIndex;
            ehciPipePointer->startUframe       = uframeIntervalIndex;
            ehciPipePointer->dataTime          = timeData;
            ehciPipePointer->startSplitTime    = timeStartSplit;
            ehciPipePointer->completeSplitTime = timeCompleteSplit;
            if (ehciPipePointer->pipeCommon.direction == USB_OUT)
            {
                index = uframeIntervalIndex;
                for (; index < (uframeIntervalIndex + SsCsNumber); ++index)
                {
                    ehciPipePointer->uframeSmask = (uint32_t)ehciPipePointer->uframeSmask | (uint32_t)(0x01 << index);
                }
            }
            else
            {
                index                        = uframeIntervalIndex;
                ehciPipePointer->uframeSmask = (uint32_t)ehciPipePointer->uframeSmask | (uint32_t)(0x01 << index);
                index                        = uframeIntervalIndex + 2;
                for (; index < (uframeIntervalIndex + 2 + SsCsNumber); ++index)
                {
                    ehciPipePointer->uframeCmask = (uint32_t)ehciPipePointer->uframeCmask | (uint32_t)(0x01 << index);
                }
            }

            return kStatus_USB_Success;
        }
    }

    return kStatus_USB_Error;
}

#endif

static usb_status_t USB_HostBandwidthHsHostAllocateInterrupt(usb_host_ehci_instance_t *ehciInstance,
                                                             usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_status_t status;
    uint32_t deviceInfo;
    uint32_t hubNumber;
    uint16_t uframeIntervalIndex = 0;
    uint16_t frameIntervalIndex  = 0;
    uint16_t frameIndex;
    uint16_t timeCompleteSplit;
    uint16_t timeStartSplit;
    uint32_t timeData;
    uint8_t SsCsNumber;
    uint16_t frameInterval;
    uint8_t frameTimes[8];
    uint8_t allocateOk = 1;
    uint8_t index;

    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed,
                                           &deviceInfo);

    timeData = USB_HostBandwidthComputeTime(
        deviceInfo, USB_ENDPOINT_INTERRUPT, ehciPipePointer->pipeCommon.direction,
        ehciPipePointer->pipeCommon.maxPacketSize * ehciPipePointer->pipeCommon.numberPerUframe);
    /* pipe is high-speed */
    if (deviceInfo == USB_SPEED_HIGH)
    {
        uframeIntervalIndex = 0;
        status = USB_HostBandwidthHsHostAllocateHsCommon(ehciInstance, ehciPipePointer->uframeInterval, timeData,
                                                         &uframeIntervalIndex);
        if (status == kStatus_USB_Success)
        {
            ehciPipePointer->startFrame  = (uframeIntervalIndex / 8);
            ehciPipePointer->startUframe = (uframeIntervalIndex & 0x0007);
            /* for HS interrupt start transaction position */
            if (ehciPipePointer->uframeInterval >= 8)
            {
                ehciPipePointer->uframeSmask = (0x01 << ehciPipePointer->startUframe);
            }
            else
            {
                ehciPipePointer->uframeSmask = 0x00u;
                for (index = ehciPipePointer->startUframe; index < 8; index += ehciPipePointer->uframeInterval)
                {
                    ehciPipePointer->uframeSmask |= (0x01U << index);
                }
            }
            ehciPipePointer->dataTime = timeData;

            return kStatus_USB_Success;
        }
    }
    else /* pipe is full-speed or low-speed */
    {
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetHubThinkTime,
                                               &deviceInfo);
        timeData += (deviceInfo * 7 / (6 * 12));
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHSHubNumber,
                                               &hubNumber);
        frameInterval = ehciPipePointer->pipeCommon.interval;
        SsCsNumber    = 3; /* complete split number */

        /* compute start-split and complete-split bandwidth */
        if (ehciPipePointer->pipeCommon.direction == USB_OUT)
        {
            timeStartSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_OUT,
                                                          ehciPipePointer->pipeCommon.maxPacketSize) +
                             USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_OUT, 1);
            timeCompleteSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_OUT, 0);
        }
        else
        {
            timeStartSplit    = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_IN, 1);
            timeCompleteSplit = USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_IN,
                                                             ehciPipePointer->pipeCommon.maxPacketSize) +
                                USB_HostBandwidthComputeTime(USB_SPEED_HIGH, USB_ENDPOINT_INTERRUPT, USB_IN, 0);
        }
        /* note: bandwidth must put in one frame */
        for (uframeIntervalIndex = 0; uframeIntervalIndex <= 4; ++uframeIntervalIndex) /* uframe interval */
        {
            for (frameIntervalIndex = 0; frameIntervalIndex < frameInterval; ++frameIntervalIndex) /* frame interval */
            {
                allocateOk = 1;
                for (frameIndex = frameIntervalIndex; frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE;
                     frameIndex += frameInterval) /* check all the frames */
                {
                    /* allocate data bandwidth */
                    USB_HostBandwidthHsHostComputeCurrentFsls(ehciInstance, hubNumber, frameIndex, frameTimes);
                    index = uframeIntervalIndex + 1;
                    for (; index <= (uframeIntervalIndex + 3); ++index) /* data bandwidth number is 3.
                                                                             uframeIntervalIndex don't exceed 4, so
                                                                             index cannot exceed 7 */
                    {
                        if (frameTimes[index] + timeData > s_SlotMaxBandwidth[index])
                        {
                            allocateOk = 0;
                            break;
                        }
                    }

                    if (allocateOk)
                    {
                        USB_HostBandwidthHsHostComputeCurrentHsAll(ehciInstance, frameIndex, frameTimes);
                        /* allocate start_split bandwidth */
                        if (frameTimes[uframeIntervalIndex] + timeStartSplit >
                            s_SlotMaxBandwidthHs[uframeIntervalIndex])
                        {
                            allocateOk = 0;
                        }
                        if (allocateOk)
                        {
                            /* allocate complete_split bandwidth */
                            index = uframeIntervalIndex + 2;
                            /* complete-split number is normal 3. When uframeIntervalIndex is 4, complete-split number
                             * is 2. */
                            for (; (index <= (uframeIntervalIndex + 1 + SsCsNumber)) && (index < 8); ++index)
                            {
                                if (frameTimes[index] + timeCompleteSplit > s_SlotMaxBandwidthHs[index])
                                {
                                    allocateOk = 0;
                                    break;
                                }
                            }
                        }
                    }

                    if (!allocateOk)
                    {
                        break; /* allocate fail */
                    }
                }
                if (allocateOk)
                {
                    break;
                }
            }
            if (allocateOk)
            {
                break;
            }
        }

        if (allocateOk)
        {
            ehciPipePointer->startFrame  = frameIntervalIndex;
            ehciPipePointer->startUframe = uframeIntervalIndex;
            ehciPipePointer->uframeSmask = (0x01 << ehciPipePointer->startUframe);
            ehciPipePointer->uframeCmask = 0;
            index                        = uframeIntervalIndex + 2;
            for (; (index <= (uframeIntervalIndex + 1 + SsCsNumber)) && (index < 8); ++index)
            {
                ehciPipePointer->uframeCmask = (uint32_t)ehciPipePointer->uframeCmask | (uint32_t)(0x01 << index);
            }
            ehciPipePointer->dataTime          = timeData;
            ehciPipePointer->startSplitTime    = timeStartSplit;
            ehciPipePointer->completeSplitTime = timeCompleteSplit;

            return kStatus_USB_Success;
        }
    }

    return kStatus_USB_BandwidthFail;
}

static usb_status_t USB_HostBandwidthFslsHostAllocate(usb_host_ehci_instance_t *ehciInstance,
                                                      usb_host_ehci_pipe_t *ehciPipePointer)
{
    uint32_t FslsTime = 0;
    uint32_t speed    = 0;
    uint16_t uframeIntervalIndex;
    uint16_t frameIndex;
    uint16_t frameInterval;
    uint16_t frameTime;

    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetHubThinkTime,
                                           &FslsTime);
    FslsTime += (FslsTime * 7 / (6 * 12));
    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, &speed);
    FslsTime = FslsTime + USB_HostBandwidthComputeTime(speed, ehciPipePointer->pipeCommon.pipeType,
                                                       ehciPipePointer->pipeCommon.direction,
                                                       ehciPipePointer->pipeCommon.maxPacketSize);

    frameInterval = ehciPipePointer->pipeCommon.interval;
    for (uframeIntervalIndex = 0; uframeIntervalIndex < ehciPipePointer->uframeInterval;
         ++uframeIntervalIndex) /* uframeIntervalIndex can exceed 8 */
    {
        for (frameIndex = (uframeIntervalIndex >> 3); frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE;
             frameIndex += frameInterval)
        {
            USB_HostBandwidthFslsHostComputeCurrent(ehciInstance, frameIndex, &frameTime);
            if (frameTime + FslsTime > USB_HOST_EHCI_BANDWIDTH_FRAME_TOTOAL_TIME)
            {
                break;
            }
        }
        if (frameIndex >= USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE)
        {
            break;
        }
    }
    if (uframeIntervalIndex < ehciPipePointer->uframeInterval)
    {
        ehciPipePointer->startFrame  = (uframeIntervalIndex >> 3);
        ehciPipePointer->startUframe = (uframeIntervalIndex & 0x0007);
        ehciPipePointer->uframeSmask = 0; /* useless */
        ehciPipePointer->uframeCmask = 0;
        ehciPipePointer->dataTime    = FslsTime;

        return kStatus_USB_Success;
    }

    return kStatus_USB_BandwidthFail;
}

static uint8_t USB_HostEhciGet2PowerValue(uint8_t value)
{
    if ((value == 0) || (value == 1))
    {
        return value;
    }
    if (value & 0xf0)
    {
        if (value & 0x80)
        {
            return 128;
        }
        else if (value & 0x40)
        {
            return 64;
        }
        else if (value & 0x20)
        {
            return 32;
        }
        else
        {
            return 16;
        }
    }
    else
    {
        if (value & 0x08)
        {
            return 8;
        }
        else if (value & 0x04)
        {
            return 4;
        }
        else if (value & 0x02)
        {
            return 2;
        }
        else
        {
            return 1;
        }
    }
}

static void USB_HostEhciZeroMem(uint32_t *buffer, uint32_t length)
{
    /* note: the zero unit is uint32_t */
    while (length--)
    {
        *buffer = 0;
        buffer++;
    }
}

static void USB_HostEhciDelay(USBHS_Type *ehciIpBase, uint32_t ms)
{
    /* note: the max delay time cannot exceed half of max value (0x4000) */
    int32_t sofStart;
    int32_t SofEnd;
    uint32_t distance;

    sofStart = (int32_t)(ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE);

    do
    {
        SofEnd   = (int32_t)(ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE);
        distance = (uint32_t)(SofEnd - sofStart + EHCI_MAX_UFRAME_VALUE + 1);
    } while ((distance & EHCI_MAX_UFRAME_VALUE) < (ms * 8)); /* compute the distance between sofStart and SofEnd */
}

static void USB_HostEhciStartAsync(usb_host_ehci_instance_t *ehciInstance)
{
    uint32_t stateSync;

    if (!(ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK))
    {
        /* the status must be same when change USBCMD->ASE */
        do
        {
            stateSync = ((ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK) |
                         (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_ASE_MASK));
        } while ((stateSync == USBHS_USBSTS_AS_MASK) || (stateSync == USBHS_USBCMD_ASE_MASK));

        ehciInstance->ehciIpBase->ASYNCLISTADDR = (uint32_t)(ehciInstance->shedFirstQh);
        ehciInstance->ehciIpBase->USBCMD |= USBHS_USBCMD_ASE_MASK;
        while (!(ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK))
        {
        }
    }
}

static void USB_HostEhciStopAsync(usb_host_ehci_instance_t *ehciInstance)
{
    uint32_t stateSync;

    /* the status must be same when change USBCMD->ASE */
    do
    {
        stateSync = ((ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK) |
                     (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_ASE_MASK));
    } while ((stateSync == USBHS_USBSTS_AS_MASK) || (stateSync == USBHS_USBCMD_ASE_MASK));

    ehciInstance->ehciIpBase->USBCMD &= (uint32_t)(~(uint32_t)USBHS_USBCMD_ASE_MASK); /* disable async schedule */
    while (ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK)
    {
    }
}

static void USB_HostEhciStartPeriodic(usb_host_ehci_instance_t *ehciInstance)
{
    uint32_t stateSync;

    if (!(ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK))
    {
        /* the status must be same when change USBCMD->PSE */
        do
        {
            stateSync = ((ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK) |
                         (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_PSE_MASK));
        } while ((stateSync == USBHS_USBSTS_PS_MASK) || (stateSync == USBHS_USBCMD_PSE_MASK));
        ehciInstance->ehciIpBase->PERIODICLISTBASE = (uint32_t)(ehciInstance->ehciFrameList);
        if (!(ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_PSE_MASK))
        {
            ehciInstance->ehciIpBase->USBCMD |= USBHS_USBCMD_PSE_MASK; /* start periodic schedule */
        }
        while (!(ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK))
        {
        }
    }
    return;
}

static void USB_HostEhciStopPeriodic(usb_host_ehci_instance_t *ehciInstance)
{
    uint32_t stateSync;

    /* the status must be same when change USBCMD->PSE */
    do
    {
        stateSync = ((ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK) |
                     (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_PSE_MASK));
    } while ((stateSync == USBHS_USBSTS_PS_MASK) || (stateSync == USBHS_USBCMD_PSE_MASK));

    ehciInstance->ehciIpBase->USBCMD &= (~USBHS_USBCMD_PSE_MASK); /* stop periodic schedule */
    while (ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_PS_MASK)
    {
    }
}

static usb_status_t USB_HostEhciQhQtdListInit(usb_host_ehci_instance_t *ehciInstance,
                                              usb_host_ehci_pipe_t *ehciPipePointer,
                                              usb_host_transfer_t *transfer)
{
    volatile usb_host_ehci_qh_t *vltQhPointer;
    usb_host_ehci_qtd_t *qtdPointer     = NULL;
    usb_host_ehci_qtd_t *BaseQtdPointer = NULL;
    volatile uint32_t *entryPointer;
    uint32_t qtdNumber;
    uint32_t dataLength;
    uint32_t dataAddress;
    uint32_t endAddress;
    uint8_t index;

    /* compute the qtd number */
    if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_CONTROL)
    {
        /* assume setup data don't exceed one qtd data size, one qtd can transfer least 16k data */
        if (transfer->transferLength == 0)
        {
            qtdNumber = 2;
        }
        else
        {
            qtdNumber = 3;
        }
    }
    else
    {
        qtdNumber =
            (((transfer->transferLength) & 0xFFFFC000U) >> 14) + (((transfer->transferLength) & 0x00003FFF) ? 1 : 0);
    }

    vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;
    /* get qtd list */
    USB_HostEhciLock();
    if (qtdNumber <= ehciInstance->ehciQtdNumber)
    {
        ehciInstance->ehciQtdNumber -= qtdNumber;
        BaseQtdPointer = ehciInstance->ehciQtdHead;
        qtdPointer     = NULL;
        do
        {
            if (qtdPointer != NULL)
            {
                qtdPointer->nextQtdPointer = (uint32_t)ehciInstance->ehciQtdHead;
            }
            qtdPointer                 = ehciInstance->ehciQtdHead;
            ehciInstance->ehciQtdHead  = (usb_host_ehci_qtd_t *)qtdPointer->nextQtdPointer;
            qtdPointer->nextQtdPointer = 0;
        } while (--qtdNumber);
        if (ehciInstance->ehciQtdNumber == 0)
        {
            ehciInstance->ehciQtdTail = NULL;
        }
    }
    else
    {
        USB_HostEhciUnlock();
        return kStatus_USB_Error;
    }
    USB_HostEhciUnlock();

    /* int qTD list */
    if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_CONTROL)
    {
        /* setup transaction qtd */
        qtdPointer                          = BaseQtdPointer;
        qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
        /* dt: need set; ioc: 0; C_Page: 0; PID Code: SETUP; Status: Active */
        qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0;
        qtdPointer->transferResults[0] =
            ((0x00000000 << EHCI_HOST_QTD_DT_SHIFT) | (8 << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) |
             (EHCI_HOST_PID_SETUP << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));
        dataAddress                    = ((uint32_t)transfer->setupPacket);
        qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */
        /* set buffer pointer no matter data length */
        for (index = 0; index < 4; ++index)
        {
            qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000U);
        }

        /* data transaction qtd */
        dataLength = transfer->transferLength;
        if (dataLength != 0)
        {
            qtdPointer = (usb_host_ehci_qtd_t *)(qtdPointer->nextQtdPointer);

            qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
            /* dt: need set; ioc: 0; C_Page: 0; PID Code: IN/OUT; Status: Active */
            qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0;
            if (transfer->direction == USB_OUT)
            {
                qtdPointer->transferResults[0] =
                    ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (dataLength << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) |
                     (EHCI_HOST_PID_OUT << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));
            }
            else
            {
                qtdPointer->transferResults[0] =
                    ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (dataLength << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) |
                     (EHCI_HOST_PID_IN << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));
            }

            dataAddress                    = (uint32_t)transfer->transferBuffer;
            qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */
            /* set buffer pointer no matter data length */
            for (index = 0; index < 4; ++index)
            {
                qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000U);
            }
        }

        /* status transaction qtd */
        qtdPointer                          = (usb_host_ehci_qtd_t *)(qtdPointer->nextQtdPointer);
        qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
        /* dt: dont care; ioc: 1; C_Page: 0; PID Code: IN/OUT; Status: Active */
        qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0;
        if ((dataLength == 0) || (transfer->direction == USB_OUT))
        {
            qtdPointer->transferResults[0] =
                ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (EHCI_HOST_PID_IN << EHCI_HOST_QTD_PID_CODE_SHIFT) |
                 (EHCI_HOST_QTD_IOC_MASK) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));
        }
        else
        {
            qtdPointer->transferResults[0] =
                ((0x00000001U << EHCI_HOST_QTD_DT_SHIFT) | (EHCI_HOST_PID_OUT << EHCI_HOST_QTD_PID_CODE_SHIFT) |
                 (EHCI_HOST_QTD_IOC_MASK) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));
        }
        qtdPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE;
    }
    else
    {
        dataLength  = transfer->transferLength;
        dataAddress = (uint32_t)transfer->transferBuffer;
        qtdPointer  = BaseQtdPointer;
        while (1)
        {
            endAddress = dataAddress + (16 * 1024);
            if (endAddress > (uint32_t)(transfer->transferBuffer + transfer->transferLength))
            {
                endAddress = (uint32_t)(transfer->transferBuffer + transfer->transferLength);
            }

            qtdPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
            /* dt: set; ioc: 0; C_Page: 0; PID Code: IN/OUT; Status: Active */
            qtdPointer->transferResults[0] = qtdPointer->transferResults[1] = 0;
            if (transfer->direction == USB_OUT)
            {
                qtdPointer->transferResults[0] =
                    (((endAddress - dataAddress) << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) |
                     ((uint32_t)ehciPipePointer->pipeCommon.nextdata01 << EHCI_HOST_QTD_DT_SHIFT) |
                     (EHCI_HOST_QTD_CERR_MAX_VALUE << EHCI_HOST_QTD_CERR_SHIFT) |
                     (EHCI_HOST_PID_OUT << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));
            }
            else
            {
                qtdPointer->transferResults[0] =
                    (((endAddress - dataAddress) << EHCI_HOST_QTD_TOTAL_BYTES_SHIFT) |
                     ((uint32_t)ehciPipePointer->pipeCommon.nextdata01 << EHCI_HOST_QTD_DT_SHIFT) |
                     (EHCI_HOST_QTD_CERR_MAX_VALUE << EHCI_HOST_QTD_CERR_SHIFT) |
                     (EHCI_HOST_PID_IN << EHCI_HOST_QTD_PID_CODE_SHIFT) | (EHCI_HOST_QTD_STATUS_ACTIVE_MASK));
            }
            qtdPointer->transferResults[1] = dataAddress; /* current offset is set too */
            /* set buffer pointer no matter data length */
            for (index = 0; index < 4; ++index)
            {
                qtdPointer->bufferPointers[index] = ((dataAddress + (index + 1) * 4 * 1024) & 0xFFFFF000U);
            }
            dataAddress = endAddress; /* for next qtd */

            if (qtdPointer->nextQtdPointer == 0)
            {
                break;
            }
            qtdPointer = (usb_host_ehci_qtd_t *)(qtdPointer->nextQtdPointer);
        }

        qtdPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE;
        qtdPointer->transferResults[0] |= EHCI_HOST_QTD_IOC_MASK; /* last one set IOC */
    }

    /* save qtd to transfer */
    transfer->union1.unitHead = (uint32_t)BaseQtdPointer;
    transfer->union2.unitTail = (uint32_t)qtdPointer;
    /* link transfer to qh */
    transfer->next = NULL;
    if (vltQhPointer->ehciTransferHead == NULL)
    {
        transfer->next                 = NULL;
        vltQhPointer->ehciTransferHead = vltQhPointer->ehciTransferTail = transfer;
    }
    else
    {
        transfer->next                       = NULL;
        vltQhPointer->ehciTransferTail->next = transfer;
        vltQhPointer->ehciTransferTail       = transfer;
    }

    USB_HostEhciLock();
    /* link qtd to qh (link to end) */
    entryPointer = &(vltQhPointer->nextQtdPointer);
    dataAddress  = *entryPointer; /* dataAddress variable means entry value here */
    while ((dataAddress) && (!(dataAddress & EHCI_HOST_T_INVALID_VALUE)))
    {
        entryPointer = (volatile uint32_t *)dataAddress;
        dataAddress  = *entryPointer;
    }
    *entryPointer = (uint32_t)BaseQtdPointer;
    USB_HostEhciUnlock();
    USB_HostEhciStartAsync(ehciInstance);

    return kStatus_USB_Success;
}

static uint32_t USB_HostEhciQtdListRelease(usb_host_ehci_instance_t *ehciInstance,
                                           usb_host_ehci_qtd_t *ehciQtdStart,
                                           usb_host_ehci_qtd_t *ehciQtdEnd)
{
    uint32_t length = 0;
    usb_host_ehci_qtd_t *qtdPointer;

    ehciQtdEnd->nextQtdPointer = 0;

    /* compute remaining length */
    qtdPointer = ehciQtdStart;
    while (qtdPointer != ehciQtdEnd)
    {
        length +=
            ((qtdPointer->transferResults[0] & EHCI_HOST_QTD_TOTAL_BYTES_MASK) >> EHCI_HOST_QTD_TOTAL_BYTES_SHIFT);
        qtdPointer = (usb_host_ehci_qtd_t *)qtdPointer->nextQtdPointer;
    }
    qtdPointer = ehciQtdEnd;
    length += ((qtdPointer->transferResults[0] & EHCI_HOST_QTD_TOTAL_BYTES_MASK) >> EHCI_HOST_QTD_TOTAL_BYTES_SHIFT);

    /* put releasing qtd to idle qtd list */
    USB_HostEhciLock();
    if (ehciInstance->ehciQtdNumber == 0)
    {
        ehciInstance->ehciQtdHead = ehciQtdStart;
        ehciInstance->ehciQtdTail = ehciQtdEnd;
    }
    else
    {
        ehciInstance->ehciQtdTail->nextQtdPointer = (uint32_t)ehciQtdStart;
        ehciInstance->ehciQtdTail                 = ehciQtdEnd;
    }

    while (ehciQtdStart != ehciQtdEnd)
    {
        ehciInstance->ehciQtdNumber++;
        ehciQtdStart = (usb_host_ehci_qtd_t *)ehciQtdStart->nextQtdPointer;
    }
    ehciInstance->ehciQtdNumber++;
    USB_HostEhciUnlock();

    return length;
}

static usb_status_t USB_HostEhciQhQtdListDeinit(usb_host_ehci_instance_t *ehciInstance,
                                                usb_host_ehci_pipe_t *ehciPipePointer)
{
    volatile usb_host_ehci_qh_t *vltQhPointer;
    usb_host_transfer_t *transfer;
    usb_host_transfer_t *nextTransfer;
    uint8_t needStop = 0;

    vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;

    USB_HostEhciLock(); /* this API is called from APP, the host task may occupy to access the same resource */
    /* remove qtd from qh */
    if ((!((uint32_t)vltQhPointer->nextQtdPointer & EHCI_HOST_T_INVALID_VALUE)) ||
        (!((uint32_t)vltQhPointer->currentQtdPointer & EHCI_HOST_T_INVALID_VALUE)))
    {
        /* need stop async schedule */
        if ((!(vltQhPointer->horizontalLinkPointer & EHCI_HOST_T_INVALID_VALUE)) &&
            (ehciPipePointer->pipeCommon.pipeType != USB_ENDPOINT_INTERRUPT))
        {
            needStop = 1;
        }
        if (needStop)
        {
            USB_HostEhciStopAsync(ehciInstance);
        }
        vltQhPointer->currentQtdPointer = EHCI_HOST_T_INVALID_VALUE;             /* invalid current qtd */
        vltQhPointer->nextQtdPointer    = EHCI_HOST_T_INVALID_VALUE;             /* invalid next qtd */
        vltQhPointer->transferOverlayResults[0] &= (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */
        if (needStop)
        {
            USB_HostEhciStartAsync(ehciInstance);
        }
    }

    /* remove transfer from the QH transfer list */
    transfer                       = vltQhPointer->ehciTransferHead;
    vltQhPointer->ehciTransferHead = vltQhPointer->ehciTransferTail = NULL;
    USB_HostEhciUnlock();

    /* release qtd  and transfer callback*/
    while (transfer != NULL)
    {
        nextTransfer = transfer->next; /* the transfer is released when call back */
        transfer->transferSofar =
            USB_HostEhciQtdListRelease(ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead),
                                       (usb_host_ehci_qtd_t *)(transfer->union2.unitTail));
        transfer->transferSofar = (transfer->transferLength < transfer->transferSofar) ?
                                      0 :
                                      (transfer->transferLength - transfer->transferSofar);
        /* callback function is different from the current condition */
        transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferCancel);
        transfer = nextTransfer;
    }

    return kStatus_USB_Success;
}

static usb_status_t USB_HostEhciTransferQtdListDeinit(usb_host_ehci_instance_t *ehciInstance,
                                                      usb_host_ehci_pipe_t *ehciPipePointer,
                                                      usb_host_transfer_t *transfer)
{
    volatile usb_host_ehci_qh_t *vltQhPointer;
    usb_host_transfer_t *preSearchTransfer;
    uint32_t qhNextQtdValue;
    uint32_t qtdPointerEntry;
    uint32_t *searchQtdEntryPointer;

    vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;

    USB_HostEhciLock(); /* this API is called from APP, the host task may occupy to access the same resource */
    /* remove qtd from qh */
    qhNextQtdValue  = (uint32_t)vltQhPointer->currentQtdPointer;
    qtdPointerEntry = *((uint32_t *)qhNextQtdValue + 2); /* note: qtdPointerEntry means qtd status */
    if ((qhNextQtdValue & EHCI_HOST_T_INVALID_VALUE) || (!(qtdPointerEntry & EHCI_HOST_QTD_STATUS_ACTIVE_MASK)))
    {
        qhNextQtdValue = (uint32_t)vltQhPointer->nextQtdPointer;
    }
    if (!(qhNextQtdValue & EHCI_HOST_T_INVALID_VALUE)) /* there is pending qtd in the qh */
    {
        /* this qh don't schedule temporarily */
        if (ehciPipePointer->pipeCommon.pipeType != USB_ENDPOINT_INTERRUPT)
        {
            USB_HostEhciStopAsync(ehciInstance);
        }
        vltQhPointer->currentQtdPointer |= EHCI_HOST_T_INVALID_VALUE; /* invalid current qtd */
        vltQhPointer->nextQtdPointer |= EHCI_HOST_T_INVALID_VALUE;    /* invalid next qtd */
        if (ehciPipePointer->pipeCommon.pipeType != USB_ENDPOINT_INTERRUPT)
        {
            USB_HostEhciStartAsync(ehciInstance);
        }

        /* remove qtd from qh one by one */
        qtdPointerEntry = transfer->union1.unitHead;
        while (1)
        {
            /* search qh's qtd list for qtdPointerEntry */
            searchQtdEntryPointer = &qhNextQtdValue;
            while (!((*searchQtdEntryPointer) & EHCI_HOST_T_INVALID_VALUE))
            {
                if ((*searchQtdEntryPointer) == qtdPointerEntry)
                {
                    *searchQtdEntryPointer = *((uint32_t *)qtdPointerEntry); /* remove the qtd from qh */
                    break;
                }
                else
                {
                    searchQtdEntryPointer = (uint32_t *)(*searchQtdEntryPointer);
                }
            }
            if (qtdPointerEntry == transfer->union2.unitTail)
            {
                break;
            }
            qtdPointerEntry = *((uint32_t *)qtdPointerEntry);
        }
    }

    /* remove transfer from the QH transfer list */
    preSearchTransfer = vltQhPointer->ehciTransferHead;
    if (preSearchTransfer == transfer)
    {
        vltQhPointer->ehciTransferHead = preSearchTransfer->next;
    }
    else
    {
        while (preSearchTransfer != NULL)
        {
            if (preSearchTransfer->next == transfer)
            {
                preSearchTransfer->next = transfer->next;
                break;
            }
            else
            {
                preSearchTransfer = preSearchTransfer->next;
            }
        }
    }
    USB_HostEhciUnlock();

    /* release qtd and callback */
    transfer->transferSofar =
        USB_HostEhciQtdListRelease(ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead),
                                   (usb_host_ehci_qtd_t *)(transfer->union2.unitTail));
    transfer->transferSofar =
        (transfer->transferLength < transfer->transferSofar) ? 0 : (transfer->transferLength - transfer->transferSofar);
    /* callback function is different from the current condition */
    transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferCancel);

    /* start this qh schedule */
    vltQhPointer->transferOverlayResults[0] &= (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */
    if ((qhNextQtdValue != 0) && (!(qhNextQtdValue & EHCI_HOST_T_INVALID_VALUE)))
    {
        vltQhPointer->nextQtdPointer = qhNextQtdValue;
    }

    return kStatus_USB_Success;
}

static usb_status_t USB_HostEhciQhInit(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_host_ehci_qh_t *qhPointer = NULL;
    uint32_t address, speed, portNumber, hubNumber;
    uint32_t controlBits1 = 0;
    uint32_t controlBits2 = 0;
    /* get qh */
    USB_HostEhciLock();
    if (ehciInstance->ehciQhList != NULL)
    {
        qhPointer = (usb_host_ehci_qh_t *)ehciInstance->ehciQhList;
        ehciInstance->ehciQhList =
            (usb_host_ehci_qh_t *)(ehciInstance->ehciQhList->horizontalLinkPointer & EHCI_HOST_POINTER_ADDRESS_MASK);
    }
    USB_HostEhciUnlock();
    if (qhPointer == NULL)
    {
#ifdef HOST_EHCO
        usb_echo("get qh error\r\n");
#endif
        return kStatus_USB_Error;
    }
    ehciPipePointer->ehciQh = (void *)qhPointer;

    /* initialize qh */
    USB_HostEhciZeroMem((uint32_t *)qhPointer, sizeof(usb_host_ehci_qh_t) / 4);
    qhPointer->horizontalLinkPointer   = EHCI_HOST_T_INVALID_VALUE;
    qhPointer->currentQtdPointer       = EHCI_HOST_T_INVALID_VALUE;
    qhPointer->nextQtdPointer          = EHCI_HOST_T_INVALID_VALUE;
    qhPointer->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
    qhPointer->ehciPipePointer         = ehciPipePointer;
    qhPointer->timeOutLabel            = 0;
    qhPointer->timeOutValue            = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE;
    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, &speed);
    /* initialize staticEndpointStates[0] */
    if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT)
    {
        /* Software should set the RL field to zero if the queue head is an interrupt endpoint. */
        controlBits1 |= ((0U << EHCI_HOST_QH_RL_SHIFT) & EHCI_HOST_QH_RL_MASK);
    }
    else
    {
        if (ehciPipePointer->pipeCommon.nakCount >= 16)
        {
            controlBits1 |= ((15U << EHCI_HOST_QH_RL_SHIFT) & EHCI_HOST_QH_RL_MASK);
        }
        else
        {
            controlBits1 |=
                (((uint32_t)ehciPipePointer->pipeCommon.nakCount << EHCI_HOST_QH_RL_SHIFT) & EHCI_HOST_QH_RL_MASK);
        }
    }
    if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_CONTROL)
    {
        if (speed != USB_SPEED_HIGH)
        {
            controlBits1 |= (1 << EHCI_HOST_QH_C_SHIFT);
        }
        controlBits1 |= (1 << EHCI_HOST_QH_DTC_SHIFT);
    }
    controlBits1 |= ((uint32_t)ehciPipePointer->pipeCommon.maxPacketSize << EHCI_HOST_QH_MAX_PACKET_LENGTH_SHIFT);
    controlBits1 |= (speed << EHCI_HOST_QH_EPS_SHIFT);
    controlBits1 |= ((uint32_t)ehciPipePointer->pipeCommon.endpointAddress << EHCI_HOST_QH_ENDPT_SHIFT);
    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress,
                                           &address);
    controlBits1 |= (address << EHCI_HOST_QH_DEVICE_ADDRESS_SHIFT);
    qhPointer->staticEndpointStates[0] = controlBits1;
    if (speed == USB_SPEED_HIGH)
    {
        controlBits2 |= ((uint32_t)ehciPipePointer->pipeCommon.numberPerUframe << EHCI_HOST_QH_MULT_SHIFT);
    }
    else
    {
        controlBits2 |= (0x00000001U << EHCI_HOST_QH_MULT_SHIFT);
    }
    /*initialize staticEndpointStates[1] */
    if (speed != USB_SPEED_HIGH)
    {
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHSHubNumber,
                                               &hubNumber);
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHSHubPort,
                                               &portNumber);
    }
    else
    {
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHubNumber,
                                               &hubNumber);
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDevicePortNumber,
                                               &portNumber);
    }
    controlBits2 |= (portNumber << EHCI_HOST_QH_PORT_NUMBER_SHIFT);
    controlBits2 |= (hubNumber << EHCI_HOST_QH_HUB_ADDR_SHIFT);
    controlBits2 |= ((uint32_t)ehciPipePointer->uframeCmask << EHCI_HOST_QH_UFRAME_CMASK_SHIFT);
    controlBits2 |= ((uint32_t)ehciPipePointer->uframeSmask << EHCI_HOST_QH_UFRAME_SMASK_SHIFT);
    qhPointer->staticEndpointStates[1] = controlBits2;

    return kStatus_USB_Success;
}

static usb_status_t USB_HostEhciQhDeinit(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_host_ehci_qh_t *qhPointer;

    qhPointer = (usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;
    /* de-initialize qtd from qh */
    USB_HostEhciQhQtdListDeinit(ehciInstance, ehciPipePointer);

    /* release QH */
    USB_HostEhciLock();
    qhPointer->horizontalLinkPointer = (uint32_t)ehciInstance->ehciQhList;
    ehciInstance->ehciQhList         = qhPointer;
    USB_HostEhciUnlock();

    return kStatus_USB_Success;
}

static void USB_HostEhciAddQhToFrame(usb_host_ehci_instance_t *ehciInstance,
                                     uint32_t entryPointerValue,
                                     uint16_t framePos,
                                     uint16_t uframeInterval)
{
    volatile uint32_t *frameEntryPointer;
    uint32_t frameEntryValue;

    /* search for the inserting point by interval */
    frameEntryPointer = (volatile uint32_t *)(&((uint32_t *)ehciInstance->ehciFrameList)[framePos]);
    while (frameEntryPointer)
    {
        frameEntryValue = *frameEntryPointer;
        if (frameEntryValue & EHCI_HOST_T_INVALID_VALUE)
        {
            /* insert into the end */
            *((uint32_t *)entryPointerValue) = EHCI_HOST_T_INVALID_VALUE;
            *frameEntryPointer               = (entryPointerValue | EHCI_HOST_POINTER_TYPE_QH);
            break;
        }

        if ((frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK) == entryPointerValue)
        {
            return; /* has inserted */
        }
        if (((frameEntryValue & EHCI_HOST_POINTER_TYPE_MASK) == EHCI_HOST_POINTER_TYPE_QH) &&
            (((usb_host_ehci_qh_t *)(frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK))
                 ->ehciPipePointer->uframeInterval <= uframeInterval))
        {
            /* insert into this point */
            *((uint32_t *)entryPointerValue) = frameEntryValue;
            *frameEntryPointer               = (entryPointerValue | EHCI_HOST_POINTER_TYPE_QH);
            return;
        }
        else
        {
            frameEntryPointer = (volatile uint32_t *)(frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK);
        }
    }
}

static void USB_HostEhciRemoveFromFrame(usb_host_ehci_instance_t *ehciInstance,
                                        uint32_t entryPointerValue,
                                        uint16_t framePos)
{
    volatile uint32_t *frameEntryPointer;
    uint32_t frameEntryValue;

    /* search for the qh/itd/sitd entry */
    frameEntryPointer = (volatile uint32_t *)(&((uint32_t *)ehciInstance->ehciFrameList)[framePos]);

    while (frameEntryPointer)
    {
        frameEntryValue = *frameEntryPointer;
        if (frameEntryValue & EHCI_HOST_T_INVALID_VALUE)
        {
            return;
        }

        if ((frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK) == entryPointerValue)
        {
            /* remove the entry */
            *frameEntryPointer = *((uint32_t *)entryPointerValue);
            break;
        }
        else
        {
            frameEntryPointer = (volatile uint32_t *)(frameEntryValue & EHCI_HOST_POINTER_ADDRESS_MASK);
        }
    }
}

#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))
static void USB_HostEhciLinkSitd(usb_host_ehci_instance_t *ehciInstance,
                                 usb_host_ehci_pipe_t *ehciPipePointer,
                                 void *startEntryPointer)
{
    usb_host_ehci_iso_t *isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh;
    usb_host_ehci_sitd_t *sitdPointer;
    uint32_t distance;
    uint32_t frameInterval;
    int32_t shouldLinkFrame;
    int32_t currentFrame;

    frameInterval = (ehciPipePointer->uframeInterval >> 3);

    if (isoPointer->lastLinkFrame == 0xFFFF) /* first link */
    {
        currentFrame = ((ehciInstance->ehciIpBase->FRINDEX & USB_HOST_EHCI_MAX_MICRFRAME_VALUE) >> 3);
        currentFrame = ((uint32_t)(currentFrame + USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER) &
                        (USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3)); /* add USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER */
        /* frame should align with interval */
        currentFrame -= ehciPipePointer->startFrame;
        currentFrame =
            ((uint32_t)(currentFrame + frameInterval - 1) & (~(frameInterval - 1))); /* frameInterval is power of 2 */
        currentFrame += ehciPipePointer->startFrame;
    }
    else
    {
        shouldLinkFrame = isoPointer->lastLinkFrame + frameInterval; /* continuous next should link frame */
        if (shouldLinkFrame > (int32_t)(USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3))
        {
            shouldLinkFrame = shouldLinkFrame - ((USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3) + 1);
        }
        currentFrame = ((ehciInstance->ehciIpBase->FRINDEX & USB_HOST_EHCI_MAX_MICRFRAME_VALUE) >> 3);
        distance =
            ((shouldLinkFrame - currentFrame + (USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3) + 1) &
             (USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3)); /* get the distance from shouldLinkFrame to currentFrame */
        /* shouldLinkFrame has add frameInterval, think about the align with interval, so here add (frameInterval *
         * 2) */
        if ((distance <= (USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER + frameInterval * 2)) && (distance > 0))
        {
            currentFrame = shouldLinkFrame;
        }
        else /* re-link */
        {
            currentFrame = ((uint32_t)(currentFrame + USB_HOST_EHCI_ISO_BOUNCE_FRAME_NUMBER) &
                            (USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3));
            if (currentFrame > (int32_t)(USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3))
            {
                currentFrame = currentFrame - ((USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3) + 1);
            }
            /* frame should align with interval */
            currentFrame -= ehciPipePointer->startFrame;
            currentFrame = ((uint32_t)(currentFrame + frameInterval - 1) & (~(frameInterval - 1)));
            currentFrame += ehciPipePointer->startFrame;
        }
    }
    if (currentFrame >= (int32_t)USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE) /* frame turn around */
    {
        shouldLinkFrame =
            (currentFrame - USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE); /* shouldLinkFrame means inserted frame position */
    }
    else
    {
        shouldLinkFrame = currentFrame; /* shouldLinkFrame means inserted frame position */
    }

    sitdPointer = (usb_host_ehci_sitd_t *)startEntryPointer;
    while (sitdPointer)
    {
        sitdPointer->frameEntryIndex = shouldLinkFrame;
        /* add to frame list head */
        sitdPointer->nextLinkPointer = ((uint32_t *)ehciInstance->ehciFrameList)[shouldLinkFrame];
        ((uint32_t *)ehciInstance->ehciFrameList)[shouldLinkFrame] =
            ((uint32_t)sitdPointer | EHCI_HOST_POINTER_TYPE_SITD);
        if (sitdPointer->nextSitdIndex == 0xFF) /* 0xFF is invalid value */
        {
            break;
        }
        sitdPointer = &(ehciInstance->ehciSitdIndexBase[sitdPointer->nextSitdIndex]); /* next sitd */

        shouldLinkFrame += frameInterval;
        currentFrame += frameInterval;
        if (shouldLinkFrame >= (int32_t)USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE)
        {
            shouldLinkFrame = (shouldLinkFrame - USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE);
        }
    }

    if (currentFrame > (int32_t)(USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3))
    {
        currentFrame = currentFrame - ((USB_HOST_EHCI_MAX_MICRFRAME_VALUE >> 3) + 1);
    }
    isoPointer->lastLinkFrame = currentFrame; /* save the last link frame value */
}

static usb_status_t USB_HostEhciSitdArrayInit(usb_host_ehci_instance_t *ehciInstance,
                                              usb_host_ehci_pipe_t *ehciPipePointer,
                                              usb_host_transfer_t *transfer)
{
    usb_host_ehci_iso_t *isoPointer;
    uint32_t sitdNumber = 0;
    usb_host_ehci_sitd_t *sitdPointer;
    uint32_t dataLength = 0;
    uint32_t sitdLength = 0;
    uint32_t dataBufferValue;
    uint32_t hubNumber;
    uint32_t portNumber;
    uint32_t address;
    uint32_t tmp;
    uint8_t index;

    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress,
                                           &address);

    sitdNumber = ((transfer->transferLength - 1 + (ehciPipePointer->pipeCommon.maxPacketSize)) /
                  (ehciPipePointer->pipeCommon.maxPacketSize));
    /* get sitd array */
    tmp = ehciPipePointer - ehciInstance->ehciPipeIndexBase; /* pipe index */
    /* USB_HostEhciLock(); */
    if (ehciInstance->ehciSitdNumber >= sitdNumber)
    {
        sitdPointer               = ehciInstance->ehciSitdList;
        transfer->union1.unitHead = (uint32_t)sitdPointer;
        for (index = 1; index < sitdNumber; ++index)
        {
            sitdPointer->nextSitdIndex =
                (((usb_host_ehci_sitd_t *)sitdPointer->nextLinkPointer) - ehciInstance->ehciSitdIndexBase);
            sitdPointer = (usb_host_ehci_sitd_t *)sitdPointer->nextLinkPointer;
        }
        sitdPointer->nextSitdIndex = 0xFF;
        ehciInstance->ehciSitdList = (usb_host_ehci_sitd_t *)sitdPointer->nextLinkPointer;
        ehciInstance->ehciSitdNumber -= sitdNumber;
    }
    else
    {
        /* USB_HostEhciUnlock(); */
        return kStatus_USB_Error;
    }
    /* USB_HostEhciUnlock(); */
    transfer->union2.unitTail = (uint32_t)sitdPointer;
    /* initialize sitd array */
    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceHubNumber,
                                           &hubNumber);
    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDevicePortNumber,
                                           &portNumber);
    sitdPointer = (usb_host_ehci_sitd_t *)transfer->union1.unitHead;
    dataLength  = transfer->transferLength;
    while (sitdNumber--)
    {
        USB_HostEhciZeroMem((uint32_t *)sitdPointer, 7);
        sitdLength = dataLength;
        if (sitdLength > ehciPipePointer->pipeCommon.maxPacketSize)
        {
            sitdLength = ehciPipePointer->pipeCommon.maxPacketSize;
        }
        dataBufferValue = (uint32_t)(transfer->transferBuffer + (transfer->transferLength - dataLength));
        dataLength -= sitdLength; /* update left data length */
        sitdPointer->transferResults[1] = dataBufferValue;
        sitdPointer->transferResults[2] = ((dataBufferValue + 4 * 1024) & 0xFFFFF000U);
        sitdPointer->endpointStates[0] =
            (((uint32_t)ehciPipePointer->pipeCommon.direction << EHCI_HOST_SITD_DIRECTION_SHIFT) |
             (portNumber << EHCI_HOST_SITD_PORT_NUMBER_SHIFT) | (hubNumber << EHCI_HOST_SITD_HUB_ADDR_SHIFT) |
             ((uint32_t)ehciPipePointer->pipeCommon.endpointAddress << EHCI_HOST_SITD_ENDPT_SHIFT) |
             (address << EHCI_HOST_SITD_DEVICE_ADDRESS_SHIFT));
        sitdPointer->transferResults[0] =
            ((sitdLength << EHCI_HOST_SITD_TOTAL_BYTES_SHIFT) | (EHCI_HOST_SITD_STATUS_ACTIVE_MASK));

        if (ehciInstance->firstDeviceSpeed == USB_SPEED_HIGH)
        {
            sitdPointer->endpointStates[1] = (((uint32_t)ehciPipePointer->uframeCmask << EHCI_HOST_SITD_CMASK_SHIFT) |
                                              ((uint32_t)ehciPipePointer->uframeSmask << EHCI_HOST_SITD_SMASK_SHIFT));

            tmp = (sitdLength + 187) / 188;
            if (tmp > 1)
            {
                sitdPointer->transferResults[2] |= (0x01 << EHCI_HOST_SITD_TP_SHIFT); /* for iso split */
            }
            else
            {
                sitdPointer->transferResults[2] |= (0x00 << EHCI_HOST_SITD_TP_SHIFT); /* for iso split */
            }
            sitdPointer->transferResults[2] |= (tmp << EHCI_HOST_SITD_TCOUNT_SHIFT); /* for iso split */
        }

        sitdPointer->backPointer = EHCI_HOST_T_INVALID_VALUE;

        sitdPointer = (ehciInstance->ehciSitdIndexBase + sitdPointer->nextSitdIndex);
    }
    sitdPointer = (usb_host_ehci_sitd_t *)transfer->union2.unitTail;
    sitdPointer->transferResults[0] |= (1U << EHCI_HOST_SITD_IOC_SHIFT); /* last set IOC */

    /* link transfer to usb_host_ehci_iso_t transfer list */
    isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh;
    USB_HostEhciLock();
    if (isoPointer->ehciTransferHead == NULL)
    {
        transfer->next               = NULL;
        isoPointer->ehciTransferHead = isoPointer->ehciTransferTail = transfer;
    }
    else
    {
        transfer->next                     = NULL;
        isoPointer->ehciTransferTail->next = transfer;
        isoPointer->ehciTransferTail       = transfer;
    }
    USB_HostEhciUnlock();

    /* link itd to frame list (note: initialize frameEntryIndex)*/
    USB_HostEhciLinkSitd(ehciInstance, ehciPipePointer, (void *)transfer->union1.unitHead);

    return kStatus_USB_Success;
}

static uint32_t USB_HostEhciSitdArrayRelease(usb_host_ehci_instance_t *ehciInstance,
                                             usb_host_ehci_sitd_t *startSitdPointer,
                                             usb_host_ehci_sitd_t *endSitdPointer)
{
    usb_host_ehci_sitd_t *sitdPointer = startSitdPointer;
    uint32_t leftLength               = 0;
    /* remove itd from frame list */
    while (1)
    {
        /* record the transfer's result length */
        leftLength +=
            ((sitdPointer->transferResults[0] & EHCI_HOST_SITD_TOTAL_BYTES_MASK) >> EHCI_HOST_SITD_TOTAL_BYTES_SHIFT);
        USB_HostEhciRemoveFromFrame(ehciInstance, (uint32_t)sitdPointer,
                                    sitdPointer->frameEntryIndex); /* remove from the inserted frame list */

        /* release itd */
        /* USB_HostEhciLock(); */
        sitdPointer->nextLinkPointer = (uint32_t)ehciInstance->ehciSitdList;
        ehciInstance->ehciSitdList   = sitdPointer;
        ehciInstance->ehciSitdNumber++;
        /* USB_HostEhciUnlock(); */

        if (sitdPointer == endSitdPointer)
        {
            break;
        }

        sitdPointer = &(ehciInstance->ehciSitdIndexBase[sitdPointer->nextSitdIndex]);
    }

    return leftLength;
}

static usb_status_t USB_HostEhciSitdArrayDeinit(usb_host_ehci_instance_t *ehciInstance,
                                                usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_host_ehci_iso_t *isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh;
    usb_host_transfer_t *transfer;
    usb_host_transfer_t *nextTransfer;

    /* firstly remove the transfer (because host task may occupy to access the resource) */
    USB_HostEhciLock();
    transfer                     = isoPointer->ehciTransferHead;
    isoPointer->ehciTransferHead = isoPointer->ehciTransferTail = NULL;
    USB_HostEhciUnlock();

    while (transfer != NULL)
    {
        nextTransfer = transfer->next;
        /* remove sitd from frame list and release itd */
        transfer->transferSofar =
            transfer->transferLength - USB_HostEhciSitdArrayRelease(ehciInstance,
                                                                    (usb_host_ehci_sitd_t *)transfer->union1.unitHead,
                                                                    (usb_host_ehci_sitd_t *)transfer->union2.unitTail);
        /* callback function is different from the current condition */
        transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferCancel);
        /* next transfer */
        transfer = nextTransfer;
    }

    return kStatus_USB_Success;
}
#endif /* USB_HOST_CONFIG_EHCI_MAX_SITD */

#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
static uint32_t USB_HostEhciGetItdLinkFrame(usb_host_ehci_instance_t *ehciInstance,
                                            uint32_t lastLinkUframe,
                                            uint16_t startUframe,
                                            uint16_t uframeInterval)
{
    int32_t shouldLinkUframe;
    int32_t currentUframe;
    int32_t distance;

    if (lastLinkUframe != 0xFFFF)
    {
        shouldLinkUframe = lastLinkUframe + uframeInterval;
        if (shouldLinkUframe > (int32_t)USB_HOST_EHCI_MAX_MICRFRAME_VALUE)
        {
            shouldLinkUframe = shouldLinkUframe - (USB_HOST_EHCI_MAX_MICRFRAME_VALUE + 1);
        }
        currentUframe = (ehciInstance->ehciIpBase->FRINDEX & USB_HOST_EHCI_MAX_MICRFRAME_VALUE);
        distance      = ((shouldLinkUframe - currentUframe + USB_HOST_EHCI_MAX_MICRFRAME_VALUE + 1) &
                    USB_HOST_EHCI_MAX_MICRFRAME_VALUE); /* get the distance */
        /* shouldLinkUframe has add uframeInterval, think about the align with interval, so here add (uframeInterval
         * * 2) */
        if ((distance <= (int32_t)(USB_HOST_EHCI_ISO_BOUNCE_UFRAME_NUMBER + (uframeInterval * 8))) && (distance > 2))
        {
            currentUframe = shouldLinkUframe;
        }
        else /* re-link */
        {
            currentUframe = ((uint32_t)(currentUframe + USB_HOST_EHCI_ISO_BOUNCE_UFRAME_NUMBER) &
                             USB_HOST_EHCI_MAX_MICRFRAME_VALUE);
            if (currentUframe > (int32_t)USB_HOST_EHCI_MAX_MICRFRAME_VALUE)
            {
                currentUframe = currentUframe - (USB_HOST_EHCI_MAX_MICRFRAME_VALUE + 1);
            }
            /* uframe should align with interval */
            currentUframe -= startUframe;
            currentUframe = ((uint32_t)(currentUframe + uframeInterval) &
                             (~((uint32_t)uframeInterval - 1))); /* uframeInterval is power of 2 */
            currentUframe += startUframe;
        }
    }
    else
    {
        currentUframe = (ehciInstance->ehciIpBase->FRINDEX & USB_HOST_EHCI_MAX_MICRFRAME_VALUE);
        currentUframe =
            ((uint32_t)(currentUframe + USB_HOST_EHCI_ISO_BOUNCE_UFRAME_NUMBER) & USB_HOST_EHCI_MAX_MICRFRAME_VALUE);
        /* uframe should align with interval */
        currentUframe -= startUframe;
        currentUframe = ((uint32_t)(currentUframe + uframeInterval) &
                         (~((uint32_t)uframeInterval - 1))); /* uframeInterval is power of 2 */
        currentUframe += startUframe;
    }

    return currentUframe;
}

static usb_status_t USB_HostEhciItdArrayInit(usb_host_ehci_instance_t *ehciInstance,
                                             usb_host_ehci_pipe_t *ehciPipePointer,
                                             usb_host_transfer_t *transfer)
{
    usb_host_ehci_iso_t *isoPointer;
    usb_host_ehci_itd_t *itdPointer = NULL;
    usb_host_ehci_itd_t *itdHead    = NULL;
    usb_host_ehci_itd_t *tmpItdPointer;
    uint32_t dataLength;        /* the remaining data for sending */
    uint32_t transactionLength; /* the initializing transaction descriptor data length */
    uint32_t itdBufferValue;
    uint32_t itdBufferBaseValue; /* for calculating PG value */
    uint32_t address;
    uint32_t lastShouldLinkUframe;
    uint32_t linkUframe;
    uint32_t minDataPerItd = ehciPipePointer->pipeCommon.numberPerUframe * ehciPipePointer->pipeCommon.maxPacketSize;
    uint8_t maxItdNumber;
    uint8_t index = 0;

    isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh;
    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress,
                                           &address);

    /* max needed itd number, the actual needed number may be less because micro-frame interval may be less than 8 */
    maxItdNumber = ((transfer->transferLength - 1 + minDataPerItd) / minDataPerItd);
    if (ehciPipePointer->uframeInterval < 8)
    {
        maxItdNumber = ((maxItdNumber * ehciPipePointer->uframeInterval + 7) / 8) + 1;
    }
    if (maxItdNumber > ehciInstance->ehciItdNumber)
    {
        return kStatus_USB_Error;
    }

    /* link transfer to usb_host_ehci_iso_t transfer list */
    transfer->next = NULL;
    /* USB_HostEhciLock(); */
    if (isoPointer->ehciTransferHead == NULL)
    {
        isoPointer->ehciTransferHead = isoPointer->ehciTransferTail = transfer;
    }
    else
    {
        isoPointer->ehciTransferTail->next = transfer;
        isoPointer->ehciTransferTail       = transfer;
    }
    /* USB_HostEhciUnlock(); */

    dataLength                = transfer->transferLength;
    transfer->union1.unitHead = (uint32_t)NULL;
    /* get the link micro-frame */
    lastShouldLinkUframe = USB_HostEhciGetItdLinkFrame(
        ehciInstance, isoPointer->lastLinkFrame,
        (uint16_t)((ehciPipePointer->startFrame << 3) + ehciPipePointer->startUframe), ehciPipePointer->uframeInterval);
    if (lastShouldLinkUframe > USB_HOST_EHCI_MAX_MICRFRAME_VALUE)
    {
        linkUframe = lastShouldLinkUframe - (USB_HOST_EHCI_MAX_MICRFRAME_VALUE + 1);
    }
    else
    {
        linkUframe = lastShouldLinkUframe;
    }
    itdHead = ehciInstance->ehciItdList;
    while (dataLength)
    {
        /* get one idle itd */
        tmpItdPointer             = ehciInstance->ehciItdList;
        ehciInstance->ehciItdList = (usb_host_ehci_itd_t *)tmpItdPointer->nextLinkPointer;
        ehciInstance->ehciItdNumber -= 1;
        if (tmpItdPointer == NULL)
        {
            return kStatus_USB_Error; /* this should not reach */
        }
        tmpItdPointer->nextItdPointer = NULL;

        /* use the itd */
        if (transfer->union1.unitHead == (uint32_t)NULL) /* first itd */
        {
            transfer->union1.unitHead = (uint32_t)tmpItdPointer;
        }
        else /* link itd list */
        {
            itdPointer->nextItdPointer = tmpItdPointer;
        }
        itdPointer = tmpItdPointer;

        /* itd has been set to all zero when releasing */
        itdBufferBaseValue = itdBufferValue =
            (uint32_t)(transfer->transferBuffer + (transfer->transferLength - dataLength));
        for (index = 0; index < 7; ++index)
        {
            itdPointer->bufferPointers[index] = ((itdBufferBaseValue + (index * 4 * 1024)) & 0xFFFFF000U);
        }
        /* initialize iTD common fields */
        itdPointer->bufferPointers[0] |=
            (((uint32_t)ehciPipePointer->pipeCommon.endpointAddress << EHCI_HOST_ITD_ENDPT_SHIFT) |
             (address << EHCI_HOST_ITD_DEVICE_ADDRESS_SHIFT));
        itdPointer->bufferPointers[1] |=
            (((uint32_t)ehciPipePointer->pipeCommon.direction << EHCI_HOST_ITD_DIRECTION_SHIFT) |
             ((uint32_t)ehciPipePointer->pipeCommon.maxPacketSize << EHCI_HOST_ITD_MAX_PACKET_SIZE_SHIFT));
        itdPointer->bufferPointers[2] |= (ehciPipePointer->pipeCommon.numberPerUframe);
        /* initialize transaction descriptors */
        for (index = (linkUframe & 0x0007); index < 8; index += ehciPipePointer->uframeInterval)
        {
            transactionLength = ((dataLength > minDataPerItd) ? minDataPerItd : dataLength);
            /* initialize the uframeIndex's transaction descriptor in itd */
            itdPointer->transactions[index] =
                ((EHCI_HOST_ITD_STATUS_ACTIVE_MASK) | (transactionLength << EHCI_HOST_ITD_TRANSACTION_LEN_SHIFT) |
                 ((((itdBufferValue & 0xFFFFF000U) - (itdBufferBaseValue & 0xFFFFF000U)) >>
                   EHCI_HOST_ITD_BUFFER_POINTER_SHIFT)
                  << EHCI_HOST_ITD_PG_SHIFT) |
                 (itdBufferValue & EHCI_HOST_ITD_TRANSACTION_OFFSET_MASK));
            dataLength -= transactionLength;
            itdBufferValue += transactionLength;
            if (dataLength <= 0)
            {
                break;
            }
        }
    }

    transfer->union2.unitTail = (uint32_t)itdPointer;
    itdPointer->transactions[index] |= (1 << EHCI_HOST_ITD_IOC_SHIFT); /* last set IOC */

    itdPointer = itdHead;
    /* link itd to frame list (note: initialize frameEntryIndex)*/
    while (itdPointer)
    {
        uint32_t *linkPointer       = &((uint32_t *)ehciInstance->ehciFrameList)[linkUframe >> 3];
        uint32_t linkValue          = *linkPointer;
        itdPointer->frameEntryIndex = linkUframe >> 3;
        while ((!(linkValue & EHCI_HOST_T_INVALID_VALUE)) &&
               ((linkValue & EHCI_HOST_POINTER_TYPE_MASK) == EHCI_HOST_POINTER_TYPE_ITD))
        {
            linkPointer = (uint32_t *)(linkValue & EHCI_HOST_POINTER_ADDRESS_MASK);
            linkValue   = *linkPointer;
        }
        itdPointer->nextLinkPointer = *linkPointer;
        *linkPointer                = ((uint32_t)itdPointer | EHCI_HOST_POINTER_TYPE_ITD);
        itdPointer                  = itdPointer->nextItdPointer;
        if (itdPointer == NULL)
        {
            break;
        }

        linkUframe += ehciPipePointer->uframeInterval;
        lastShouldLinkUframe += ehciPipePointer->uframeInterval;
        if (linkUframe >= (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE << 3))
        {
            linkUframe = (linkUframe - (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE << 3));
        }
    }

    if (lastShouldLinkUframe > USB_HOST_EHCI_MAX_MICRFRAME_VALUE)
    {
        lastShouldLinkUframe = lastShouldLinkUframe - (USB_HOST_EHCI_MAX_MICRFRAME_VALUE + 1);
    }
    isoPointer->lastLinkFrame = lastShouldLinkUframe;

    return kStatus_USB_Success;
}

static uint32_t USB_HostEhciItdArrayRelease(usb_host_ehci_instance_t *ehciInstance,
                                            usb_host_ehci_itd_t *startItdPointer,
                                            usb_host_ehci_itd_t *endItdPointer)
{
    usb_host_ehci_itd_t *itdPointer = startItdPointer;
    uint8_t index;
    uint32_t doneLength = 0;

    /* remove itd from frame list */
    while (1)
    {
        /* record the transfer's result length */
        for (index = 0; index < 8; ++index)
        {
            doneLength += ((itdPointer->transactions[index] & EHCI_HOST_ITD_TRANSACTION_LEN_MASK) >>
                           EHCI_HOST_ITD_TRANSACTION_LEN_SHIFT);
        }

        USB_HostEhciRemoveFromFrame(ehciInstance, (uint32_t)itdPointer,
                                    itdPointer->frameEntryIndex); /* remove from the inserted frame list */

        /* release itd */
        /* USB_HostEhciLock(); */
        USB_HostEhciZeroMem((uint32_t *)itdPointer, sizeof(usb_host_ehci_itd_t) >> 2);
        itdPointer->nextLinkPointer = (uint32_t)ehciInstance->ehciItdList;
        ehciInstance->ehciItdList   = itdPointer;
        ehciInstance->ehciItdNumber++;
        /* USB_HostEhciUnlock(); */

        if (itdPointer == endItdPointer)
        {
            break;
        }
        itdPointer = itdPointer->nextItdPointer;
    }

    return doneLength;
}

static usb_status_t USB_HostEhciItdArrayDeinit(usb_host_ehci_instance_t *ehciInstance,
                                               usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_host_ehci_iso_t *isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh;
    usb_host_transfer_t *transfer;
    usb_host_transfer_t *nextTransfer;
    uint32_t doneLength = 0;

    /* firstly remove the transfer (because host task may occupy to access the resource) */
    USB_HostEhciLock();
    transfer                     = isoPointer->ehciTransferHead;
    isoPointer->ehciTransferHead = isoPointer->ehciTransferTail = NULL;
    USB_HostEhciUnlock();

    while (transfer != NULL)
    {
        nextTransfer = transfer->next;
        doneLength   = 0;
        /* remove itd from frame list and release itd */
        doneLength = USB_HostEhciItdArrayRelease(ehciInstance, (usb_host_ehci_itd_t *)transfer->union1.unitHead,
                                                 (usb_host_ehci_itd_t *)transfer->union2.unitTail);

        /* transfer callback */
        if (ehciPipePointer->pipeCommon.direction == USB_OUT)
        {
            doneLength = transfer->transferLength;
        }
        transfer->transferSofar = doneLength;
        /* callback function is different from the current condition */
        transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferCancel);

        /* next transfer */
        transfer = nextTransfer;
    }

    return kStatus_USB_Success;
}
#endif /* USB_HOST_CONFIG_EHCI_MAX_ITD */

static usb_status_t USB_HostEhciOpenControlBulk(usb_host_ehci_instance_t *ehciInstance,
                                                usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_host_ehci_qh_t *qhPointer;

    if (USB_HostEhciQhInit(ehciInstance, ehciPipePointer) != kStatus_USB_Success) /* initialize control/bulk qh */
    {
        return kStatus_USB_Error;
    }

    qhPointer = (usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;

    /* add qh to async */
    qhPointer->horizontalLinkPointer                 = ehciInstance->shedFirstQh->horizontalLinkPointer;
    ehciInstance->shedFirstQh->horizontalLinkPointer = ((uint32_t)qhPointer | EHCI_HOST_POINTER_TYPE_QH);

    return kStatus_USB_Success;
}

static usb_status_t USB_HostEhciCloseControlBulk(usb_host_ehci_instance_t *ehciInstance,
                                                 usb_host_ehci_pipe_t *ehciPipePointer)
{
    volatile usb_host_ehci_qh_t *vltPrevQhPointer;
    uint32_t horizontalLinkValue;

    /* remove qh from async schedule */
    if ((ehciInstance->shedFirstQh->horizontalLinkPointer & EHCI_HOST_POINTER_ADDRESS_MASK) ==
        (uint32_t)ehciPipePointer->ehciQh) /* the removing qh is the first qh in the async list */
    {
        USB_HostEhciStopAsync(ehciInstance);
        ehciInstance->shedFirstQh->horizontalLinkPointer =
            ((usb_host_ehci_qh_t *)ehciPipePointer->ehciQh)->horizontalLinkPointer;
        USB_HostEhciStartAsync(ehciInstance);
    }
    else
    {
        /* search for the removing qh from the async list */
        vltPrevQhPointer = ehciInstance->shedFirstQh;
        while (vltPrevQhPointer != NULL)
        {
            horizontalLinkValue = vltPrevQhPointer->horizontalLinkPointer;
            if ((horizontalLinkValue & EHCI_HOST_T_INVALID_VALUE) ||
                ((horizontalLinkValue & EHCI_HOST_POINTER_ADDRESS_MASK) == (uint32_t)ehciPipePointer->ehciQh) ||
                ((horizontalLinkValue & EHCI_HOST_POINTER_ADDRESS_MASK) == (uint32_t)ehciInstance->shedFirstQh))
            {
                break;
            }

            vltPrevQhPointer = (volatile usb_host_ehci_qh_t *)(horizontalLinkValue & EHCI_HOST_POINTER_ADDRESS_MASK);
        }

        /* remove the qh from async list */
        if ((vltPrevQhPointer != NULL) && (!(horizontalLinkValue & EHCI_HOST_T_INVALID_VALUE)) &&
            ((horizontalLinkValue & EHCI_HOST_POINTER_ADDRESS_MASK) == (uint32_t)ehciPipePointer->ehciQh))
        {
            USB_HostEhciStopAsync(ehciInstance);
            vltPrevQhPointer->horizontalLinkPointer =
                ((usb_host_ehci_qh_t *)ehciPipePointer->ehciQh)->horizontalLinkPointer;
            USB_HostEhciStartAsync(ehciInstance);
        }
    }
    ((usb_host_ehci_qh_t *)ehciPipePointer->ehciQh)->horizontalLinkPointer =
        EHCI_HOST_T_INVALID_VALUE;                              /* invalid next qh link */
    return USB_HostEhciQhDeinit(ehciInstance, ehciPipePointer); /* de-initialize qh and release qh */
}

static usb_status_t USB_HostEhciOpenInterrupt(usb_host_ehci_instance_t *ehciInstance,
                                              usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_status_t status = kStatus_USB_Success;
    uint32_t frameIndex;

    /* allocate bandwidth */
    if (ehciInstance->firstDeviceSpeed == USB_SPEED_HIGH)
    {
        status = USB_HostBandwidthHsHostAllocateInterrupt(ehciInstance, ehciPipePointer); /* host works as high-speed */
    }
    else
    {
        status = USB_HostBandwidthFslsHostAllocate(ehciInstance,
                                                   ehciPipePointer); /* host works as full-speed or low-speed */
    }

    if (status != kStatus_USB_Success)
    {
        return status;
    }
    if (USB_HostEhciQhInit(ehciInstance, ehciPipePointer) != kStatus_USB_Success)
    {
        return kStatus_USB_Error;
    }

    /* insert QH to frame list */
    for (frameIndex = ehciPipePointer->startFrame; frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE;
         frameIndex += ((ehciPipePointer->uframeInterval + 7) / 8))
    {
        USB_HostEhciAddQhToFrame(ehciInstance, (uint32_t)ehciPipePointer->ehciQh, frameIndex,
                                 ehciPipePointer->uframeInterval);
    }

    return kStatus_USB_Success;
}

static usb_status_t USB_HostEhciCloseInterrupt(usb_host_ehci_instance_t *ehciInstance,
                                               usb_host_ehci_pipe_t *ehciPipePointer)
{
    uint32_t frameIndex;

    /* remove from frame list */
    for (frameIndex = ehciPipePointer->startFrame; frameIndex < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE;
         frameIndex += ((ehciPipePointer->uframeInterval + 7) / 8))
    {
        USB_HostEhciRemoveFromFrame(ehciInstance, (uint32_t)ehciPipePointer->ehciQh, frameIndex);
    }
    ((usb_host_ehci_qh_t *)ehciPipePointer->ehciQh)->horizontalLinkPointer |=
        EHCI_HOST_T_INVALID_VALUE; /* invalid next qh link */

    return USB_HostEhciQhDeinit(ehciInstance, ehciPipePointer); /* de-initilaze qh and release qh */
}

#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))

static usb_status_t USB_HostEhciOpenIso(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_host_ehci_iso_t *isoPointer;
    usb_status_t status = kStatus_USB_Success;

    if (ehciInstance->firstDeviceSpeed == USB_SPEED_HIGH)
    {
        status = USB_HostBandwidthHsHostAllocateIso(
            ehciInstance, ehciPipePointer); /* allocate iso bandwidth when host works as high-speed */
    }
    else
    {
        status = USB_HostBandwidthFslsHostAllocate(
            ehciInstance, ehciPipePointer); /* allocate iso bandwidth when host works as full-speed or low-speed */
    }

    if (status != kStatus_USB_Success)
    {
        return status;
    }

    /* get usb_host_ehci_iso_t */
    if (ehciInstance->ehciIsoList == NULL)
    {
        return kStatus_USB_Error;
    }
    USB_HostEhciLock();
    isoPointer                = ehciInstance->ehciIsoList;
    ehciInstance->ehciIsoList = ehciInstance->ehciIsoList->next;
    USB_HostEhciUnlock();
    isoPointer->lastLinkFrame = 0xFFFF;
    ehciPipePointer->ehciQh   = isoPointer;

    return status;
}

static usb_status_t USB_HostEhciCloseIso(usb_host_ehci_instance_t *ehciInstance, usb_host_ehci_pipe_t *ehciPipePointer)
{
    usb_host_ehci_iso_t *isoPointer;
    uint32_t speed;

    isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh;

    if (isoPointer->ehciTransferHead != NULL)
    {
        USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed,
                                               &speed);
        if (speed == USB_SPEED_HIGH)
        {
#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
            USB_HostEhciItdArrayDeinit(ehciInstance, ehciPipePointer); /* de-initialize itd list and free them */
#endif
        }
        else
        {
#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))
            USB_HostEhciSitdArrayDeinit(ehciInstance, ehciPipePointer); /* de-initialize sitd list and free them */
#endif
        }
    }

    /* release usb_host_ehci_iso_t */
    USB_HostEhciLock();
    isoPointer->next          = ehciInstance->ehciIsoList;
    ehciInstance->ehciIsoList = isoPointer;
    USB_HostEhciUnlock();
    return kStatus_USB_Success;
}

#endif

static usb_status_t USB_HostEhciResetIP(usb_host_ehci_instance_t *ehciInstance)
{
    /* reset controller */
    ehciInstance->ehciIpBase->USBCMD = USBHS_USBCMD_RST_MASK;
    while (ehciInstance->ehciIpBase->USBCMD & USBHS_USBCMD_RST_MASK)
    {
    }
/* set host mode */
#if (ENDIANNESS == USB_LITTLE_ENDIAN)
    ehciInstance->ehciIpBase->USBMODE |= 0x03;
#else
    ehciInstance->ehciIpBase->USBMODE |= (0x03 | (0x01 << USBHS_USBMODE_ES_SHIFT));
#endif
    /* check frame list size */
    if (!(ehciInstance->ehciIpBase->HCCPARAMS & USBHS_HCCPARAMS_PFL_MASK))
    {
#if ((USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE < 8) || (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE > 1024))
        return kStatus_USB_Error;
#endif
#if (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE & (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE - 1))
        return kStatus_USB_Error; /* frame size must be 1024/512/256/128/64/32/16/8 */
#endif
    }
    return kStatus_USB_Success;
}

static usb_status_t USB_HostEhciStartIP(usb_host_ehci_instance_t *ehciInstance)
{
    uint32_t tmp = 0;

    if (ehciInstance->ehciIpBase->HCSPARAMS & USBHS_HCSPARAMS_PPC_MASK) /* Ports have power port switches */
    {
        /* only has one port */
        tmp = ehciInstance->ehciIpBase->PORTSC1;
        tmp &= (~EHCI_PORTSC1_W1_BITS);
        ehciInstance->ehciIpBase->PORTSC1 = (tmp | USBHS_PORTSC1_PP_MASK); /* turn on port power */
    }

    /* set frame list size */
    if (ehciInstance->ehciIpBase->HCCPARAMS & USBHS_HCCPARAMS_PFL_MASK)
    {
#if (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE <= 64)
        ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_FS2_MASK);
#if (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 64)
        ehciInstance->ehciIpBase->USBCMD |= (0x00 << USBHS_USBCMD_FS_SHIFT);
#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 32)
        ehciInstance->ehciIpBase->USBCMD |= (0x01 << USBHS_USBCMD_FS_SHIFT);
#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 16)
        ehciInstance->ehciIpBase->USBCMD |= (0x02 << USBHS_USBCMD_FS_SHIFT);
#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 8)
        ehciInstance->ehciIpBase->USBCMD |= (0x03 << USBHS_USBCMD_FS_SHIFT);
#endif
#else
#if (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 1024)
        ehciInstance->ehciIpBase->USBCMD |= (0x00 << USBHS_USBCMD_FS_SHIFT);
#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 512)
        ehciInstance->ehciIpBase->USBCMD |= (0x01 << USBHS_USBCMD_FS_SHIFT);
#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 256)
        ehciInstance->ehciIpBase->USBCMD |= (0x02 << USBHS_USBCMD_FS_SHIFT);
#elif (USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE == 128)
        ehciInstance->ehciIpBase->USBCMD |= (0x03 << USBHS_USBCMD_FS_SHIFT);
#endif
#endif
    }

    /* start the controller */
    ehciInstance->ehciIpBase->USBCMD |= USBHS_USBCMD_RS_MASK;

    /* set timer0 */
    ehciInstance->ehciIpBase->GPTIMER0LD = (100 * 1000 - 1); /* 100ms */

    /* enable interrupt (USB interrupt enable + USB error interrupt enable + port change detect enable + system error
     * enable + interrupt on async advance enable) + general purpos Timer 0 Interrupt enable */
    ehciInstance->ehciIpBase->USBINTR |= (0x1000037);

    return kStatus_USB_Success;
}

static usb_status_t USB_HostEhciCancelPipe(usb_host_ehci_instance_t *ehciInstance,
                                           usb_host_ehci_pipe_t *ehciPipePointer,
                                           usb_host_transfer_t *transfer)
{
    usb_host_ehci_qh_t *qhPointer;
#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
    usb_host_ehci_iso_t *isoPointer;
    uint32_t speed;
#endif
    uint8_t cancelPipe = 0;

    switch (ehciPipePointer->pipeCommon.pipeType)
    {
        case USB_ENDPOINT_BULK:
        case USB_ENDPOINT_CONTROL:
        case USB_ENDPOINT_INTERRUPT:
            qhPointer = (usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;
            if (qhPointer->ehciTransferHead == NULL) /* there is no transfer to cancel */
            {
                return kStatus_USB_Success;
            }
            if (transfer != NULL)
            {
                if ((qhPointer->ehciTransferHead == transfer) &&
                    (qhPointer->ehciTransferHead == qhPointer->ehciTransferTail)) /* only has this one transfer */
                {
                    cancelPipe = 1;
                }
                else
                {
                    cancelPipe = 0;
                }
            }
            else
            {
                cancelPipe = 1;
            }
            if (cancelPipe == 1) /* cancel all pipe */
            {
                USB_HostEhciQhQtdListDeinit(ehciInstance, ehciPipePointer); /* release all the qtd */
            }
            else /* cancel one transfer */
            {
                USB_HostEhciTransferQtdListDeinit(ehciInstance, ehciPipePointer, transfer);
            }
            break;

#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
        case USB_ENDPOINT_ISOCHRONOUS:
            isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh;
            if (isoPointer->ehciTransferHead == NULL) /* there is no transfer to cancel */
            {
                return kStatus_USB_Success;
            }
            /* cancel all pipe, don't implement canceling transfer for iso */
            USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed,
                                                   &speed);
            if (speed == USB_SPEED_HIGH)
            {
#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
                USB_HostEhciItdArrayDeinit(ehciInstance, ehciPipePointer); /* de-initialize itd */
#endif
            }
            else
            {
#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))
                USB_HostEhciSitdArrayDeinit(ehciInstance, ehciPipePointer); /* de-initialize sitd */
#endif
            }
            break;
#endif

        default:
            break;
    }

    return kStatus_USB_Success;
}

static usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint8_t busControl)
{
    usb_status_t status = kStatus_USB_Success;
    uint32_t portScRegister;

    switch (busControl)
    {
        case kUSB_HostBusReset:
            /* reset port */
            portScRegister = ehciInstance->ehciIpBase->PORTSC1;
            portScRegister &= (~EHCI_PORTSC1_W1_BITS);
            ehciInstance->ehciIpBase->PORTSC1 = (portScRegister | USBHS_PORTSC1_PR_MASK);
            while (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_PR_MASK)
            {
            }
            break;

        case kUSB_HostBusRestart:
            ehciInstance->deviceAttached = kEHCIDeviceDetached;
            ehciInstance->ehciIpBase->USBINTR |= (USBHS_USBINTR_PCE_MASK); /* enable ehci port change interrupt */
            break;

        case kUSB_HostBusEnableAttach: /* enable device attach */
            if (ehciInstance->deviceAttached == kEHCIDeviceDetached)
            {
                ehciInstance->ehciIpBase->USBINTR |= (USBHS_USBINTR_PCE_MASK); /* enable ehci port change interrupt */
            }
            break;

        case kUSB_HostBusDisableAttach:                                     /* disable device attach */
            ehciInstance->ehciIpBase->USBINTR &= (~USBHS_USBINTR_PCE_MASK); /* disable ehci port change interrupt */
            break;
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
        case kUSB_HostBusSuspend:
            if (ehciInstance->ehciIpBase->PORTSC1 && USBHS_PORTSC1_CCS_MASK)
            {
                /* set timer1 */
                ehciInstance->ehciIpBase->GPTIMER1LD = (1 * 1000); /* 1ms */
                ehciInstance->ehciIpBase->GPTIMER1CTL |=
                    (USBHS_GPTIMER0CTL_RUN_MASK | USBHS_GPTIMER0CTL_MODE_MASK | USBHS_GPTIMER0CTL_RST_MASK);

                USB_HostEhciStopAsync(ehciInstance);
                USB_HostEhciStopPeriodic(ehciInstance);
                while (ehciInstance->ehciIpBase->USBSTS & (USBHS_USBSTS_PS_MASK | USBHS_USBSTS_AS_MASK))
                {
                    __ASM("nop");
                }
                ehciInstance->ehciIpBase->PORTSC1 &= ~USBHS_PORTSC1_WKCN_MASK;
                ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_WKDS_MASK;
                ehciInstance->ehciIpBase->PORTSC1 |= (USBHS_PORTSC1_SUSP_MASK); /* Suspend the device */

                ehciInstance->matchTick = 0U;
                ehciInstance->ehciIpBase->USBINTR |= (USBHS_USBINTR_TIE1_MASK);
                ehciInstance->busSuspendStatus = kBus_EhciStartSuspend;
            }
            else
            {
                status = kStatus_USB_Error;
            }
            break;
        case kUSB_HostBusResume:
            ehciInstance->ehciIpBase->PORTSC1 &= ~(USBHS_PORTSC1_SUSP_MASK); /* Clear Suspend bit */
            ehciInstance->ehciIpBase->PORTSC1 &= ~USBHS_PORTSC1_PHCD_MASK;
            if (ehciInstance->deviceAttached != kEHCIDeviceDetached)
            {
                ehciInstance->busSuspendStatus = kBus_EhciStartResume;
#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
                ehciInstance->registerNcBase->USB_OTGn_CTRL &= ~USBNC_USB_OTGn_CTRL_WIE_MASK;
#else
                ehciInstance->ehciIpBase->USBGENCTRL &= ~USBHS_USBGENCTRL_WU_IE_MASK;
#endif
                ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_RS_MASK);
                ehciInstance->ehciIpBase->PORTSC1 |= (USBHS_PORTSC1_FPR_MASK); /* Resume the device */
            }
            else
            {
                status = kStatus_USB_Error;
            }
            break;
#endif
        default:
            status = kStatus_USB_Error;
            break;
    }
    return status;
}

void USB_HostEhciTransactionDone(usb_host_ehci_instance_t *ehciInstance)
{
    /* process async QH */
    usb_host_ehci_pipe_t *ehciPipePointer;
    usb_host_ehci_pipe_t *ehciClearPipePointer = NULL;
    volatile usb_host_ehci_qh_t *vltQhPointer;
    volatile usb_host_ehci_qtd_t *vltQtdPointer;
    usb_host_transfer_t *transfer;
    usb_host_transfer_t *nextTransfer;
    uint32_t qtdStatus = 0;
#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
    volatile usb_host_ehci_itd_t *vltItdPointer;
    uint8_t index = 0;
#endif
#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))
    volatile usb_host_ehci_sitd_t *vltSitdPointer;
#endif
#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
    usb_host_ehci_iso_t *isoPointer;
    uint32_t dataLength;
    uint32_t speed;
#endif

    ehciPipePointer = ehciInstance->ehciRunningPipeList; /* check all the running pipes */
    while (ehciPipePointer != NULL)
    {
        switch (ehciPipePointer->pipeCommon.pipeType)
        {
            case USB_ENDPOINT_BULK:
            case USB_ENDPOINT_INTERRUPT:
            case USB_ENDPOINT_CONTROL:
                vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; /* pipe's qh */
                transfer     = vltQhPointer->ehciTransferHead;                         /* qh's transfer */
                while (transfer != NULL)
                {
                    nextTransfer = transfer->next;
                    /* normal case */
                    vltQtdPointer = (volatile usb_host_ehci_qtd_t *)transfer->union2.unitTail;
                    if ((vltQtdPointer->transferResults[0] & (EHCI_HOST_QTD_IOC_MASK)) &&
                        (!(vltQtdPointer->transferResults[0] &
                           EHCI_HOST_QTD_STATUS_ACTIVE_MASK))) /* transfer is done */
                    {
                        qtdStatus = (vltQtdPointer->transferResults[0] & EHCI_HOST_QTD_STATUS_ERROR_MASK);
                        transfer->transferSofar =
                            USB_HostEhciQtdListRelease(ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead),
                                                       (usb_host_ehci_qtd_t *)(transfer->union2.unitTail));
                        transfer->transferSofar = (transfer->transferLength < transfer->transferSofar) ?
                                                      0 :
                                                      (transfer->transferLength - transfer->transferSofar);

                        vltQhPointer->ehciTransferHead = transfer->next;
                        vltQhPointer->timeOutLabel     = 0;
                        vltQhPointer->timeOutValue     = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE;
                        if (qtdStatus) /* has errors */
                        {
                            if (!(vltQhPointer->transferOverlayResults[0] & EHCI_HOST_QTD_STATUS_ACTIVE_MASK))
                            {
                                vltQhPointer->transferOverlayResults[0] &=
                                    (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */
                            }
                            if (qtdStatus & EHCI_HOST_QH_STATUS_NOSTALL_ERROR_MASK)
                            {
                                /* callback function is different from the current condition */
                                transfer->callbackFn(transfer->callbackParam, transfer,
                                                     kStatus_USB_TransferFailed); /* transfer fail */
                            }
                            else
                            {
                                /* callback function is different from the current condition */
                                transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferStall);
                            }
                        }
                        else
                        {
                            if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_CONTROL) &&
                                (transfer->setupPacket->bRequest == USB_REQUEST_STANDARD_CLEAR_FEATURE) &&
                                (transfer->setupPacket->bmRequestType == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) &&
                                ((USB_SHORT_FROM_LITTLE_ENDIAN(transfer->setupPacket->wValue) & 0x00FFu) ==
                                 USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT))
                            {
                                ehciClearPipePointer = ehciInstance->ehciRunningPipeList;
                                while (ehciClearPipePointer != NULL)
                                {
                                    /* only compute bulk and interrupt pipe */
                                    if (((ehciClearPipePointer->pipeCommon.endpointAddress |
                                          (ehciClearPipePointer->pipeCommon.direction
                                           << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) ==
                                         (uint8_t)(USB_SHORT_FROM_LITTLE_ENDIAN(transfer->setupPacket->wIndex))) &&
                                        (ehciClearPipePointer->pipeCommon.deviceHandle ==
                                         ehciPipePointer->pipeCommon.deviceHandle))
                                    {
                                        break;
                                    }
                                    ehciClearPipePointer =
                                        (usb_host_ehci_pipe_t *)ehciClearPipePointer->pipeCommon.next;
                                }

                                if ((ehciClearPipePointer != NULL) &&
                                    ((ehciClearPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT) ||
                                     (ehciClearPipePointer->pipeCommon.pipeType == USB_ENDPOINT_BULK)))
                                {
                                    ((volatile usb_host_ehci_qh_t *)(ehciClearPipePointer->ehciQh))
                                        ->transferOverlayResults[0] &= (~EHCI_HOST_QTD_DT_MASK);
                                }
                            }
                            /* callback function is different from the current condition */
                            transfer->callbackFn(transfer->callbackParam, transfer,
                                                 kStatus_USB_Success); /* transfer success */
                        }
                    }
                    else if ((!(vltQhPointer->transferOverlayResults[0] & EHCI_HOST_QTD_STATUS_ACTIVE_MASK)) &&
                             (vltQhPointer->transferOverlayResults[0] &
                              EHCI_HOST_QH_STATUS_ERROR_MASK)) /* there is error and transfer is done */
                    {
                        qtdStatus     = (vltQhPointer->transferOverlayResults[0] & EHCI_HOST_QH_STATUS_ERROR_MASK);
                        vltQtdPointer = (volatile usb_host_ehci_qtd_t *)(vltQhPointer->currentQtdPointer);

                        if (((uint32_t)vltQtdPointer & EHCI_HOST_T_INVALID_VALUE) ||
                            (vltQtdPointer == NULL)) /* the error status is unreasonable */
                        {
                            vltQhPointer->transferOverlayResults[0] &=
                                (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */
                        }
                        else
                        {
                            /* remove qtd from qh */
                            while ((vltQtdPointer != NULL) && (!(vltQtdPointer->transferResults[0] &
                                                                 EHCI_HOST_QTD_IOC_MASK))) /* find the IOC qtd */
                            {
                                vltQtdPointer = (volatile usb_host_ehci_qtd_t *)vltQtdPointer->nextQtdPointer;
                            }

                            vltQhPointer->nextQtdPointer    = EHCI_HOST_T_INVALID_VALUE;
                            vltQhPointer->currentQtdPointer = EHCI_HOST_T_INVALID_VALUE;
                            vltQhPointer->transferOverlayResults[0] &=
                                (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */
                            if (vltQtdPointer != NULL)
                            {
                                vltQhPointer->nextQtdPointer = vltQtdPointer->nextQtdPointer;
                            }

                            transfer->transferSofar = USB_HostEhciQtdListRelease(
                                ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead),
                                (usb_host_ehci_qtd_t *)(transfer->union2.unitTail));
                            transfer->transferSofar = (transfer->transferLength < transfer->transferSofar) ?
                                                          0 :
                                                          (transfer->transferLength - transfer->transferSofar);
                            vltQhPointer->ehciTransferHead = transfer->next;
                            vltQhPointer->timeOutLabel     = 0;
                            vltQhPointer->timeOutValue     = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE;
                            if (qtdStatus & EHCI_HOST_QH_STATUS_NOSTALL_ERROR_MASK)
                            {
                                /* callback function is different from the current condition */
                                transfer->callbackFn(transfer->callbackParam, transfer,
                                                     kStatus_USB_TransferFailed); /* transfer fail */
                            }
                            else
                            {
                                /* callback function is different from the current condition */
                                transfer->callbackFn(transfer->callbackParam, transfer,
                                                     kStatus_USB_TransferStall); /* transfer stall */
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                    transfer = nextTransfer;
                }
                break;
#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
            case USB_ENDPOINT_ISOCHRONOUS:
                qtdStatus  = 0; /* qtdStatus means break here, because there is only one break in while for misra */
                isoPointer = (usb_host_ehci_iso_t *)ehciPipePointer->ehciQh; /* pipe's usb_host_ehci_iso_t */
                transfer   = isoPointer->ehciTransferHead;                   /* usb_host_ehci_iso_t's transfer */
                while (transfer != NULL)
                {
                    nextTransfer = transfer->next;
                    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle,
                                                           kUSB_HostGetDeviceSpeed, &speed);
                    if (speed == USB_SPEED_HIGH)
                    {
#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
                        vltItdPointer =
                            (volatile usb_host_ehci_itd_t *)(transfer->union2.unitTail); /* transfer's last itd */
                        for (index = 0; index < 8; ++index)
                        {
                            if (vltItdPointer->transactions[index] & EHCI_HOST_ITD_STATUS_ACTIVE_MASK)
                            {
                                break;
                            }
                        }
                        if (index == 8) /* transfer is done */
                        {
                            /* remove itd from frame list and release itd */
                            dataLength                   = USB_HostEhciItdArrayRelease(ehciInstance,
                                                                     (usb_host_ehci_itd_t *)transfer->union1.unitHead,
                                                                     (usb_host_ehci_itd_t *)transfer->union2.unitTail);
                            transfer->transferSofar      = dataLength;
                            isoPointer->ehciTransferHead = transfer->next;
                            /* callback function is different from the current condition */
                            transfer->callbackFn(transfer->callbackParam, transfer,
                                                 kStatus_USB_Success); /* transfer callback success */
                            /* TODO: iso callback error */
                        }
                        else
                        {
                            qtdStatus = 1; /* break */
                        }
#endif
                    }
                    else
                    {
#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))
                        vltSitdPointer =
                            (volatile usb_host_ehci_sitd_t *)(transfer->union2.unitTail); /* transfer's last sitd */
                        if (!(vltSitdPointer->transferResults[0] &
                              EHCI_HOST_SITD_STATUS_ACTIVE_MASK)) /* transfer is done */
                        {
                            /* remove sitd from frame list and release itd */
                            dataLength = USB_HostEhciSitdArrayRelease(
                                ehciInstance, (usb_host_ehci_sitd_t *)transfer->union1.unitHead,
                                (usb_host_ehci_sitd_t *)transfer->union2.unitTail);
                            transfer->transferSofar      = transfer->transferLength - dataLength;
                            isoPointer->ehciTransferHead = transfer->next;
                            /* callback function is different from the current condition */
                            transfer->callbackFn(transfer->callbackParam, transfer,
                                                 kStatus_USB_Success); /* transfer callback success */
                            /* TODO: iso callback error */
                        }
                        else
                        {
                            qtdStatus = 1; /* break */
                        }
#endif
                    }
                    if (qtdStatus == 1)
                    {
                        break;
                    }
                    transfer = nextTransfer;
                }
                break;
#endif

            default:
                break;
        }
        ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next;
    }
}

static void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance)
{
    /* note: only has one port */
    uint32_t portScRegister = ehciInstance->ehciIpBase->PORTSC1;
    int32_t sofStart        = 0;
    int32_t sofCount        = 0;
    uint32_t index;

    if (portScRegister & USBHS_PORTSC1_CSC_MASK) /* connection status change */
    {
        sofStart = (int32_t)(ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE);

        /* process CSC bit */
        while (1)
        {
            portScRegister = ehciInstance->ehciIpBase->PORTSC1;
            if (portScRegister & USBHS_PORTSC1_CSC_MASK)
            {
                /* clear csc bit */
                portScRegister = ehciInstance->ehciIpBase->PORTSC1;
                portScRegister &= (~EHCI_PORTSC1_W1_BITS);
                ehciInstance->ehciIpBase->PORTSC1 = (portScRegister | USBHS_PORTSC1_CSC_MASK);
            }
            sofCount = (int32_t)(ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE);
            if (((sofCount - sofStart + EHCI_MAX_UFRAME_VALUE + 1) & EHCI_MAX_UFRAME_VALUE) >
                (1 * 8)) /* delay 1ms to clear CSC */
            {
                break;
            }
        }
    }

    /* process CCS bit */
    portScRegister = ehciInstance->ehciIpBase->PORTSC1;
    if (portScRegister & USBHS_PORTSC1_CCS_MASK) /* process attach */
    {
        if ((ehciInstance->deviceAttached == kEHCIDevicePhyAttached) ||
            (ehciInstance->deviceAttached == kEHCIDeviceAttached))
        {
            return;
        }
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
        ehciInstance->busSuspendStatus = kBus_EhciIdle;
        ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK);
#endif
        for (index = 0; index < USB_HOST_EHCI_PORT_CONNECT_DEBOUNCE_DELAY; ++index)
        {
            USB_HostEhciDelay(ehciInstance->ehciIpBase, 1);
            if (!(ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK))
            {
                break;
            }
        }
        if (index < USB_HOST_EHCI_PORT_CONNECT_DEBOUNCE_DELAY) /* CCS is cleared */
        {
            ehciInstance->deviceAttached = kEHCIDeviceDetached;
            return;
        }
        /* reset port */
        portScRegister = ehciInstance->ehciIpBase->PORTSC1;
        portScRegister &= (~EHCI_PORTSC1_W1_BITS);
        ehciInstance->ehciIpBase->PORTSC1 = (portScRegister | USBHS_PORTSC1_PR_MASK);
        while (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_PR_MASK)
        {
        }
        ehciInstance->firstDeviceSpeed =
            ((ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_PSPD_MASK) >> USBHS_PORTSC1_PSPD_SHIFT);
        /* enable ehci phy disconnection */
        if (ehciInstance->firstDeviceSpeed == USB_SPEED_HIGH)
        {
            USB_EhcihostPhyDisconnectDetectCmd(ehciInstance->controllerId, 1);
        }

        /* wait for reset */
        USB_HostEhciDelay(ehciInstance->ehciIpBase, USB_HOST_EHCI_PORT_RESET_DELAY);
        /* process attach */
        OSA_EventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_DEVICE_ATTACH);
        /* gpt timer start */
        ehciInstance->ehciIpBase->GPTIMER0CTL |=
            (USBHS_GPTIMER0CTL_RUN_MASK | USBHS_GPTIMER0CTL_MODE_MASK | USBHS_GPTIMER0CTL_RST_MASK);
        ehciInstance->deviceAttached = kEHCIDevicePhyAttached;
    }
    else
    {
        if ((ehciInstance->deviceAttached == kEHCIDevicePhyAttached) ||
            (ehciInstance->deviceAttached == kEHCIDeviceAttached))
        {
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
            ehciInstance->busSuspendStatus = kBus_EhciIdle;
            ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK);
#endif
            /* disable ehci phy disconnection */
            USB_EhcihostPhyDisconnectDetectCmd(ehciInstance->controllerId, 0);
            /* disable async and periodic */
            USB_HostEhciStopAsync(ehciInstance);
            USB_HostEhciStopPeriodic(ehciInstance);
            OSA_EventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_DEVICE_DETACH);
        }
    }
}

static void USB_HostEhciTimer0(usb_host_ehci_instance_t *ehciInstance)
{
    volatile usb_host_ehci_qh_t *vltQhPointer;
    volatile usb_host_ehci_qtd_t *vltQtdPointer;
    usb_host_transfer_t *transfer;
    uint32_t backValue;
    volatile uint32_t *totalBytesAddress  = NULL;
    usb_host_ehci_pipe_t *ehciPipePointer = ehciInstance->ehciRunningPipeList;
    uint8_t timeoutLabel;

    while (ehciPipePointer != NULL)
    {
        switch (ehciPipePointer->pipeCommon.pipeType)
        {
            case USB_ENDPOINT_BULK:
            case USB_ENDPOINT_CONTROL:
                vltQhPointer = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh; /* pipe's qh */
                transfer     = vltQhPointer->ehciTransferHead;                         /* qh's transfer */
                if ((transfer != NULL))                                                /* there is transfering data */
                {
                    timeoutLabel = 0;
                    if (ehciInstance->deviceAttached != kEHCIDeviceAttached)
                    {
                        vltQtdPointer = (volatile usb_host_ehci_qtd_t *)transfer->union2.unitTail;

                        vltQhPointer->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; /* invalid next qtd */
                        vltQhPointer->transferOverlayResults[0] &=
                            (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */
                        timeoutLabel = 1;
                    }
                    else
                    {
                        if (vltQhPointer->transferOverlayResults[0] & EHCI_HOST_QTD_STATUS_ACTIVE_MASK)
                        {
                            vltQtdPointer     = (volatile usb_host_ehci_qtd_t *)vltQhPointer->currentQtdPointer;
                            totalBytesAddress = &(vltQhPointer->transferOverlayResults[0]);
                        }
                        else
                        {
                            vltQtdPointer     = (volatile usb_host_ehci_qtd_t *)transfer->union2.unitTail;
                            totalBytesAddress = ((uint32_t *)vltQtdPointer + 2);
                        }

                        backValue =
                            (((*totalBytesAddress) & EHCI_HOST_QTD_TOTAL_BYTES_MASK) >>
                             EHCI_HOST_QTD_TOTAL_BYTES_SHIFT);       /* backValue is used for total bytes to transfer */
                        if (vltQhPointer->timeOutLabel != backValue) /* use total bytes to reflect the time out */
                        {
                            vltQhPointer->timeOutValue = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE;
                            vltQhPointer->timeOutLabel = backValue;
                        }
                        else
                        {
                            /* time out when the total bytes don't change for the duration
                             * USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE
                             */
                            (vltQhPointer->timeOutValue)--;
                            if (vltQhPointer->timeOutValue == 0)
                            {
                                /* stop the qh schedule */
                                USB_HostEhciStopAsync(ehciInstance);
                                if (backValue != (((*totalBytesAddress) & EHCI_HOST_QTD_TOTAL_BYTES_MASK) >>
                                                  EHCI_HOST_QTD_TOTAL_BYTES_SHIFT))
                                {
                                    USB_HostEhciStartAsync(ehciInstance);
                                }
                                else
                                {
                                    vltQhPointer->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; /* invalid next qtd */
                                    vltQhPointer->transferOverlayResults[0] &=
                                        (~EHCI_HOST_QTD_STATUS_MASK); /* clear error status */
                                    USB_HostEhciStartAsync(ehciInstance);
                                    timeoutLabel = 1;
                                }
                            }
                        }
                    }

                    if (timeoutLabel == 1)
                    {
                        /* remove qtd from qh */
                        while ((vltQtdPointer != NULL) &&
                               (!(vltQtdPointer->transferResults[0] & EHCI_HOST_QTD_IOC_MASK)) &&
                               (vltQtdPointer != (usb_host_ehci_qtd_t *)vltQhPointer->ehciTransferTail))
                        {
                            vltQtdPointer = (volatile usb_host_ehci_qtd_t *)vltQtdPointer->nextQtdPointer;
                        }
                        if ((vltQtdPointer != NULL) && (!(vltQtdPointer->nextQtdPointer & EHCI_HOST_T_INVALID_VALUE)))
                        {
                            vltQhPointer->nextQtdPointer =
                                vltQtdPointer->nextQtdPointer; /* start qh if there are other qtd that don't belong to
                                                                  the transfer */
                        }
                        transfer->transferSofar =
                            USB_HostEhciQtdListRelease(ehciInstance, (usb_host_ehci_qtd_t *)(transfer->union1.unitHead),
                                                       (usb_host_ehci_qtd_t *)(transfer->union2.unitTail));
                        transfer->transferSofar = (transfer->transferLength < transfer->transferSofar) ?
                                                      0 :
                                                      (transfer->transferLength - transfer->transferSofar);

                        vltQhPointer->ehciTransferHead = transfer->next;
                        vltQhPointer->timeOutValue     = USB_HOST_EHCI_CONTROL_BULK_TIME_OUT_VALUE;
                        /* callback function is different from the current condition */
                        transfer->callbackFn(transfer->callbackParam, transfer, kStatus_USB_TransferFailed);
                    }
                }
                break;
            default:
                break;
        }
        ehciPipePointer = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next;
    }
}

#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
static void USB_HostEhciTimer1(usb_host_ehci_instance_t *ehciInstance)
{
    if (ehciInstance->deviceAttached != kEHCIDeviceDetached)
    {
        if (kBus_EhciStartSuspend == ehciInstance->busSuspendStatus)
        {
            usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle;

            if (0 == ehciInstance->matchTick)
            {
                ehciInstance->matchTick = hostPointer->hwTick;
            }
            else
            {
                if ((hostPointer->hwTick - ehciInstance->matchTick) >= 5)
                {
                    ehciInstance->ehciIpBase->USBCMD &= ~USBHS_USBCMD_RS_MASK;
                    ehciInstance->ehciIpBase->USBSTS |= USBHS_USBSTS_SRI_MASK;
#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
#if 0
                    ehciInstance->registerPhyBase->CTRL |= USBPHY_CTRL_ENVBUSCHG_WKUP_MASK
                                                      | USBPHY_CTRL_ENIDCHG_WKUP_MASK
                                                      | USBPHY_CTRL_ENDPDMCHG_WKUP_MASK
                                                      | USBPHY_CTRL_ENIRQRESUMEDETECT_MASK
                                                      ;
#endif
#endif
                    ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_PHCD_MASK;

                    ehciInstance->registerPhyBase->PWD = 0xFFFFFFFFU;

                    while (ehciInstance->registerPhyBase->CTRL & (USBPHY_CTRL_UTMI_SUSPENDM_MASK))
                    {
                        __ASM("nop");
                    }

#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
                    ehciInstance->registerNcBase->USB_OTGn_CTRL |= USBNC_USB_OTGn_CTRL_WKUP_ID_EN_MASK |
                                                                   USBNC_USB_OTGn_CTRL_WKUP_VBUS_EN_MASK |
                                                                   USBNC_USB_OTGn_CTRL_WKUP_DPDM_EN_MASK;
                    ehciInstance->registerNcBase->USB_OTGn_CTRL |= USBNC_USB_OTGn_CTRL_WIE_MASK;
#else
                    ehciInstance->ehciIpBase->USBGENCTRL = USBHS_USBGENCTRL_WU_IE_MASK;
#endif
                    ehciInstance->registerPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK;
                    hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
                                                kUSB_HostEventSuspended); /* call host callback function */
                    ehciInstance->busSuspendStatus = kBus_EhciSuspended;
                }
            }
        }
        else if (kBus_EhciStartResume == ehciInstance->busSuspendStatus)
        {
            usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle;
            if (!(ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_FPR_MASK))
            {
                ehciInstance->ehciIpBase->PORTSC1 &= ~USBHS_PORTSC1_WKDS_MASK;
                if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK)
                {
                    USB_HostEhciStartAsync(ehciInstance);
                    USB_HostEhciStartPeriodic(ehciInstance);
                }
                hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
                                            kUSB_HostEventResumed); /* call host callback function */
                hostPointer->suspendedDevice   = NULL;
                ehciInstance->busSuspendStatus = kBus_EhciIdle;
                ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK);
            }
        }
        else
        {
        }
    }
    else
    {
        ehciInstance->busSuspendStatus = kBus_EhciIdle;
        ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK);
    }
}
#endif

void *USB_EhciGetValidFrameList(usb_host_ehci_instance_t *ehciInstance, uint8_t *instanceIndex)
{
    if (ehciInstance->controllerId < kUSB_ControllerEhci0)
    {
        return NULL;
    }

#if (USB_HOST_CONFIG_EHCI == 1U)
    if (!usbHostEhciFramListStatus[0])
    {
        usbHostEhciFramListStatus[0] = 1;
        *instanceIndex               = 0;
        return &s_UsbHostEhciFrameList1[0];
    }
#elif (USB_HOST_CONFIG_EHCI == 2U)
    if (!usbHostEhciFramListStatus[0])
    {
        usbHostEhciFramListStatus[0] = 1;
        *instanceIndex               = 0;
        return &s_UsbHostEhciFrameList1[0];
    }
    else if (!usbHostEhciFramListStatus[1])
    {
        usbHostEhciFramListStatus[1] = 1;
        *instanceIndex               = 1;
        return &s_UsbHostEhciFrameList2[0];
    }
    else
    {
    }
#endif

    return NULL;
}

usb_status_t USB_HostEhciCreate(uint8_t controllerId,
                                usb_host_handle upperLayerHandle,
                                usb_host_controller_handle *controllerHandle)
{
    uint32_t index = 0;
    osa_status_t osaStatus;
    usb_host_ehci_instance_t *ehciInstance;
    uint32_t usbhsBaseAddrs[]               = USBHS_BASE_ADDRS;
    usb_host_ehci_data_t *usbHostEhciData[] = USB_HOST_EHCI_DATA_ARRAY;
    uint32_t *framePointer;
    uint8_t instanceIndex;

    if ((uint32_t)(controllerId - kUSB_ControllerEhci0) >= (sizeof(usbhsBaseAddrs) / sizeof(usbhsBaseAddrs[0])))
    {
        return kStatus_USB_ControllerNotFound;
    }

    *controllerHandle = NULL;
    ehciInstance      = (usb_host_ehci_instance_t *)OSA_MemoryAllocate(
        sizeof(usb_host_ehci_instance_t)); /* malloc host ehci instance */
    if (ehciInstance == NULL)
    {
        return kStatus_USB_AllocFail;
    }
    ehciInstance->controllerId   = controllerId;
    ehciInstance->hostHandle     = upperLayerHandle;
    ehciInstance->deviceAttached = kEHCIDeviceDetached;
    ehciInstance->ehciIpBase     = (USBHS_Type *)
        usbhsBaseAddrs[controllerId - kUSB_ControllerEhci0]; /* operate ehci ip through the base address */
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
    ehciInstance->busSuspendStatus = kBus_EhciIdle;

#if (defined(USB_HOST_CONFIG_LOW_POWER_MODE) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
    ehciInstance->registerPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId);

#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
    ehciInstance->registerNcBase = (USBNC_Type *)USB_EhciNCGetBase(controllerId);
#endif

#endif

#endif

    if (USB_HostEhciResetIP(ehciInstance) != kStatus_USB_Success) /* reset ehci ip */
    {
        OSA_MemoryFree(ehciInstance);
        return kStatus_USB_Error;
    }

    /* initialize ehci frame list */
    ehciInstance->ehciFrameList = USB_EhciGetValidFrameList(ehciInstance, &instanceIndex);
    if (ehciInstance->ehciFrameList == NULL)
    {
        return kStatus_USB_Error;
    }

    /* initialize ehci units */
    ehciInstance->ehciUnitBase = (uint32_t *)(usbHostEhciData[instanceIndex]);
    /* initialize qh/qtd/itd/sitd/iso list */
    ehciInstance->ehciQhList   = (usb_host_ehci_qh_t *)((uint32_t)(ehciInstance->ehciUnitBase));
    ehciInstance->ehciQtdHead  = (usb_host_ehci_qtd_t *)((uint32_t)ehciInstance->ehciQhList +
                                                        (sizeof(usb_host_ehci_qh_t) * USB_HOST_CONFIG_EHCI_MAX_QH));
    ehciInstance->ehciItdList  = (usb_host_ehci_itd_t *)((uint32_t)ehciInstance->ehciQtdHead +
                                                        (sizeof(usb_host_ehci_qtd_t) * USB_HOST_CONFIG_EHCI_MAX_QTD));
    ehciInstance->ehciSitdList = ehciInstance->ehciSitdIndexBase =
        (usb_host_ehci_sitd_t *)((uint32_t)ehciInstance->ehciItdList +
                                 (sizeof(usb_host_ehci_itd_t) * USB_HOST_CONFIG_EHCI_MAX_ITD));
    ehciInstance->ehciIsoList = (usb_host_ehci_iso_t *)((uint32_t)ehciInstance->ehciSitdList +
                                                        (sizeof(usb_host_ehci_sitd_t) * USB_HOST_CONFIG_EHCI_MAX_SITD));
    ehciInstance->ehciPipeIndexBase =
        (usb_host_ehci_pipe_t *)((uint32_t)ehciInstance->ehciIsoList +
                                 (sizeof(usb_host_ehci_iso_t) * USB_HOST_EHCI_ISO_NUMBER));
    for (index = 1; index < USB_HOST_CONFIG_EHCI_MAX_QH; ++index)
    {
        ehciInstance->ehciQhList[index - 1].horizontalLinkPointer = (uint32_t)(&ehciInstance->ehciQhList[index]);
    }
    ehciInstance->ehciQhList[USB_HOST_CONFIG_EHCI_MAX_QH - 1].horizontalLinkPointer = (uint32_t)NULL;
    for (index = 1; index < USB_HOST_CONFIG_EHCI_MAX_QTD; ++index)
    {
        ehciInstance->ehciQtdHead[index - 1].nextQtdPointer = (uint32_t)(&ehciInstance->ehciQtdHead[index]);
    }
    ehciInstance->ehciQtdNumber                                                = USB_HOST_CONFIG_EHCI_MAX_QTD;
    ehciInstance->ehciQtdHead[USB_HOST_CONFIG_EHCI_MAX_QTD - 1].nextQtdPointer = (uint32_t)NULL;
    ehciInstance->ehciQtdTail = &ehciInstance->ehciQtdHead[USB_HOST_CONFIG_EHCI_MAX_QTD - 1];

#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
    for (index = 1; index < USB_HOST_CONFIG_EHCI_MAX_ITD; ++index)
    {
        ehciInstance->ehciItdList[index - 1].nextLinkPointer = (uint32_t)(&ehciInstance->ehciItdList[index]);
    }
    ehciInstance->ehciItdNumber                                                 = USB_HOST_CONFIG_EHCI_MAX_ITD;
    ehciInstance->ehciItdList[USB_HOST_CONFIG_EHCI_MAX_ITD - 1].nextLinkPointer = (uint32_t)NULL;
#endif /* USB_HOST_CONFIG_EHCI_MAX_ITD */

#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))
    for (index = 1; index < USB_HOST_CONFIG_EHCI_MAX_SITD; ++index)
    {
        ehciInstance->ehciSitdList[index - 1].nextLinkPointer = (uint32_t)(&ehciInstance->ehciSitdList[index]);
    }
    ehciInstance->ehciSitdNumber                                                  = USB_HOST_CONFIG_EHCI_MAX_SITD;
    ehciInstance->ehciSitdList[USB_HOST_CONFIG_EHCI_MAX_SITD - 1].nextLinkPointer = (uint32_t)NULL;
#endif /* USB_HOST_CONFIG_EHCI_MAX_SITD */

#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
    for (index = 1; index < USB_HOST_EHCI_ISO_NUMBER; ++index)
    {
        ehciInstance->ehciIsoList[index - 1].next = &ehciInstance->ehciIsoList[index];
    }
    ehciInstance->ehciIsoList[USB_HOST_EHCI_ISO_NUMBER - 1].next = NULL;
#endif

    /* initialize pipes */
    ehciInstance->ehciPipeList = ehciInstance->ehciPipeIndexBase;
    for (index = 1; index < USB_HOST_CONFIG_MAX_PIPES; ++index)
    {
        ehciInstance->ehciPipeList[index - 1].pipeCommon.next = (usb_host_pipe_t *)&ehciInstance->ehciPipeList[index];
    }
    /* initialize mutext */
    ehciInstance->ehciMutex = (osa_mutex_handle_t)(&ehciInstance->mutexBuffer[0]);
    osaStatus = OSA_MutexCreate(ehciInstance->ehciMutex);
    if (osaStatus != KOSA_StatusSuccess)
    {
#ifdef HOST_ECHO
        usb_echo("ehci mutex init fail\r\n");
#endif
        OSA_MemoryFree(ehciInstance);
        return kStatus_USB_Error;
    }
    /* initialize task event */
    ehciInstance->taskEventHandle = (osa_event_handle_t)&ehciInstance->taskEventHandleBuffer[0];
    osaStatus = OSA_EventCreate(ehciInstance->taskEventHandle, 1);
    if (osaStatus != KOSA_StatusSuccess)
    {
#ifdef HOST_ECHO
        usb_echo("ehci event init fail\r\n");
#endif
        OSA_MutexDestroy(ehciInstance->ehciMutex);
        OSA_MemoryFree(ehciInstance);
        return kStatus_USB_Error;
    }

    /* initialize first qh */
    ehciInstance->shedFirstQh = ehciInstance->ehciQhList;
    ehciInstance->ehciQhList =
        (usb_host_ehci_qh_t *)(ehciInstance->ehciQhList->horizontalLinkPointer & EHCI_HOST_POINTER_ADDRESS_MASK);
    ehciInstance->shedFirstQh->staticEndpointStates[0] |= (1 << EHCI_HOST_QH_H_SHIFT); /* first qh */
    ehciInstance->shedFirstQh->horizontalLinkPointer   = EHCI_HOST_T_INVALID_VALUE;
    ehciInstance->shedFirstQh->currentQtdPointer       = EHCI_HOST_T_INVALID_VALUE;
    ehciInstance->shedFirstQh->nextQtdPointer          = EHCI_HOST_T_INVALID_VALUE;
    ehciInstance->shedFirstQh->alternateNextQtdPointer = EHCI_HOST_T_INVALID_VALUE;
    ehciInstance->shedFirstQh->horizontalLinkPointer =
        (uint32_t)((uint32_t)(ehciInstance->shedFirstQh) | EHCI_HOST_POINTER_TYPE_QH);

    /* initialize periodic list */
    framePointer = (uint32_t *)ehciInstance->ehciFrameList;
    for (index = 0; index < USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE; ++index)
    {
        framePointer[index] = EHCI_HOST_T_INVALID_VALUE;
    }

    USB_HostEhciStartIP(ehciInstance); /* start ehci ip */

    *controllerHandle = ehciInstance;

    return kStatus_USB_Success;
}

usb_status_t USB_HostEhciDestory(usb_host_controller_handle controllerHandle)
{
    usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle;

    /* disable all interrupts */
    ehciInstance->ehciIpBase->USBINTR = 0;
    /* stop the controller */
    ehciInstance->ehciIpBase->USBCMD = 0;
/* free memory */
#if (USB_HOST_CONFIG_EHCI == 1U)
    if (ehciInstance->ehciFrameList == &s_UsbHostEhciFrameList1[0])
    {
        usbHostEhciFramListStatus[0] = 0;
    }
#elif (USB_HOST_CONFIG_EHCI == 2U)
    if (ehciInstance->ehciFrameList == &s_UsbHostEhciFrameList1[0])
    {
        usbHostEhciFramListStatus[0] = 0;
    }
    else if (ehciInstance->ehciFrameList == &s_UsbHostEhciFrameList2[0])
    {
        usbHostEhciFramListStatus[1] = 0;
    }
    else
    {
    }
#endif
    OSA_MutexDestroy(ehciInstance->ehciMutex);
    OSA_EventDestroy(ehciInstance->taskEventHandle);
    OSA_MemoryFree(ehciInstance);

    return kStatus_USB_Success;
}

usb_status_t USB_HostEhciOpenPipe(usb_host_controller_handle controllerHandle,
                                  usb_host_pipe_handle *pipeHandle,
                                  usb_host_pipe_init_t *pipeInit)
{
    usb_host_ehci_pipe_t *ehciPipePointer = NULL;
    usb_status_t status;
    uint32_t speed;
    usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle;
    uint32_t val32;

    /* get one pipe */
    USB_HostEhciLock();
    if (ehciInstance->ehciPipeList != NULL)
    {
        ehciPipePointer            = ehciInstance->ehciPipeList;
        ehciInstance->ehciPipeList = (usb_host_ehci_pipe_t *)ehciPipePointer->pipeCommon.next;
    }
    USB_HostEhciUnlock();
    if (ehciPipePointer == NULL)
    {
#ifdef HOST_ECHO
        usb_echo("ehci open pipe failed\r\n");
#endif
        return kStatus_USB_Busy;
    }

    /* initialize pipe informations */
    USB_HostEhciZeroMem((uint32_t *)ehciPipePointer, sizeof(usb_host_ehci_pipe_t) / 4);
    ehciPipePointer->pipeCommon.deviceHandle    = pipeInit->devInstance;
    ehciPipePointer->pipeCommon.endpointAddress = pipeInit->endpointAddress;
    ehciPipePointer->pipeCommon.direction       = pipeInit->direction;
    ehciPipePointer->pipeCommon.interval        = pipeInit->interval;
    ehciPipePointer->pipeCommon.maxPacketSize   = pipeInit->maxPacketSize;
    ehciPipePointer->pipeCommon.pipeType        = pipeInit->pipeType;
    ehciPipePointer->pipeCommon.numberPerUframe = pipeInit->numberPerUframe + 1;
    if (ehciPipePointer->pipeCommon.numberPerUframe > 3)
    {
        ehciPipePointer->pipeCommon.numberPerUframe = 3;
    }
    ehciPipePointer->pipeCommon.nakCount   = pipeInit->nakCount;
    ehciPipePointer->pipeCommon.nextdata01 = 0;
    ehciPipePointer->ehciQh                = NULL;
    USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed, &speed);
    if ((ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS) ||
        (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT))
    {
        if (ehciPipePointer->pipeCommon.pipeType == USB_ENDPOINT_ISOCHRONOUS)
        {
            ehciPipePointer->pipeCommon.interval =
                (1 << (ehciPipePointer->pipeCommon.interval - 1)); /* iso interval is the power of 2 */
        }
        else
        {
            if (speed == USB_SPEED_HIGH)
            {
                ehciPipePointer->pipeCommon.interval =
                    (1 << (ehciPipePointer->pipeCommon.interval - 1)); /* HS interrupt interval is the power of 2 */
            }
            else
            {
                ehciPipePointer->pipeCommon.interval = USB_HostEhciGet2PowerValue(
                    ehciPipePointer->pipeCommon.interval); /* FS/LS interrupt interval should be the power of 2, it is
                                                              used for ehci bandwidth */
            }
        }

        if ((speed == USB_SPEED_HIGH) && (ehciPipePointer->pipeCommon.interval < 8))
        {
            val32 = ehciInstance->ehciIpBase->USBCMD;
            val32 &= (~USBHS_USBCMD_ITC_MASK);
            val32 |= USBHS_USBCMD_ITC((ehciPipePointer->pipeCommon.interval));
            ehciInstance->ehciIpBase->USBCMD = val32;
        }
    }

    /* save the micro-frame interval, it is convenient for the interval process */
    if (speed == USB_SPEED_HIGH)
    {
        ehciPipePointer->uframeInterval = ehciPipePointer->pipeCommon.interval;
    }
    else
    {
        ehciPipePointer->uframeInterval = 8 * ehciPipePointer->pipeCommon.interval;
    }

    /* open pipe */
    switch (ehciPipePointer->pipeCommon.pipeType)
    {
        case USB_ENDPOINT_CONTROL:
        case USB_ENDPOINT_BULK:
            status = USB_HostEhciOpenControlBulk(ehciInstance, ehciPipePointer);
            break;

#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
        case USB_ENDPOINT_ISOCHRONOUS:
            status = USB_HostEhciOpenIso(ehciInstance, ehciPipePointer);
            break;
#endif

        case USB_ENDPOINT_INTERRUPT:
            status = USB_HostEhciOpenInterrupt(ehciInstance, ehciPipePointer);
            break;

        default:
            status = kStatus_USB_Error;
            break;
    }

    if (status != kStatus_USB_Success)
    {
        /* release pipe */
        USB_HostEhciLock();
        ehciPipePointer->pipeCommon.next = (usb_host_pipe_t *)ehciInstance->ehciPipeList;
        ehciInstance->ehciPipeList       = ehciPipePointer;
        USB_HostEhciUnlock();
        return status;
    }

    /* add pipe to run pipe list */
    USB_HostEhciLock();
    ehciPipePointer->pipeCommon.next  = (usb_host_pipe_t *)ehciInstance->ehciRunningPipeList;
    ehciInstance->ehciRunningPipeList = ehciPipePointer;
    USB_HostEhciUnlock();

    *pipeHandle = ehciPipePointer;
    return status;
}

usb_status_t USB_HostEhciClosePipe(usb_host_controller_handle controllerHandle, usb_host_pipe_handle pipeHandle)
{
    usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle;
    usb_host_ehci_pipe_t *ehciPipePointer  = (usb_host_ehci_pipe_t *)pipeHandle;
    usb_host_pipe_t *prevPointer           = NULL;

    switch (ehciPipePointer->pipeCommon.pipeType)
    {
        case USB_ENDPOINT_BULK:
        case USB_ENDPOINT_CONTROL:
            USB_HostEhciCloseControlBulk(ehciInstance, ehciPipePointer);
            break;

        case USB_ENDPOINT_INTERRUPT:
            USB_HostEhciCloseInterrupt(ehciInstance, ehciPipePointer);
            break;

#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
        case USB_ENDPOINT_ISOCHRONOUS:
            USB_HostEhciCloseIso(ehciInstance, ehciPipePointer);
            break;
#endif

        default:
            break;
    }

    /* delete pipe from run pipe list */
    USB_HostEhciLock();
    prevPointer = (usb_host_pipe_t *)ehciInstance->ehciRunningPipeList;
    if (prevPointer == (usb_host_pipe_t *)ehciPipePointer)
    {
        ehciInstance->ehciRunningPipeList = (usb_host_ehci_pipe_t *)(prevPointer->next);
    }
    else
    {
        while (prevPointer != NULL)
        {
            if (prevPointer->next == (usb_host_pipe_t *)ehciPipePointer)
            {
                prevPointer->next = ehciPipePointer->pipeCommon.next;
                break;
            }
            else
            {
                prevPointer = prevPointer->next;
            }
        }
    }
    USB_HostEhciUnlock();

    /* release pipe */
    USB_HostEhciLock();
    ehciPipePointer->pipeCommon.next = (usb_host_pipe_t *)ehciInstance->ehciPipeList;
    ehciInstance->ehciPipeList       = ehciPipePointer;
    USB_HostEhciUnlock();

    return kStatus_USB_Success;
}

usb_status_t USB_HostEhciWritePipe(usb_host_controller_handle controllerHandle,
                                   usb_host_pipe_handle pipeHandle,
                                   usb_host_transfer_t *transfer)
{
    usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle;
    usb_host_ehci_pipe_t *ehciPipePointer  = (usb_host_ehci_pipe_t *)pipeHandle;
    usb_status_t status                    = kStatus_USB_Success;
#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
    uint32_t speed;
#endif

    switch (ehciPipePointer->pipeCommon.pipeType)
    {
        case USB_ENDPOINT_BULK:
        case USB_ENDPOINT_CONTROL:
        case USB_ENDPOINT_INTERRUPT:
            status = USB_HostEhciQhQtdListInit(ehciInstance, ehciPipePointer,
                                               transfer); /* initialize qtd for control/bulk transfer */
            break;

#if (((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD)) || \
     ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD)))
        case USB_ENDPOINT_ISOCHRONOUS:
            USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceSpeed,
                                                   &speed);
            if (speed == USB_SPEED_HIGH)
            {
#if ((defined USB_HOST_CONFIG_EHCI_MAX_ITD) && (USB_HOST_CONFIG_EHCI_MAX_ITD))
                status = USB_HostEhciItdArrayInit(ehciInstance, ehciPipePointer,
                                                  transfer); /* initialize itd for iso transfer */
#endif
            }
            else
            {
#if ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))
                status = USB_HostEhciSitdArrayInit(ehciInstance, ehciPipePointer,
                                                   transfer); /* initialize sitd for iso transfer */
#endif
            }
            break;
#endif

        default:
            break;
    }
    return status;
}

usb_status_t USB_HostEhciReadpipe(usb_host_controller_handle controllerHandle,
                                  usb_host_pipe_handle pipeHandle,
                                  usb_host_transfer_t *transfer)
{
    return USB_HostEhciWritePipe(controllerHandle, pipeHandle, transfer); /* same as write */
}

usb_status_t USB_HostEhciIoctl(usb_host_controller_handle controllerHandle, uint32_t ioctlEvent, void *ioctlParam)
{
    usb_status_t status                    = kStatus_USB_Success;
    usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle;
    usb_host_cancel_param_t *param;
    usb_host_ehci_pipe_t *ehciPipePointer;
    volatile usb_host_ehci_qh_t *vltQhPointer;
    uint32_t deviceAddress;

    if (controllerHandle == NULL)
    {
        return kStatus_USB_InvalidHandle;
    }

    switch (ioctlEvent)
    {
        case kUSB_HostCancelTransfer: /* cancel pipe or one transfer */
            param  = (usb_host_cancel_param_t *)ioctlParam;
            status = USB_HostEhciCancelPipe(ehciInstance, (usb_host_ehci_pipe_t *)param->pipeHandle, param->transfer);
            break;

        case kUSB_HostBusControl: /* bus control */
            status = USB_HostEhciControlBus(ehciInstance, *((uint8_t *)ioctlParam));
            break;

        case kUSB_HostGetFrameNumber: /* get frame number */
            *((uint32_t *)ioctlParam) = ((ehciInstance->ehciIpBase->FRINDEX & EHCI_MAX_UFRAME_VALUE) >> 3);
            break;

        case kUSB_HostUpdateControlEndpointAddress:
            ehciPipePointer = (usb_host_ehci_pipe_t *)ioctlParam;
            vltQhPointer    = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;
            /* update address */
            USB_HostHelperGetPeripheralInformation(ehciPipePointer->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress,
                                                   &deviceAddress);
            vltQhPointer->staticEndpointStates[0] |= deviceAddress;
            USB_HostEhciDelay(ehciInstance->ehciIpBase, 2U);
            break;

        case kUSB_HostUpdateControlPacketSize:
            ehciPipePointer = (usb_host_ehci_pipe_t *)ioctlParam;
            vltQhPointer    = (volatile usb_host_ehci_qh_t *)ehciPipePointer->ehciQh;
            USB_HostEhciLock();
            if (ehciInstance->ehciIpBase->USBSTS & USBHS_USBSTS_AS_MASK)
            {
                USB_HostEhciStopAsync(ehciInstance);
                /* update max packet size */
                vltQhPointer->staticEndpointStates[0] =
                    (((vltQhPointer->staticEndpointStates[0]) & (~EHCI_HOST_QH_MAX_PACKET_LENGTH_MASK)) |
                     ((uint32_t)ehciPipePointer->pipeCommon.maxPacketSize << EHCI_HOST_QH_MAX_PACKET_LENGTH_SHIFT));
                USB_HostEhciStartAsync(ehciInstance);
            }
            else
            {
                /* update max packet size */
                vltQhPointer->staticEndpointStates[0] =
                    (((vltQhPointer->staticEndpointStates[0]) & (~EHCI_HOST_QH_MAX_PACKET_LENGTH_MASK)) |
                     ((uint32_t)ehciPipePointer->pipeCommon.maxPacketSize << EHCI_HOST_QH_MAX_PACKET_LENGTH_SHIFT));
            }
            USB_HostEhciUnlock();
            break;

        default:
            status = kStatus_USB_NotSupported;
            break;
    }
    return status;
}

void USB_HostEhciTaskFunction(void *hostHandle)
{
    usb_host_ehci_instance_t *ehciInstance;
    uint32_t bitSet;
    usb_device_handle deviceHandle;

    if (hostHandle == NULL)
    {
        return;
    }
    ehciInstance = (usb_host_ehci_instance_t *)((usb_host_instance_t *)hostHandle)->controllerHandle;

    if (OSA_EventWait(ehciInstance->taskEventHandle, 0xFF, 0, USB_OSA_WAIT_TIMEOUT, &bitSet) ==
        KOSA_StatusSuccess) /* wait all event */
    {
        if (bitSet & EHCI_TASK_EVENT_PORT_CHANGE) /* port change */
        {
            USB_HostEhciPortChange(ehciInstance);
        }

        if (bitSet & EHCI_TASK_EVENT_TIMER0) /* timer0 */
        {
            USB_HostEhciTimer0(ehciInstance);
        }

#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
        if (bitSet & EHCI_TASK_EVENT_TIMER1) /* timer1 */
        {
            USB_HostEhciTimer1(ehciInstance);
        }
#endif

        if (ehciInstance->deviceAttached == kEHCIDeviceAttached)
        {
            if (bitSet & EHCI_TASK_EVENT_TRANSACTION_DONE) /* transaction done */
            {
                USB_HostEhciTransactionDone(ehciInstance);
            }

            if (bitSet & EHCI_TASK_EVENT_DEVICE_DETACH) /* device detach */
            {
                ehciInstance->ehciIpBase->USBINTR &=
                    (~USBHS_USBINTR_PCE_MASK); /* disable attach, enable when the detach process is done */
                ehciInstance->deviceAttached = kEHCIDeviceDetached;
                USB_HostDetachDevice(ehciInstance->hostHandle, 0, 0);
            }
        }
        else if (ehciInstance->deviceAttached != kEHCIDeviceAttached)
        {
            if (bitSet & EHCI_TASK_EVENT_DEVICE_ATTACH) /* device is attached */
            {
                USB_HostEhciStartAsync(ehciInstance);
                USB_HostEhciStartPeriodic(ehciInstance);

                if (USB_HostAttachDevice(ehciInstance->hostHandle, ehciInstance->firstDeviceSpeed, 0, 0, 1,
                                         &deviceHandle) == kStatus_USB_Success)
                {
                    ehciInstance->deviceAttached = kEHCIDeviceAttached;
                }
            }
        }
        else
        {
        }
    }
}

void USB_HostEhciIsrFunction(void *hostHandle)
{
    usb_host_ehci_instance_t *ehciInstance;
    static uint32_t interruptStatus = 0;

    if (hostHandle == NULL)
    {
        return;
    }

    ehciInstance = (usb_host_ehci_instance_t *)((usb_host_instance_t *)hostHandle)->controllerHandle;

#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))

#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
    if (ehciInstance->registerNcBase->USB_OTGn_CTRL & USBNC_USB_OTGn_CTRL_WIE_MASK)
    {
        usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle;
        ehciInstance->registerNcBase->USB_OTGn_CTRL &= ~USBNC_USB_OTGn_CTRL_WIE_MASK;
        hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
                                    kUSB_HostEventDetectResume); /* call host callback function */

        while (!(ehciInstance->registerNcBase->USB_OTGn_PHY_CTRL_0 & USBNC_USB_OTGn_PHY_CTRL_0_UTMI_CLK_VLD_MASK))
        {
        }

        if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK)
        {
            USB_HostEhciStartAsync(ehciInstance);
            USB_HostEhciStartPeriodic(ehciInstance);
        }
        ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_RS_MASK);
        if ((kBus_EhciSuspended == ehciInstance->busSuspendStatus))
        {
            /* ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_FPR_MASK; */
            ehciInstance->busSuspendStatus = kBus_EhciStartResume;
        }
        else
        {
        }
    }
    else
    {
    }
#else
    if (ehciInstance->ehciIpBase->USBGENCTRL & USBHS_USBGENCTRL_WU_IE_MASK)
    {
        usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle;

        hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
                                    kUSB_HostEventDetectResume); /* call host callback function */

        while (!(USBPHY->PLL_SIC & USBPHY_PLL_SIC_PLL_LOCK_MASK))
        {
        }
        ehciInstance->ehciIpBase->USBGENCTRL |= USBHS_USBGENCTRL_WU_INT_CLR_MASK;
        ehciInstance->ehciIpBase->USBGENCTRL &= ~USBHS_USBGENCTRL_WU_IE_MASK;
        if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK)
        {
            USB_HostEhciStartAsync(ehciInstance);
            USB_HostEhciStartPeriodic(ehciInstance);
        }
        ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_RS_MASK);
        if ((kBus_EhciSuspended == ehciInstance->busSuspendStatus))
        {
            ehciInstance->busSuspendStatus = kBus_EhciStartResume;
            /*ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_FPR_MASK; */
        }
        else
        {
        }
    }
    else
    {
    }
#endif /* FSL_FEATURE_SOC_USBNC_COUNT */

#endif /* USB_HOST_CONFIG_LOW_POWER_MODE */

    interruptStatus = ehciInstance->ehciIpBase->USBSTS;
    interruptStatus &= ehciInstance->ehciIpBase->USBINTR;
    while (interruptStatus) /* there are usb interrupts */
    {
        ehciInstance->ehciIpBase->USBSTS = interruptStatus; /* clear interrupt */

        if (interruptStatus & USBHS_USBSTS_SRI_MASK) /* SOF interrupt */
        {
        }

        if (interruptStatus & USBHS_USBSTS_SEI_MASK) /* system error interrupt */
        {
        }

        if ((interruptStatus & USBHS_USBSTS_UI_MASK) ||
            (interruptStatus & USBHS_USBSTS_UEI_MASK)) /* USB interrupt or USB error interrupt */
        {
            OSA_EventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_TRANSACTION_DONE);
        }

        if (interruptStatus & USBHS_USBSTS_PCI_MASK) /* port change detect interrupt */
        {
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
            usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle;
            if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_FPR_MASK)
            {
                if (kBus_EhciStartSuspend == ehciInstance->busSuspendStatus)
                {
                    if (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK)
                    {
                        USB_HostEhciStartAsync(ehciInstance);
                        USB_HostEhciStartPeriodic(ehciInstance);
                    }
                    hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
                                                kUSB_HostEventNotSuspended); /* call host callback function */
                    hostPointer->suspendedDevice   = NULL;
                    ehciInstance->busSuspendStatus = kBus_EhciIdle;
                    ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK);
                }
                else
                {
                }
            }
#endif
            OSA_EventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_PORT_CHANGE);
        }

        if (interruptStatus & USBHS_USBSTS_TI0_MASK) /* timer 0 interrupt */
        {
            OSA_EventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_TIMER0);
        }

#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
        if (interruptStatus & USBHS_USBSTS_TI1_MASK) /* timer 1 interrupt */
        {
            OSA_EventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_TIMER1);
        }
#endif

        interruptStatus = ehciInstance->ehciIpBase->USBSTS;
        interruptStatus &= ehciInstance->ehciIpBase->USBINTR;
    }
}

#endif /* USB_HOST_CONFIG_EHCI */
