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

#include "usb_host_config.h"
#if (defined(USB_HOST_CONFIG_OHCI) && (USB_HOST_CONFIG_OHCI > 0U))
#include "usb_host.h"
#include "usb_host_hci.h"
#include "fsl_device_registers.h"
#include "usb_host_ohci.h"
#include "usb_host_devices.h"

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

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
static usb_status_t USB_HostOhciLinkGtdControlTr(usb_host_ohci_state_struct_t *usbHostState,
                                                 usb_host_ohci_pipe_struct_t *pipe,
                                                 usb_host_transfer_t *tr);
static usb_status_t USB_HostOhciLinkItdTr(usb_host_ohci_state_struct_t *usbHostState,
                                          usb_host_ohci_pipe_struct_t *pipe,
                                          usb_host_transfer_t *tr);
static usb_status_t USB_HostOhciLinkGtdTr(usb_host_ohci_state_struct_t *usbHostState,
                                          usb_host_ohci_pipe_struct_t *pipe,
                                          usb_host_transfer_t *tr);
static usb_status_t USB_HostOhciFreeItd(usb_host_ohci_state_struct_t *usbHostState,
                                        usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd);
static usb_status_t USB_HostOhciFreeGtd(usb_host_ohci_state_struct_t *usbHostState,
                                        usb_host_ohci_general_transfer_descritpor_struct_t *gtd);
static void USB_HostOhciTdDoneHandle(usb_host_ohci_state_struct_t *usbHostState,
                                     usb_host_ohci_pipe_struct_t *pipe,
                                     usb_host_transfer_t *currentTr,
                                     usb_host_ohci_general_transfer_descritpor_struct_t *gtd,
                                     usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd);

/*******************************************************************************
 * Variables
 ******************************************************************************/
/* The hcca for interrupt tansaction, 256-byte alignment*/
USB_CONTROLLER_DATA USB_RAM_ADDRESS_ALIGNMENT(256) static usb_host_ohci_hcca_struct_t
    s_UsbHostOhciHcca[USB_HOST_CONFIG_OHCI];
USB_CONTROLLER_DATA USB_RAM_ADDRESS_ALIGNMENT(32) static usb_host_ohci_td_struct_t
    s_UsbHostOhciTd[USB_HOST_CONFIG_OHCI];
static usb_host_ohci_state_struct_t s_UsbHostOhciState[USB_HOST_CONFIG_OHCI];

/*******************************************************************************
 * Code
 ******************************************************************************/
static void USB_HostOhciDisableIsr(usb_host_ohci_state_struct_t *usbHostState)
{
    USB_OSA_SR_ALLOC();

    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();
    if (!usbHostState->isrLevel)
    {
        NVIC_DisableIRQ((IRQn_Type)usbHostState->isrNumber);
    }
    usbHostState->isrLevel++;
    USB_OSA_EXIT_CRITICAL();
}

static void USB_HostOhciEnableIsr(usb_host_ohci_state_struct_t *usbHostState)
{
    USB_OSA_SR_ALLOC();

    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();
    usbHostState->isrLevel--;
    if (!usbHostState->isrLevel)
    {
        NVIC_EnableIRQ((IRQn_Type)usbHostState->isrNumber);
    }
    USB_OSA_EXIT_CRITICAL();
}

static void USB_HostOhciDelay(usb_host_ohci_state_struct_t *usbHostState, 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)(s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber & USB_HOST_OHCI_FMNUMBER_FN_MASK);

    do
    {
        SofEnd =
            (int32_t)(s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber & USB_HOST_OHCI_FMNUMBER_FN_MASK);
        distance = (uint32_t)(SofEnd - sofStart + USB_HOST_OHCI_FMNUMBER_FN_MASK + 1) & USB_HOST_OHCI_FMNUMBER_FN_MASK;
    } while ((distance) < (ms)); /* compute the distance between sofStart and SofEnd */
}

static usb_status_t USB_HostOhciControlBus(usb_host_ohci_state_struct_t *usbHostState, uint8_t busControl)
{
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
    uint32_t portStatus;
#endif
    usb_status_t status = kStatus_USB_Success;

    switch (busControl)
    {
        case kUSB_HostBusReset:
            break;

        case kUSB_HostBusRestart:
            break;

        case kUSB_HostBusEnableAttach:
            usbHostState->controlIsBusy = 0U;
            break;

        case kUSB_HostBusDisableAttach:
            break;

#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
        case kUSB_HostBusSuspend:
            if (usbHostState->usbRegBase->HcRhPortStatus[0] & USB_HOST_OHCI_RHPORTSTATUS_CCS_MASK)
            {
                usb_host_instance_t *hostPointer = (usb_host_instance_t *)usbHostState->hostHandle;
                portStatus = usbHostState->usbRegBase->HcRhPortStatus[0];

                portStatus &= ~USB_HOST_OHCI_RHPORTSTATUS_WIC;
                portStatus |= USB_HOST_OHCI_RHPORTSTATUS_PSS_MASK;
                usbHostState->usbRegBase->HcRhPortStatus[0] = portStatus;

                portStatus = usbHostState->usbRegBase->HcControl;
                portStatus &= ~USB_HOST_OHCI_CONTROL_HCFS_MASK;
                portStatus |= USB_HOST_OHCI_CONTROL_HCFS(USB_HOST_OHCI_CONTROL_HCFS_SUSPEND) |
                              USB_HOST_OHCI_CONTROL_RWC_MASK | USB_HOST_OHCI_CONTROL_RWE_MASK;
                usbHostState->usbRegBase->HcControl = portStatus;

                usbHostState->matchTick = hostPointer->hwTick;
                usbHostState->busSuspendStatus = kBus_OhciStartSuspend;

                while ((hostPointer->hwTick - usbHostState->matchTick) <= 3)
                {
                }

                usbHostState->usbRegBase->HcRhStatus |= USB_HOST_OHCI_RHSTATUS_DRWE_MASK;
                /* call host callback function, function is initialized in USB_HostInit */
                hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
                                            kUSB_HostEventSuspended); /* call host callback function */
                usbHostState->busSuspendStatus = kBus_OhciSuspended;
            }
            else
            {
                status = kStatus_USB_Error;
            }
            break;

        case kUSB_HostBusResume:
            if (usbHostState->usbRegBase->HcRhPortStatus[0] & USB_HOST_OHCI_RHPORTSTATUS_CCS_MASK)
            {
                portStatus = usbHostState->usbRegBase->HcRhPortStatus[0];
                portStatus &= ~(USB_HOST_OHCI_RHPORTSTATUS_WIC);
                portStatus |= USB_HOST_OHCI_RHPORTSTATUS_POCI_MASK;
                usbHostState->usbRegBase->HcRhPortStatus[0] = portStatus;
                usbHostState->busSuspendStatus = kBus_OhciStartResume;
            }
            else
            {
                usb_host_instance_t *hostPointer = (usb_host_instance_t *)usbHostState->hostHandle;

                portStatus = usbHostState->usbRegBase->HcControl;
                portStatus &= ~(USB_HOST_OHCI_CONTROL_HCFS_MASK | USB_HOST_OHCI_CONTROL_RWE_MASK |
                                USB_HOST_OHCI_CONTROL_RWC_MASK);
                portStatus |= USB_HOST_OHCI_CONTROL_HCFS(USB_HOST_OHCI_CONTROL_HCFS_OPERATIONAL);
                usbHostState->usbRegBase->HcControl = portStatus;
                portStatus = usbHostState->usbRegBase->HcRhPortStatus[0];
                portStatus &= ~(USB_HOST_OHCI_RHPORTSTATUS_WIC);
                portStatus |= USB_HOST_OHCI_RHPORTSTATUS_PES_MASK;
                usbHostState->usbRegBase->HcRhPortStatus[0] = portStatus;
                hostPointer->suspendedDevice = NULL;
                usbHostState->busSuspendStatus = kBus_OhciIdle;
                status = kStatus_USB_Error;
            }
            break;
#endif
        default:
            status = kStatus_USB_Error;
            break;
    }
    return status;
}

static uint32_t USB_HostOhciBusTime(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_FULL)
        {
            if (direction == USB_IN)
            {
                result = 7268000 + 83540 * result + USB_HOST_OHCI_TIME_DELAY;
            }
            else
            {
                result = 6265000 + 83540 * result + USB_HOST_OHCI_TIME_DELAY;
            }
        }
        else
        {
        }
    }
    else /* interrupt */
    {
        if (speed == USB_SPEED_FULL)
        {
            result = 9107000 + 83540 * result + USB_HOST_OHCI_TIME_DELAY;
        }
        else if (speed == USB_SPEED_LOW)
        {
            if (direction == USB_IN)
            {
                result = 64060000 + 2000 * USB_HOST_OHCI_HUB_LS_SETUP_TIME_DELAY + 676670 * result +
                         USB_HOST_OHCI_TIME_DELAY;
            }
            else
            {
                result = 64107000 + 2000 * USB_HOST_OHCI_HUB_LS_SETUP_TIME_DELAY + 667000 * result +
                         USB_HOST_OHCI_TIME_DELAY;
            }
        }
        else
        {
        }
    }

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

    return result;
}

static usb_status_t USB_HostOhciGetPipe(usb_host_ohci_pipe_struct_t **pipeQueue, usb_host_ohci_pipe_struct_t **pipe)
{
    usb_status_t error = kStatus_USB_Busy;
    USB_OSA_SR_ALLOC();

    /* get a pipe instance */
    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();
    if (NULL != (*pipeQueue))
    {
        *pipe = *pipeQueue;
        *pipeQueue = (usb_host_ohci_pipe_struct_t *)((*pipe)->pipeCommon.next);
        error = kStatus_USB_Success;
    }
    /* Exit critical */
    USB_OSA_EXIT_CRITICAL();
    return error;
}

