summaryrefslogtreecommitdiff
path: root/usb_1.1.0/host/usb_host_khci.c
diff options
context:
space:
mode:
Diffstat (limited to 'usb_1.1.0/host/usb_host_khci.c')
-rw-r--r--usb_1.1.0/host/usb_host_khci.c1886
1 files changed, 1886 insertions, 0 deletions
diff --git a/usb_1.1.0/host/usb_host_khci.c b/usb_1.1.0/host/usb_host_khci.c
new file mode 100644
index 0000000..57af624
--- /dev/null
+++ b/usb_1.1.0/host/usb_host_khci.c
@@ -0,0 +1,1886 @@
+/*
+ * Copyright (c) 2015 -2016, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "usb_host_config.h"
+#if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI))
+#include "usb_host.h"
+#include "usb_host_hci.h"
+#include "fsl_device_registers.h"
+#include "usb_host_khci.h"
+#include "usb_host_devices.h"
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if defined(__ICCCF__) || defined(__ICCARM__)
+#pragma segment = "USB_BDT_Z"
+#pragma data_alignment = 512
+__no_init static uint8_t bdt[512] @"USB_BDT_Z";
+#elif defined(__GNUC__)
+__attribute__((aligned(512))) static uint8_t bdt[512];
+#elif defined(__CC_ARM)
+__align(512) uint8_t bdt[512];
+#else
+#error Unsupported compiler, please use IAR, Keil or arm gcc compiler and rebuild the project.
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * @brief get the 2 power value of uint32_t.
+ *
+ * @param data input uint32_t value.
+ *
+ */
+static uint32_t _USB_HostKhciGetRoundUpPow2(uint32_t data)
+{
+ uint8_t i = 0U;
+
+ if ((data == 1U) || (data == 0U))
+ {
+ return data;
+ }
+ while (data != 1U)
+ {
+ data = data >> 1U;
+ i++;
+ }
+ return 1U << (i);
+}
+
+/*!
+ * @brief get the current host khci frame number count.
+ *
+ * @param handle Pointer of the host KHCI state structure.
+ *
+ * @return current frame number count.
+ */
+static uint32_t _USB_HostKhciGetFrameCount(usb_host_controller_handle handle)
+{
+ uint32_t tempFrameCount;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle;
+
+ tempFrameCount = usbHostPointer->usbRegBase->FRMNUMH;
+
+ return (uint16_t)((tempFrameCount << 8U) | (usbHostPointer->usbRegBase->FRMNUML));
+}
+
+/*!
+ * @brief get the total of host khci frame number count.
+ *
+ * @param usbHostPointer Pointer of the host KHCI state structure.
+ *
+ * @return total of frame number count.
+ */
+static uint32_t _USB_HostKhciGetFrameCountSum(usb_khci_host_state_struct_t *usbHostPointer)
+{
+ static uint32_t totalFrameNumber = 0U;
+ static uint16_t oldFrameNumber = 0U;
+ uint16_t frameNumber = 0xFFFFU;
+
+ frameNumber = _USB_HostKhciGetFrameCount((usb_host_controller_handle)usbHostPointer);
+
+ if (frameNumber < oldFrameNumber)
+ {
+ totalFrameNumber += 2048U;
+ }
+
+ oldFrameNumber = frameNumber;
+
+ return (frameNumber + totalFrameNumber);
+}
+
+/*!
+ * @brief host khci delay.
+ *
+ * @param usbHostPointer Pointer of the host KHCI state structure.
+ * @param ms milliseconds.
+ *
+ */
+static void _USB_HostKhciDelay(usb_khci_host_state_struct_t *usbHostPointer, uint32_t ms)
+{
+ uint32_t sofStart;
+ uint32_t sofEnd;
+ sofStart = _USB_HostKhciGetFrameCountSum(usbHostPointer);
+
+ do
+ {
+ sofEnd = _USB_HostKhciGetFrameCountSum(usbHostPointer);
+ } while ((sofEnd - sofStart) < ms);
+}
+
+/*!
+ * @brief Device KHCI isr function.
+ *
+ * The function is KHCI interrupt service routine.
+ *
+ * @param hostHandle The host handle.
+ */
+void USB_HostKhciIsrFunction(void *hostHandle)
+{
+ usb_khci_host_state_struct_t *usbHostPointer;
+
+ uint8_t status;
+
+ if (hostHandle == NULL)
+ {
+ return;
+ }
+
+ usbHostPointer = (usb_khci_host_state_struct_t *)((usb_host_instance_t *)hostHandle)->controllerHandle;
+
+ while (1U)
+ {
+ status = (uint8_t)((usbHostPointer->usbRegBase->ISTAT));
+ status &= (uint8_t)(usbHostPointer->usbRegBase->INTEN);
+
+ if (!status)
+ {
+ break;
+ }
+
+ usbHostPointer->usbRegBase->ISTAT = status;
+
+ if (status & USB_ISTAT_SOFTOK_MASK)
+ {
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_SOF_TOK);
+ }
+
+ if (status & USB_ISTAT_ATTACH_MASK)
+ {
+ usbHostPointer->usbRegBase->INTEN &= (~USB_INTEN_ATTACHEN_MASK);
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_ATTACH);
+ }
+
+ if (status & USB_ISTAT_TOKDNE_MASK)
+ {
+ /* atom transaction done - token done */
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_TOK_DONE);
+ }
+
+ if (status & USB_ISTAT_USBRST_MASK)
+ {
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_RESET);
+ }
+ }
+}
+
+/*!
+ * @brief Handle khci host controller attach event.
+ *
+ * The function is used to handle attach event when a device is attached to khci host controller, the process is detect
+ * the line state, do bus reset, and call device attached function.
+ *
+ * @param usbHostPointer Pointer of the host KHCI state structure.
+ *
+ */
+static void _USB_HostKhciAttach(usb_khci_host_state_struct_t *usbHostPointer)
+{
+ uint8_t speed;
+ uint8_t temp;
+ usb_device_handle deviceHandle;
+ uint8_t index = 0U;
+
+ usbHostPointer->usbRegBase->CTL |= USB_CTL_ODDRST_MASK;
+ usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK;
+ usbHostPointer->usbRegBase->ADDR = ((usbHostPointer->usbRegBase->ADDR & (~USB_ADDR_ADDR_MASK)) |
+ ((((0U) << USB_ADDR_ADDR_SHIFT) & USB_ADDR_ADDR_MASK)));
+ usbHostPointer->usbRegBase->ADDR &= (~USB_ADDR_LSEN_MASK);
+
+ /* here wait for about 120ms to check line state */
+ for (volatile uint32_t i = 0U; i < 2000000U; i++)
+ {
+ __ASM("nop");
+ }
+
+ do
+ {
+ temp = ((usbHostPointer->usbRegBase->CTL) & USB_CTL_JSTATE_MASK) ? 0U : 1U;
+ for (volatile uint32_t i = 0U; i < 100000U; i++)
+ {
+ __ASM("nop");
+ }
+ speed = ((usbHostPointer->usbRegBase->CTL) & USB_CTL_JSTATE_MASK) ? 0U : 1U;
+ index++;
+ } while ((temp != speed) && (index < USB_KHCI_MAX_SPEED_DETECTION_COUNT));
+
+ if (temp != speed)
+ {
+#ifdef HOST_ECHO
+ usb_echo("speed not match!\n");
+#endif
+ usbHostPointer->usbRegBase->INTEN |= USB_INTEN_ATTACHEN_MASK;
+ return;
+ }
+ if (((usbHostPointer->usbRegBase->CTL) & USB_CTL_SE0_MASK) == USB_CTL_SE0_MASK)
+ {
+ usbHostPointer->usbRegBase->INTEN |= USB_INTEN_ATTACHEN_MASK;
+ return;
+ }
+
+ if (speed == USB_SPEED_FULL)
+ {
+ usbHostPointer->usbRegBase->ADDR &= (~USB_ADDR_LSEN_MASK);
+ }
+ else if (speed == USB_SPEED_LOW)
+ {
+ usbHostPointer->usbRegBase->ENDPOINT[0U].ENDPT = USB_ENDPT_HOSTWOHUB_MASK;
+ usbHostPointer->usbRegBase->ADDR |= USB_ADDR_LSEN_MASK;
+ }
+ else
+ {
+ }
+
+ usbHostPointer->usbRegBase->CTL |= USB_CTL_USBENSOFEN_MASK;
+
+ usbHostPointer->usbRegBase->ISTAT = 0xffU;
+ usbHostPointer->usbRegBase->INTEN &= (~(USB_INTEN_TOKDNEEN_MASK | USB_INTEN_USBRSTEN_MASK));
+
+ /* Do USB bus reset here */
+ usbHostPointer->usbRegBase->CTL |= USB_CTL_RESET_MASK;
+ _USB_HostKhciDelay(usbHostPointer, 30U);
+ usbHostPointer->usbRegBase->CTL &= (~USB_CTL_RESET_MASK);
+
+#ifdef USBCFG_OTG
+ _USB_HostKhciDelay(usbHostPointer, 30U);
+#else
+ _USB_HostKhciDelay(usbHostPointer, 100U);
+#endif
+ usbHostPointer->usbRegBase->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
+ usbHostPointer->usbRegBase->INTEN |= (USB_INTEN_TOKDNEEN_MASK | USB_INTEN_USBRSTEN_MASK);
+ usbHostPointer->deviceAttached++;
+ USB_OsaEventClear(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_TOK_DONE);
+ USB_HostAttachDevice(usbHostPointer->hostHandle, speed, 0U, 0U, 1, &deviceHandle);
+
+ usbHostPointer->txBd = 0U;
+ usbHostPointer->rxBd = 0U;
+}
+
+/*!
+ * @brief Handle khci host controller bus reset event.
+ *
+ * The function is used to handle khci host controller bus reset event, reset event also is used for khci detached
+ * detecction.
+ *
+ * @param usbHostPointer Pointer of the host KHCI state structure.
+ *
+ */
+static void _USB_HostKhciReset(usb_khci_host_state_struct_t *usbHostPointer)
+{
+ volatile uint32_t i = 0xfffU;
+ /* clear attach flag */
+ usbHostPointer->usbRegBase->ISTAT = USB_ISTAT_ATTACH_MASK;
+ while (i--)
+ {
+ __ASM("nop");
+ }
+ /* Test the presence of USB device */
+ if ((usbHostPointer->usbRegBase->ISTAT) & USB_ISTAT_ATTACH_MASK)
+ {
+ /* device attached, so really normal reset was performed */
+ usbHostPointer->usbRegBase->INTEN |= USB_ISTAT_USBRST_MASK;
+ usbHostPointer->usbRegBase->ADDR = ((usbHostPointer->usbRegBase->ADDR & (~USB_ADDR_ADDR_MASK)) |
+ ((((0U) << USB_ADDR_ADDR_SHIFT) & USB_ADDR_ADDR_MASK)));
+ usbHostPointer->usbRegBase->ENDPOINT[0U].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
+ }
+ else
+ {
+ /* device was detached,, notify about detach */
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_DETACH);
+ }
+}
+
+/*!
+ * @brief Handle khci host controller bus detach event.
+ *
+ * @param usbHostPointer Pointer of the host KHCI state structure.
+ *
+ */
+static void _USB_HostKhciDetach(usb_khci_host_state_struct_t *usbHostPointer)
+{
+ if (usbHostPointer->deviceAttached > 0)
+ {
+ usbHostPointer->deviceAttached--;
+ }
+ else
+ {
+ return;
+ }
+ USB_HostDetachDevice(usbHostPointer->hostHandle, 0U, 0U);
+ /* Enable USB week pull-downs, useful for detecting detach (effectively bus discharge) */
+ usbHostPointer->usbRegBase->USBCTRL |= USB_USBCTRL_PDE_MASK;
+ /* Remove suspend state */
+ usbHostPointer->usbRegBase->USBCTRL &= (~USB_USBCTRL_SUSP_MASK);
+
+ usbHostPointer->usbRegBase->CTL |= USB_CTL_ODDRST_MASK;
+
+ usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK;
+
+ usbHostPointer->txBd = 0U;
+ usbHostPointer->rxBd = 0U;
+
+ usbHostPointer->usbRegBase->ISTAT = 0xffU;
+ USB_OsaEventClear(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG);
+}
+
+/*!
+ * @brief get a right transfer from periodic and async list.
+ *
+ * This function return a right transfer for khci atom transfer, the function implemented simple USB transaction
+ * dispatch algorithm.
+ *
+ * @param handle Pointer of the host khci controller handle.
+ * @param transfer Pointer of pointer of transfer node struct, will get the a tr quest pointer if operator
+ * success, will get NULL pointer if fail.
+ *
+ */
+static void _USB_HostKhciGetRightTrRequest(usb_host_controller_handle handle, usb_host_transfer_t **transfer)
+{
+ usb_host_transfer_t *tempTransfer;
+ usb_host_transfer_t *firstTransfer;
+ usb_host_transfer_t *prevTtransfer;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle;
+ uint32_t frame_number;
+
+ if (handle == NULL)
+ {
+ *transfer = NULL;
+ return;
+ }
+
+ USB_HostKhciLock();
+ /* First check whether periodic list is active, will get transfer from periodic list */
+ if (usbHostPointer->periodicListAvtive)
+ {
+ prevTtransfer = tempTransfer = usbHostPointer->periodicListPointer;
+ frame_number = _USB_HostKhciGetFrameCount(usbHostPointer);
+ /* Will get the transfer if the pipe frame count and current frame count is equal */
+ while (tempTransfer != NULL)
+ {
+ if ((tempTransfer->transferPipe->currentCount != frame_number) &&
+ (frame_number % tempTransfer->transferPipe->interval == 0U) &&
+ (tempTransfer->transferPipe->pipeType == USB_ENDPOINT_INTERRUPT))
+ {
+ tempTransfer->transferPipe->currentCount = frame_number;
+ *transfer = firstTransfer = tempTransfer;
+ /* Will move the selected interrupt transfer to end of the periodic list */
+ if ((tempTransfer->transferPipe->pipeType == USB_ENDPOINT_INTERRUPT) && (tempTransfer->next != NULL))
+ {
+ if (tempTransfer == usbHostPointer->periodicListPointer)
+ {
+ usbHostPointer->periodicListPointer = tempTransfer->next;
+ }
+ else
+ {
+ prevTtransfer->next = tempTransfer->next;
+ }
+ while (tempTransfer != NULL)
+ {
+ prevTtransfer = tempTransfer;
+ tempTransfer = tempTransfer->next;
+ }
+ prevTtransfer->next = firstTransfer;
+ firstTransfer->next = NULL;
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG);
+ }
+ USB_HostKhciUnlock();
+ return;
+ }
+ prevTtransfer = tempTransfer;
+ tempTransfer = tempTransfer->next;
+ }
+ }
+ /* will get the first transfer from active list if no active transfer in async list */
+ if (usbHostPointer->asyncListAvtive)
+ {
+ firstTransfer = tempTransfer = usbHostPointer->asyncListPointer;
+ *transfer = firstTransfer;
+
+ if (tempTransfer->next != NULL)
+ {
+ usbHostPointer->asyncListPointer = tempTransfer->next;
+ }
+ else
+ {
+ USB_HostKhciUnlock();
+ return;
+ }
+ tempTransfer = tempTransfer->next;
+ while (tempTransfer != NULL)
+ {
+ prevTtransfer = tempTransfer;
+ tempTransfer = tempTransfer->next;
+ }
+ prevTtransfer->next = firstTransfer;
+ firstTransfer->next = NULL;
+ }
+ USB_HostKhciUnlock();
+}
+
+/*!
+ * @brief unlink transfer from periodic and async khci transfer list.
+ *
+ * @param handle Pointer of the host khci controller handle.
+ * @param transfer Pointer of transfer node struct, which will be unlink from transfer list.
+ *
+ */
+static void _USB_HostKhciUnlinkTrRequestFromList(usb_host_controller_handle handle, usb_host_transfer_t *transfer)
+{
+ usb_host_transfer_t *temptr = NULL;
+ usb_host_transfer_t *pretr = NULL;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle;
+
+ if ((handle == NULL) || (transfer == NULL))
+ {
+ return;
+ }
+
+ USB_HostKhciLock();
+ if (usbHostPointer->asyncListAvtive == 1U)
+ {
+ temptr = usbHostPointer->asyncListPointer;
+ if (transfer == temptr)
+ {
+ usbHostPointer->asyncListPointer = temptr->next;
+ }
+ else
+ {
+ while (temptr != NULL)
+ {
+ pretr = temptr;
+ temptr = temptr->next;
+ if (transfer == temptr)
+ {
+ pretr->next = temptr->next;
+ break;
+ }
+ }
+ }
+ if (usbHostPointer->asyncListPointer == NULL)
+ {
+ usbHostPointer->asyncListAvtive = 0U;
+ }
+ }
+ if (usbHostPointer->periodicListAvtive == 1U)
+ {
+ temptr = usbHostPointer->periodicListPointer;
+ if (transfer == temptr)
+ {
+ usbHostPointer->periodicListPointer = temptr->next;
+ }
+ else
+ {
+ while (temptr != NULL)
+ {
+ pretr = temptr;
+ temptr = temptr->next;
+ if (transfer == temptr)
+ {
+ pretr->next = temptr->next;
+ break;
+ }
+ }
+ }
+ if (usbHostPointer->periodicListPointer == NULL)
+ {
+ usbHostPointer->periodicListAvtive = 0U;
+ }
+ }
+ USB_HostKhciUnlock();
+}
+
+/*!
+ * @brief link transfer to periodic and async khci transfer list.
+ *
+ * @param handle Pointer of the host khci controller handle.
+ * @param transfer Pointer of transfer node struct, which will be link to transfer list.
+ *
+ */
+static usb_status_t _USB_HostKhciLinkTrRequestToList(usb_host_controller_handle controllerHandle,
+ usb_host_transfer_t *transfer)
+{
+ usb_host_transfer_t *temptransfer;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle;
+
+ if ((transfer == NULL))
+ {
+ return kStatus_USB_InvalidParameter;
+ }
+
+ USB_HostKhciLock();
+ if ((transfer->transferPipe->pipeType == USB_ENDPOINT_ISOCHRONOUS) ||
+ (transfer->transferPipe->pipeType == USB_ENDPOINT_INTERRUPT))
+ {
+ if (usbHostPointer->periodicListAvtive == 0U)
+ {
+ usbHostPointer->periodicListPointer = transfer;
+ transfer->next = NULL;
+ usbHostPointer->periodicListAvtive = 1U;
+ }
+ else
+ {
+ temptransfer = usbHostPointer->periodicListPointer;
+ while (temptransfer->next != NULL)
+ {
+ temptransfer = temptransfer->next;
+ }
+ temptransfer->next = transfer;
+ transfer->next = NULL;
+ }
+ }
+ else if ((transfer->transferPipe->pipeType == USB_ENDPOINT_CONTROL) ||
+ (transfer->transferPipe->pipeType == USB_ENDPOINT_BULK))
+ {
+ if (usbHostPointer->asyncListAvtive == 0U)
+ {
+ usbHostPointer->asyncListPointer = transfer;
+ transfer->next = NULL;
+ usbHostPointer->asyncListAvtive = 1U;
+ }
+ else
+ {
+ temptransfer = usbHostPointer->asyncListPointer;
+ while (temptransfer->next != NULL)
+ {
+ temptransfer = temptransfer->next;
+ }
+ temptransfer->next = transfer;
+ transfer->next = NULL;
+ }
+ }
+ else
+ {
+ }
+ USB_HostKhciUnlock();
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief khci process tranfer callback function.
+ *
+ * @param controllerHandle Pointer of the host khci controller handle.
+ * @param transfer Pointer of transfer , which will be process callback.
+ * @param err The return value of transfer.
+ *
+ */
+static void _USB_HostKhciProcessTrCallback(usb_host_controller_handle controllerHandle,
+ usb_host_transfer_t *transfer,
+ int32_t err)
+{
+ usb_status_t status = kStatus_USB_Success;
+
+ if (err == USB_KHCI_ATOM_TR_STALL)
+ {
+ status = kStatus_USB_TransferStall;
+ }
+ else if ((err == USB_KHCI_ATOM_TR_NAK) || (err >= 0))
+ {
+ status = kStatus_USB_Success;
+
+ if (err == USB_KHCI_ATOM_TR_NAK)
+ {
+ status = kStatus_USB_TransferFailed;
+ }
+ }
+ else if (err < 0)
+ {
+ status = kStatus_USB_TransferFailed;
+ }
+ else
+ {
+ }
+
+ transfer->callbackFn(transfer->callbackParam, transfer, status);
+}
+
+/*!
+ * @brief khci transaction done process function.
+ *
+ * @param usbHostPointer Pointer of the host khci controller handle.
+ * @param transfer Pointer of transfer node struct, which will be handled process done.
+ *1400
+ */
+static int32_t _USB_HostKhciTransactionDone(usb_khci_host_state_struct_t *usbHostPointer, usb_host_transfer_t *transfer)
+{
+ uint32_t bd;
+ uint8_t err;
+ int32_t transferResult = 0U;
+ uint32_t type = kTr_Unknown;
+ uint32_t *bdPointer = NULL;
+ usb_host_pipe_t *pipeDescPointer = transfer->transferPipe;
+
+ if (pipeDescPointer->pipeType == USB_ENDPOINT_CONTROL)
+ {
+ if (transfer->setupStatus == kTransfer_Setup0)
+ {
+ type = kTr_Ctrl;
+ }
+ else if ((transfer->setupStatus == kTransfer_Setup1))
+ {
+ if (transfer->transferLength)
+ {
+ if (transfer->direction == USB_IN)
+ {
+ type = kTr_In;
+ }
+ else
+ {
+ type = kTr_Out;
+ }
+ }
+ else
+ {
+ type = kTr_In;
+ }
+ }
+ else if (transfer->setupStatus == kTransfer_Setup2)
+ {
+ if (transfer->transferLength)
+ {
+ if (transfer->direction == USB_IN)
+ {
+ type = kTr_Out;
+ }
+ else
+ {
+ type = kTr_In;
+ }
+ }
+ else
+ {
+ type = kTr_In;
+ }
+ }
+ else if (transfer->setupStatus == kTransfer_Setup3)
+ {
+ type = kTr_In;
+ }
+ else
+ {
+ }
+ }
+ else
+ {
+ if (pipeDescPointer->direction == USB_IN)
+ {
+ type = kTr_In;
+ }
+ else if (pipeDescPointer->direction == USB_OUT)
+ {
+ type = kTr_Out;
+ }
+ else
+ {
+ }
+ }
+ switch (type)
+ {
+ case kTr_Ctrl:
+ case kTr_Out:
+ usbHostPointer->txBd ^= 1U;
+ bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 1, usbHostPointer->txBd);
+ usbHostPointer->txBd ^= 1U;
+ break;
+
+ case kTr_In:
+ usbHostPointer->rxBd ^= 1U;
+ bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 0U, usbHostPointer->rxBd);
+ usbHostPointer->rxBd ^= 1U;
+ break;
+
+ default:
+ bdPointer = NULL;
+ break;
+ }
+
+ if (bdPointer == NULL)
+ {
+ return -1;
+ }
+
+ bd = *bdPointer;
+ err = usbHostPointer->usbRegBase->ERRSTAT;
+ if (err & (USB_ERRSTAT_PIDERR_MASK | USB_ERRSTAT_CRC5EOF_MASK | USB_ERRSTAT_CRC16_MASK | USB_ERRSTAT_DFN8_MASK |
+ USB_ERRSTAT_DMAERR_MASK | USB_ERRSTAT_BTSERR_MASK))
+ {
+ transferResult = -(int32_t)err;
+ return transferResult;
+ }
+ else
+ {
+ if (bd & USB_KHCI_BD_OWN)
+ {
+#ifdef HOST_ECHO
+ usb_echo("Own bit is not clear 0x%x\n", (unsigned int)bd);
+#endif
+ *bdPointer = 0U;
+ }
+ if ((pipeDescPointer->pipeType == USB_ENDPOINT_ISOCHRONOUS))
+ {
+ transferResult = (bd >> 16) & 0x3ffU;
+ }
+ else
+ {
+ switch (bd >> 2 & 0xfU)
+ {
+ case 0x03: /* Last Transfer status is DATA0 */
+ case 0x0b: /* Last Transfer status is DATA1 */
+ case 0x02: /* Last Transfer status is ACK */
+ transferResult = (bd >> 16) & 0x3ffU;
+ /* switch data toggle */
+ pipeDescPointer->nextdata01 ^= 1U;
+ break;
+
+ case 0x0e: /* Last Transfer status is STALL */
+ transferResult = USB_KHCI_ATOM_TR_STALL;
+ break;
+
+ case 0x0a: /* Last Transfer status is NAK */
+ transferResult = USB_KHCI_ATOM_TR_NAK;
+ break;
+
+ case 0x00: /* Last Transfer status is bus timeout **/
+ transferResult = USB_KHCI_ATOM_TR_BUS_TIMEOUT;
+ break;
+
+ case 0x0f: /* Last Transfer status is data error */
+ transferResult = USB_KHCI_ATOM_TR_DATA_ERROR;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if ((kTr_In == type) && (0 == usbHostPointer->sXferSts.isDmaAlign))
+ {
+ usbHostPointer->sXferSts.isDmaAlign = 1U;
+ if (transferResult > 0)
+ {
+ for (int j = 0; j < transferResult; j++)
+ {
+ usbHostPointer->sXferSts.rxBufOrig[j] = usbHostPointer->sXferSts.rxBuf[j];
+ }
+ }
+ }
+ return transferResult;
+}
+
+/*!
+ * @brief khci atom transaction process function.
+ *
+ * @param usbHostPointer Pointer of the host khci controller instance.
+ * @param type The USB transfer type.
+ * @param pipeDescPointer Pointer of usb pipe desc.
+ * @param bufPointer The memory address is needed to be transferred.
+ * @param len Transferred data length.
+ *
+ * @return 0 mean sucess or other opertor failure error code.
+ *
+ */
+static int32_t _USB_HostKhciAtomNonblockingTransaction(usb_khci_host_state_struct_t *usbHostPointer,
+ uint32_t type,
+ usb_host_pipe_t *pipeDescPointer,
+ uint8_t *bufPointer,
+ uint32_t len)
+{
+ uint32_t *bdPointer = NULL;
+ uint8_t *buf = bufPointer;
+ int32_t transferResult;
+ uint32_t speed;
+ uint32_t address;
+ uint32_t level;
+ uint8_t counter = 0U;
+ uint32_t eventBit;
+ usb_osa_status_t osaStatus;
+ uint8_t epCtlVal;
+
+ len = (len > pipeDescPointer->maxPacketSize) ? pipeDescPointer->maxPacketSize : len;
+ USB_HostHelperGetPeripheralInformation(pipeDescPointer->deviceHandle, kUSB_HostGetDeviceLevel, &level);
+ USB_HostHelperGetPeripheralInformation(pipeDescPointer->deviceHandle, kUSB_HostGetDeviceSpeed, &speed);
+ USB_HostHelperGetPeripheralInformation(pipeDescPointer->deviceHandle, kUSB_HostGetDeviceAddress, &address);
+
+ if (speed == USB_SPEED_LOW)
+ {
+ usbHostPointer->usbRegBase->ADDR |= USB_ADDR_LSEN_MASK;
+ }
+ else
+ {
+ usbHostPointer->usbRegBase->ADDR &= (~USB_ADDR_LSEN_MASK);
+ }
+ usbHostPointer->usbRegBase->ADDR = ((usbHostPointer->usbRegBase->ADDR & (~USB_ADDR_ADDR_MASK)) |
+ ((((address) << USB_ADDR_ADDR_SHIFT) & USB_ADDR_ADDR_MASK)));
+
+#if (FSL_FEATURE_USB_KHCI_HOST_ENABLED)
+ epCtlVal = (level == 1 ? USB_ENDPT_HOSTWOHUB_MASK : 0U) | USB_ENDPT_RETRYDIS_MASK | USB_ENDPT_EPTXEN_MASK |
+ USB_ENDPT_EPRXEN_MASK |
+ ((pipeDescPointer->pipeType == USB_ENDPOINT_ISOCHRONOUS ? 0 : USB_ENDPT_EPHSHK_MASK));
+#else
+ epCtlVal = USB_ENDPT_EPTXEN_MASK | USB_ENDPT_EPRXEN_MASK |
+ ((pipeDescPointer->pipeType == USB_ENDPOINT_ISOCHRONOUS ? 0 : USB_ENDPT_EPHSHK_MASK));
+#endif
+ usbHostPointer->usbRegBase->ENDPOINT[0U].ENDPT = epCtlVal;
+
+ transferResult = 0U;
+ counter = 0U;
+ /* wait for USB conttoller is ready, and with timeout */
+ while ((usbHostPointer->usbRegBase->CTL) & USB_CTL_TXSUSPENDTOKENBUSY_MASK)
+ {
+ _USB_HostKhciDelay(usbHostPointer, 1U);
+ osaStatus = USB_OsaEventWait(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_TOK_DONE, 0U, 1, &eventBit);
+ if (osaStatus == kStatus_USB_OSA_Success)
+ {
+ transferResult = USB_KHCI_ATOM_TR_RESET;
+ break;
+ }
+ else
+ {
+ counter++;
+ if (counter >= 3)
+ {
+ transferResult = USB_KHCI_ATOM_TR_CRC_ERROR;
+ return transferResult;
+ }
+ }
+ }
+
+ if (!transferResult)
+ {
+#if defined(FSL_FEATURE_USB_KHCI_DYNAMIC_SOF_THRESHOLD_COMPARE_ENABLED) && \
+ (FSL_FEATURE_USB_KHCI_DYNAMIC_SOF_THRESHOLD_COMPARE_ENABLED == 1U)
+ if (speed == USB_SPEED_LOW)
+ {
+ usbHostPointer->usbRegBase->SOFTHLD = (len * 12 * 7 / 6 + KHCICFG_THSLD_DELAY) / 8;
+ }
+ else
+ {
+ usbHostPointer->usbRegBase->SOFTHLD = (len * 7 / 6 + KHCICFG_THSLD_DELAY) / 8;
+ }
+#endif
+ usbHostPointer->usbRegBase->ERRSTAT = 0xffU;
+
+ if ((kTr_In == type) && ((len & USB_MEM4_ALIGN_MASK) || ((uint32_t)bufPointer & USB_MEM4_ALIGN_MASK)))
+ {
+ if ((usbHostPointer->khciSwapBufPointer != NULL) && (len <= USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER))
+ {
+ buf = (uint8_t *)USB_MEM4_ALIGN((uint32_t)(usbHostPointer->khciSwapBufPointer + 4));
+ usbHostPointer->sXferSts.rxBuf = buf;
+ usbHostPointer->sXferSts.rxBufOrig = bufPointer;
+ usbHostPointer->sXferSts.rxLen = len;
+ usbHostPointer->sXferSts.isDmaAlign = 0U;
+ }
+ }
+ else
+ {
+ usbHostPointer->sXferSts.isDmaAlign = 1U;
+ }
+
+ switch (type)
+ {
+ case kTr_Ctrl:
+ bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 1, usbHostPointer->txBd);
+ *(bdPointer + 1U) = USB_LONG_TO_LITTLE_ENDIAN((uint32_t)buf);
+ *bdPointer = USB_LONG_TO_LITTLE_ENDIAN(USB_KHCI_BD_BC(len) | USB_KHCI_BD_OWN);
+ usbHostPointer->usbRegBase->TOKEN =
+ (USB_TOKEN_TOKENENDPT((uint8_t)pipeDescPointer->endpointAddress) | USB_TOKEN_TOKENPID(0xD));
+ usbHostPointer->txBd ^= 1U;
+ break;
+ case kTr_In:
+ bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 0U, usbHostPointer->rxBd);
+ *(bdPointer + 1U) = USB_LONG_TO_LITTLE_ENDIAN((uint32_t)buf);
+ *bdPointer = USB_LONG_TO_LITTLE_ENDIAN(USB_KHCI_BD_BC(len) | USB_KHCI_BD_OWN |
+ USB_KHCI_BD_DATA01(pipeDescPointer->nextdata01));
+ usbHostPointer->usbRegBase->TOKEN =
+ (USB_TOKEN_TOKENENDPT((uint8_t)pipeDescPointer->endpointAddress) | USB_TOKEN_TOKENPID(0x9));
+ usbHostPointer->rxBd ^= 1U;
+ break;
+ case kTr_Out:
+ bdPointer = (uint32_t *)USB_KHCI_BD_PTR(0U, 1, usbHostPointer->txBd);
+ *(bdPointer + 1U) = USB_LONG_TO_LITTLE_ENDIAN((uint32_t)buf);
+ *bdPointer = USB_LONG_TO_LITTLE_ENDIAN(USB_KHCI_BD_BC(len) | USB_KHCI_BD_OWN |
+ USB_KHCI_BD_DATA01(pipeDescPointer->nextdata01));
+ usbHostPointer->usbRegBase->TOKEN =
+ (USB_TOKEN_TOKENENDPT((uint8_t)pipeDescPointer->endpointAddress) | USB_TOKEN_TOKENPID(0x1));
+ usbHostPointer->txBd ^= 1U;
+ break;
+ default:
+ bdPointer = NULL;
+ break;
+ }
+ }
+
+ return transferResult;
+}
+
+/*!
+ * @brief khci host start tramsfer.
+ *
+ * @param handle Pointer of the host khci controller handle.
+ * @param transfer Pointer of transfer node struct, which will transfer.
+ *
+ * @retval kKhci_TrTransmiting khci host transaction prime successfully, will enter next stage.
+ * @retval kKhci_TrTransmitDone khci host transaction prime unsuccessfully, will enter exit stage.
+ *
+ */
+static khci_tr_state_t _USB_HostKhciStartTranfer(usb_host_controller_handle handle, usb_host_transfer_t *transfer)
+{
+ static int32_t transferResult;
+ uint8_t *buf;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle;
+
+ if (transfer->transferPipe->pipeType == USB_ENDPOINT_CONTROL)
+ {
+ if ((transfer->setupStatus == kTransfer_Setup0))
+ {
+ transferResult = _USB_HostKhciAtomNonblockingTransaction(usbHostPointer, kTr_Ctrl, transfer->transferPipe,
+ (uint8_t *)&transfer->setupPacket, 8U);
+ }
+ else if (transfer->setupStatus == kTransfer_Setup1)
+ {
+ if (transfer->transferLength)
+ {
+ buf = transfer->transferBuffer;
+ buf += transfer->transferSofar;
+ transferResult = _USB_HostKhciAtomNonblockingTransaction(
+ usbHostPointer, (transfer->direction == USB_IN) ? kTr_In : kTr_Out, transfer->transferPipe, buf,
+ transfer->transferLength - transfer->transferSofar);
+ }
+ else
+ {
+ transfer->transferPipe->nextdata01 = 1U;
+ transfer->setupStatus = kTransfer_Setup3;
+ transferResult =
+ _USB_HostKhciAtomNonblockingTransaction(usbHostPointer, kTr_In, transfer->transferPipe, 0U, 0U);
+ }
+ }
+ else if (transfer->setupStatus == kTransfer_Setup2)
+ {
+ if (transfer->transferLength)
+ {
+ transfer->transferPipe->nextdata01 = 1U;
+
+ transferResult = _USB_HostKhciAtomNonblockingTransaction(
+ usbHostPointer, (transfer->direction == USB_IN) ? kTr_Out : kTr_In, transfer->transferPipe, 0U, 0U);
+ }
+ else
+ {
+ transfer->transferPipe->nextdata01 = 1U;
+ transferResult =
+ _USB_HostKhciAtomNonblockingTransaction(usbHostPointer, kTr_In, transfer->transferPipe, 0U, 0U);
+ }
+ }
+ else if (transfer->setupStatus == kTransfer_Setup3)
+ {
+ transfer->transferPipe->nextdata01 = 1U;
+ transferResult =
+ _USB_HostKhciAtomNonblockingTransaction(usbHostPointer, kTr_In, transfer->transferPipe, 0U, 0U);
+ }
+ else
+ {
+ }
+ }
+ else
+ {
+ buf = transfer->transferBuffer;
+ buf += transfer->transferSofar;
+ transferResult = _USB_HostKhciAtomNonblockingTransaction(
+ usbHostPointer, (transfer->transferPipe->direction == USB_IN) ? kTr_In : kTr_Out, transfer->transferPipe,
+ buf, transfer->transferLength - transfer->transferSofar);
+ }
+
+ transfer->transferResult = transferResult;
+
+ if (transfer->transferResult == 0U)
+ {
+ usbHostPointer->trState = kKhci_TrTransmiting;
+ }
+ else
+ {
+ usbHostPointer->trState = kKhci_TrTransmitDone;
+ }
+ return (khci_tr_state_t)usbHostPointer->trState;
+}
+
+/*!
+ * @brief khci host finish tramsfer.
+ *
+ * @param handle Pointer of the host khci controller handle.
+ * @param transfer Pointer of transfer node struct, which will be transfer.
+ *
+ * @retval kKhci_TrGetMsg The current of transaction is transfer done, will enter first stage.
+ * @retval kKhci_TrTransmitDone All of khci host transaction of the transfer have transfer done, will enter exit
+ * stage.
+ *
+ */
+static khci_tr_state_t _USB_HostKhciFinishTranfer(usb_host_controller_handle handle, usb_host_transfer_t *transfer)
+{
+ static int32_t transferResult;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle;
+
+ transfer->transferResult = transferResult = _USB_HostKhciTransactionDone(usbHostPointer, transfer);
+ if (transferResult >= 0)
+ {
+ if (transfer->transferPipe->pipeType == USB_ENDPOINT_CONTROL)
+ {
+ if ((transfer->setupStatus == kTransfer_Setup2) || (transfer->setupStatus == kTransfer_Setup3))
+ {
+ usbHostPointer->trState = kKhci_TrTransmitDone;
+ }
+ else
+ {
+ usbHostPointer->trState = kKhci_TrStartTransmit;
+ if (transfer->setupStatus == kTransfer_Setup1)
+ {
+ transfer->transferSofar += transferResult;
+ if (((transfer->transferLength - transfer->transferSofar) <= 0U) ||
+ (transferResult < transfer->transferPipe->maxPacketSize))
+ {
+ transfer->setupStatus++;
+ }
+ }
+ else
+ {
+ transfer->setupStatus++;
+ }
+ }
+ }
+ else
+ {
+ transfer->transferSofar += transferResult;
+ if (((transfer->transferLength - transfer->transferSofar) == 0U) ||
+ (transferResult < transfer->transferPipe->maxPacketSize))
+ {
+ usbHostPointer->trState = kKhci_TrTransmitDone;
+ }
+ else
+ {
+ usbHostPointer->trState = kKhci_TrStartTransmit;
+ }
+ }
+ }
+ else
+ {
+ if ((transferResult == USB_KHCI_ATOM_TR_NAK))
+ {
+ if (transfer->transferPipe->pipeType == USB_ENDPOINT_INTERRUPT)
+ {
+ usbHostPointer->trState = kKhci_TrGetMsg;
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG);
+ }
+ else
+ {
+ if ((_USB_HostKhciGetFrameCountSum(usbHostPointer) - transfer->frame) > transfer->nakTimeout)
+ {
+ usbHostPointer->trState = kKhci_TrTransmitDone;
+ transfer->transferResult = USB_KHCI_ATOM_TR_BUS_TIMEOUT;
+ }
+ else
+ {
+ usbHostPointer->trState = kKhci_TrGetMsg;
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG);
+ }
+ }
+ }
+ else
+ {
+ usbHostPointer->trState = kKhci_TrTransmitDone;
+ }
+ }
+ return (khci_tr_state_t)usbHostPointer->trState;
+}
+
+/*!
+ * @brief host khci controller transfer clear up
+ *
+ * The function is used to handle controller transfer clear up.
+ * @param handle Pointer of the host khci controller handle.
+ *
+ *
+ */
+void _USB_HostKhciTransferClearUp(usb_host_controller_handle controllerHandle)
+{
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle;
+ usb_host_transfer_t *trCancel;
+
+ USB_HostKhciLock();
+ trCancel = usbHostPointer->periodicListPointer;
+ USB_HostKhciUnlock();
+ while (trCancel != NULL)
+ {
+ _USB_HostKhciUnlinkTrRequestFromList(controllerHandle, trCancel);
+ trCancel->callbackFn(trCancel->callbackParam, trCancel, kStatus_USB_TransferCancel);
+ USB_HostKhciLock();
+ trCancel = usbHostPointer->periodicListPointer;
+ USB_HostKhciUnlock();
+ }
+
+ USB_HostKhciLock();
+ trCancel = usbHostPointer->asyncListPointer;
+ USB_HostKhciUnlock();
+ while (trCancel != NULL)
+ {
+ _USB_HostKhciUnlinkTrRequestFromList(controllerHandle, trCancel);
+ trCancel->callbackFn(trCancel->callbackParam, trCancel, kStatus_USB_TransferCancel);
+ USB_HostKhciLock();
+ trCancel = usbHostPointer->asyncListPointer;
+ USB_HostKhciUnlock();
+ }
+ usbHostPointer->trState = kKhci_TrGetMsg;
+}
+
+/*!
+ * @brief host khci controller transfer state machine
+ *
+ * The function is used to handle controller transfer state machine.
+ * @param handle Pointer of the host khci controller handle.
+ * @param transfer Pointer of transfer node struct, which will be transfer.
+ *
+ *
+ */
+void _USB_HostKhciTransferStateMachine(usb_host_controller_handle controllerHandle, usb_host_transfer_t **ptransfer)
+{
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle;
+ usb_host_transfer_t *transfer = *ptransfer;
+ usb_host_transfer_t *tempTransfer = NULL;
+ uint32_t eventBit = 0;
+
+ switch (usbHostPointer->trState)
+ {
+ case kKhci_TrGetMsg:
+ transfer = NULL;
+ _USB_HostKhciGetRightTrRequest(controllerHandle, &transfer);
+ if (transfer != NULL)
+ {
+ *ptransfer = transfer;
+ usbHostPointer->trState = _USB_HostKhciStartTranfer(controllerHandle, transfer);
+ usbHostPointer->trState = kKhci_TrTransmiting;
+ }
+ break;
+
+ case kKhci_IsoTrGetMsg:
+ *ptransfer = NULL;
+ if (usbHostPointer->periodicListAvtive)
+ {
+ tempTransfer = usbHostPointer->periodicListPointer;
+ while (tempTransfer != NULL)
+ {
+ if ((_USB_HostKhciGetFrameCount(usbHostPointer) % tempTransfer->transferPipe->interval == 0U) &&
+ (tempTransfer->transferPipe->pipeType == USB_ENDPOINT_ISOCHRONOUS))
+ {
+ *ptransfer = tempTransfer;
+
+ _USB_HostKhciStartTranfer(controllerHandle, tempTransfer);
+ usbHostPointer->trState = kKhci_TrTransmiting;
+ if (kStatus_USB_OSA_Success == USB_OsaEventWait(usbHostPointer->khciEventPointer,
+ USB_KHCI_EVENT_TOK_DONE, 0U, 0, &eventBit))
+ {
+ if (eventBit & USB_KHCI_EVENT_TOK_DONE)
+ {
+ _USB_HostKhciTransactionDone(usbHostPointer, tempTransfer);
+ _USB_HostKhciUnlinkTrRequestFromList(usbHostPointer, tempTransfer);
+ _USB_HostKhciProcessTrCallback(usbHostPointer, tempTransfer, transfer->transferResult);
+ usbHostPointer->trState = kKhci_TrGetMsg;
+ }
+ }
+ else
+ {
+ usbHostPointer->trState = kKhci_TrTransmiting;
+ }
+ break;
+ }
+ tempTransfer = tempTransfer->next;
+ }
+ }
+ if (*ptransfer == NULL)
+ {
+ usbHostPointer->trState = kKhci_TrGetMsg;
+ }
+ break;
+
+ case kKhci_TrStartTransmit:
+ if (transfer != NULL)
+ {
+ usbHostPointer->trState = _USB_HostKhciStartTranfer(controllerHandle, transfer);
+ }
+ break;
+
+ case kKhci_TrTransmiting:
+ if (transfer != NULL)
+ {
+ if ((_USB_HostKhciGetFrameCountSum(usbHostPointer) - transfer->frame) > USB_TIMEOUT_OTHER)
+ {
+ if ((transfer->transferPipe->pipeType == USB_ENDPOINT_CONTROL) ||
+ (transfer->transferPipe->pipeType == USB_ENDPOINT_BULK))
+ {
+ /* clear current bdt status */
+ _USB_HostKhciTransactionDone(usbHostPointer, transfer);
+ usbHostPointer->trState = kKhci_TrTransmitDone;
+ transfer->transferResult = USB_KHCI_ATOM_TR_BUS_TIMEOUT;
+ return;
+ }
+ }
+ }
+ break;
+
+ case kKhci_TrTransmitDone:
+ if (transfer != NULL)
+ {
+ _USB_HostKhciUnlinkTrRequestFromList(usbHostPointer, transfer);
+ _USB_HostKhciProcessTrCallback(usbHostPointer, transfer, transfer->transferResult);
+ usbHostPointer->trState = kKhci_TrGetMsg;
+ if ((usbHostPointer->asyncListAvtive == 1U) || (usbHostPointer->periodicListAvtive == 1U))
+ {
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*!
+ * @brief khci task function.
+ *
+ * The function is used to handle KHCI controller message.
+ * In the BM environment, this function should be called periodically in the main function.
+ * And in the RTOS environment, this function should be used as a function entry to create a task.
+ *
+ * @param hostHandle The host handle.
+ */
+void USB_HostKhciTaskFunction(void *hostHandle)
+{
+ volatile ptr_usb_host_khci_state_struct_t usbHostPointer;
+ uint32_t eventBit = 0;
+ static usb_host_transfer_t *transfer;
+
+ if (hostHandle == NULL)
+ {
+ return;
+ }
+
+ usbHostPointer = (usb_khci_host_state_struct_t *)(((usb_host_instance_t *)hostHandle)->controllerHandle);
+ if (USB_OsaEventWait(usbHostPointer->khciEventPointer, 0xff, 0U, 1U, &eventBit) ==
+ kStatus_USB_OSA_Success) /* wait all event */
+ {
+ if (eventBit & USB_KHCI_EVENT_ATTACH)
+ {
+ _USB_HostKhciAttach(usbHostPointer);
+ usbHostPointer->trState = kKhci_TrGetMsg;
+ }
+ if (eventBit & USB_KHCI_EVENT_RESET)
+ {
+ _USB_HostKhciReset(usbHostPointer);
+ }
+ if (eventBit & USB_KHCI_EVENT_DETACH)
+ {
+ _USB_HostKhciDetach(usbHostPointer);
+ }
+ if (eventBit & USB_KHCI_EVENT_SOF_TOK)
+ {
+ if ((kKhci_TrGetMsg == usbHostPointer->trState) && (usbHostPointer->deviceAttached))
+ {
+ usbHostPointer->trState = kKhci_IsoTrGetMsg;
+ _USB_HostKhciTransferStateMachine(usbHostPointer, &transfer);
+ }
+ }
+ if (eventBit & USB_KHCI_EVENT_TOK_DONE)
+ {
+ if (transfer != NULL)
+ {
+ usbHostPointer->trState =
+ _USB_HostKhciFinishTranfer(((usb_host_instance_t *)hostHandle)->controllerHandle, transfer);
+ }
+ }
+ }
+ if (usbHostPointer->deviceAttached)
+ {
+ _USB_HostKhciTransferStateMachine(usbHostPointer, &transfer);
+ }
+ else
+ {
+ _USB_HostKhciTransferClearUp(usbHostPointer);
+ }
+}
+
+/*!
+ * @brief create the USB host khci instance.
+ *
+ * This function initializes the USB host khci 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, KHCI/EHCI mutex or KHCI/EHCI event create fail.
+ * Or, KHCI/EHCI IP initialize fail.
+ *
+ */
+usb_status_t USB_HostKhciCreate(uint8_t controllerId,
+ usb_host_handle hostHandle,
+ usb_host_controller_handle *controllerHandle)
+{
+ usb_khci_host_state_struct_t *usbHostPointer;
+ usb_status_t status = kStatus_USB_Success;
+ usb_osa_status_t osaStatus;
+ uint32_t usb_base_addrs[] = USB_BASE_ADDRS;
+
+ if (((controllerId - kUSB_ControllerKhci0) >= (uint8_t)USB_HOST_CONFIG_KHCI) ||
+ ((controllerId - kUSB_ControllerKhci0) >= (sizeof(usb_base_addrs) / sizeof(uint32_t))))
+ {
+ return kStatus_USB_ControllerNotFound;
+ }
+
+ usbHostPointer = (usb_khci_host_state_struct_t *)USB_OsaMemoryAllocate(sizeof(usb_khci_host_state_struct_t));
+ if (NULL == usbHostPointer)
+ {
+ *controllerHandle = NULL;
+ return kStatus_USB_AllocFail;
+ }
+
+ /* Allocate the USB Host Pipe Descriptors */
+ usbHostPointer->pipeDescriptorBasePointer = NULL;
+ usbHostPointer->hostHandle = hostHandle;
+ *controllerHandle = (usb_host_handle)usbHostPointer;
+
+ if (NULL == (usbHostPointer->khciSwapBufPointer =
+ (uint8_t *)USB_OsaMemoryAllocate(USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER + 4)))
+ {
+#ifdef HOST_DEBUG_
+ usb_echo("usbHostPointer->khciSwapBufPointer- memory allocation failed");
+#endif
+ USB_HostKhciDestory(controllerHandle);
+ return kStatus_USB_AllocFail;
+ }
+
+ /* init khci mutext */
+ osaStatus = USB_OsaMutexCreate(&usbHostPointer->khciMutex);
+ if (osaStatus != kStatus_USB_OSA_Success)
+ {
+#ifdef HOST_ECHO
+ usb_echo("khci mutex init fail\r\n");
+#endif
+ USB_HostKhciDestory(controllerHandle);
+ return kStatus_USB_Error;
+ }
+
+ USB_OsaEventCreate(&usbHostPointer->khciEventPointer, 1U);
+ if (usbHostPointer->khciEventPointer == NULL)
+ {
+#ifdef HOST_ECHO
+ usb_echo(" memalloc failed in usb_khci_init\n");
+#endif
+
+ return kStatus_USB_AllocFail;
+ } /* Endif */
+
+ usbHostPointer->usbRegBase = (USB_Type *)usb_base_addrs[controllerId - kUSB_ControllerKhci0];
+
+ usbHostPointer->asyncListAvtive = 0U;
+ usbHostPointer->periodicListAvtive = 0U;
+ usbHostPointer->periodicListPointer = NULL;
+ usbHostPointer->asyncListPointer = NULL;
+ usbHostPointer->sXferSts.isDmaAlign = 0U;
+
+ /* set internal register pull down */
+ usbHostPointer->usbRegBase->CTL = USB_CTL_SE0_MASK;
+
+ /* Reset USB CTRL register */
+ usbHostPointer->usbRegBase->CTL = 0UL;
+ usbHostPointer->usbRegBase->ISTAT = 0xffU;
+ /* Enable week pull-downs, useful for detecting detach (effectively bus discharge) */
+ usbHostPointer->usbRegBase->USBCTRL |= USB_USBCTRL_PDE_MASK;
+ /* Remove suspend state */
+ usbHostPointer->usbRegBase->USBCTRL &= (~USB_USBCTRL_SUSP_MASK);
+ usbHostPointer->usbRegBase->CTL |= USB_CTL_ODDRST_MASK;
+
+ usbHostPointer->usbRegBase->BDTPAGE1 = (uint8_t)((uint32_t)USB_KHCI_BDT_BASE >> 8U);
+ usbHostPointer->usbRegBase->BDTPAGE2 = (uint8_t)((uint32_t)USB_KHCI_BDT_BASE >> 16);
+ usbHostPointer->usbRegBase->BDTPAGE3 = (uint8_t)((uint32_t)USB_KHCI_BDT_BASE >> 24);
+ /* Set SOF threshold */
+ usbHostPointer->usbRegBase->SOFTHLD = 255;
+
+ usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK;
+ /* Wait for attach interrupt */
+ usbHostPointer->usbRegBase->INTEN |= (USB_INTEN_ATTACHEN_MASK);// | USB_INTEN_SOFTOKEN_MASK);
+#if defined(FSL_FEATURE_USB_KHCI_DYNAMIC_SOF_THRESHOLD_COMPARE_ENABLED) && \
+ (FSL_FEATURE_USB_KHCI_DYNAMIC_SOF_THRESHOLD_COMPARE_ENABLED == 1U)
+ usbHostPointer->usbRegBase->MISCCTRL |= USB_MISCCTRL_SOFDYNTHLD_MASK;
+#endif
+ usbHostPointer->trState = kKhci_TrGetMsg;
+ return status;
+}
+
+/*!
+ * @brief destroy USB host khci instance.
+ *
+ * This function de-initialize the USB host khci controller driver.
+ *
+ * @param handle the controller handle.
+ *
+ * @retval kStatus_USB_Success The host is initialized successfully.
+ */
+usb_status_t USB_HostKhciDestory(usb_host_controller_handle controllerHandle)
+{
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle;
+
+ usbHostPointer->usbRegBase->INTEN &= (~0xFFU);
+
+ usbHostPointer->usbRegBase->ADDR = ((usbHostPointer->usbRegBase->ADDR & (~USB_ADDR_ADDR_MASK)) |
+ ((((0U) << USB_ADDR_ADDR_SHIFT) & USB_ADDR_ADDR_MASK)));
+ usbHostPointer->usbRegBase->CTL &= (~0xFFu);
+ usbHostPointer->usbRegBase->USBCTRL |= USB_USBCTRL_PDE_MASK;
+ usbHostPointer->usbRegBase->USBCTRL |= USB_USBCTRL_SUSP_MASK;
+ usbHostPointer->usbRegBase->ADDR &= (~USB_ADDR_LSEN_MASK);
+
+ if (NULL != usbHostPointer->khciEventPointer)
+ {
+ USB_OsaEventDestroy(usbHostPointer->khciEventPointer);
+ }
+ if (NULL != usbHostPointer->khciMutex)
+ {
+ USB_OsaMutexDestroy(usbHostPointer->khciMutex);
+ }
+
+ if (NULL != usbHostPointer->khciSwapBufPointer)
+ {
+ USB_OsaMemoryFree(usbHostPointer->khciSwapBufPointer);
+ usbHostPointer->khciSwapBufPointer = NULL;
+ }
+
+ USB_OsaMemoryFree(usbHostPointer);
+ usbHostPointer = NULL;
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief open USB host pipe.
+ *
+ * This function open one pipe according to the pipeInitPointer parameter.
+ *
+ * @param controllerHandle the controller handle.
+ * @param pipeHandlePointer the pipe handle pointer, it is used to return the pipe handle.
+ * @param pipeInitPointer it is used to initialize the pipe.
+ *
+ * @retval kStatus_USB_Success The host is initialized successfully.
+ * @retval kStatus_USB_Error there is no idle pipe.
+*
+*/
+usb_status_t USB_HostKhciOpenPipe(usb_host_controller_handle controllerHandle,
+ usb_host_pipe_handle *pipeHandlePointer,
+ usb_host_pipe_init_t *pipeInitPointer)
+{
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle;
+ usb_host_pipe_t *pipePointer;
+ usb_host_pipe_t *prePipePointer;
+ usb_host_pipe_t *tempPipePointer;
+
+ USB_OSA_SR_ALLOC();
+ USB_OSA_ENTER_CRITICAL();
+ pipePointer = (usb_host_pipe_t *)USB_OsaMemoryAllocate(sizeof(usb_host_pipe_t));
+ if (pipePointer == NULL)
+ {
+ USB_OsaMemoryFree(usbHostPointer);
+ return kStatus_USB_AllocFail;
+ }
+ else
+ {
+ if (usbHostPointer->pipeDescriptorBasePointer == NULL)
+ {
+ usbHostPointer->pipeDescriptorBasePointer = pipePointer;
+ }
+ else
+ {
+ tempPipePointer = usbHostPointer->pipeDescriptorBasePointer;
+ while (NULL != tempPipePointer)
+ {
+ prePipePointer = tempPipePointer;
+ tempPipePointer = tempPipePointer->next;
+ }
+ prePipePointer->next = pipePointer;
+ }
+ pipePointer->next = NULL;
+ }
+ USB_OSA_EXIT_CRITICAL();
+
+ pipePointer->deviceHandle = pipeInitPointer->devInstance;
+ pipePointer->endpointAddress = pipeInitPointer->endpointAddress;
+ pipePointer->direction = pipeInitPointer->direction;
+ pipePointer->interval = pipeInitPointer->interval;
+ pipePointer->maxPacketSize = pipeInitPointer->maxPacketSize;
+ pipePointer->pipeType = pipeInitPointer->pipeType;
+ pipePointer->numberPerUframe = pipeInitPointer->numberPerUframe;
+ pipePointer->nakCount = pipeInitPointer->nakCount;
+ pipePointer->nextdata01 = 0U;
+ pipePointer->open = (uint8_t)1U;
+ pipePointer->currentCount = 0xffffU;
+
+ if (pipePointer->pipeType == USB_ENDPOINT_ISOCHRONOUS)
+ {
+ pipePointer->interval = 1 << (pipeInitPointer->interval - 1U);
+ }
+ else
+ {
+ pipePointer->interval = _USB_HostKhciGetRoundUpPow2(pipeInitPointer->interval);
+ }
+ *pipeHandlePointer = pipePointer;
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief close USB host pipe.
+ *
+ * This function close one pipe and release the related resources.
+ *
+ * @param controllerHandle the controller handle.
+ * @param pipeHandle the closing pipe handle.
+ *
+ * @retval kStatus_USB_Success The host is initialized successfully.
+ */
+usb_status_t USB_HostKhciClosePipe(usb_host_controller_handle controllerHandle, usb_host_pipe_handle pipeHandle)
+{
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle;
+ usb_host_pipe_t *pipePointer = (usb_host_pipe_t *)pipeHandle;
+ usb_host_pipe_t *prePipePointer;
+
+ USB_OSA_SR_ALLOC();
+ USB_OSA_ENTER_CRITICAL();
+
+ if ((pipePointer != NULL) && (pipePointer->open == (uint8_t)1U))
+ {
+ if (pipeHandle == usbHostPointer->pipeDescriptorBasePointer)
+ {
+ usbHostPointer->pipeDescriptorBasePointer = usbHostPointer->pipeDescriptorBasePointer->next;
+ USB_OsaMemoryFree(pipeHandle);
+ }
+ else
+ {
+ pipePointer = usbHostPointer->pipeDescriptorBasePointer;
+ prePipePointer = pipePointer;
+ while (NULL != pipePointer)
+ {
+ if ((pipePointer->open) && (pipePointer == pipeHandle))
+ {
+ prePipePointer->next = pipePointer->next;
+ if (NULL != pipePointer)
+ {
+ USB_OsaMemoryFree(pipePointer);
+ pipePointer = NULL;
+ }
+ break;
+ }
+ prePipePointer = pipePointer;
+ pipePointer = pipePointer->next;
+ }
+ }
+ }
+ else
+ {
+#ifdef HOST_ECHO
+ usb_echo("usb_khci_close_pipe invalid pipe \n");
+#endif
+ }
+ USB_OSA_EXIT_CRITICAL();
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief send data to pipe.
+ *
+ * This function request to send the transfer to the specified pipe.
+ *
+ * @param controllerHandle the controller handle.
+ * @param pipeHandle the sending pipe handle.
+ * @param transfer the transfer which will be wrote.
+ *
+ * @retval kStatus_USB_Success send successfully.
+ * @retval kStatus_USB_LackSwapBuffer there is no swap buffer for KHCI.
+ *
+ */
+usb_status_t USB_HostKhciWritePipe(usb_host_controller_handle controllerHandle,
+ usb_host_pipe_handle pipeHandle,
+ usb_host_transfer_t *transfer)
+{
+ usb_status_t status = kStatus_USB_Success;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle;
+
+ usb_host_pipe_t *pipePointer = (usb_host_pipe_t *)pipeHandle;
+
+ transfer->transferPipe = pipePointer;
+ transfer->retry = RETRY_TIME;
+
+ if (pipePointer->endpointAddress == 0U)
+ {
+ if ((transfer->direction == USB_IN) && (transfer->transferBuffer != NULL) &&
+ ((transfer->transferLength & USB_MEM4_ALIGN_MASK) ||
+ ((uint32_t)transfer->transferBuffer & USB_MEM4_ALIGN_MASK)))
+ {
+ if (usbHostPointer->khciSwapBufPointer == NULL)
+ {
+ return kStatus_USB_LackSwapBuffer;
+ }
+ if (pipePointer->maxPacketSize > USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER)
+ {
+ return kStatus_USB_LackSwapBuffer;
+ }
+ }
+ transfer->setupStatus = kTransfer_Setup0;
+
+ if (transfer->transferLength)
+ {
+ if (transfer->direction == USB_IN)
+ {
+ transfer->nakTimeout = USB_TIMEOUT_TOHOST;
+ }
+ else
+ {
+ transfer->nakTimeout = USB_TIMEOUT_TODEVICE;
+ }
+ }
+ else
+ {
+ transfer->nakTimeout = USB_TIMEOUT_NODATA;
+ }
+ }
+ else
+ {
+ if (pipePointer->nakCount == 0U)
+ {
+ transfer->nakTimeout = USB_TIMEOUT_DEFAULT;
+ }
+ else
+ {
+ transfer->nakTimeout = pipePointer->nakCount * NAK_RETRY_TIME;
+ }
+ }
+ transfer->frame = _USB_HostKhciGetFrameCountSum(usbHostPointer);
+
+ _USB_HostKhciLinkTrRequestToList(controllerHandle, transfer);
+
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG);
+
+ return status;
+}
+
+/*!
+ * @brief receive data from pipe.
+ *
+ * This function request to receive the transfer from the specified pipe.
+ *
+ * @param controllerHandle the controller handle.
+ * @param pipeHandle the receiving pipe handle.
+ * @param transfer the transfer which will be read.
+ *
+ * @retval kStatus_USB_Success send successfully.
+ * @retval kStatus_USB_LackSwapBuffer there is no swap buffer for KHCI.
+ *
+ */
+usb_status_t USB_HostKhciReadpipe(usb_host_controller_handle controllerHandle,
+ usb_host_pipe_handle pipeHandle,
+ usb_host_transfer_t *transfer)
+{
+ usb_status_t status = kStatus_USB_Success;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)controllerHandle;
+ usb_host_pipe_t *pipePointer = (usb_host_pipe_t *)pipeHandle;
+
+ if ((transfer->transferLength & USB_MEM4_ALIGN_MASK) || ((uint32_t)transfer->transferBuffer & USB_MEM4_ALIGN_MASK))
+ {
+ if (usbHostPointer->khciSwapBufPointer == NULL)
+ {
+ return kStatus_USB_LackSwapBuffer;
+ }
+ if (pipePointer->maxPacketSize > USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER)
+ {
+ return kStatus_USB_LackSwapBuffer;
+ }
+ }
+
+ transfer->transferPipe = pipePointer;
+ transfer->transferSofar = 0U;
+ if (pipePointer->nakCount == 0U)
+ {
+ transfer->nakTimeout = USB_TIMEOUT_DEFAULT;
+ }
+ else
+ {
+ transfer->nakTimeout = pipePointer->nakCount * NAK_RETRY_TIME;
+ }
+ transfer->retry = RETRY_TIME;
+ transfer->frame = _USB_HostKhciGetFrameCountSum(usbHostPointer);
+
+ _USB_HostKhciLinkTrRequestToList(controllerHandle, transfer);
+ USB_OsaEventSet(usbHostPointer->khciEventPointer, USB_KHCI_EVENT_MSG);
+
+ return status;
+}
+
+/*!
+ * @brief cancel pipe's transfers.
+ *
+ * @param handle Pointer of the host khci controller handle.
+ * @param pipePointer Pointer of the pipe.
+ * @param trPointer The canceling transfer.
+ *
+ * @return kStatus_USB_Success or error codes.
+ */
+static usb_status_t _USB_HostKhciCancelPipe(usb_host_controller_handle handle,
+ usb_host_pipe_t *pipePointer,
+ usb_host_transfer_t *trPointer)
+{
+ usb_host_transfer_t *temptr = NULL;
+ usb_khci_host_state_struct_t *usbHostPointer = (usb_khci_host_state_struct_t *)handle;
+
+ if ((pipePointer->pipeType == USB_ENDPOINT_ISOCHRONOUS) || (pipePointer->pipeType == USB_ENDPOINT_INTERRUPT))
+ {
+ temptr = usbHostPointer->periodicListPointer;
+ }
+ else if ((pipePointer->pipeType == USB_ENDPOINT_CONTROL) || (pipePointer->pipeType == USB_ENDPOINT_BULK))
+ {
+ temptr = usbHostPointer->asyncListPointer;
+ }
+ else
+ {
+ }
+
+ while (temptr != NULL)
+ {
+ if (((usb_host_pipe_t *)(temptr->transferPipe) == pipePointer) &&
+ ((trPointer == NULL) || (trPointer == temptr)))
+ {
+ _USB_HostKhciUnlinkTrRequestFromList(handle, temptr);
+ temptr->callbackFn(temptr->callbackParam, temptr, kStatus_USB_TransferCancel);
+ return kStatus_USB_Success;
+ }
+ temptr = temptr->next;
+ }
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief khci bus control.
+ *
+ * @param handle Pointer of the host khci controller handle.
+ * @param busControl Bus control code.
+ *
+ * @return kStatus_USB_Success
+ */
+static usb_status_t _USB_HostKhciBusControl(usb_host_controller_handle handle, uint8_t busControl)
+{
+ ptr_usb_host_khci_state_struct_t usbHostPointer = (usb_khci_host_state_struct_t *)handle;
+ if (busControl == kUSB_HostBusReset)
+ {
+ usbHostPointer->usbRegBase->CTL |= USB_CTL_RESET_MASK;
+ /* wait for 30 milliseconds (2.5 is minimum for reset, 10 recommended) */
+ _USB_HostKhciDelay(usbHostPointer, 30U);
+ usbHostPointer->usbRegBase->CTL &= (~USB_CTL_RESET_MASK);
+ usbHostPointer->usbRegBase->CTL |= USB_CTL_ODDRST_MASK;
+ usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK;
+
+ usbHostPointer->txBd = 0U;
+ usbHostPointer->rxBd = 0U;
+ }
+ else if (busControl == kUSB_HostBusRestart)
+ {
+ usbHostPointer->deviceAttached = 0U;
+
+ usbHostPointer->usbRegBase->CTL = USB_CTL_HOSTMODEEN_MASK;
+ usbHostPointer->usbRegBase->ISTAT = 0xffU;
+ /* Now, enable only USB interrupt attach for host mode */
+ usbHostPointer->usbRegBase->INTEN |= USB_INTEN_ATTACHEN_MASK;
+ }
+ else if (busControl == kUSB_HostBusEnableAttach)
+ {
+ if (usbHostPointer->deviceAttached <= 0)
+ {
+ usbHostPointer->usbRegBase->INTEN |= USB_INTEN_ATTACHEN_MASK;
+ }
+ }
+ else if (busControl == kUSB_HostBusDisableAttach)
+ {
+ usbHostPointer->usbRegBase->INTEN &= (~USB_INTEN_ATTACHEN_MASK);
+ }
+ else
+ {
+ }
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief io control khci.
+ *
+ * This function implemented khci io control khci.
+ *
+ * @param controllerHandle the controller handle.
+ * @param ioctlEvent please reference to enumeration host_busControl_t.
+ * @param ioctlParam the control parameter.
+ *
+ * @retval kStatus_USB_Success io ctrol successfully.
+ * @retval kStatus_USB_InvalidHandle The controllerHandle is a NULL pointer.
+ */
+usb_status_t USB_HostKciIoctl(usb_host_controller_handle controllerHandle, uint32_t ioctlEvent, void *ioctlParam)
+{
+ usb_status_t status = kStatus_USB_Success;
+ usb_host_cancel_param_t *param;
+
+ if (controllerHandle == NULL)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ switch (ioctlEvent)
+ {
+ case kUSB_HostCancelTransfer:
+ param = (usb_host_cancel_param_t *)ioctlParam;
+ status = _USB_HostKhciCancelPipe(controllerHandle, (usb_host_pipe_t *)param->pipeHandle, param->transfer);
+ break;
+
+ case kUSB_HostBusControl:
+ status = _USB_HostKhciBusControl(controllerHandle, *((uint8_t *)ioctlParam));
+ break;
+
+ case kUSB_HostGetFrameNumber:
+ *((uint32_t *)ioctlParam) = _USB_HostKhciGetFrameCount(controllerHandle);
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+#endif /* USB_HOST_CONFIG_KHCI */