summaryrefslogtreecommitdiff
path: root/usb_1.1.0/host/usb_host_devices.c
diff options
context:
space:
mode:
Diffstat (limited to 'usb_1.1.0/host/usb_host_devices.c')
-rw-r--r--usb_1.1.0/host/usb_host_devices.c1345
1 files changed, 1345 insertions, 0 deletions
diff --git a/usb_1.1.0/host/usb_host_devices.c b/usb_1.1.0/host/usb_host_devices.c
new file mode 100644
index 0000000..f4ec31b
--- /dev/null
+++ b/usb_1.1.0/host/usb_host_devices.c
@@ -0,0 +1,1345 @@
+/*
+ * 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"
+
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+#include "usb_host_hub.h"
+#endif /* USB_HOST_CONFIG_HUB */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief enumeration transfer callback function.
+ *
+ * @param param callback parameter.
+ * @param transfer the transfer.
+ * @param status transfer result status.
+ */
+static void USB_HostEnumerationTransferCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
+
+/*!
+ * @brief process the new step state.
+ *
+ * @param deviceInstance device instance pointer.
+ *
+ * @return kStatus_USB_Success or error codes
+ */
+static usb_status_t USB_HostProcessState(usb_host_device_instance_t *deviceInstance);
+
+/*!
+ * @brief process the previous step transfer result.
+ *
+ * @param deviceInstance device instance pointer.
+ *
+ * @return kStatus_USB_Success or error codes
+ */
+static usb_status_t USB_HostProcessCallback(usb_host_device_instance_t *deviceInstance);
+
+/*!
+ * @brief notify the application event, the callback is registered when initializing host.
+ *
+ * @param deviceInstance device instance pointer.
+ * @param eventCode event code.
+ *
+ * @return kStatus_USB_Success or error codes
+ */
+static usb_status_t USB_HostNotifyDevice(usb_host_device_instance_t *deviceInstance, uint32_t eventCode);
+
+/*!
+ * @brief allocate one address.
+ *
+ * @param hostInstance host instance pointer.
+ *
+ * @return address, 0 is invalid.
+ */
+static uint8_t USB_HostAllocateDeviceAddress(usb_host_instance_t *hostInstance);
+
+/*!
+ * @brief release one address.
+ *
+ * @param hostInstance host instance pointer.
+ * @param address releasing address.
+ */
+static void USB_HostReleaseDeviceAddress(usb_host_instance_t *hostInstance, uint8_t address);
+
+/*!
+ * @brief release device resource.
+ *
+ * @param hostInstance host instance pointer.
+ * @param deviceInstance device instance pointer.
+ */
+static void USB_HostReleaseDeviceResource(usb_host_instance_t *hostInstance,
+ usb_host_device_instance_t *deviceInstance);
+
+/*!
+ * @brief parse device configuration descriptor.
+ *
+ * @param deviceHandle device handle.
+ *
+ * @return kStatus_USB_Success or error codes.
+ */
+static usb_status_t USB_HostParseDeviceConfigurationDescriptor(usb_device_handle deviceHandle);
+
+/*!
+ * @brief remove device instance from host device list.
+ *
+ * @param hostHandle host instance handle.
+ * @param deviceHandle device handle.
+ *
+ * @return kStatus_USB_Success or error codes.
+ */
+static usb_status_t USB_HostRemoveDeviceInstance(usb_host_handle hostHandle, usb_device_handle deviceHandle);
+
+/*!
+ * @brief control the bus.
+ *
+ * This function control the host bus.
+ *
+ * @param[in] hostHandle the host handle.
+ * @param[in] controlType the control code, please reference to bus_event_t.
+ *
+ * @retval kStatus_USB_Success control successfully.
+ * @retval kStatus_USB_InvalidHandle The hostHandle is a NULL pointer.
+ */
+static usb_status_t USB_HostControlBus(usb_host_handle hostHandle, uint8_t controlType);
+
+extern usb_status_t USB_HostStandardSetGetDescriptor(usb_host_device_instance_t *deviceInstance,
+ usb_host_transfer_t *transfer,
+ void *param);
+extern usb_status_t USB_HostStandardSetAddress(usb_host_device_instance_t *deviceInstance,
+ usb_host_transfer_t *transfer,
+ void *param);
+extern usb_status_t USB_HostCh9RequestCommon(usb_host_device_instance_t *deviceInstance,
+ usb_host_transfer_t *transfer,
+ uint8_t *buffer,
+ uint32_t bufferLen);
+
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+
+extern usb_status_t USB_HostHubDeviceEvent(usb_device_handle deviceHandle,
+ usb_host_configuration_handle configurationHandle,
+ uint32_t eventCode);
+
+extern uint32_t USB_HostHubGetHsHubNumber(uint8_t parentHubNo);
+
+extern uint32_t USB_HostHubGetHsHubPort(uint8_t parentHubNo, uint8_t parentPortNo);
+
+extern usb_status_t USB_HostHubRemovePort(uint8_t hubNumber, uint8_t portNumber);
+
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+extern usb_host_instance_t g_UsbHostInstance[USB_HOST_CONFIG_MAX_HOST];
+
+/*! @brief enumeration step process array */
+static const usb_host_enum_process_entry_t s_EnumEntries[] = \
+{
+ /* kStatus_dev_initial */
+ {
+ 0, 0, NULL,
+ },
+ /* kStatus_DEV_GetDes8 */
+ {
+ kStatus_DEV_SetAddress, kStatus_DEV_GetDes8, USB_HostProcessCallback,
+ },
+ /* kStatus_DEV_SetAddress */
+ {
+ kStatus_DEV_GetDes, kStatus_DEV_SetAddress, USB_HostProcessCallback,
+ },
+ /* kStatus_DEV_GetDes */
+ {
+ kStatus_DEV_GetCfg9, kStatus_DEV_GetDes, NULL,
+ },
+ /* kStatus_DEV_GetCfg9 */
+ {
+ kStatus_DEV_GetCfg, kStatus_DEV_GetCfg9, USB_HostProcessCallback,
+ },
+ /* kStatus_DEV_GetCfg */
+ {
+ kStatus_DEV_SetCfg, kStatus_DEV_GetCfg9, USB_HostProcessCallback,
+ },
+ /* kStatus_DEV_SetCfg */
+ {
+ kStatus_DEV_EnumDone, kStatus_DEV_SetCfg, NULL,
+ },
+};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void USB_HostEnumerationTransferCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
+{
+ uint8_t nextStep = 0;
+ usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)param;
+
+ USB_HostFreeTransfer(deviceInstance->hostHandle, transfer); /* free transfer */
+
+ if (status == kStatus_USB_Success)
+ {
+ nextStep = 1;
+ }
+ else if (status == kStatus_USB_TransferStall)
+ {
+#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST))
+ usb_echo("no response from device\r\n");
+#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */
+ if (deviceInstance->stallRetries > 0) /* retry same transfer when stall */
+ {
+ deviceInstance->stallRetries--;
+ }
+ else /* process next state when all retries stall */
+ {
+ nextStep = 1;
+ }
+ }
+ else if (status == kStatus_USB_TransferCancel)
+ {
+ return;
+ }
+ else
+ {
+ if (deviceInstance->enumRetries > 0) /* next whole retry */
+ {
+ deviceInstance->enumRetries--;
+ deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES;
+ deviceInstance->configurationValue = 0;
+ deviceInstance->state = kStatus_DEV_GetDes8;
+ }
+ else
+ {
+#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST))
+ usb_echo("Device No Response\r\n");
+#endif
+ return;
+ }
+ }
+
+ if (nextStep == 1)
+ {
+ deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES;
+ if (s_EnumEntries[deviceInstance->state - 1].process == NULL)
+ {
+ deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].successState; /* next state */
+ }
+ else
+ {
+ status = s_EnumEntries[deviceInstance->state - 1].process(
+ deviceInstance); /* process the previous state result */
+ if (status == kStatus_USB_Success) /* process success */
+ {
+ deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].successState;
+ }
+ else if (status == kStatus_USB_Retry) /* need retry */
+ {
+ deviceInstance->state = s_EnumEntries[deviceInstance->state - 1].retryState;
+ }
+ else if (status == kStatus_USB_NotSupported) /* device don't suport by the application */
+ {
+ return; /* unrecoverable fail */
+ }
+ else /* process error, next retry */
+ {
+ if (deviceInstance->enumRetries > 0) /* next whole retry */
+ {
+ deviceInstance->enumRetries--;
+ deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES;
+ deviceInstance->configurationValue = 0;
+ deviceInstance->state = kStatus_DEV_GetDes8;
+ }
+ else
+ {
+#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST))
+ usb_echo("Device No Response\r\n");
+#endif
+ return; /* unrecoverable fail */
+ }
+ }
+ }
+ }
+
+ if (USB_HostProcessState(deviceInstance) != kStatus_USB_Success) /* process the new state */
+ {
+#ifdef HOST_ECHO
+ usb_echo("enumation setup error\r\n");
+#endif
+ return;
+ }
+}
+
+static usb_status_t USB_HostProcessState(usb_host_device_instance_t *deviceInstance)
+{
+ usb_status_t status = kStatus_USB_Success;
+ usb_host_process_descriptor_param_t getDescriptorParam;
+ usb_host_transfer_t *transfer;
+
+ /* malloc transfer */
+ if (deviceInstance->state != kStatus_DEV_EnumDone)
+ {
+ if (USB_HostMallocTransfer(deviceInstance->hostHandle, &transfer) != kStatus_USB_Success)
+ {
+#ifdef HOST_ECHO
+ usb_echo("error to get transfer\r\n");
+#endif
+ return kStatus_USB_Error;
+ }
+ transfer->callbackFn = USB_HostEnumerationTransferCallback;
+ transfer->callbackParam = deviceInstance;
+
+ /* reset transfer fields */
+ transfer->setupPacket.bmRequestType = 0x00;
+ transfer->setupPacket.wIndex = 0;
+ transfer->setupPacket.wLength = 0;
+ transfer->setupPacket.wValue = 0;
+ }
+
+ switch (deviceInstance->state)
+ {
+ case kStatus_DEV_GetDes8:
+ case kStatus_DEV_GetDes: /* get descriptor state */
+ getDescriptorParam.descriptorLength = sizeof(usb_descriptor_device_t);
+ if (deviceInstance->state == kStatus_DEV_GetDes8)
+ {
+ getDescriptorParam.descriptorLength = 8;
+ }
+ getDescriptorParam.descriptorBuffer = (uint8_t *)&deviceInstance->deviceDescriptor;
+ getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_DEVICE;
+ getDescriptorParam.descriptorIndex = 0;
+ getDescriptorParam.languageId = 0;
+
+ transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN;
+ transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR;
+ status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam);
+ break;
+ case kStatus_DEV_SetAddress: /* set address state */
+ transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_ADDRESS;
+ status = USB_HostStandardSetAddress(deviceInstance, transfer, &deviceInstance->allocatedAddress);
+ break;
+
+ case kStatus_DEV_GetCfg9: /* get 9 bytes configuration state */
+ getDescriptorParam.descriptorBuffer = deviceInstance->enumBuffer;
+ getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_CONFIGURE;
+ getDescriptorParam.descriptorIndex = deviceInstance->configurationValue;
+ getDescriptorParam.descriptorLength = 9;
+ getDescriptorParam.languageId = 0;
+
+ transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN;
+ transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR;
+ status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam);
+ break;
+
+ case kStatus_DEV_GetCfg: /* get configuration state */
+ getDescriptorParam.descriptorBuffer = deviceInstance->configurationDesc;
+ getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_CONFIGURE;
+ getDescriptorParam.descriptorIndex = deviceInstance->configurationValue;
+ getDescriptorParam.descriptorLength = deviceInstance->configurationLen;
+ getDescriptorParam.languageId = 0;
+
+ transfer->setupPacket.bmRequestType |= USB_REQUEST_TYPE_DIR_IN;
+ transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR;
+ status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam);
+ break;
+
+ case kStatus_DEV_SetCfg: /* set configuration state */
+ transfer->setupPacket.wValue =
+ USB_SHORT_TO_LITTLE_ENDIAN(deviceInstance->configuration.configurationDesc->bConfigurationValue);
+ transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_CONFIGURATION;
+ status = USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0);
+ break;
+
+ case kStatus_DEV_EnumDone: /* enumeration done state */
+ status = USB_HostNotifyDevice(deviceInstance,
+ kUSB_HostEventEnumerationDone); /* notify device enumeration done */
+ if (status == kStatus_USB_Success)
+ {
+ deviceInstance->state = kStatus_DEV_AppUsed;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+static usb_status_t USB_HostProcessCallback(usb_host_device_instance_t *deviceInstance)
+{
+ usb_host_pipe_t *pipe = (usb_host_pipe_t *)deviceInstance->controlPipe;
+ usb_status_t status = kStatus_USB_Success;
+ usb_descriptor_configuration_t *configureDesc;
+ usb_host_instance_t *hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle;
+
+ switch (deviceInstance->state)
+ {
+ case kStatus_DEV_GetDes8: /* process get 8 bytes descriptor result */
+ pipe->maxPacketSize = deviceInstance->deviceDescriptor.bMaxPacketSize0;
+ hostInstance->controllerTable->controllerIoctl(
+ hostInstance->controllerHandle, kUSB_HostUpdateControlPacketSize, deviceInstance->controlPipe);
+ break;
+
+ case kStatus_DEV_SetAddress: /* process set address result */
+ deviceInstance->setAddress = deviceInstance->allocatedAddress;
+ hostInstance->controllerTable->controllerIoctl(
+ hostInstance->controllerHandle, kUSB_HostUpdateControlEndpointAddress, deviceInstance->controlPipe);
+ break;
+
+ case kStatus_DEV_GetDes: /* process set address result */
+ /* NULL */
+ break;
+
+ case kStatus_DEV_GetCfg9: /* process get 9 bytes configuration result */
+ configureDesc = (usb_descriptor_configuration_t *)&deviceInstance->enumBuffer[0];
+
+ deviceInstance->configurationLen = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(configureDesc->wTotalLength);
+ if (deviceInstance->configurationDesc != NULL)
+ {
+ USB_OsaMemoryFree(deviceInstance->configurationDesc);
+ deviceInstance->configurationDesc = NULL;
+ }
+ /* for KHCI, the start address and the length should be 4 byte align */
+ if ((deviceInstance->configurationLen & 0x03) != 0)
+ {
+ deviceInstance->configurationDesc =
+ (uint8_t *)USB_OsaMemoryAllocate((deviceInstance->configurationLen & 0xFFFFFFFCu) + 4);
+ }
+ else
+ {
+ deviceInstance->configurationDesc = (uint8_t *)USB_OsaMemoryAllocate(deviceInstance->configurationLen);
+ }
+ if (deviceInstance->configurationDesc == NULL)
+ {
+ return kStatus_USB_Error;
+ }
+ break;
+
+ case kStatus_DEV_GetCfg: /* process get cofiguration result */
+ if (((usb_descriptor_configuration_t *)deviceInstance->configurationDesc)->bMaxPower >
+ USB_HOST_CONFIG_MAX_POWER)
+ {
+ return kStatus_USB_Error;
+ }
+ deviceInstance->configurationValue++;
+ if (USB_HostParseDeviceConfigurationDescriptor(deviceInstance) !=
+ kStatus_USB_Success) /* parse configuration descriptor */
+ {
+ return kStatus_USB_Error;
+ }
+
+ status = USB_HostNotifyDevice(deviceInstance, kUSB_HostEventAttach);
+
+ if (status != kStatus_USB_Success)
+ {
+ /* next configuration */
+ if (deviceInstance->configurationValue < deviceInstance->deviceDescriptor.bNumConfigurations)
+ {
+ return kStatus_USB_Retry;
+ }
+ else
+ {
+ USB_HostNotifyDevice(deviceInstance,
+ kUSB_HostEventNotSupported); /* notify application device is not supported */
+ return kStatus_USB_NotSupported;
+ }
+ }
+ break;
+
+ case kStatus_DEV_SetCfg:
+ /* NULL */
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+static usb_status_t USB_HostNotifyDevice(usb_host_device_instance_t *deviceInstance, uint32_t eventCode)
+{
+ usb_host_instance_t *hostInstance;
+ usb_status_t status1 = kStatus_USB_Error;
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ usb_status_t status2 = kStatus_USB_Error;
+ uint8_t haveHub;
+ uint8_t haveNoHub;
+ uint8_t interfaceIndex;
+#endif /* USB_HOST_CONFIG_HUB */
+
+ if (deviceInstance == NULL)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+ hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle;
+
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ haveHub = 0;
+ haveNoHub = 0;
+ for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex)
+ {
+ if (((usb_descriptor_interface_t *)deviceInstance->configuration.interfaceList[interfaceIndex].interfaceDesc)
+ ->bInterfaceClass == USB_HOST_HUB_CLASS_CODE)
+ {
+ haveHub = 1;
+ }
+ else
+ {
+ haveNoHub = 1;
+ }
+ }
+
+ if ((haveNoHub == 1) && (hostInstance->deviceCallback != NULL))
+ {
+ status1 = hostInstance->deviceCallback(deviceInstance, &deviceInstance->configuration,
+ eventCode); /* notify application event */
+ }
+ if (haveHub)
+ {
+ status2 =
+ USB_HostHubDeviceEvent(deviceInstance, &deviceInstance->configuration, eventCode); /* notify hub event */
+ }
+
+ if ((status1 == kStatus_USB_Success) || (status2 == kStatus_USB_Success)) /* the device is supported */
+ {
+ return kStatus_USB_Success;
+ }
+ else if (eventCode == kUSB_HostEventAttach) /* attach event */
+ {
+ status1 = kStatus_USB_NotSupported;
+ }
+ else
+ {
+ status1 = kStatus_USB_Error;
+ }
+#else
+ if (hostInstance->deviceCallback != NULL)
+ {
+ status1 = hostInstance->deviceCallback(deviceInstance, &deviceInstance->configuration,
+ eventCode); /* call host callback function */
+ }
+#endif
+ return status1;
+}
+
+static uint8_t USB_HostAllocateDeviceAddress(usb_host_instance_t *hostInstance)
+{
+ uint8_t address = 0;
+ uint8_t addressIndex;
+ uint8_t addressBitIndex;
+ for (addressIndex = 0; addressIndex < 8; ++addressIndex) /* find the idle address postion byte */
+ {
+ if (hostInstance->addressBitMap[addressIndex] != 0xFF)
+ {
+ break;
+ }
+ }
+ if (addressIndex < 8)
+ {
+ for (addressBitIndex = 0; addressBitIndex < 8; ++addressBitIndex) /* find the idle address position bit */
+ {
+ if (!(hostInstance->addressBitMap[addressIndex] & (0x01u << addressBitIndex)))
+ {
+ hostInstance->addressBitMap[addressIndex] |= (0x01u << addressBitIndex); /* set the allocated bit */
+ address = addressIndex * 8 + addressBitIndex + 1; /* the address minimum is 1 */
+ break;
+ }
+ }
+ }
+ return address;
+}
+
+static void USB_HostReleaseDeviceAddress(usb_host_instance_t *hostInstance, uint8_t address)
+{
+ USB_HostLock();
+ hostInstance->addressBitMap[(uint32_t)(address - 1) >> 3] &=
+ (~(0x01u << (((uint32_t)address - 1) & 0x07U))); /* reset the allocated bit */
+ USB_HostUnlock();
+}
+
+static usb_status_t USB_HostRemoveDeviceInstance(usb_host_handle hostHandle, usb_device_handle deviceHandle)
+{
+ usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle;
+ usb_host_device_instance_t *currentInstance;
+ usb_host_device_instance_t *prevInstance;
+ if ((hostHandle == NULL) || (deviceHandle == NULL))
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ /* search and remove device instance */
+ prevInstance = (usb_host_device_instance_t *)hostInstance->deviceList;
+ if (prevInstance == deviceHandle)
+ {
+ hostInstance->deviceList = prevInstance->next;
+ return kStatus_USB_Success;
+ }
+ else
+ {
+ currentInstance = prevInstance->next;
+ }
+
+ while (currentInstance != NULL)
+ {
+ if (currentInstance == deviceHandle)
+ {
+ prevInstance->next = currentInstance->next;
+ return kStatus_USB_Success;
+ }
+ prevInstance = currentInstance;
+ currentInstance = currentInstance->next;
+ }
+
+ return kStatus_USB_Success;
+}
+
+static void USB_HostReleaseDeviceResource(usb_host_instance_t *hostInstance, usb_host_device_instance_t *deviceInstance)
+{
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ uint8_t level = 0;
+#endif
+ /* release device's address */
+ if (deviceInstance->setAddress != 0)
+ {
+ USB_HostReleaseDeviceAddress(hostInstance, deviceInstance->setAddress);
+ }
+ else
+ {
+ if (deviceInstance->allocatedAddress != 0)
+ {
+ USB_HostReleaseDeviceAddress(hostInstance, deviceInstance->allocatedAddress);
+ }
+ }
+
+ /* close control pipe */
+ if (deviceInstance->controlPipe != NULL)
+ {
+ USB_HostCancelTransfer(hostInstance, deviceInstance->controlPipe, NULL);
+ if (USB_HostClosePipe(hostInstance, deviceInstance->controlPipe) != kStatus_USB_Success)
+ {
+#ifdef HOST_ECHO
+ usb_echo("error when close pipe\r\n");
+#endif
+ }
+ deviceInstance->controlPipe = NULL;
+ }
+
+ /* free configuration buffer */
+ if (deviceInstance->configurationDesc != NULL)
+ {
+ USB_OsaMemoryFree(deviceInstance->configurationDesc);
+ }
+
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ level = deviceInstance->level;
+#endif
+
+ /* free device instance buffer */
+ USB_OsaMemoryFree(deviceInstance);
+
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ /* enable controller attach if root hub */
+ if (level == 1)
+ {
+ USB_HostControlBus(hostInstance, kUSB_HostBusEnableAttach);
+ }
+#else
+ /* enable controller attach */
+ USB_HostControlBus(hostInstance, kUSB_HostBusEnableAttach);
+#endif
+}
+
+static usb_status_t USB_HostParseDeviceConfigurationDescriptor(usb_device_handle deviceHandle)
+{
+ usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
+ uint32_t endPos;
+ usb_descriptor_union_t *unionDes;
+ usb_host_interface_t *interfaceParse = NULL;
+ usb_host_ep_t *epParse;
+ uint8_t *buffer;
+
+ if (deviceHandle == NULL)
+ {
+ return kStatus_USB_InvalidParameter;
+ }
+
+ buffer = (uint8_t *)&deviceInstance->configuration;
+ /* clear the previous parse result, note: end_pos means buffer index here*/
+ for (endPos = 0; endPos < sizeof(usb_host_configuration_t); endPos++)
+ {
+ buffer[endPos] = 0;
+ }
+ for (endPos = 0; endPos < USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE; ++endPos)
+ {
+ deviceInstance->interfaceStatus[endPos] = 0;
+ }
+
+ /* parse configuration descriptor */
+ unionDes = (usb_descriptor_union_t *)deviceInstance->configurationDesc;
+ endPos = (uint32_t)(deviceInstance->configurationDesc + deviceInstance->configurationLen);
+
+ if ((unionDes->common.bLength == USB_DESCRIPTOR_LENGTH_CONFIGURE) &&
+ (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_CONFIGURE))
+ {
+ /* configuration descriptor */
+ deviceInstance->configuration.configurationDesc = (usb_descriptor_configuration_t *)unionDes;
+ deviceInstance->configuration.configurationExtensionLength = 0;
+ deviceInstance->configuration.configurationExtension = NULL;
+ deviceInstance->configuration.interfaceCount = 0;
+ unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength);
+ while ((uint32_t)unionDes < endPos)
+ {
+ if (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)
+ {
+ if (deviceInstance->configuration.configurationExtension == NULL)
+ {
+ deviceInstance->configuration.configurationExtension = (uint8_t *)unionDes;
+ }
+ if ((unionDes->common.bDescriptorType == 0x00) ||
+ (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */
+ {
+ return kStatus_USB_Error;
+ }
+ deviceInstance->configuration.configurationExtensionLength += unionDes->common.bLength;
+ unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* interface descriptor */
+ deviceInstance->configuration.interfaceCount = 0;
+ while ((uint32_t)unionDes < endPos)
+ {
+ if (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE)
+ {
+ if (unionDes->interface.bAlternateSetting == 0x00)
+ {
+ if (deviceInstance->configuration.interfaceCount >= USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE)
+ {
+#ifdef HOST_ECHO
+ usb_echo(
+ "Unsupported Device attached\r\n too many interfaces in one configuration, please increase "
+ "the USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE value\n");
+#endif
+ return kStatus_USB_Error;
+ }
+ interfaceParse =
+ &deviceInstance->configuration.interfaceList[deviceInstance->configuration.interfaceCount];
+ deviceInstance->configuration.interfaceCount++;
+ interfaceParse->alternateSettingNumber = 0;
+ interfaceParse->epCount = 0;
+ interfaceParse->interfaceDesc = &unionDes->interface;
+ interfaceParse->interfaceExtensionLength = 0;
+ interfaceParse->interfaceExtension = NULL;
+ interfaceParse->interfaceIndex = unionDes->interface.bInterfaceNumber;
+ if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */
+ {
+ return kStatus_USB_Error;
+ }
+ unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength);
+ interfaceParse->interfaceExtension = (uint8_t *)unionDes;
+ while ((uint32_t)unionDes < endPos)
+ {
+ if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) &&
+ (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT))
+ {
+ if ((unionDes->common.bDescriptorType == 0x00) ||
+ (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */
+ {
+ return kStatus_USB_Error;
+ }
+ interfaceParse->interfaceExtensionLength += unionDes->common.bLength;
+ unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* endpoint descriptor */
+ if (interfaceParse->interfaceDesc->bNumEndpoints != 0)
+ {
+ if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) ||
+ (interfaceParse->interfaceDesc->bNumEndpoints > USB_HOST_CONFIG_INTERFACE_MAX_EP))
+ {
+#ifdef HOST_ECHO
+ usb_echo("interface descriptor error\n");
+#endif
+ return kStatus_USB_Error;
+ }
+ for (; interfaceParse->epCount < interfaceParse->interfaceDesc->bNumEndpoints;
+ (interfaceParse->epCount)++)
+ {
+ if (((uint32_t)unionDes >= endPos) ||
+ (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 *)&interfaceParse->epList[interfaceParse->epCount];
+ epParse->epDesc = (usb_descriptor_endpoint_t *)unionDes;
+ epParse->epExtensionLength = 0;
+ epParse->epExtension = NULL;
+ if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */
+ {
+ return kStatus_USB_Error;
+ }
+ interfaceParse->interfaceExtensionLength += unionDes->common.bLength;
+ unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength);
+ epParse->epExtension = (uint8_t *)unionDes;
+ while ((uint32_t)unionDes < endPos)
+ {
+ if ((unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) &&
+ (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE))
+ {
+ if ((unionDes->common.bDescriptorType == 0x00) ||
+ (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */
+ {
+ return kStatus_USB_Error;
+ }
+ epParse->epExtensionLength += unionDes->common.bLength;
+ interfaceParse->interfaceExtensionLength += unionDes->common.bLength;
+ unionDes =
+ (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (interfaceParse == NULL)
+ {
+ return kStatus_USB_Error; /* in normal situation this cannot reach */
+ }
+ interfaceParse->alternateSettingNumber++;
+ if (unionDes->common.bLength == 0x00) /* the descriptor data is wrong */
+ {
+ return kStatus_USB_Error;
+ }
+ interfaceParse->interfaceExtensionLength += unionDes->common.bLength;
+ unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength);
+ while ((uint32_t)unionDes < endPos)
+ {
+ if (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)
+ {
+ if ((unionDes->common.bDescriptorType == 0x00) ||
+ (unionDes->common.bLength == 0x00)) /* the descriptor data is wrong */
+ {
+ return kStatus_USB_Error;
+ }
+ interfaceParse->interfaceExtensionLength += unionDes->common.bLength;
+ unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ return kStatus_USB_Error;
+ }
+ }
+ }
+
+ for (endPos = 0; endPos < deviceInstance->configuration.interfaceCount; ++endPos)
+ {
+ deviceInstance->interfaceStatus[endPos] = kStatus_interface_Attached;
+ }
+
+ return kStatus_USB_Success;
+}
+
+usb_status_t USB_HostAttachDevice(usb_host_handle hostHandle,
+ uint8_t speed,
+ uint8_t hubNumber,
+ uint8_t portNumber,
+ uint8_t level,
+ usb_device_handle *deviceHandle)
+{
+ usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle;
+ usb_host_device_instance_t *newInstance;
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ usb_host_device_instance_t *currentInstance;
+#endif
+ uint8_t address;
+ usb_host_pipe_init_t pipeInit;
+
+ if (hostHandle == NULL)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+/* check whether is the device attached? */
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ currentInstance = (usb_host_device_instance_t *)hostInstance->deviceList;
+ while (currentInstance != NULL)
+ {
+ if ((currentInstance->hubNumber == hubNumber) && (currentInstance->portNumber == portNumber))
+ {
+ *deviceHandle = NULL;
+#ifdef HOST_ECHO
+ usb_echo("device has attached\r\n");
+#endif
+ return kStatus_USB_Busy;
+ }
+ else
+ {
+ currentInstance = currentInstance->next;
+ }
+ }
+#else
+ if (hostInstance->deviceList != NULL)
+ {
+ *deviceHandle = NULL;
+ usb_echo("device has attached\r\n");
+ return kStatus_USB_Busy;
+ }
+#endif
+
+ /* Allocate new device instance */
+ newInstance = (usb_host_device_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_device_instance_t));
+ if (newInstance == NULL)
+ {
+#ifdef HOST_ECHO
+ usb_echo("allocate dev instance fail\r\n");
+#endif
+ return kStatus_USB_AllocFail;
+ }
+
+ /* new instance fields init */
+ newInstance->hostHandle = hostHandle;
+ newInstance->speed = speed;
+ newInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES;
+ newInstance->enumRetries = USB_HOST_CONFIG_ENUMERATION_MAX_RETRIES;
+ newInstance->setAddress = 0;
+ newInstance->deviceAttachState = kStatus_device_Attached;
+
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ newInstance->hubNumber = hubNumber;
+ newInstance->portNumber = portNumber;
+ newInstance->level = level;
+
+ if ((speed != USB_SPEED_HIGH) && (level > 1))
+ {
+ newInstance->hsHubNumber = USB_HostHubGetHsHubNumber(hubNumber);
+ newInstance->hsHubPort = USB_HostHubGetHsHubPort(hubNumber, portNumber);
+ }
+ else
+ {
+ newInstance->hsHubNumber = hubNumber;
+ newInstance->hsHubPort = portNumber;
+ }
+#endif /* USB_HOST_CONFIG_HUB */
+
+ USB_HostLock();
+ /* allocate address && insert to the dev list */
+ address = USB_HostAllocateDeviceAddress(hostInstance);
+ if (address == 0)
+ {
+#ifdef HOST_ECHO
+ usb_echo("allocate address fail\r\n");
+#endif
+ USB_HostUnlock();
+ USB_OsaMemoryFree(newInstance);
+ return kStatus_USB_Error;
+ }
+ newInstance->allocatedAddress = address;
+
+ newInstance->next = (usb_host_device_instance_t *)hostInstance->deviceList;
+ hostInstance->deviceList = newInstance;
+ newInstance->state = kStatus_DEV_Initial;
+ USB_HostUnlock();
+
+ /* open control pipe */
+ pipeInit.devInstance = newInstance;
+ pipeInit.pipeType = USB_ENDPOINT_CONTROL;
+ pipeInit.direction = 0;
+ pipeInit.endpointAddress = 0;
+ pipeInit.interval = 0;
+ pipeInit.maxPacketSize = 8;
+ pipeInit.numberPerUframe = 0;
+ pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK;
+ if (USB_HostOpenPipe(hostHandle, &newInstance->controlPipe, &pipeInit) != kStatus_USB_Success)
+ {
+ /* don't need release resource, resource is released when detach */
+ *deviceHandle = newInstance;
+ return kStatus_USB_Error;
+ }
+
+ /* start enumeration */
+ newInstance->state = kStatus_DEV_GetDes8;
+ USB_HostProcessState(newInstance); /* process enumeration state machine */
+
+ *deviceHandle = newInstance;
+ return kStatus_USB_Success;
+}
+
+usb_status_t USB_HostDetachDevice(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber)
+{
+ usb_host_device_instance_t *deviceInstance;
+ usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle;
+
+ if (hostHandle == NULL)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ USB_HostLock();
+/* search for device instance handle */
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList;
+ while (deviceInstance != NULL)
+ {
+ if ((deviceInstance->hubNumber == hubNumber) && (deviceInstance->portNumber == portNumber))
+ {
+ break;
+ }
+ deviceInstance = deviceInstance->next;
+ }
+#else
+ deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList;
+#endif
+ USB_HostUnlock();
+ if (deviceInstance != NULL)
+ {
+ return USB_HostDetachDeviceInternal(hostHandle, deviceInstance); /* device instance detach */
+ }
+ return kStatus_USB_Success;
+}
+
+usb_status_t USB_HostDetachDeviceInternal(usb_host_handle hostHandle, usb_device_handle deviceHandle)
+{
+ usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
+ usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle;
+ if ((hostHandle == NULL) || (deviceHandle == NULL))
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ deviceInstance->deviceAttachState = kStatus_device_Detached; /* mark the device is detached from host */
+
+ if (deviceInstance->state >= kStatus_DEV_Initial) /* device instance is valid */
+ {
+ /* detach internally */
+ if (deviceInstance->state < kStatus_DEV_AppUsed) /* enumeration is not done */
+ {
+ if (deviceInstance->controlPipe != NULL)
+ {
+ USB_HostCancelTransfer(hostInstance, deviceInstance->controlPipe, NULL);
+ }
+
+ /* remove device instance from host */
+ USB_HostRemoveDeviceInstance(hostInstance, deviceInstance);
+ USB_HostReleaseDeviceResource(hostInstance, deviceInstance);
+ }
+ else /* enumeration has be done and notifed application */
+ {
+ USB_HostNotifyDevice(deviceInstance, kUSB_HostEventDetach); /* notify application device detach */
+ }
+ }
+
+ return kStatus_USB_Success;
+}
+
+uint8_t USB_HostGetDeviceAttachState(usb_device_handle deviceHandle)
+{
+ return deviceHandle ? ((usb_host_device_instance_t *)deviceHandle)->deviceAttachState : 0x0;
+}
+
+usb_status_t USB_HostValidateDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle)
+{
+ usb_host_device_instance_t *searchDev;
+
+ if (deviceHandle == NULL)
+ {
+ return kStatus_USB_InvalidParameter;
+ }
+ /* search for the device */
+ searchDev = (usb_host_device_instance_t *)((usb_host_instance_t *)hostHandle)->deviceList;
+ while ((searchDev != NULL) && ((usb_device_handle)searchDev != deviceHandle))
+ {
+ searchDev = searchDev->next;
+ }
+
+ if (searchDev)
+ {
+ return kStatus_USB_Success;
+ }
+ return kStatus_USB_Error;
+}
+
+static usb_status_t USB_HostControlBus(usb_host_handle hostHandle, uint8_t controlType)
+{
+ usb_status_t status = kStatus_USB_Success;
+ usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle;
+
+ if (hostHandle == NULL)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl,
+ &controlType);
+
+ return status;
+}
+
+usb_status_t USB_HostOpenDeviceInterface(usb_device_handle deviceHandle, usb_host_interface_handle interfaceHandle)
+{
+ usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
+ usb_host_instance_t *hostInstance = NULL;
+ uint8_t interfaceIndex;
+ uint8_t index = 0;
+
+ if ((deviceHandle == NULL) || (interfaceHandle == NULL))
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle;
+ USB_HostLock();
+ /* check host_instance valid? */
+ for (; index < USB_HOST_CONFIG_MAX_HOST; ++index)
+ {
+ if ((g_UsbHostInstance[index].occupied == 1) &&
+ ((usb_host_instance_t *)(&g_UsbHostInstance[index]) == (hostInstance)))
+ {
+ break;
+ }
+ }
+ if (index >= USB_HOST_CONFIG_MAX_HOST)
+ {
+ USB_HostUnlock();
+ return kStatus_USB_Error;
+ }
+
+ /* check deviceHandle valid? */
+ if (USB_HostValidateDevice(hostInstance, deviceHandle) != kStatus_USB_Success)
+ {
+ USB_HostUnlock();
+ return kStatus_USB_Error;
+ }
+
+ /* search interface and set the interface as opened */
+ for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex)
+ {
+ if (&deviceInstance->configuration.interfaceList[interfaceIndex] == interfaceHandle)
+ {
+ deviceInstance->interfaceStatus[interfaceIndex] = kStatus_interface_Opened;
+ break;
+ }
+ }
+ USB_HostUnlock();
+
+ return kStatus_USB_Success;
+}
+
+usb_status_t USB_HostCloseDeviceInterface(usb_device_handle deviceHandle, usb_host_interface_handle interfaceHandle)
+{
+ usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
+ usb_host_instance_t *hostInstance = NULL;
+ uint8_t interfaceIndex;
+ uint8_t removeLabel = 1;
+ uint8_t index = 0;
+
+ if (deviceHandle == NULL)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle;
+ USB_HostLock();
+ /* check host_instance valid? */
+ for (; index < USB_HOST_CONFIG_MAX_HOST; ++index)
+ {
+ if ((g_UsbHostInstance[index].occupied == 1) &&
+ ((usb_host_instance_t *)(&g_UsbHostInstance[index]) == (hostInstance)))
+ {
+ break;
+ }
+ }
+ if (index >= USB_HOST_CONFIG_MAX_HOST)
+ {
+ USB_HostUnlock();
+ return kStatus_USB_Error;
+ }
+
+ /* check deviceHandle valid? */
+ if (USB_HostValidateDevice(hostInstance, deviceHandle) != kStatus_USB_Success)
+ {
+ USB_HostUnlock();
+ return kStatus_USB_Error;
+ }
+
+ if (interfaceHandle != NULL)
+ {
+ /* search interface and set the interface as detached */
+ for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex)
+ {
+ if (&deviceInstance->configuration.interfaceList[interfaceIndex] == interfaceHandle)
+ {
+ deviceInstance->interfaceStatus[interfaceIndex] = kStatus_interface_Detached;
+ break;
+ }
+ }
+ }
+
+ if (deviceInstance->deviceAttachState == kStatus_device_Detached) /* device is removed from host */
+ {
+ removeLabel = 1;
+ /* check all the interfaces of the device are not opened */
+ for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex)
+ {
+ if (deviceInstance->interfaceStatus[interfaceIndex] == kStatus_interface_Opened)
+ {
+ removeLabel = 0;
+ break;
+ }
+ }
+ if (removeLabel == 1)
+ {
+ /* remove device instance from host */
+ USB_HostRemoveDeviceInstance(hostInstance, deviceInstance);
+ }
+ USB_HostUnlock();
+
+ if (removeLabel == 1)
+ {
+ USB_HostReleaseDeviceResource((usb_host_instance_t *)deviceInstance->hostHandle,
+ deviceInstance); /* release device resource */
+ }
+ }
+ else
+ {
+ USB_HostUnlock();
+ }
+
+ return kStatus_USB_Success;
+}
+
+usb_status_t USB_HostRemoveDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle)
+{
+ usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle;
+ usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
+ uint8_t interfaceIndex = 0;
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ uint8_t level = 0;
+ uint8_t devHubNo;
+ uint8_t devPortNo;
+#endif
+
+ if ((hostHandle == NULL) || (deviceHandle == NULL))
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+ if (deviceInstance->hostHandle != hostHandle)
+ {
+ return kStatus_USB_InvalidParameter;
+ }
+
+ if (USB_HostValidateDevice(hostInstance, deviceInstance) == kStatus_USB_Success) /* device is valid */
+ {
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ devHubNo = deviceInstance->hubNumber;
+ devPortNo = deviceInstance->portNumber;
+ level = deviceInstance->level;
+#endif
+
+ deviceInstance->deviceAttachState = kStatus_device_Detached;
+ if (deviceInstance->state >= kStatus_DEV_Initial) /* device is valid */
+ {
+ if (deviceInstance->state < kStatus_DEV_AppUsed) /* enumeraion is not done or application don't use */
+ {
+ /* detach internally */
+ USB_HostDetachDeviceInternal(hostHandle, deviceHandle);
+ }
+ else /* application use the device */
+ {
+ for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount;
+ ++interfaceIndex)
+ {
+ if (deviceInstance->interfaceStatus[interfaceIndex] == kStatus_interface_Opened)
+ {
+#ifdef HOST_ECHO
+ usb_echo("error: there is class instance that is not deinited\r\n");
+#endif
+ break;
+ }
+ }
+ /* remove device instance from host */
+ USB_HostRemoveDeviceInstance(hostInstance, deviceInstance);
+ USB_HostReleaseDeviceResource(hostInstance, deviceInstance); /* release resource */
+ }
+ }
+
+#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB))
+ if (level == 1)
+ {
+ USB_HostControlBus(hostHandle, kUSB_HostBusReset); /* reset controller port */
+ USB_HostControlBus(hostHandle, kUSB_HostBusRestart); /* restart controller port */
+ }
+ else
+ {
+ USB_HostHubRemovePort(devHubNo, devPortNo); /* reset hub port */
+ }
+#else
+ USB_HostControlBus(hostHandle, kUSB_HostBusReset); /* reset controller port */
+ USB_HostControlBus(hostHandle, kUSB_HostBusRestart); /* restart controller port */
+#endif /* USB_HOST_CONFIG_HUB */
+ }
+
+ return kStatus_USB_Success;
+}