static usb_status_t USB_HostOhciRemovePipe(usb_host_ohci_pipe_struct_t **pipeQueue, usb_host_ohci_pipe_struct_t *pipe)
{
    usb_host_ohci_pipe_struct_t *p = *pipeQueue;
    usb_host_ohci_pipe_struct_t *pre;

    USB_OSA_SR_ALLOC();

    /* get a pipe instance */
    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();
    pre = NULL;
    while (NULL != p)
    {
        if (p != pipe)
        {
            pre = p;
            p = (usb_host_ohci_pipe_struct_t *)p->pipeCommon.next;
        }
        else
        {
            if (NULL == pre)
            {
                *pipeQueue = (usb_host_ohci_pipe_struct_t *)p->pipeCommon.next;
            }
            else
            {
                pre->pipeCommon.next = p->pipeCommon.next;
            }
            break;
        }
    }
    USB_OSA_EXIT_CRITICAL();
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciInsertPipe(usb_host_ohci_pipe_struct_t **pipeQueue, usb_host_ohci_pipe_struct_t *pipe)
{
    usb_host_ohci_pipe_struct_t *p = *pipeQueue;

    USB_OSA_SR_ALLOC();

    /* get a pipe instance */
    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();
    while (NULL != p)
    {
        if (p != pipe)
        {
            p = (usb_host_ohci_pipe_struct_t *)p->pipeCommon.next;
        }
        else
        {
            break;
        }
    }
    if (NULL == p)
    {
        pipe->pipeCommon.next = (usb_host_pipe_t *)(*pipeQueue);
        *pipeQueue = pipe;
    }
    USB_OSA_EXIT_CRITICAL();
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciGetGtd(usb_host_ohci_state_struct_t *usbHostState,
                                       usb_host_ohci_general_transfer_descritpor_struct_t **gtd,
                                       uint32_t count)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *p = NULL;
    uint32_t *tmp;
    USB_OSA_SR_ALLOC();

    /* get a td */
    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();
    if (count > usbHostState->gtdCount)
    {
        USB_OSA_EXIT_CRITICAL();
        return kStatus_USB_Busy;
    }
    *gtd = NULL;
    while ((count) && (NULL != usbHostState->gtdList))
    {
        if (NULL == (*gtd))
        {
            *gtd = usbHostState->gtdList;
        }
        else
        {
            p->NextTD = (uint32_t)usbHostState->gtdList;
        }
        p = usbHostState->gtdList;

        usbHostState->gtdList = (usb_host_ohci_general_transfer_descritpor_struct_t *)usbHostState->gtdList->nextGtd;
        tmp = (uint32_t *)(p);
        usbHostState->gtdCount--;
        for (int i = 0; i < (sizeof(usb_host_ohci_general_transfer_descritpor_struct_t) / sizeof(uint32_t)); i++)
        {
            tmp[i] = 0U;
        }
        count--;
    }
    if (NULL == p)
    {
        USB_OSA_EXIT_CRITICAL();
        return kStatus_USB_Busy;
    }
    p->NextTD = 0U;
    /* Exit critical */
    USB_OSA_EXIT_CRITICAL();
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciFreeGtd(usb_host_ohci_state_struct_t *usbHostState,
                                        usb_host_ohci_general_transfer_descritpor_struct_t *gtd)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *p;
    USB_OSA_SR_ALLOC();

    if (!gtd)
    {
        return kStatus_USB_Error;
    }

    /* free a td */
    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();
    p = usbHostState->gtdList;
    while (p)
    {
        if (p == gtd)
        {
            USB_OSA_EXIT_CRITICAL();
            return kStatus_USB_Success;
        }
        p = (usb_host_ohci_general_transfer_descritpor_struct_t *)p->nextGtd;
    }
    gtd->nextGtd = usbHostState->gtdList;
    usbHostState->gtdList = gtd;
    usbHostState->gtdCount++;
    /* Exit critical */
    USB_OSA_EXIT_CRITICAL();
    return kStatus_USB_Success;
}

#if (defined(USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD > 0U))
static usb_status_t USB_HostOhciGetItd(usb_host_ohci_state_struct_t *usbHostState,
                                       usb_host_ohci_isochronous_transfer_descritpor_struct_t **itd,
                                       uint32_t count)
{
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *p = NULL;
    uint32_t *tmp;
    USB_OSA_SR_ALLOC();

    /* free a td */
    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();
    if (count > usbHostState->itdCount)
    {
        USB_OSA_EXIT_CRITICAL();
        return kStatus_USB_Busy;
    }
    *itd = NULL;
    while ((count) && (NULL != usbHostState->itdList))
    {
        if (NULL == (*itd))
        {
            *itd = usbHostState->itdList;
        }
        else
        {
            p->NextTD = (uint32_t)usbHostState->itdList;
        }
        p = usbHostState->itdList;
        usbHostState->itdList = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)usbHostState->itdList->NextTD;
        tmp = (uint32_t *)(p);
        usbHostState->itdCount--;
        for (int i = 0; i < (sizeof(usb_host_ohci_isochronous_transfer_descritpor_struct_t) / sizeof(uint32_t)); i++)
        {
            tmp[i] = 0U;
        }
        count--;
    }
    if (NULL == p)
    {
        USB_OSA_EXIT_CRITICAL();
        return kStatus_USB_Busy;
    }
    p->NextTD = 0U;
    /* Exit critical */
    USB_OSA_EXIT_CRITICAL();
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciFreeItd(usb_host_ohci_state_struct_t *usbHostState,
                                        usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd)
{
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *p;
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *pre;
    USB_OSA_SR_ALLOC();

    if (!itd)
    {
        return kStatus_USB_Error;
    }
    /* free a td */
    /* Enter critical */
    pre = NULL;
    USB_OSA_ENTER_CRITICAL();
    p = usbHostState->itdList;
    while (p)
    {
        if (p == itd)
        {
            USB_OSA_EXIT_CRITICAL();
            return kStatus_USB_Success;
        }
        pre = p;
        p = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)p->NextTD;
    }
    if (NULL == pre)
    {
        usbHostState->itdList = itd;
    }
    else
    {
        pre->NextTD = (uint32_t)itd;
    }
    itd->NextTD = 0U;
    usbHostState->itdCount++;
    /* Exit critical */
    USB_OSA_EXIT_CRITICAL();
    return kStatus_USB_Success;
}
#endif

static void USB_HostOhciLinkTdToDoneList(usb_host_ohci_state_struct_t *usbHostState)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *tdList;
    usb_host_ohci_general_transfer_descritpor_struct_t *tdListPos;
    tdList = (usb_host_ohci_general_transfer_descritpor_struct_t
                  *)(s_UsbHostOhciHcca[usbHostState->controllerId].HccaDoneHead & USB_HOST_OHCI_HD_MASK);

    while (tdList)
    {
        tdListPos = (usb_host_ohci_general_transfer_descritpor_struct_t *)(tdList->NextTD & USB_HOST_OHCI_HD_MASK);
        {
            if (usbHostState->tdDoneListTail)
            {
                usbHostState->tdDoneListTail->NextTD = (uint32_t)tdList;
            }
            else
            {
                usbHostState->tdDoneListHead = tdList;
            }
            usbHostState->tdDoneListTail = tdList;
        }
        tdList = tdListPos;
    }
    if (usbHostState->tdDoneListTail)
    {
        usbHostState->tdDoneListTail->NextTD = 0U;
    }
    usbHostState->writeBackCount++;
    s_UsbHostOhciHcca[usbHostState->controllerId].HccaDoneHead = 0U;
}

static usb_status_t USB_HostOhciPortChange(usb_host_ohci_state_struct_t *usbHostState)
{
    uint32_t portStatus;
    int i;
    uint32_t portCount = (usbHostState->usbRegBase->HcRhDescriptorA & USB_HOST_OHCI_RHDESCRIPTORA_NDP_MASK);

    for (i = 0; i < portCount; i++)
    {
        portStatus = usbHostState->usbRegBase->HcRhPortStatus[i];
        if (portStatus & USB_HOST_OHCI_RHPORTSTATUS_CSC_MASK)
        {
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
            if (kBus_OhciIdle != usbHostState->busSuspendStatus)
            {
                usb_host_instance_t *hostPointer = (usb_host_instance_t *)usbHostState->hostHandle;
                portStatus = usbHostState->usbRegBase->HcRhPortStatus[i];
                portStatus &= ~USB_HOST_OHCI_RHPORTSTATUS_WIC;
                usbHostState->usbRegBase->HcRhPortStatus[i] = portStatus | USB_HOST_OHCI_RHPORTSTATUS_PSSC_MASK;
                while ((usbHostState->usbRegBase->HcRhPortStatus[i] & USB_HOST_OHCI_RHPORTSTATUS_PSS_MASK))
                {
                }
                portStatus = usbHostState->usbRegBase->HcControl;
                portStatus &= ~(USB_HOST_OHCI_CONTROL_HCFS_MASK | USB_HOST_OHCI_CONTROL_RWE_MASK |
                                USB_HOST_OHCI_CONTROL_RWC_MASK);
                portStatus |= USB_HOST_OHCI_CONTROL_HCFS(USB_HOST_OHCI_CONTROL_HCFS_OPERATIONAL);
                usbHostState->usbRegBase->HcControl = portStatus;
                portStatus = usbHostState->usbRegBase->HcRhPortStatus[i];
                portStatus &= ~(USB_HOST_OHCI_RHPORTSTATUS_WIC);
                portStatus |= USB_HOST_OHCI_RHPORTSTATUS_PES_MASK;
                usbHostState->usbRegBase->HcRhPortStatus[i] = portStatus;
                hostPointer->suspendedDevice = NULL;
                usbHostState->busSuspendStatus = kBus_OhciIdle;
            }
#endif
            uint32_t sofStart =
                s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber & USB_HOST_OHCI_FMNUMBER_FN_MASK;
            uint32_t sof;
            while (1)
            {
                portStatus = usbHostState->usbRegBase->HcRhPortStatus[i];
                if (portStatus & USB_HOST_OHCI_RHPORTSTATUS_CSC_MASK)
                {
                    portStatus &= ~USB_HOST_OHCI_RHPORTSTATUS_WIC;
                    usbHostState->usbRegBase->HcRhPortStatus[i] = portStatus | USB_HOST_OHCI_RHPORTSTATUS_CSC_MASK;
                }
                sof = s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber & USB_HOST_OHCI_FMNUMBER_FN_MASK;
                if ((((sof + USB_HOST_OHCI_FMNUMBER_FN_MASK + 1) - sofStart) & USB_HOST_OHCI_FMNUMBER_FN_MASK) > 1)
                {
                    break;
                }
            }
        }

        portStatus = usbHostState->usbRegBase->HcRhPortStatus[i];

        if (portStatus & USB_HOST_OHCI_RHPORTSTATUS_CCS_MASK)
        {
            int index;
            if (kUSB_DeviceOhciPortDetached != usbHostState->portState[i].portStatus)
            {
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
                if ((kBus_OhciSuspended == usbHostState->busSuspendStatus) ||
                    (kBus_OhciStartResume == usbHostState->busSuspendStatus))
                {
                    if (portStatus & USB_HOST_OHCI_RHPORTSTATUS_PSSC_MASK)
                    {
                        usb_host_instance_t *hostPointer = (usb_host_instance_t *)usbHostState->hostHandle;
                        usbHostState->busSuspendStatus = kBus_OhciStartResume;
                        /* call host callback function, function is initialized in USB_HostInit */
                        hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
                                                    kUSB_HostEventDetectResume); /* call host callback function */
                        portStatus &= ~USB_HOST_OHCI_RHPORTSTATUS_WIC;
                        usbHostState->usbRegBase->HcRhPortStatus[i] = portStatus | USB_HOST_OHCI_RHPORTSTATUS_PSSC_MASK;
                        while ((usbHostState->usbRegBase->HcRhPortStatus[i] & USB_HOST_OHCI_RHPORTSTATUS_PSS_MASK))
                        {
                        }
                        portStatus = usbHostState->usbRegBase->HcControl;
                        portStatus &= ~(USB_HOST_OHCI_CONTROL_HCFS_MASK | USB_HOST_OHCI_CONTROL_RWE_MASK |
                                        USB_HOST_OHCI_CONTROL_RWC_MASK);
                        portStatus |= USB_HOST_OHCI_CONTROL_HCFS(USB_HOST_OHCI_CONTROL_HCFS_OPERATIONAL);
                        usbHostState->usbRegBase->HcControl = portStatus;
                        portStatus = usbHostState->usbRegBase->HcRhPortStatus[i];
                        portStatus &= ~(USB_HOST_OHCI_RHPORTSTATUS_WIC);
                        portStatus |= USB_HOST_OHCI_RHPORTSTATUS_PES_MASK;
                        usbHostState->usbRegBase->HcRhPortStatus[i] = portStatus;
                        /* call host callback function, function is initialized in USB_HostInit */
                        hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
                                                    kUSB_HostEventResumed); /* call host callback function */
                        hostPointer->suspendedDevice = NULL;
                        usbHostState->busSuspendStatus = kBus_OhciIdle;
                    }
                }
#endif
                break;
            }
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
            usbHostState->busSuspendStatus = kBus_OhciIdle;
#endif
            for (index = 0; index < USB_HOST_OHCI_PORT_CONNECT_DEBOUNCE_DELAY; index++)
            {
                USB_HostOhciDelay(usbHostState, 1);
                if (!(usbHostState->usbRegBase->HcRhPortStatus[i] & USB_HOST_OHCI_RHPORTSTATUS_CCS_MASK))
                {
                    break;
                }
            }

            portStatus = usbHostState->usbRegBase->HcRhPortStatus[i];

            /* CCS is cleared ?*/
            if ((!(portStatus & USB_HOST_OHCI_RHPORTSTATUS_CCS_MASK)) ||
                (index < USB_HOST_OHCI_PORT_CONNECT_DEBOUNCE_DELAY))
            {
                usbHostState->portState[i].portStatus = kUSB_DeviceOhciPortDetached;
                continue;
            }

            portStatus &= ~USB_HOST_OHCI_RHPORTSTATUS_WIC;
            usbHostState->usbRegBase->HcRhPortStatus[i] = portStatus | USB_HOST_OHCI_RHPORTSTATUS_PRS_MASK;

            while (usbHostState->usbRegBase->HcRhPortStatus[i] & USB_HOST_OHCI_RHPORTSTATUS_PRS_MASK)
            {
                __ASM("nop");
            }

            usbHostState->portState[i].portSpeed =
                (usbHostState->usbRegBase->HcRhPortStatus[i] & USB_HOST_OHCI_RHPORTSTATUS_LSDA_MASK) ? USB_SPEED_LOW :
                                                                                                       USB_SPEED_FULL;
            usbHostState->portState[i].portStatus = kUSB_DeviceOhciPortPhyAttached;
            USB_OsaEventSet(usbHostState->ohciEvent, USB_HOST_OHCI_EVENT_ATTACH);
        }
        else
        {
            if (kUSB_DeviceOhciPortDetached == usbHostState->portState[i].portStatus)
            {
                continue;
            }
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
            usbHostState->busSuspendStatus = kBus_OhciIdle;
#endif
            usbHostState->portState[i].portStatus = kUSB_DeviceOhciPortPhyDetached;
            USB_OsaEventSet(usbHostState->ohciEvent, USB_HOST_OHCI_EVENT_DETACH);
        }
    }
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciFindStartFrame(usb_host_ohci_state_struct_t *usbHostState,
                                               usb_host_ohci_pipe_struct_t *pipe)
{
    usb_host_ohci_pipe_struct_t *p;
    uint32_t startFrame;
    uint32_t frame;
    uint32_t total = 0U;

    pipe->startFrame = 0U;

    if (NULL == usbHostState->pipeListInUsing)
    {
        return kStatus_USB_Success;
    }

    for (startFrame = 0U; startFrame < pipe->pipeCommon.interval; startFrame++)
    {
        for (frame = startFrame; frame < USB_HOST_OHCI_HCCA_SIZE; frame++)
        {
            total = 0U;
            for (p = usbHostState->pipeListInUsing; NULL != p; p = (usb_host_ohci_pipe_struct_t *)p->pipeCommon.next)
            {
                if ((frame >= p->startFrame) && (0U == ((frame - p->startFrame) % p->pipeCommon.interval)))
                {
                    total += p->busTime;
                }
            }
            if (total > USB_HOST_OHCI_PERIODIC_BANDWIDTH)
            {
                break;
            }
        }
        if (frame >= USB_HOST_OHCI_HCCA_SIZE)
        {
            pipe->startFrame = startFrame;
            return kStatus_USB_Success;
        }
    }
    return kStatus_USB_BandwidthFail;
}

