/* * 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" #include "usb_host.h" #include "usb_host_hci.h" #include "usb_host_devices.h" #include "fsl_device_registers.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ extern uint32_t USB_HostHubGetTotalThinkTime(uint8_t parentHubNo); /*! * @brief get the idle host instance. * * @return host instance pointer. */ static usb_host_instance_t *USB_HostGetInstance(void); /*! * @brief release host instance. * * @param hostInstance host instance pointer. */ static void USB_HostReleaseInstance(usb_host_instance_t *hostInstance); /*! * @brief get the khci/ehci interface. * * @param controllerId controller id. * @param controllerTable return controller interface structure. */ static void USB_HostGetControllerInterface(uint8_t controllerId, const usb_host_controller_interface_t **controllerTable); #if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) #if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) extern void USB_HostEhciTestModeInit(usb_device_handle devHandle); #endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */ #endif /* USB_HOST_CONFIG_EHCI */ /******************************************************************************* * Variables ******************************************************************************/ /*! @brief USB host instance resource */ usb_host_instance_t g_UsbHostInstance[USB_HOST_CONFIG_MAX_HOST]; #if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) #include "usb_host_ehci.h" static const usb_host_controller_interface_t s_EhciInterface = \ { USB_HostEhciCreate, USB_HostEhciDestory, USB_HostEhciOpenPipe, USB_HostEhciClosePipe, USB_HostEhciWritePipe, USB_HostEhciReadpipe, USB_HostEhciIoctl, }; #endif /* USB_HOST_CONFIG_EHCI */ #if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) #include "usb_host_khci.h" static const usb_host_controller_interface_t s_KhciInterface = \ { USB_HostKhciCreate, USB_HostKhciDestory, USB_HostKhciOpenPipe, USB_HostKhciClosePipe, USB_HostKhciWritePipe, USB_HostKhciReadpipe, USB_HostKciIoctl, }; #endif /* USB_HOST_CONFIG_KHCI */ /******************************************************************************* * Code ******************************************************************************/ #if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) /*FUNCTION*---------------------------------------------------------------- * * Function Name : usb_test_mode_init * Returned Value : None * Comments : * This function is called by common class to initialize the class driver. It * is called in response to a select interface call by application * *END*--------------------------------------------------------------------*/ usb_status_t USB_HostTestModeInit(usb_device_handle deviceHandle) { #if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; usb_host_instance_t *hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; #endif uint32_t productId; uint32_t vendorId; usb_echo("usb host test init\r\n"); USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDevicePID, &productId); USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceVID, &vendorId); usb_echo(" vendor id :0x%x product id:0x%x \r\n", vendorId, productId); if ((productId != 0x0200U) && (productId != 0x0101) && (productId != 0x0102) && (productId != 0x0103) && (productId != 0x0104) && (productId != 0x0105) && (productId != 0x0106) && (productId != 0x0107) && (productId != 0x0108)) { usb_echo("Unsupported Device\r\n"); } if (productId == 0x0200U) { usb_echo("PET test device attached\r\n"); } else { #if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) if (hostInstance->controllerTable == &s_EhciInterface) { USB_HostEhciTestModeInit(deviceHandle); } #endif } return kStatus_USB_Success; } #endif static usb_host_instance_t *USB_HostGetInstance(void) { uint8_t i = 0; USB_OSA_SR_ALLOC(); USB_OSA_ENTER_CRITICAL(); for (; i < USB_HOST_CONFIG_MAX_HOST; i++) { if (g_UsbHostInstance[i].occupied != 1) { uint8_t *buffer = (uint8_t *)&g_UsbHostInstance[i]; for (uint32_t j = 0U; j < sizeof(usb_host_instance_t); j++) { buffer[j] = 0x00U; } g_UsbHostInstance[i].occupied = 1; USB_OSA_EXIT_CRITICAL(); return &g_UsbHostInstance[i]; } } USB_OSA_EXIT_CRITICAL(); return NULL; } static void USB_HostReleaseInstance(usb_host_instance_t *hostInstance) { USB_OSA_SR_ALLOC(); USB_OSA_ENTER_CRITICAL(); hostInstance->occupied = 0; USB_OSA_EXIT_CRITICAL(); } static void USB_HostGetControllerInterface(uint8_t controllerId, const usb_host_controller_interface_t **controllerTable) { #if ((defined USB_HOST_CONFIG_KHCI) && (USB_HOST_CONFIG_KHCI)) if (controllerId == kUSB_ControllerKhci0) { *controllerTable = &s_KhciInterface; } #endif /* USB_HOST_CONFIG_KHCI */ #if ((defined USB_HOST_CONFIG_EHCI) && (USB_HOST_CONFIG_EHCI)) if (controllerId == kUSB_ControllerEhci0) { *controllerTable = &s_EhciInterface; } #endif /* USB_HOST_CONFIG_EHCI */ } usb_status_t USB_HostInit(uint8_t controllerId, usb_host_handle *hostHandle, host_callback_t callbackFn) { usb_status_t status = kStatus_USB_Success; usb_host_instance_t *hostInstance = NULL; usb_host_transfer_t *transferPrev = NULL; uint8_t i = 0; hostInstance = USB_HostGetInstance(); /* get one host instance */ if (hostInstance == NULL) { return kStatus_USB_InvalidHandle; } /* get khci/ehci API table */ USB_HostGetControllerInterface(controllerId, &hostInstance->controllerTable); if (hostInstance->controllerTable == NULL) { USB_HostReleaseInstance(hostInstance); return kStatus_USB_ControllerNotFound; } /* judge the controller interface one time at here */ if ((hostInstance->controllerTable->controllerCreate == NULL) || (hostInstance->controllerTable->controllerDestory == NULL) || (hostInstance->controllerTable->controllerOpenPipe == NULL) || (hostInstance->controllerTable->controllerClosePipe == NULL) || (hostInstance->controllerTable->controllerWritePipe == NULL) || (hostInstance->controllerTable->controllerReadPipe == NULL) || (hostInstance->controllerTable->controllerIoctl == NULL)) { return kStatus_USB_Error; } /* HOST instance init*/ hostInstance->controllerId = controllerId; hostInstance->deviceCallback = callbackFn; hostInstance->deviceList = NULL; if (kStatus_USB_OSA_Success != USB_OsaMutexCreate(&hostInstance->hostMutex)) { USB_HostReleaseInstance(hostInstance); #ifdef HOST_ECHO usb_echo("host init: create host mutex fail\r\n"); #endif return kStatus_USB_Error; } /* initialize transfer list */ hostInstance->transferHead = &hostInstance->transferList[0]; transferPrev = hostInstance->transferHead; for (i = 1; i < USB_HOST_CONFIG_MAX_TRANSFERS; ++i) { transferPrev->next = &hostInstance->transferList[i]; transferPrev = transferPrev->next; } /* controller create */ status = hostInstance->controllerTable->controllerCreate(controllerId, hostInstance, &(hostInstance->controllerHandle)); if ((status != kStatus_USB_Success) || (hostInstance->controllerHandle == NULL)) { USB_OsaMutexDestroy(hostInstance->hostMutex); USB_HostReleaseInstance(hostInstance); #ifdef HOST_ECHO usb_echo("host init: controller init fail\r\n"); #endif return kStatus_USB_Error; } *hostHandle = hostInstance; return kStatus_USB_Success; } usb_status_t USB_HostDeinit(usb_host_handle hostHandle) { usb_status_t status = kStatus_USB_Success; usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; usb_host_device_instance_t *deviceInstance = NULL; if (hostHandle == NULL) { return kStatus_USB_InvalidHandle; } /* device list detach */ deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; while (deviceInstance != NULL) { deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; USB_HostDetachDeviceInternal(hostHandle, deviceInstance); } /* controller instance destory */ status = hostInstance->controllerTable->controllerDestory(hostInstance->controllerHandle); hostInstance->controllerHandle = NULL; if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("host controller destory fail\r\n"); #endif } /* resource release */ if (hostInstance->hostMutex) { USB_OsaMutexDestroy(hostInstance->hostMutex); hostInstance->hostMutex = NULL; } USB_HostReleaseInstance(hostInstance); return status; } usb_status_t USB_HostOpenPipe(usb_host_handle hostHandle, usb_host_pipe_handle *pipeHandle, usb_host_pipe_init_t *pipeInit) { usb_status_t status = kStatus_USB_Success; usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; if ((hostHandle == NULL) || (pipeInit == NULL)) { return kStatus_USB_InvalidHandle; } /* call controller open pipe interface */ status = hostInstance->controllerTable->controllerOpenPipe(hostInstance->controllerHandle, pipeHandle, pipeInit); return status; } usb_status_t USB_HostClosePipe(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle) { usb_status_t status = kStatus_USB_Success; usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; if ((hostHandle == NULL) || (pipeHandle == NULL)) { return kStatus_USB_InvalidHandle; } /* call controller close pipe interface */ status = hostInstance->controllerTable->controllerClosePipe(hostInstance->controllerHandle, pipeHandle); return status; } usb_status_t USB_HostSend(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle, usb_host_transfer_t *transfer) { usb_status_t status = kStatus_USB_Success; usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) { return kStatus_USB_InvalidHandle; } /* initialize transfer */ transfer->transferSofar = 0; transfer->direction = USB_OUT; USB_HostLock(); /* This api can be called by host task and app task */ /* keep this code: in normal situation application will guarantee the device is attached when call send/receive function */ #if 0 if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) { USB_HostUnlock(); return status; } #endif /* call controller write pipe interface */ #if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) if (transfer->transferLength > 0) { USB_CacheFlushLines((void *)transfer->transferBuffer, transfer->transferLength); } #endif status = hostInstance->controllerTable->controllerWritePipe(hostInstance->controllerHandle, pipeHandle, transfer); USB_HostUnlock(); return status; } usb_status_t USB_HostSendSetup(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle, usb_host_transfer_t *transfer) { usb_status_t status = kStatus_USB_Success; usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) { return kStatus_USB_InvalidHandle; } /* initialize transfer */ transfer->transferSofar = 0; transfer->next = NULL; transfer->setupStatus = 0; if ((transfer->setupPacket.bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN) { transfer->direction = USB_IN; } else { transfer->direction = USB_OUT; } USB_HostLock(); /* This API can be called by host task and application task */ /* keep this code: in normal situation application will guarantee the device is attached when call send/receive function */ #if 0 if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) { USB_HostUnlock(); return status; } #endif /* call controller write pipe interface */ #if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) if (transfer->transferLength > 0) { USB_CacheFlushLines((void *)transfer->transferBuffer, transfer->transferLength); } #endif status = hostInstance->controllerTable->controllerWritePipe(hostInstance->controllerHandle, pipeHandle, transfer); USB_HostUnlock(); return status; } usb_status_t USB_HostRecv(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle, usb_host_transfer_t *transfer) { usb_status_t status = kStatus_USB_Success; usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; if ((hostHandle == NULL) || (pipeHandle == NULL) || (transfer == NULL)) { return kStatus_USB_InvalidHandle; } /* initialize transfer */ transfer->transferSofar = 0; transfer->direction = USB_IN; USB_HostLock(); /* This API can be called by host task and application task */ /* keep this code: in normal situation application will guarantee the device is attached when call send/receive function */ #if 0 if ((USB_HostValidateDevice(pipe_ptr->deviceHandle) != kStatus_USB_Success) || (!(USB_HostGetDeviceAttachState(pipe_ptr->deviceHandle)))) { USB_HostUnlock(); return status; } #endif #if ((defined USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) if (transfer->transferLength > 0) { USB_CacheInvalidateLines((void *)transfer->transferBuffer, transfer->transferLength); } #endif status = hostInstance->controllerTable->controllerReadPipe(hostInstance->controllerHandle, pipeHandle, transfer); USB_HostUnlock(); return status; } usb_status_t USB_HostCancelTransfer(usb_host_handle hostHandle, usb_host_pipe_handle pipeHandle, usb_host_transfer_t *transfer) { usb_status_t status = kStatus_USB_Success; usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; usb_host_cancel_param_t cancelParam; if ((hostHandle == NULL) || (pipeHandle == NULL)) { return kStatus_USB_InvalidHandle; } /* initialize cancel parameter */ cancelParam.pipeHandle = pipeHandle; cancelParam.transfer = transfer; /* USB_HostLock(); This api can be called by host task and app task */ status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostCancelTransfer, &cancelParam); /* USB_HostUnlock(); */ return status; } usb_status_t USB_HostMallocTransfer(usb_host_handle hostHandle, usb_host_transfer_t **transfer) { usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; if ((hostHandle == NULL) || (transfer == NULL)) { return kStatus_USB_InvalidHandle; } /* get one from the transfer_head */ USB_HostLock(); if (hostInstance->transferHead != NULL) { *transfer = hostInstance->transferHead; hostInstance->transferHead = hostInstance->transferHead->next; USB_HostUnlock(); return kStatus_USB_Success; } else { *transfer = NULL; USB_HostUnlock(); return kStatus_USB_Error; } } usb_status_t USB_HostFreeTransfer(usb_host_handle hostHandle, usb_host_transfer_t *transfer) { usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; if (hostHandle == NULL) { return kStatus_USB_InvalidHandle; } if (transfer == NULL) { return kStatus_USB_Success; } /* release one to the transfer_head */ USB_HostLock(); transfer->next = hostInstance->transferHead; hostInstance->transferHead = transfer; USB_HostUnlock(); return kStatus_USB_Success; } usb_status_t USB_HostHelperGetPeripheralInformation(usb_device_handle deviceHandle, uint32_t infoCode, uint32_t *infoValue) { usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; if ((deviceHandle == NULL) || (infoValue == NULL)) { return kStatus_USB_InvalidParameter; } switch (infoCode) { case kUSB_HostGetDeviceAddress: /* device address */ *infoValue = (uint32_t)deviceInstance->setAddress; break; case kUSB_HostGetDeviceControlPipe: /* device control pipe */ *infoValue = (uint32_t)deviceInstance->controlPipe; break; case kUSB_HostGetHostHandle: /* device host handle */ *infoValue = (uint32_t)deviceInstance->hostHandle; break; #if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) case kUSB_HostGetDeviceHubNumber: /* device hub address */ *infoValue = (uint32_t)deviceInstance->hubNumber; break; case kUSB_HostGetDevicePortNumber: /* device port no */ *infoValue = (uint32_t)deviceInstance->portNumber; break; case kUSB_HostGetDeviceLevel: /* device level */ *infoValue = (uint32_t)deviceInstance->level; break; case kUSB_HostGetDeviceHSHubNumber: /* device high-speed hub address */ *infoValue = (uint32_t)deviceInstance->hsHubNumber; break; case kUSB_HostGetDeviceHSHubPort: /* device high-speed hub port no */ *infoValue = (uint32_t)deviceInstance->hsHubPort; break; case kUSB_HostGetHubThinkTime: /* device hub think time */ *infoValue = USB_HostHubGetTotalThinkTime(deviceInstance->hubNumber); break; #else case kUSB_HostGetDeviceHubNumber: /* device hub address */ case kUSB_HostGetDevicePortNumber: /* device port no */ case kUSB_HostGetDeviceHSHubNumber: /* device high-speed hub address */ case kUSB_HostGetDeviceHSHubPort: /* device high-speed hub port no */ case kUSB_HostGetHubThinkTime: /* device hub think time */ *infoValue = 0; break; case kUSB_HostGetDeviceLevel: /* device level */ *infoValue = 1; break; #endif /* USB_HOST_CONFIG_HUB */ case kUSB_HostGetDeviceSpeed: /* device speed */ *infoValue = (uint32_t)deviceInstance->speed; break; case kUSB_HostGetDevicePID: /* device pid */ *infoValue = (uint32_t)USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(deviceInstance->deviceDescriptor.idProduct); break; case kUSB_HostGetDeviceVID: /* device vid */ *infoValue = (uint32_t)USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(deviceInstance->deviceDescriptor.idVendor); break; case kUSB_HostGetDeviceConfigIndex: /* device config index */ *infoValue = (uint32_t)deviceInstance->configurationValue - 1U; break; default: return kStatus_USB_Error; } return kStatus_USB_Success; } usb_status_t USB_HostHelperParseAlternateSetting(usb_host_interface_handle interfaceHandle, uint8_t alternateSetting, usb_host_interface_t *interface) { uint32_t endPosition; usb_descriptor_union_t *unionDes; usb_host_ep_t *epParse; if (interfaceHandle == NULL) { return kStatus_USB_InvalidHandle; } if (alternateSetting == 0) { return kStatus_USB_InvalidParameter; } /* parse configuration descriptor */ /* interface extend descriptor start */ unionDes = (usb_descriptor_union_t *)(((usb_host_interface_t *)interfaceHandle)->interfaceExtension); /* interface extend descriptor end */ endPosition = (uint32_t)unionDes + ((usb_host_interface_t *)interfaceHandle)->interfaceExtensionLength; /* search for the alternate setting interface descritpor */ while ((uint32_t)unionDes < endPosition) { if (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) { if (unionDes->interface.bAlternateSetting == alternateSetting) { break; } else { unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); } } else { unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); } } if ((uint32_t)unionDes >= endPosition) { return kStatus_USB_Error; } /* initialize interface handle structure instance */ interface->interfaceDesc = &unionDes->interface; interface->alternateSettingNumber = 0; interface->epCount = 0; interface->interfaceExtension = NULL; interface->interfaceExtensionLength = 0; interface->interfaceIndex = unionDes->interface.bInterfaceNumber; /* search for endpoint descriptor start position */ unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); interface->interfaceExtension = (uint8_t *)unionDes; while ((uint32_t)unionDes < endPosition) { if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) && (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) { interface->interfaceExtensionLength += unionDes->common.bLength; unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); } else { break; } } /* parse endpoint descriptor */ if (interface->interfaceDesc->bNumEndpoints != 0) { if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) || (interface->interfaceDesc->bNumEndpoints > USB_HOST_CONFIG_INTERFACE_MAX_EP)) { #ifdef HOST_ECHO usb_echo("interface descriptor error\n"); #endif return kStatus_USB_Error; } for (; interface->epCount < interface->interfaceDesc->bNumEndpoints; (interface->epCount)++) { if (((uint32_t)unionDes >= endPosition) || (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) { #ifdef HOST_ECHO usb_echo("endpoint descriptor error\n"); #endif return kStatus_USB_Error; } epParse = (usb_host_ep_t *)&interface->epList[interface->epCount]; epParse->epDesc = (usb_descriptor_endpoint_t *)unionDes; epParse->epExtensionLength = 0; epParse->epExtension = NULL; interface->interfaceExtensionLength += unionDes->common.bLength; unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); epParse->epExtension = (uint8_t *)unionDes; while ((uint32_t)unionDes < endPosition) { if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) && (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)) { epParse->epExtensionLength += unionDes->common.bLength; interface->interfaceExtensionLength += unionDes->common.bLength; unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); } else { break; } } } } return kStatus_USB_Success; } void USB_HostGetVersion(uint32_t *version) { if (version) { *version = (uint32_t)USB_MAKE_VERSION(USB_STACK_VERSION_MAJOR, USB_STACK_VERSION_MINOR, USB_STACK_VERSION_BUGFIX); } }