/* * 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 */