static usb_status_t USB_HostOhciAddToPeriodicList(usb_host_ohci_state_struct_t *usbHostState,
                                                  usb_host_ohci_pipe_struct_t *pipe)
{
    uint32_t i;
    uint32_t dummy = (uint32_t)&s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_PERIODIC_ED_DUMMY];
    usb_host_ohci_endpoint_descritpor_struct_t *ed;
    usb_host_ohci_endpoint_descritpor_struct_t *pre;

    for (i = pipe->startFrame; i < USB_HOST_OHCI_HCCA_SIZE; i += pipe->pipeCommon.interval)
    {
        ed = (usb_host_ohci_endpoint_descritpor_struct_t *)s_UsbHostOhciHcca[usbHostState->controllerId]
                 .HccaInterrruptTable[i];
        pre = ed;

        while (NULL != pre)
        {
            if (pre == pipe->ed)
            {
                break;
            }
            pre = (usb_host_ohci_endpoint_descritpor_struct_t *)pre->NextED;
        }

        if (NULL != pre)
        {
            continue;
        }

        pre = NULL;
        while (dummy != (uint32_t)ed)
        {
            if (ed->pipe->pipeCommon.interval <= pipe->pipeCommon.interval)
            {
                if ((USB_ENDPOINT_ISOCHRONOUS == pipe->pipeCommon.pipeType) && (dummy != (uint32_t)ed))
                {
                }
                else
                {
                    break;
                }
            }
            pre = ed;
            ed = (usb_host_ohci_endpoint_descritpor_struct_t *)ed->NextED;
        }
        pipe->ed->NextED = (uint32_t)ed;
        if (NULL != pre)
        {
            pre->NextED = (uint32_t)pipe->ed;
        }
        else
        {
            s_UsbHostOhciHcca[usbHostState->controllerId].HccaInterrruptTable[i] = (uint32_t)pipe->ed;
        }
    }
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciOpenControlBulkPipe(usb_host_ohci_state_struct_t *usbHostState,
                                                    usb_host_ohci_pipe_struct_t *pipe)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *gtd;
    usb_status_t error;

    error = USB_HostOhciGetGtd(usbHostState, &gtd, 1);
    if (kStatus_USB_Success != error)
    {
        return error;
    }

    gtd->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
    gtd->stateUnion.stateBitField.R = 1U;

    pipe->ed->TailP = (uint32_t)gtd;
    pipe->ed->HeadP = (uint32_t)gtd;
    if (USB_ENDPOINT_CONTROL == pipe->pipeCommon.pipeType)
    {
        pipe->ed->NextED = s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_CONTROL_ED_DUMMY].NextED;
        s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_CONTROL_ED_DUMMY].NextED = (uint32_t)pipe->ed;
        usbHostState->usbRegBase->HcControl |= USB_HOST_OHCI_CONTROL_CLE_MASK;
    }
    else
    {
        pipe->ed->NextED = s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_BULK_ED_DUMMY].NextED;
        s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_BULK_ED_DUMMY].NextED = (uint32_t)pipe->ed;
        usbHostState->usbRegBase->HcControl |= USB_HOST_OHCI_CONTROL_BLE_MASK;
    }

    return kStatus_USB_Success;
}

#if (defined(USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD > 0U))
static usb_status_t USB_HostOhciOpenIsoPipe(usb_host_ohci_state_struct_t *usbHostState,
                                            usb_host_ohci_pipe_struct_t *pipe)
{
#if (defined(FSL_FEATURE_USBFSH_VERSION) && (FSL_FEATURE_USBFSH_VERSION >= 200U))
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd;
#endif
    usb_status_t error;
    USB_OSA_SR_ALLOC();

    pipe->busTime = USB_HostOhciBusTime(((usb_host_device_instance_t *)pipe->pipeCommon.deviceHandle)->speed,
                                        pipe->pipeCommon.pipeType, pipe->pipeCommon.direction,
                                        pipe->pipeCommon.maxPacketSize * pipe->pipeCommon.numberPerUframe);

    USB_OSA_ENTER_CRITICAL();
    error = USB_HostOhciFindStartFrame(usbHostState, pipe);
    if (kStatus_USB_Success != error)
    {
        USB_OSA_EXIT_CRITICAL();
        return error;
    }

#if (defined(FSL_FEATURE_USBFSH_VERSION) && (FSL_FEATURE_USBFSH_VERSION >= 200U))
    error = USB_HostOhciGetItd(usbHostState, &itd, 1);
    if (kStatus_USB_Success != error)
    {
        USB_OSA_EXIT_CRITICAL();
        return error;
    }
    itd->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;

    pipe->ed->TailP = (uint32_t)itd;
    pipe->ed->HeadP = (uint32_t)itd;
#else
    pipe->ed->TailP = (uint32_t)0;
    pipe->ed->HeadP = (uint32_t)0;
#endif

    usbHostState->usbRegBase->HcControl &= ~(USB_HOST_OHCI_CONTROL_PLE_MASK | USB_HOST_OHCI_CONTROL_IE_MASK);

    USB_HostOhciAddToPeriodicList(usbHostState, pipe);

    usbHostState->usbRegBase->HcControl |= USB_HOST_OHCI_CONTROL_PLE_MASK | USB_HOST_OHCI_CONTROL_IE_MASK;

    USB_OSA_EXIT_CRITICAL();
    return kStatus_USB_Success;
}
#endif

static usb_status_t USB_HostOhciOpenInterruptPipe(usb_host_ohci_state_struct_t *usbHostState,
                                                  usb_host_ohci_pipe_struct_t *pipe)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *gtd;
    usb_status_t error;
    USB_OSA_SR_ALLOC();

    pipe->busTime = USB_HostOhciBusTime(((usb_host_device_instance_t *)pipe->pipeCommon.deviceHandle)->speed,
                                        pipe->pipeCommon.pipeType, pipe->pipeCommon.direction,
                                        pipe->pipeCommon.maxPacketSize * pipe->pipeCommon.numberPerUframe);

    USB_OSA_ENTER_CRITICAL();
    error = USB_HostOhciFindStartFrame(usbHostState, pipe);
    if (kStatus_USB_Success != error)
    {
        USB_OSA_EXIT_CRITICAL();
        return error;
    }

    error = USB_HostOhciGetGtd(usbHostState, &gtd, 1);
    if (kStatus_USB_Success != error)
    {
        USB_OSA_EXIT_CRITICAL();
        return error;
    }
    gtd->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
    gtd->stateUnion.stateBitField.R = 1U;

    pipe->ed->TailP = (uint32_t)gtd;
    pipe->ed->HeadP = (uint32_t)gtd;

    USB_HostOhciAddToPeriodicList(usbHostState, pipe);
    USB_OSA_EXIT_CRITICAL();

    usbHostState->usbRegBase->HcControl |= USB_HOST_OHCI_CONTROL_PLE_MASK;

    return kStatus_USB_Success;
}

static void USB_HostOhciTdDoneHandle(usb_host_ohci_state_struct_t *usbHostState,
                                     usb_host_ohci_pipe_struct_t *pipe,
                                     usb_host_transfer_t *currentTr,
                                     usb_host_ohci_general_transfer_descritpor_struct_t *gtd,
                                     usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd)
{
    usb_host_transfer_t *trPos;
    usb_host_transfer_t *trPre;
    usb_host_ohci_pipe_struct_t *p;
    uint32_t startFrame;
    uint32_t currentFrame;

    pipe->isDone = 0U;
    if (NULL == currentTr)
    {
#if (defined(USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD > 0U))
        if (itd)
        {
            itd->stateUnion.state = 0U;
            itd->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
            itd->NextTD = 0U;
            itd->BE = 0U;
            itd->BP0 = 0U;
            USB_HostOhciFreeItd(usbHostState, itd);
        }
        else
#endif
        {
            gtd->stateUnion.state = 0U;
            gtd->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
            gtd->stateUnion.stateBitField.R = 1U;
            gtd->CBP = 0U;
            gtd->NextTD = 0U;
            gtd->BE = 0U;
        }
        return;
    }

    if (USB_HOST_OHCI_CC_NO_ERROR != gtd->stateUnion.stateBitField.CC)
    {
        if (kStatus_USB_Success == currentTr->union2.frame)
        {
            currentTr->union2.frame = kStatus_USB_TransferFailed;
        }

        if (pipe->ed->HeadP & USB_HOST_OHCI_ED_HEADP_HALT_MASK)
        {
            currentTr->union2.frame = kStatus_USB_TransferStall;
        }
        pipe->ed->HeadP &= ~USB_HOST_OHCI_ED_HEADP_HALT_MASK;
    }

#if (defined(USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD > 0U))
    if (itd)
    {
        usb_host_ohci_isochronous_transfer_descritpor_struct_t *itdP;
        usb_host_ohci_isochronous_transfer_descritpor_struct_t *itdQ = NULL;
        itdP = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)currentTr->union1.unitHead;

        while (itdP)
        {
            if (itd == itdP)
            {
                if (itdQ)
                {
                    itdQ->nextItd = itdP->nextItd;
                }
                else
                {
                    currentTr->union1.unitHead = (uint32_t)itdP->nextItd;
                }
                break;
            }
            itdQ = itdP;
            itdP = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)itdP->nextItd;
        }
        USB_HostOhciFreeItd(usbHostState, itd);
    }
    else
