From f7cd9b461ca33845339f4a11f49bdc142696827a Mon Sep 17 00:00:00 2001 From: Dominik Sliwa Date: Tue, 28 Jun 2016 09:51:29 +0200 Subject: Apalis_TK1_K20: SPI Communication, ADC, TSC, GPIO Support for Communication between TK1 SoC and K20 MCU This patch includes ADC, TSC and GPIO functionality. Signed-off-by: Dominik Sliwa --- usb_1.1.0/host/usb_host_devices.c | 1345 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1345 insertions(+) create mode 100644 usb_1.1.0/host/usb_host_devices.c (limited to 'usb_1.1.0/host/usb_host_devices.c') 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; +} -- cgit v1.2.3