#endif
    {
        usb_host_ohci_general_transfer_descritpor_struct_t *gtdP;
        usb_host_ohci_general_transfer_descritpor_struct_t *gtdQ = NULL;

        gtdP = (usb_host_ohci_general_transfer_descritpor_struct_t *)currentTr->union1.unitHead;
        while (gtdP)
        {
            if (gtd == gtdP)
            {
                if (gtdQ)
                {
                    gtdQ->nextGtd = gtdP->nextGtd;
                }
                else
                {
                    uint32_t tail = pipe->ed->TailP & USB_HOST_OHCI_ED_TAILP_MASK;
                    uint32_t head = pipe->ed->HeadP & USB_HOST_OHCI_ED_HEADP_MASK;
                    currentTr->union1.unitHead = (uint32_t)gtdP->nextGtd;
                    if (head != tail)
                    {
                        pipe->ed->HeadP &= ~USB_HOST_OHCI_ED_HEADP_MASK;
                        pipe->ed->HeadP |= (uint32_t)gtdP->NextTD;
                    }
                }
                break;
            }
            gtdQ = gtdP;
            gtdP = (usb_host_ohci_general_transfer_descritpor_struct_t *)gtdP->nextGtd;
        }
        if ((gtd->CBP) && (USB_HOST_OHCI_GTD_DP_SETUP != gtd->stateUnion.stateBitField.DP))
        {
            currentTr->transferLength -= ((((gtd->BE) ^ (gtd->CBP)) & 0xFFFFF000U) ? 0x00001000U : 0U) +
                                         ((gtd->BE) & 0x00000FFFU) - ((gtd->CBP) & 0x00000FFFU) + 1U;
        }
        currentTr->transferSofar = currentTr->transferLength;
        USB_HostOhciFreeGtd(usbHostState, gtd);
    }

    if (NULL == (void *)(currentTr->union1.unitHead))
    {
        if (!pipe->isCanceling)
        {
            if (USB_ENDPOINT_CONTROL == pipe->pipeCommon.pipeType)
            {
                if (pipe->ed->trListHead)
                {
                    USB_HostOhciLinkGtdControlTr(usbHostState, pipe, pipe->ed->trListHead);
                }
            }
        }
    }

    if (NULL == (void *)(currentTr->union1.unitHead))
    {
        uint8_t trIsFound = 0;
        trPre = NULL;
        trPos = pipe->ed->trListHead;

        while (trPos)
        {
            if (currentTr == trPos)
            {
                if (NULL == trPre)
                {
                    pipe->ed->trListHead = trPos->next;
                }
                else
                {
                    trPre->next = trPos->next;
                }
                trIsFound = 1;
                break;
            }
            trPre = trPos;
            trPos = trPos->next;
        }
        if (NULL == pipe->ed->trListHead)
        {
            pipe->ed->trListTail = NULL;
        }

        if (trIsFound)
        {
            pipe->cutOffTime = USB_HOST_OHCI_TRANSFER_TIMEOUT_GAP;

            if ((kStatus_USB_Success == ((usb_status_t)currentTr->union2.frame)) &&
                (USB_ENDPOINT_CONTROL == pipe->pipeCommon.pipeType) &&
                (USB_REQUEST_STANDARD_CLEAR_FEATURE == currentTr->setupPacket->bRequest) &&
                (USB_REQUEST_TYPE_RECIPIENT_ENDPOINT == currentTr->setupPacket->bmRequestType) &&
                (USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT ==
                 (USB_SHORT_FROM_LITTLE_ENDIAN_DATA(currentTr->setupPacket->wValue) & 0x00FFu)))
            {
                p = usbHostState->pipeListInUsing;
                while (p != NULL)
                {
                    /* only compute bulk and interrupt pipe */
                    if (((p->pipeCommon.endpointAddress |
                          (p->pipeCommon.direction << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) ==
                         ((uint8_t)(USB_SHORT_FROM_LITTLE_ENDIAN_DATA(currentTr->setupPacket->wIndex)))) &&
                        (p->pipeCommon.deviceHandle == pipe->pipeCommon.deviceHandle))
                    {
                        break;
                    }
                    p = (usb_host_ohci_pipe_struct_t *)p->pipeCommon.next;
                }

                if ((NULL != p) && ((p->pipeCommon.pipeType == USB_ENDPOINT_INTERRUPT) ||
                                    (p->pipeCommon.pipeType == USB_ENDPOINT_BULK)))
                {
                    p->ed->stateUnion.stateBitField.K = 1U;
                    startFrame = s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber;
                    currentFrame = startFrame;

                    while (currentFrame == startFrame)
                    {
                        currentFrame = s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber;
                    }

                    p->ed->HeadP &= ~USB_HOST_OHCI_ED_HEADP_CARRY_MASK;

                    p->ed->stateUnion.stateBitField.K = 0U;
                }
            }

            currentTr->callbackFn(currentTr->callbackParam, currentTr,
                                  (usb_status_t)currentTr->union2.frame); /* transfer callback */
            if (USB_ENDPOINT_CONTROL == pipe->pipeCommon.pipeType)
            {
                usbHostState->controlIsBusy = 0U;
            }
            pipe->isBusy = 0U;
        }
        else
        {
        }

        if (0U == usbHostState->controlIsBusy)
        {
            usb_host_ohci_pipe_struct_t *p = usbHostState->pipeListInUsing;

            while (p)
            {
                if (USB_ENDPOINT_CONTROL == p->pipeCommon.pipeType)
                {
                    if (p->ed->trListHead)
                    {
                        /* initialize gtd for control/bulk/interrupt transfer */
                        if (kStatus_USB_Success == USB_HostOhciLinkGtdControlTr(usbHostState, p, p->ed->trListHead))
                        {
                            usbHostState->controlIsBusy = 1U;
                            break;
                        }
                    }
                }
                p = (usb_host_ohci_pipe_struct_t *)p->pipeCommon.next;
            }
        }

        if (pipe->ed->trListHead)
        {
            switch (pipe->pipeCommon.pipeType)
            {
                case USB_ENDPOINT_CONTROL:
                    break;
                case USB_ENDPOINT_BULK:
                case USB_ENDPOINT_INTERRUPT:
                    /* initialize gtd for control/bulk/interrupt transfer */
                    USB_HostOhciLinkGtdTr(usbHostState, pipe, pipe->ed->trListHead);
                    break;
#if ((defined USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD))
                case USB_ENDPOINT_ISOCHRONOUS:
                    /* initialize itd for iso transfer */
                    /* USB_HostOhciLinkItdTr(usbHostState, pipe, pipe->ed->trListHead); */
                    break;
#endif
                default:
                    break;
            }
        }
    }
}

static usb_status_t USB_HostOhciCancelPipe(usb_host_ohci_state_struct_t *usbHostState,
                                           usb_host_ohci_pipe_struct_t *pipe,
                                           usb_host_transfer_t *tr)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *gtd;
    usb_host_ohci_general_transfer_descritpor_struct_t *gtdPre;
    usb_host_ohci_general_transfer_descritpor_struct_t *gtdPos;
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd;
    usb_host_ohci_pipe_struct_t *currentPipe;
    usb_host_transfer_t *trCurrent;
    usb_host_transfer_t *trPos;
    usb_host_transfer_t *trPre;
    uint32_t startFrame;
    uint32_t currentFrame;

    pipe->ed->stateUnion.stateBitField.K = 1U;
    startFrame = s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber;
    currentFrame = startFrame;

    while (currentFrame == startFrame)
    {
        currentFrame = s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber;
    }

    USB_HostOhciLock();
    USB_HostOhciDisableIsr(usbHostState);
    pipe->isCanceling = 1U;
    pipe->ed->HeadP &= ~USB_HOST_OHCI_ED_HEADP_MASK;
    pipe->ed->HeadP |= pipe->ed->TailP;
    /* Fetch the td from token done list */
    gtd = (usb_host_ohci_general_transfer_descritpor_struct_t *)((uint32_t)usbHostState->tdDoneListHead);
    gtdPre = NULL;
    while (gtd)
    {
        if (((uint32_t)gtd) < ((uint32_t)&s_UsbHostOhciTd[usbHostState->controllerId].gtd[0]))
        {
            itd = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)gtd;
            trCurrent = itd->tr;
            currentPipe = itd->pipe;
        }
        else
        {
            itd = NULL;
            trCurrent = gtd->tr;
            currentPipe = gtd->pipe;
        }
        if (pipe == currentPipe)
        {
            if ((NULL == tr) || (tr == trCurrent))
            {
                gtdPos = (usb_host_ohci_general_transfer_descritpor_struct_t *)gtd->NextTD;
                USB_HostOhciTdDoneHandle(usbHostState, pipe, trCurrent, gtd, itd);
                if (NULL == gtdPre)
                {
                    usbHostState->tdDoneListHead = gtdPos;
                }
                else
                {
                    gtdPre->NextTD = (uint32_t)gtdPos;
                }
                gtd = gtdPos;
                continue;
            }
        }
        gtdPre = gtd;
        gtd = (usb_host_ohci_general_transfer_descritpor_struct_t *)gtd->NextTD;
    }

    trPre = NULL;
    trCurrent = pipe->ed->trListHead;

    while (NULL != trCurrent)
    {
        trPos = trCurrent->next;
        if ((NULL == tr) || (tr == trCurrent))
        {
            if (trCurrent->union1.unitHead)
            {
                while (trCurrent->union1.unitHead)
                {
                    gtd = (usb_host_ohci_general_transfer_descritpor_struct_t *)trCurrent->union1.unitHead;
                    if (USB_ENDPOINT_ISOCHRONOUS == pipe->pipeCommon.pipeType)
                    {
                        itd = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)gtd;
                    }
                    else
                    {
                        itd = NULL;
                    }
                    USB_HostOhciTdDoneHandle(usbHostState, pipe, trCurrent, gtd, itd);
                }
            }
            else
            {
                pipe->cutOffTime = USB_HOST_OHCI_TRANSFER_TIMEOUT_GAP;

                trCurrent->callbackFn(trCurrent->callbackParam, trCurrent,
                                      kStatus_USB_TransferCancel); /* transfer callback */

                pipe->isBusy = 0U;
            }
            if (NULL == trPre)
            {
                pipe->ed->trListHead = trPos;
            }
            else
            {
                trPre->next = trPos;
            }
        }
        else
        {
            trPre = trCurrent;
        }
        trCurrent = trPos;
    }
    if (NULL == pipe->ed->trListHead)
    {
        pipe->ed->trListTail = NULL;
    }
    pipe->isCanceling = 0U;
    USB_HostOhciEnableIsr(usbHostState);
    USB_HostOhciUnlock();
    pipe->ed->stateUnion.stateBitField.K = 0U;

    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciRemoveFromPeriodicList(usb_host_ohci_state_struct_t *usbHostState,
                                                       usb_host_ohci_pipe_struct_t *pipe)
{
    uint32_t i;
    usb_host_ohci_endpoint_descritpor_struct_t *ed;
    usb_host_ohci_endpoint_descritpor_struct_t *pre;

    for (i = pipe->startFrame; i < USB_HOST_OHCI_HCCA_SIZE; i += pipe->pipeCommon.interval)
    {
        pre = NULL;
        ed = (usb_host_ohci_endpoint_descritpor_struct_t *)s_UsbHostOhciHcca[usbHostState->controllerId]
                 .HccaInterrruptTable[i];

        while (NULL != ed)
        {
            if (ed == pipe->ed)
            {
                if (NULL == pre)
                {
                    s_UsbHostOhciHcca[usbHostState->controllerId].HccaInterrruptTable[i] = ed->NextED;
                }
                else
                {
                    pre->NextED = ed->NextED;
                }
                break;
            }
            pre = ed;
            ed = (usb_host_ohci_endpoint_descritpor_struct_t *)ed->NextED;
        }
    }
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciCloseControlBulkPipe(usb_host_ohci_state_struct_t *usbHostState,
                                                     usb_host_ohci_pipe_struct_t *pipe)
{
    usb_host_ohci_endpoint_descritpor_struct_t *edHead;
    usb_host_ohci_endpoint_descritpor_struct_t *preEdHead;

    USB_HostOhciCancelPipe(usbHostState, pipe, NULL);

    pipe->ed->stateUnion.stateBitField.K = 1U;

    if (USB_ENDPOINT_CONTROL == pipe->pipeCommon.pipeType)
    {
        edHead = &s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_CONTROL_ED_DUMMY];
    }
    else
    {
        edHead = &s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_BULK_ED_DUMMY];
    }

    USB_HostOhciFreeGtd(
        usbHostState,
        (usb_host_ohci_general_transfer_descritpor_struct_t *)(pipe->ed->TailP & USB_HOST_OHCI_ED_HEADP_MASK));

    preEdHead = NULL;
    while ((edHead) && (edHead != pipe->ed))
    {
        preEdHead = edHead;
        edHead = (usb_host_ohci_endpoint_descritpor_struct_t *)edHead->NextED;
    }

    if ((NULL != preEdHead) && (NULL != edHead))
    {
        preEdHead->NextED = edHead->NextED;
    }

    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciCloseIsoInterruptPipe(usb_host_ohci_state_struct_t *usbHostState,
                                                      usb_host_ohci_pipe_struct_t *pipe)
{
    USB_HostOhciCancelPipe(usbHostState, pipe, NULL);

    pipe->ed->stateUnion.stateBitField.K = 1U;
    if (USB_ENDPOINT_ISOCHRONOUS == pipe->pipeCommon.pipeType)
    {
        USB_HostOhciFreeItd(
            usbHostState,
            (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)(pipe->ed->TailP & USB_HOST_OHCI_ED_HEADP_MASK));
    }
    else
    {
        USB_HostOhciFreeGtd(
            usbHostState,
            (usb_host_ohci_general_transfer_descritpor_struct_t *)(pipe->ed->TailP & USB_HOST_OHCI_ED_HEADP_MASK));
    }

    USB_HostOhciRemoveFromPeriodicList(usbHostState, pipe);

    return kStatus_USB_Success;
}

static void USB_HostOhciFillGtd(usb_host_ohci_pipe_struct_t *pipe,
                                usb_host_transfer_t *tr,
                                usb_host_ohci_general_transfer_descritpor_struct_t *gtd,
                                uint8_t *buffer,
                                uint32_t length,
                                uint8_t dirPid,
                                uint8_t dataToggle,
                                uint8_t ioc)
{
    gtd->CBP = (uint32_t)buffer;
    gtd->BE = (length) ? (gtd->CBP + length - 1U) : 0U;
    gtd->pipe = pipe;
    gtd->tr = tr;
    gtd->stateUnion.stateBitField.R = 1U;
    gtd->stateUnion.stateBitField.DP = dirPid;
    gtd->stateUnion.stateBitField.DI = ioc ? 0 : USB_HOST_OHCI_GTD_DI_NO_INTERRUPT;
    gtd->stateUnion.stateBitField.T = dataToggle;
    gtd->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
    gtd->length = length;
}

static usb_status_t USB_HostOhciLinkGtdControlTr(usb_host_ohci_state_struct_t *usbHostState,
                                                 usb_host_ohci_pipe_struct_t *pipe,
                                                 usb_host_transfer_t *tr)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *head;
    usb_host_ohci_general_transfer_descritpor_struct_t *p = NULL;
    usb_status_t error = kStatus_USB_Error;
    uint8_t dirPid = USB_HOST_OHCI_GTD_DP_SETUP;
    uint8_t statePid = 0U;

    USB_OSA_SR_ALLOC();

    USB_OSA_ENTER_CRITICAL();
    if ((pipe->isBusy) && (kStatus_UsbHostOhci_Idle == tr->setupStatus))
    {
        USB_OSA_EXIT_CRITICAL();
        return kStatus_USB_Success;
    }
    pipe->isBusy = 1;
    pipe->isDone = 0U;
    USB_OSA_EXIT_CRITICAL();

    switch (tr->setupStatus)
    {
        case kStatus_UsbHostOhci_Idle:
            error = USB_HostOhciGetGtd(usbHostState, &p, 1);
            if (kStatus_USB_Success != error)
            {
                USB_OSA_ENTER_CRITICAL();
                pipe->isBusy = 0;
                USB_OSA_EXIT_CRITICAL();
                return error;
            }
            head = (usb_host_ohci_general_transfer_descritpor_struct_t *)pipe->ed->TailP;
            head->NextTD = (uint32_t)p;
            p = head;
            tr->union1.unitHead = (uint32_t)p;
            USB_HostOhciFillGtd(pipe, tr, p, (uint8_t *)tr->setupPacket, 8U, USB_HOST_OHCI_GTD_DP_SETUP, 0x02U, 0U);
            if (tr->transferLength)
            {
                tr->setupStatus = kStatus_UsbHostOhci_Setup;
            }
            else
            {
                tr->setupStatus = kStatus_UsbHostOhci_Data;
            }
            break;
        case kStatus_UsbHostOhci_Setup:
            error = USB_HostOhciGetGtd(usbHostState, &p, 1);
            if (kStatus_USB_Success != error)
            {
                USB_OSA_ENTER_CRITICAL();
                pipe->isBusy = 0;
                USB_OSA_EXIT_CRITICAL();
                return error;
            }

            head = (usb_host_ohci_general_transfer_descritpor_struct_t *)pipe->ed->TailP;
            head->NextTD = (uint32_t)p;
            p = head;
            tr->union1.unitHead = (uint32_t)p;
            dirPid = (tr->direction == USB_OUT) ? USB_HOST_OHCI_GTD_DP_OUT : USB_HOST_OHCI_GTD_DP_IN;
            USB_HostOhciFillGtd(pipe, tr, p, (uint8_t *)tr->transferBuffer, tr->transferLength, dirPid, 0x03U, 1U);
            tr->setupStatus = kStatus_UsbHostOhci_Data;
            break;
        case kStatus_UsbHostOhci_Data:
            error = USB_HostOhciGetGtd(usbHostState, &p, 1);
            if (kStatus_USB_Success != error)
            {
                USB_OSA_ENTER_CRITICAL();
                pipe->isBusy = 0;
                USB_OSA_EXIT_CRITICAL();
                return error;
            }
            head = (usb_host_ohci_general_transfer_descritpor_struct_t *)pipe->ed->TailP;
            head->NextTD = (uint32_t)p;
            p = head;
            tr->union1.unitHead = (uint32_t)p;
            if (tr->transferLength)
            {
                statePid = (tr->direction == USB_OUT) ? USB_HOST_OHCI_GTD_DP_IN : USB_HOST_OHCI_GTD_DP_OUT;
            }
            else
            {
                statePid = USB_HOST_OHCI_GTD_DP_IN;
            }
            USB_HostOhciFillGtd(pipe, tr, p, NULL, 0U, statePid, 0x03, 1U);
            tr->setupStatus = kStatus_UsbHostOhci_State;
            break;
        case kStatus_UsbHostOhci_State:
            tr->setupStatus = kStatus_UsbHostOhci_Idle;
            break;
        default:
            USB_OSA_ENTER_CRITICAL();
            pipe->isBusy = 0;
            USB_OSA_EXIT_CRITICAL();
            tr->setupStatus = kStatus_UsbHostOhci_Idle;
            break;
    }

    if (!pipe->isBusy)
    {
        return kStatus_USB_Error;
    }

    if (p)
    {
        p->stateUnion.stateBitField.DI = 0U;
        p->nextGtd = NULL;
        p = (usb_host_ohci_general_transfer_descritpor_struct_t *)p->NextTD;
        p->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
        p->stateUnion.stateBitField.R = 1U;
        p->pipe = pipe;
        tr->transferPipe = (usb_host_pipe_t *)pipe;
        pipe->ed->TailP = (uint32_t)p;

        usbHostState->usbRegBase->HcCommandStatus |= USB_HOST_OHCI_COMMAND_STATUS_CLF_MASK;
    }
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciLinkGtdTr(usb_host_ohci_state_struct_t *usbHostState,
                                          usb_host_ohci_pipe_struct_t *pipe,
                                          usb_host_transfer_t *tr)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *head;
    usb_host_ohci_general_transfer_descritpor_struct_t *p;
    uint32_t remainingLength = tr->transferLength;
    uint32_t tdCount = 0U;
    uint32_t tdLength = 0U;
    uint32_t bufferAddress = (uint32_t)tr->transferBuffer;
    usb_status_t error;
    uint8_t dirPid = USB_HOST_OHCI_GTD_DP_OUT;

    USB_OSA_SR_ALLOC();

    USB_OSA_ENTER_CRITICAL();
    if (pipe->isBusy)
    {
        USB_OSA_EXIT_CRITICAL();
        return kStatus_USB_Success;
    }
    pipe->isBusy = 1;
    pipe->isDone = 0U;
    USB_OSA_EXIT_CRITICAL();

    while (remainingLength)
    {
        tdLength = USB_HOST_OHCI_GTD_MAX_LENGTH - (bufferAddress & USB_HOST_OHCI_GTD_BUFFER_ALIGN_MASK);
        if (tdLength < remainingLength)
        {
            tdLength -= tdLength % pipe->pipeCommon.maxPacketSize;
        }
        else
        {
            tdLength = remainingLength;
        }
        remainingLength -= tdLength;
        bufferAddress += tdLength;
        tdCount++;
    }

    if (!tdCount)
    {
        tdCount = 1U;
    }

    error = USB_HostOhciGetGtd(usbHostState, &p, tdCount);
    if (kStatus_USB_Success != error)
    {
        USB_OSA_ENTER_CRITICAL();
        pipe->isBusy = 0;
        USB_OSA_EXIT_CRITICAL();
        return error;
    }

    head = (usb_host_ohci_general_transfer_descritpor_struct_t *)pipe->ed->TailP;
    head->NextTD = (uint32_t)p;
    p = head;
    tr->union1.unitHead = (uint32_t)p;
    dirPid = (tr->direction == USB_OUT) ? USB_HOST_OHCI_GTD_DP_OUT : USB_HOST_OHCI_GTD_DP_IN;

    remainingLength = tr->transferLength;
    bufferAddress = (uint32_t)tr->transferBuffer;

    while (remainingLength)
    {
        tdLength = USB_HOST_OHCI_GTD_MAX_LENGTH - (bufferAddress & USB_HOST_OHCI_GTD_BUFFER_ALIGN_MASK);
        if (tdLength < remainingLength)
        {
            tdLength -= tdLength % pipe->pipeCommon.maxPacketSize;
        }
        else
        {
            tdLength = remainingLength;
        }
        remainingLength -= tdLength;
        if (remainingLength)
        {
            USB_HostOhciFillGtd(pipe, tr, p, (uint8_t *)bufferAddress, tdLength, dirPid, 0x00U, 0U);
            p->nextGtd = (usb_host_ohci_general_transfer_descritpor_struct_t *)p->NextTD;
            p = (usb_host_ohci_general_transfer_descritpor_struct_t *)p->NextTD;
        }
        else
        {
            USB_HostOhciFillGtd(pipe, tr, p, (uint8_t *)bufferAddress, tdLength, dirPid, 0x00U, 1U);
        }
        bufferAddress += tdLength;
    }

    if (0U == tr->transferLength)
    {
        USB_HostOhciFillGtd(pipe, tr, p, NULL, 0U, dirPid, 0x00U, 1U);
    }
    p->stateUnion.stateBitField.DI = 0U;
    p->nextGtd = NULL;
    p = (usb_host_ohci_general_transfer_descritpor_struct_t *)p->NextTD;
    p->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
    p->stateUnion.stateBitField.R = 1U;
    p->pipe = pipe;
    tr->transferPipe = (usb_host_pipe_t *)pipe;
    pipe->ed->TailP = (uint32_t)p;

    if (USB_ENDPOINT_BULK == pipe->pipeCommon.pipeType)
    {
        usbHostState->usbRegBase->HcCommandStatus |= USB_HOST_OHCI_COMMAND_STATUS_BLF_MASK;
    }
    else
    {
    }
    return kStatus_USB_Success;
}

#if (defined(USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD > 0U))
static void USB_HostOhciFillItd(usb_host_ohci_pipe_struct_t *pipe,
                                usb_host_transfer_t *tr,
                                usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd,
                                uint8_t *buffer,
                                uint32_t length,
                                uint32_t startFrame)
{
    itd->BP0 = ((uint32_t)buffer) & USB_HOST_OHCI_ITD_BP0_MASK;
    itd->BE = (length) ? (((uint32_t)buffer) + length - 1U) : 0U;
    itd->stateUnion.stateBitField.SF = startFrame & USB_HOST_OHCI_FMNUMBER_FN_MASK;
    itd->stateUnion.stateBitField.DI = 0U;
    itd->stateUnion.stateBitField.FC = (length - 1) / pipe->pipeCommon.maxPacketSize;
    itd->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
    itd->pipe = pipe;
    itd->tr = tr;
    for (int i = 0; i < 8; i++)
    {
        itd->OffsetPSW[i] =
            (((uint32_t)buffer + i * pipe->pipeCommon.maxPacketSize) & 0xFFFU) | (USB_HOST_OHCI_CC_NOT_ACCESSED << 12U);
        if ((((uint32_t)buffer + i * pipe->pipeCommon.maxPacketSize) & USB_HOST_OHCI_ITD_BP0_MASK) != itd->BP0)
        {
            itd->OffsetPSW[i] |= 1U << 11;
        }
    }
    itd->length = length;
}

static usb_status_t USB_HostOhciLinkItdTr(usb_host_ohci_state_struct_t *usbHostState,
                                          usb_host_ohci_pipe_struct_t *pipe,
                                          usb_host_transfer_t *tr)
{
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *head;
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *p;
    uint32_t remainingLength = tr->transferLength;
    uint32_t tdCount = 0U;
    uint32_t tdLength = 0U;
    uint32_t bufferAddress = (uint32_t)tr->transferBuffer;
    uint32_t startFrame;
    uint32_t currentFrame;
    usb_status_t error;
    uint8_t tansaction = 1U;

    if (!remainingLength)
    {
        return kStatus_USB_Success;
    }

    pipe->isDone = 0U;

    tdCount = ((remainingLength - 1) / (pipe->pipeCommon.maxPacketSize)) + 1;
    if (1U == pipe->pipeCommon.interval)
    {
        tdCount = ((tdCount - 1) >> 3) + 1;
#if (defined(FSL_FEATURE_USBFSH_VERSION) && (FSL_FEATURE_USBFSH_VERSION >= 200U))
#else
        tdCount++;
#endif
        tansaction = 8U;
    }
    error = USB_HostOhciGetItd(usbHostState, &p, tdCount);
    if (kStatus_USB_Success != error)
    {
        return error;
    }

#if (defined(FSL_FEATURE_USBFSH_VERSION) && (FSL_FEATURE_USBFSH_VERSION >= 200U))
    head = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)pipe->ed->TailP;
    head->NextTD = (uint32_t)p;
    p = head;
#else
    head = p;
#endif
    tr->union1.unitHead = (uint32_t)p;

    currentFrame = s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber;
    startFrame = currentFrame;

    while (remainingLength)
    {
        tdLength = pipe->pipeCommon.maxPacketSize * tansaction;
        if (tdLength > remainingLength)
        {
            tdLength = remainingLength;
        }
        USB_HostOhciFillItd(pipe, tr, p, (uint8_t *)bufferAddress, tdLength, startFrame);
        remainingLength -= tdLength;
        if (remainingLength)
        {
            p->nextItd = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)p->NextTD;
            p = p->nextItd;
            startFrame += tansaction * pipe->pipeCommon.interval;
        }
        bufferAddress += tdLength;
    }
    p->nextItd = NULL;
    p = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)p->NextTD;
    p->stateUnion.stateBitField.CC = USB_HOST_OHCI_CC_NOT_ACCESSED;
    p->pipe = pipe;
    tr->transferPipe = (usb_host_pipe_t *)pipe;
    pipe->ed->HeadP &= ~USB_HOST_OHCI_ED_HEADP_MASK;
    pipe->ed->HeadP |= (uint32_t)head;
    pipe->ed->TailP = (uint32_t)p;

    return kStatus_USB_Success;
}

#endif

static usb_status_t USB_HostOhciTokenDone(usb_host_ohci_state_struct_t *usbHostState)
{
    usb_host_ohci_general_transfer_descritpor_struct_t *gtd;
    usb_host_ohci_general_transfer_descritpor_struct_t *gtdPos;
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd;
    usb_host_ohci_pipe_struct_t *pipe;
    usb_host_transfer_t *trCurrent;

    /* Enter critical */
    USB_HostOhciLock();
    USB_HostOhciDisableIsr(usbHostState);

    gtd = (usb_host_ohci_general_transfer_descritpor_struct_t *)((uint32_t)usbHostState->tdDoneListHead);
    while (gtd)
    {
        if (((uint32_t)gtd) < ((uint32_t)&s_UsbHostOhciTd[usbHostState->controllerId].gtd[0]))
        {
            itd = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)gtd;
            trCurrent = itd->tr;
            pipe = itd->pipe;
        }
        else
        {
            itd = NULL;
            trCurrent = gtd->tr;
            pipe = gtd->pipe;
        }

        gtdPos = (usb_host_ohci_general_transfer_descritpor_struct_t *)gtd->NextTD;
        USB_HostOhciTdDoneHandle(usbHostState, pipe, trCurrent, gtd, itd);
        if (usbHostState->tdDoneListTail == gtd)
        {
            break;
        }
        gtd = gtdPos;
    }
    usbHostState->tdDoneListHead = NULL;
    usbHostState->tdDoneListTail = NULL;
    /* Exit critical */
    USB_HostOhciEnableIsr(usbHostState);
    USB_HostOhciUnlock();
    return kStatus_USB_Success;
}

static usb_status_t USB_HostOhciSof(usb_host_ohci_state_struct_t *usbHostState)
{
    usb_host_ohci_pipe_struct_t *pipe;
#if (defined(FSL_FEATURE_USBFSH_VERSION) && (FSL_FEATURE_USBFSH_VERSION >= 200U))
#else
    usb_host_ohci_general_transfer_descritpor_struct_t *gtd;
    usb_host_ohci_general_transfer_descritpor_struct_t *gtdP;
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd;
    uint32_t head;
    uint32_t tail;
#endif

    /* Enter critical */
    USB_HostOhciLock();
    USB_HostOhciDisableIsr(usbHostState);
    pipe = usbHostState->pipeListInUsing;
    while (pipe)
    {
        if ((USB_ENDPOINT_CONTROL == pipe->pipeCommon.pipeType) || (USB_ENDPOINT_BULK == pipe->pipeCommon.pipeType))
        {
            if (pipe->ed->trListHead)
            {
                pipe->cutOffTime--;
                if (!pipe->cutOffTime)
                {
                    USB_HostOhciCancelPipe(usbHostState, pipe, pipe->ed->trListHead);
                }
            }
        }
        else
        {
        }

#if (defined(FSL_FEATURE_USBFSH_VERSION) && (FSL_FEATURE_USBFSH_VERSION >= 200U))
#else
        tail = pipe->ed->TailP & USB_HOST_OHCI_ED_TAILP_MASK;
        head = pipe->ed->HeadP & USB_HOST_OHCI_ED_HEADP_MASK;
        if ((pipe->isBusy) && (head == tail))
        {
            if ((pipe->isDone) && (pipe->currentTr == pipe->ed->trListHead))
            {
                if (pipe->startWriteBackCount != usbHostState->writeBackCount)
                {
                    pipe->isDone = 0U;
                    gtd = (usb_host_ohci_general_transfer_descritpor_struct_t *)pipe->ed->trListHead->union1.unitHead;
                    while (gtd)
                    {
                        gtdP = (usb_host_ohci_general_transfer_descritpor_struct_t *)gtd->nextGtd;
                        if (USB_ENDPOINT_ISOCHRONOUS == pipe->pipeCommon.pipeType)
                        {
                            itd = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)gtd;
                        }
                        else
                        {
                            itd = NULL;
                        }
                        /* usb_echo("Timeout pipe\r\n"); */
                        USB_HostOhciTdDoneHandle(usbHostState, pipe, pipe->ed->trListHead, gtd, itd);
                        gtd = gtdP;
                    }
                }
            }
            else
            {
                pipe->isDone = 1;
                pipe->currentTr = pipe->ed->trListHead;
                pipe->startWriteBackCount = usbHostState->writeBackCount;
            }
        }
        else
        {
            pipe->isDone = 0U;
        }
#endif
        pipe = (usb_host_ohci_pipe_struct_t *)pipe->pipeCommon.next;
    }
    /* Exit critical */
    USB_HostOhciEnableIsr(usbHostState);
    USB_HostOhciUnlock();

    return kStatus_USB_Success;
}

static usb_status_t UBS_HostOhciControllerReset(usb_host_ohci_state_struct_t *usbHostState)
{
    usbHostState->usbRegBase->HcCommandStatus = USB_HOST_OHCI_COMMAND_STATUS_HCR_MASK;
    while (usbHostState->usbRegBase->HcCommandStatus & USB_HOST_OHCI_COMMAND_STATUS_HCR_MASK)
    {
        __ASM("nop");
    }
    return kStatus_USB_Success;
}

static usb_status_t UBS_HostOhciControllerInit(usb_host_ohci_state_struct_t *usbHostState)
{
    usb_host_ohci_pipe_struct_t *pipe;
#if (defined(USB_HOST_CONFIG_OHCI_MAX_GTD) && (USB_HOST_CONFIG_OHCI_MAX_GTD > 0U))
    usb_host_ohci_general_transfer_descritpor_struct_t *gtd;
#endif
#if (defined(USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD > 0U))
    usb_host_ohci_isochronous_transfer_descritpor_struct_t *itd;
#endif
    int i;
    USB_OSA_SR_ALLOC();

    /* Enter critical */
    USB_OSA_ENTER_CRITICAL();

    for (i = 0; i < (sizeof(s_UsbHostOhciTd[usbHostState->controllerId].ed) /
                     sizeof(usb_host_ohci_endpoint_descritpor_struct_t));
         i++)
    {
        s_UsbHostOhciTd[usbHostState->controllerId].ed[i].stateUnion.stateBitField.K = 1U;
    }

    for (i = 0; i < sizeof(usb_host_ohci_hcca_struct_t); i++)
    {
        *((uint8_t *)(&s_UsbHostOhciHcca[usbHostState->controllerId]) + i) = 0x00U;
    }

    usbHostState->pipeListInUsing = NULL;
    usbHostState->pipeList = &usbHostState->pipePool[0];
    pipe = usbHostState->pipeList;
    pipe->ed = &s_UsbHostOhciTd[usbHostState->controllerId].ed[3];
    for (i = 1; i < USB_HOST_CONFIG_OHCI_MAX_ED; i++)
    {
        pipe->pipeCommon.next = (usb_host_pipe_t *)&usbHostState->pipePool[i];
        pipe = (usb_host_ohci_pipe_struct_t *)pipe->pipeCommon.next;
        pipe->ed = &s_UsbHostOhciTd[usbHostState->controllerId].ed[3 + i];
    }
    pipe->pipeCommon.next = NULL;

#if (defined(USB_HOST_CONFIG_OHCI_MAX_GTD) && (USB_HOST_CONFIG_OHCI_MAX_GTD > 0U))
    usbHostState->gtdList = &s_UsbHostOhciTd[usbHostState->controllerId].gtd[0];
    gtd = usbHostState->gtdList;
    for (i = 1; i < USB_HOST_CONFIG_OHCI_MAX_GTD; i++)
    {
        gtd->nextGtd = &s_UsbHostOhciTd[usbHostState->controllerId].gtd[i];
        gtd = gtd->nextGtd;
    }
    gtd->nextGtd = NULL;
    usbHostState->gtdCount = USB_HOST_CONFIG_OHCI_MAX_GTD;
#endif

#if (defined(USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD > 0U))
    usbHostState->itdList = &s_UsbHostOhciTd[usbHostState->controllerId].itd[0];
    itd = usbHostState->itdList;
    for (i = 1; i < USB_HOST_CONFIG_OHCI_MAX_ITD; i++)
    {
        itd->NextTD = (uint32_t)&s_UsbHostOhciTd[usbHostState->controllerId].itd[i];
        itd = (usb_host_ohci_isochronous_transfer_descritpor_struct_t *)itd->NextTD;
    }
    itd->NextTD = (uint32_t)NULL;
    usbHostState->itdCount = USB_HOST_CONFIG_OHCI_MAX_ITD;
#endif
    usbHostState->tdDoneListTail = NULL;
    usbHostState->tdDoneListHead = NULL;
    usbHostState->writeBackCount = 0U;

    /* Exit critical */
    USB_OSA_EXIT_CRITICAL();

    usbHostState->usbRegBase->HcControl = 0U;
    usbHostState->usbRegBase->HcControl &= ~USB_HOST_OHCI_CONTROL_HCFS_MASK;
    usbHostState->usbRegBase->HcControl |= USB_HOST_OHCI_CONTROL_HCFS(USB_HOST_OHCI_CONTROL_HCFS_OPERATIONAL);
    usbHostState->usbRegBase->HcFmInterval =
        (USB_HOST_OHCI_FMINTERVAL_FSMPS((6 * (USB_HOST_OHCI_SOF_INTERVAL - 210U)) / 7)) |
        (USB_HOST_OHCI_FMINTERVAL_FI(USB_HOST_OHCI_SOF_INTERVAL));
    usbHostState->usbRegBase->HcPeriodicStart = USB_HOST_OHCI_PERIODIC_START_PS(
        (uint32_t)((float)USB_HOST_OHCI_SOF_INTERVAL * (float)USB_HOST_OHCI_PERIODIC_BANDWIDTH_PERCENT));
    s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_CONTROL_ED_DUMMY].NextED = 0U;
    usbHostState->usbRegBase->HcControlHeadED =
        (uint32_t)&s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_CONTROL_ED_DUMMY];
    s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_BULK_ED_DUMMY].NextED = 0U;
    usbHostState->usbRegBase->HcBulkHeadED =
        (uint32_t)&s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_BULK_ED_DUMMY];
    s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_PERIODIC_ED_DUMMY].NextED = 0U;
    for (i = 0; i < USB_HOST_OHCI_HCCA_SIZE; i++)
    {
        s_UsbHostOhciHcca[usbHostState->controllerId].HccaInterrruptTable[i] =
            (uint32_t)&s_UsbHostOhciTd[usbHostState->controllerId].ed[USB_HOST_OHCI_PERIODIC_ED_DUMMY];
    }
    usbHostState->usbRegBase->HcHCCA = (uint32_t)&s_UsbHostOhciHcca[usbHostState->controllerId];
    usbHostState->usbRegBase->HcControl |= USB_HOST_OHCI_CONTROL_CBSR(USB_HOST_OHCI_CONTROL_CBSR_C1_B1);
    if (usbHostState->usbRegBase->HcRhDescriptorA & USB_HOST_OHCI_RHDESCRIPTORA_NPS_MASK)
    {
    }
    else
    {
/* Use global power to turn on the port power for all ports */
#if 0
        if (usbHostState->usbRegBase->HcRhDescriptorA & USB_HOST_OHCI_RHDESCRIPTORA_PSM_MASK)
        {
            usbHostState->usbRegBase->HcRhDescriptorB |= USB_HOST_OHCI_RHDESCRIPTORB_PPCM(0xFFFEU);
            for (i = 0; i < (usbHostState->usbRegBase->HcRhDescriptorA & USB_HOST_OHCI_RHDESCRIPTORA_NDP_MASK); i++)
            {
                uint32_t portStatus = usbHostState->usbRegBase->HcRhPortStatus[i];
                portStatus &= ~USB_HOST_OHCI_RHPORTSTATUS_WIC;
                portStatus |= USB_HOST_OHCI_RHPORTSTATUS_PPS_MASK;
                usbHostState->usbRegBase->HcRhPortStatus[i] = portStatus;
            }
            usbHostState->usbRegBase->HcRhStatus = USB_HOST_OHCI_RHSTATUS_LPSC_MASK;
        }
        else
        {
            usbHostState->usbRegBase->HcRhStatus = USB_HOST_OHCI_RHSTATUS_LPSC_MASK;
        }
#else
        usbHostState->usbRegBase->HcRhDescriptorB &= ~USB_HOST_OHCI_RHDESCRIPTORB_PPCM(0xFFFEU);
        usbHostState->usbRegBase->HcRhStatus = USB_HOST_OHCI_RHSTATUS_LPSC_MASK;
#endif
    }
    usbHostState->usbRegBase->HcInterruptDisable |= USB_HOST_OHCI_INTERRUPT_DISABLE_MASK;
    usbHostState->usbRegBase->HcInterruptEnable |=
        USB_HOST_OHCI_INTERRUPT_ENABLE_MIE_MASK | USB_HOST_OHCI_INTERRUPT_ENABLE_WDH_MASK |
        USB_HOST_OHCI_INTERRUPT_ENABLE_RHSC_MASK | USB_HOST_OHCI_INTERRUPT_ENABLE_SF_MASK;

    return kStatus_USB_Success;
}

/*!
 * @brief create the USB host ohci instance.
 *
 * This function initializes the USB host ohci controller driver.
 *
 * @param controllerId        The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
 * @param hostHandle         The host level handle.
 * @param controllerHandle  Return the controller instance handle.
 *
 * @retval kStatus_USB_Success              The host is initialized successfully.
 * @retval kStatus_USB_AllocFail             allocate memory fail.
 * @retval kStatus_USB_Error                 host mutex create fail, OHCI mutex or OHCI event create fail.
 *                                                         Or, OHCI IP initialize fail.
 */
usb_status_t USB_HostOhciCreate(uint8_t controllerId,
                                usb_host_handle hostHandle,
                                usb_host_controller_handle *controllerHandle)
{
    usb_host_ohci_state_struct_t *usbHostState;
    usb_status_t status = kStatus_USB_Success;
    uint32_t usb_base_addrs[] = USBFSH_BASE_ADDRS;
    uint8_t usb_irq[] = USBFSH_IRQS;

    if (((controllerId - kUSB_ControllerOhci0) >= (uint8_t)USB_HOST_CONFIG_OHCI) ||
        ((controllerId - kUSB_ControllerOhci0) >= (sizeof(usb_base_addrs) / sizeof(uint32_t))))
    {
        return kStatus_USB_ControllerNotFound;
    }
    usbHostState = &s_UsbHostOhciState[controllerId - kUSB_ControllerOhci0];
    /* Allocate the USB Host Pipe Descriptors */
    usbHostState->hostHandle = hostHandle;
    usbHostState->controllerId = controllerId - kUSB_ControllerOhci0;

    usbHostState->usbRegBase = (usb_host_ohci_hcor_struct_t *)usb_base_addrs[usbHostState->controllerId];
    usbHostState->isrNumber = (IRQn_Type)usb_irq[usbHostState->controllerId];

    USB_OsaEventCreate(&usbHostState->ohciEvent, 1U);
    if (NULL == usbHostState->ohciEvent)
    {
#ifdef HOST_ECHO
        usb_echo(" event create failed in USB_HostOhciCreate\n");
#endif
        return kStatus_USB_AllocFail;
    } /* Endif */

    if (kStatus_USB_OSA_Success != USB_OsaMutexCreate(&usbHostState->mutex))
    {
        USB_HostOhciDestory(usbHostState);
#ifdef HOST_ECHO
        usb_echo("USB_HostOhciCreate: create host mutex fail\r\n");
#endif
        return kStatus_USB_AllocFail;
    }

    /* enable Host clock, OTG clock and AHB clock */
    usbHostState->usbRegBase->PortMode &= ~USB_HOST_OHCI_PORTMODE_DEV_ENABLE_MASK;
    usbHostState->portNumber = (usbHostState->usbRegBase->HcRhDescriptorA & USB_HOST_OHCI_RHDESCRIPTORA_NDP_MASK);
    if (!usbHostState->portNumber)
    {
#ifdef HOST_ECHO
        usb_echo(" Port number is invalid in USB_HostOhciCreate\n");
#endif
        USB_HostOhciDestory(usbHostState);
        return kStatus_USB_Error;
    }

    usbHostState->portState = (usb_host_ohci_port_state_struct_t *)USB_OsaMemoryAllocate(
        sizeof(usb_host_ohci_port_state_struct_t) * usbHostState->portNumber); /* malloc host ohci port state */
    if (NULL == usbHostState->portState)
    {
        USB_HostOhciDestory(usbHostState);
#ifdef HOST_ECHO
        usb_echo("USB_HostOhciCreate: mem alloc fail\r\n");
#endif
        return kStatus_USB_Error;
    }

    UBS_HostOhciControllerReset(usbHostState);

    UBS_HostOhciControllerInit(usbHostState);

    *controllerHandle = (usb_host_handle)usbHostState;
    return status;
}

/*!
 * @brief destroy USB host ohci instance.
 *
 * This function de-initialize the USB host ohci controller driver.
 *
 * @param handle                                    the controller handle.
 *
 * @retval kStatus_USB_Success              The host is initialized successfully.
 */
usb_status_t USB_HostOhciDestory(usb_host_controller_handle controllerHandle)
{
    usb_host_ohci_state_struct_t *usbHostState = (usb_host_ohci_state_struct_t *)controllerHandle;

    usbHostState->usbRegBase->HcInterruptDisable |= USB_HOST_OHCI_INTERRUPT_DISABLE_MASK;
    usbHostState->usbRegBase->HcRhStatus |= USB_HOST_OHCI_RHSTATUS_LPS_MASK;
    usbHostState->usbRegBase->HcControl = 0U;

    if (NULL != usbHostState->portState)
    {
        USB_OsaMemoryFree(usbHostState->portState);
        usbHostState->portState = NULL;
    }

    if (NULL != usbHostState->mutex)
    {
        USB_OsaMutexDestroy(usbHostState->mutex);
        usbHostState->mutex = NULL;
    }

    if (NULL != usbHostState->ohciEvent)
    {
        USB_OsaEventDestroy(usbHostState->ohciEvent);
        usbHostState->ohciEvent = NULL;
    }

    return kStatus_USB_Success;
}

usb_status_t USB_HostOhciOpenPipe(usb_host_controller_handle controllerHandle,
                                  usb_host_pipe_handle *pipeHandle,
                                  usb_host_pipe_init_t *pipeInit)
{
    usb_host_ohci_pipe_struct_t *pipe = NULL;
    usb_status_t status;
    usb_host_ohci_state_struct_t *usbHostState = (usb_host_ohci_state_struct_t *)controllerHandle;

    status = USB_HostOhciGetPipe(&usbHostState->pipeList, &pipe);

    if ((kStatus_USB_Success != status) || (NULL == pipe))
    {
#ifdef HOST_ECHO
        usb_echo("ohci open pipe failed\r\n");
#endif
        return kStatus_USB_Busy;
    }

    /* initialize pipe informations */
    pipe->pipeCommon.deviceHandle = pipeInit->devInstance;
    pipe->pipeCommon.endpointAddress = pipeInit->endpointAddress;
    pipe->pipeCommon.direction = pipeInit->direction;
    pipe->pipeCommon.interval = pipeInit->interval;
    pipe->pipeCommon.maxPacketSize = pipeInit->maxPacketSize;
    pipe->pipeCommon.pipeType = pipeInit->pipeType;
    pipe->pipeCommon.numberPerUframe = 1U;
    pipe->pipeCommon.nakCount = pipeInit->nakCount;
    pipe->pipeCommon.nextdata01 = 0U;
    pipe->pipeCommon.currentCount = 0U;
    pipe->pipeCommon.open = 1U;
    pipe->ed->stateUnion.stateBitField.EN = pipeInit->endpointAddress;
    pipe->ed->stateUnion.stateBitField.D = (USB_OUT == pipeInit->direction) ? 1U : 2U;
    pipe->ed->stateUnion.stateBitField.FA = ((usb_host_device_instance_t *)pipeInit->devInstance)->setAddress;
    pipe->ed->stateUnion.stateBitField.S =
        (USB_SPEED_FULL == ((usb_host_device_instance_t *)pipeInit->devInstance)->speed) ? 0U : 1U;
    pipe->ed->stateUnion.stateBitField.F = 0U;
    pipe->ed->stateUnion.stateBitField.MPS = pipeInit->maxPacketSize;
    pipe->ed->stateUnion.stateBitField.K = 0U;
    pipe->ed->TailP = 0U;
    pipe->ed->HeadP = 0U;
    pipe->ed->pipe = pipe;
    pipe->ed->NextED = 0U;
    pipe->ed->trListHead = NULL;
    pipe->ed->trListTail = NULL;
    pipe->ed->dealTr = NULL;
    pipe->cutOffTime = USB_HOST_OHCI_TRANSFER_TIMEOUT_GAP;
    pipe->isCanceling = 0U;

    if (USB_ENDPOINT_ISOCHRONOUS == pipe->pipeCommon.pipeType)
    {
        pipe->ed->stateUnion.stateBitField.F = 1U;

#if 0
        pipe->pipeCommon.interval =
            (1 << (pipe->pipeCommon.interval - 1)); /* iso interval is the power of 2 */
        if (pipe->pipeCommon.interval > USB_HOST_OHCI_HCCA_SIZE)
        {
            pipe->pipeCommon.interval = USB_HOST_OHCI_HCCA_SIZE;
        }
#else
        pipe->pipeCommon.interval = 1U;
#endif
    }
    else if (USB_ENDPOINT_INTERRUPT == pipe->pipeCommon.pipeType)
    {
        int interval = 0;
        /* FS/LS interrupt interval should be the power of 2, it is used for ohci bandwidth */
        for (int p = 0; p < 16; p++)
        {
            if (pipe->pipeCommon.interval & (1U << p))
            {
                if (p > interval)
                {
                    interval = p;
                }
            }
        }
        pipe->pipeCommon.interval = 1U << interval;
        if (pipe->pipeCommon.interval > USB_HOST_OHCI_HCCA_SIZE)
        {
            pipe->pipeCommon.interval = USB_HOST_OHCI_HCCA_SIZE;
        }
    }
    else
    {
    }

    /* open pipe */
    switch (pipe->pipeCommon.pipeType)
    {
        case USB_ENDPOINT_CONTROL:
            pipe->ed->stateUnion.stateBitField.D = 0;
            status = USB_HostOhciOpenControlBulkPipe(usbHostState, pipe);
            break;
        case USB_ENDPOINT_BULK:
            status = USB_HostOhciOpenControlBulkPipe(usbHostState, pipe);
            break;

#if ((defined(USB_HOST_CONFIG_OHCI_MAX_ITD)) && (USB_HOST_CONFIG_OHCI_MAX_ITD > 0U))
        case USB_ENDPOINT_ISOCHRONOUS:
            status = USB_HostOhciOpenIsoPipe(usbHostState, pipe);
            break;
#endif
        case USB_ENDPOINT_INTERRUPT:
            status = USB_HostOhciOpenInterruptPipe(usbHostState, pipe);
            break;

        default:
            status = kStatus_USB_Error;
            break;
    }

    if (status != kStatus_USB_Success)
    {
        pipe->ed->stateUnion.stateBitField.K = 1U;
        pipe->pipeCommon.open = 0U;
        /* release the pipe */
        USB_HostOhciInsertPipe(&usbHostState->pipeList, pipe);
        return status;
    }

    USB_HostOhciInsertPipe(&usbHostState->pipeListInUsing, pipe);

    *pipeHandle = pipe;
    return status;
}

usb_status_t USB_HostOhciClosePipe(usb_host_controller_handle controllerHandle, usb_host_pipe_handle pipeHandle)
{
    usb_host_ohci_state_struct_t *usbHostState = (usb_host_ohci_state_struct_t *)controllerHandle;
    usb_host_ohci_pipe_struct_t *pipe = (usb_host_ohci_pipe_struct_t *)pipeHandle;

    switch (pipe->pipeCommon.pipeType)
    {
        case USB_ENDPOINT_BULK:
        case USB_ENDPOINT_CONTROL:
            USB_HostOhciCloseControlBulkPipe(usbHostState, pipe);
            break;

#if ((defined USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD))
        case USB_ENDPOINT_ISOCHRONOUS:
#endif
        case USB_ENDPOINT_INTERRUPT:
            USB_HostOhciCloseIsoInterruptPipe(usbHostState, pipe);
            break;

        default:
            break;
    }
    USB_HostOhciRemovePipe(&usbHostState->pipeListInUsing, pipe);
    pipe->pipeCommon.open = 0U;
    USB_HostOhciInsertPipe(&usbHostState->pipeList, pipe);

    return kStatus_USB_Success;
}

usb_status_t USB_HostOhciWritePipe(usb_host_controller_handle controllerHandle,
                                   usb_host_pipe_handle pipeHandle,
                                   usb_host_transfer_t *transfer)
{
    usb_host_ohci_state_struct_t *usbHostState = (usb_host_ohci_state_struct_t *)controllerHandle;
    usb_host_ohci_pipe_struct_t *pipe = (usb_host_ohci_pipe_struct_t *)pipeHandle;
    usb_status_t status = kStatus_USB_Error;
    transfer->setupStatus = kStatus_UsbHostOhci_Idle;
    transfer->union2.frame = 0U;
    USB_OSA_SR_ALLOC();

    switch (pipe->pipeCommon.pipeType)
    {
        case USB_ENDPOINT_CONTROL:
            if (usbHostState->controlIsBusy)
            {
                status = kStatus_USB_Success;
            }
            else
            {
                status = USB_HostOhciLinkGtdControlTr(usbHostState, pipe, transfer);

                if (kStatus_USB_Success == status)
                {
                    usbHostState->controlIsBusy = 1U;
                }
            }
            break;
        case USB_ENDPOINT_BULK:
        case USB_ENDPOINT_INTERRUPT:
            /* initialize gtd for control/bulk/interrupt transfer */
            status = USB_HostOhciLinkGtdTr(usbHostState, pipe, transfer);
            break;
#if ((defined USB_HOST_CONFIG_OHCI_MAX_ITD) && (USB_HOST_CONFIG_OHCI_MAX_ITD))
        case USB_ENDPOINT_ISOCHRONOUS:
            /* initialize itd for iso transfer */
            /* status = USB_HostOhciLinkItdTr(usbHostState, pipe, transfer); */
            if (transfer->transferLength)
            {
                status = kStatus_USB_Success;
                USB_OSA_ENTER_CRITICAL();
                if (NULL == pipe->ed->dealTr)
                {
                    if (NULL != pipe->ed->trListHead)
                    {
                        pipe->ed->dealTr = pipe->ed->trListHead;
                    }
                    else
                    {
                        pipe->ed->dealTr = transfer;
                    }
                }
                USB_OSA_EXIT_CRITICAL();
            }
            else
            {
                status = kStatus_USB_InvalidParameter;
            }
            break;
#endif
        default:
            break;
    }

    if (kStatus_USB_Success == status)
    {
        USB_OSA_ENTER_CRITICAL();
        if (pipe->ed->trListHead)
        {
            pipe->ed->trListTail->next = transfer;
        }
        else
        {
            pipe->ed->trListHead = transfer;
        }
        pipe->ed->trListTail = transfer;
        transfer->next = NULL;
        USB_OSA_EXIT_CRITICAL();
    }
    return status;
}

usb_status_t USB_HostOhciReadPipe(usb_host_controller_handle controllerHandle,
                                  usb_host_pipe_handle pipeHandle,
                                  usb_host_transfer_t *transfer)
{
    return USB_HostOhciWritePipe(controllerHandle, pipeHandle, transfer);
}

usb_status_t USB_HostOhciIoctl(usb_host_controller_handle controllerHandle, uint32_t ioctlEvent, void *ioctlParam)
{
    usb_host_ohci_state_struct_t *usbHostState = (usb_host_ohci_state_struct_t *)controllerHandle;
    usb_host_cancel_param_t *param;
    usb_host_ohci_pipe_struct_t *pipe;
    uint32_t deviceAddress;
    usb_status_t status = kStatus_USB_Success;

    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_HostOhciCancelPipe(usbHostState, (usb_host_ohci_pipe_struct_t *)param->pipeHandle, param->transfer);
            break;

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

        case kUSB_HostGetFrameNumber:
            /* get frame number */
            *((uint32_t *)ioctlParam) = (s_UsbHostOhciHcca[usbHostState->controllerId].HccaFrameNumber);
            break;

        case kUSB_HostUpdateControlEndpointAddress:
            pipe = (usb_host_ohci_pipe_struct_t *)ioctlParam;
            pipe->ed->stateUnion.stateBitField.K = 1U;
            /* update address */
            USB_HostHelperGetPeripheralInformation(pipe->pipeCommon.deviceHandle, kUSB_HostGetDeviceAddress,
                                                   &deviceAddress);
            pipe->ed->stateUnion.stateBitField.FA = deviceAddress;
            pipe->ed->stateUnion.stateBitField.K = 0U;
            USB_HostOhciDelay(usbHostState, 2U);
            break;

        case kUSB_HostUpdateControlPacketSize:
            pipe = (usb_host_ohci_pipe_struct_t *)ioctlParam;
            pipe->ed->stateUnion.stateBitField.K = 1U;
            pipe->ed->stateUnion.stateBitField.MPS = pipe->pipeCommon.maxPacketSize;
            pipe->ed->stateUnion.stateBitField.K = 0U;
            break;

        case kUSB_HostPortAttachDisable:
            break;

        case kUSB_HostPortAttachEnable:
            break;

        default:
            break;
    }
    return status;
}

void USB_HostOhciTaskFunction(void *hostHandle)
{
    usb_host_ohci_state_struct_t *usbHostState;
    uint32_t bitSet;

    if (NULL == hostHandle)
    {
        return;
    }
    usbHostState = (usb_host_ohci_state_struct_t *)((usb_host_instance_t *)hostHandle)->controllerHandle;

    /* wait all event */
    if (kStatus_USB_OSA_Success == USB_OsaEventWait(usbHostState->ohciEvent, 0xFFU, 0, 0, &bitSet))
    {
        if (bitSet & USB_HOST_OHCI_EVENT_PORT_CHANGE)
        {
            USB_HostOhciPortChange(usbHostState);
        }
        if (bitSet & USB_HOST_OHCI_EVENT_TOKEN_DONE)
        {
            USB_HostOhciTokenDone(usbHostState);
        }
        if (bitSet & USB_HOST_OHCI_EVENT_SOF)
        {
            USB_HostOhciSof(usbHostState);
        }
        if (bitSet & USB_HOST_OHCI_EVENT_ATTACH)
        {
            for (int i = 0; i < usbHostState->portNumber; i++)
            {
                if (kUSB_DeviceOhciPortPhyAttached == usbHostState->portState[i].portStatus)
                {
                    void *deviceHandle;
                    if (kStatus_USB_Success == USB_HostAttachDevice(usbHostState->hostHandle,
                                                                    usbHostState->portState[i].portSpeed, 0, i, 1,
                                                                    &deviceHandle))
                    {
                        usbHostState->portState[i].portStatus = kUSB_DeviceOhciPortAttached;
                    }
                }
            }
        }
        if (bitSet & USB_HOST_OHCI_EVENT_DETACH)
        {
            for (int i = 0; i < usbHostState->portNumber; i++)
            {
                if (kUSB_DeviceOhciPortPhyDetached == usbHostState->portState[i].portStatus)
                {
                    usbHostState->portState[i].portStatus = kUSB_DeviceOhciPortDetached;
                    USB_HostDetachDevice(usbHostState->hostHandle, 0, i);
                }
            }
        }
    }
}

void USB_HostOhciIsrFunction(void *hostHandle)
{
    usb_host_ohci_state_struct_t *usbHostState;
    usb_host_ohci_pipe_struct_t *pipe;
    static uint32_t interruptStatus = 0U;
    static uint32_t sofCount = 0U;

    if (hostHandle == NULL)
    {
        return;
    }

    usbHostState = (usb_host_ohci_state_struct_t *)((usb_host_instance_t *)hostHandle)->controllerHandle;

    interruptStatus = usbHostState->usbRegBase->HcInterruptStatus;
    interruptStatus &= usbHostState->usbRegBase->HcInterruptEnable;

    if (interruptStatus & USB_HOST_OHCI_INTERRUPT_STATUS_WDH_MASK) /* Write back done head */
    {
        USB_HostOhciLinkTdToDoneList(usbHostState);
        USB_OsaEventSet(usbHostState->ohciEvent, USB_HOST_OHCI_EVENT_TOKEN_DONE);
    }

    if (interruptStatus & USB_HOST_OHCI_INTERRUPT_STATUS_SF_MASK) /* SOF interrupt */
    {
        for (pipe = usbHostState->pipeListInUsing; NULL != pipe;
             pipe = (usb_host_ohci_pipe_struct_t *)pipe->pipeCommon.next)
        {
            if ((USB_ENDPOINT_ISOCHRONOUS == pipe->pipeCommon.pipeType) && (NULL != pipe->ed->trListHead))
            {
                if ((NULL != pipe->ed->dealTr))
                {
                    uint32_t tail = pipe->ed->TailP & USB_HOST_OHCI_ED_TAILP_MASK;
                    uint32_t head = pipe->ed->HeadP & USB_HOST_OHCI_ED_HEADP_MASK;
                    if (head == tail)
                    {
                        if (kStatus_USB_Success == USB_HostOhciLinkItdTr(usbHostState, pipe, pipe->ed->dealTr))
                        {
                            pipe->ed->dealTr = pipe->ed->dealTr->next;
                        }
                    }
                }
                pipe->isDone = 0U;
            }
        }
        sofCount++;
        if (sofCount >= USB_HOST_OHCI_TRANSFER_SCAN_INTERVAL)
        {
            sofCount = 0U;
            USB_OsaEventSet(usbHostState->ohciEvent, USB_HOST_OHCI_EVENT_SOF);
        }
    }

    if (interruptStatus & USB_HOST_OHCI_INTERRUPT_STATUS_RHSC_MASK) /* port change detect interrupt */
    {
        USB_OsaEventSet(usbHostState->ohciEvent, USB_HOST_OHCI_EVENT_PORT_CHANGE);
    }

    usbHostState->usbRegBase->HcInterruptStatus = interruptStatus; /* clear interrupt */
}

#endif
