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/class/usb_host_hub_app.c | 1106 +++++++++++++++++++++++++++++++ 1 file changed, 1106 insertions(+) create mode 100644 usb_1.1.0/host/class/usb_host_hub_app.c (limited to 'usb_1.1.0/host/class/usb_host_hub_app.c') diff --git a/usb_1.1.0/host/class/usb_host_hub_app.c b/usb_1.1.0/host/class/usb_host_hub_app.c new file mode 100644 index 0000000..1755b69 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub_app.c @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "usb_host_config.h" +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +#include "usb_host.h" +#include "usb_host_hub.h" +#include "usb_host_hub_app.h" +#include "usb_host_devices.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief prime interrupt in data. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub process state machine. hub is enable after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcess(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port attach process state machine. one device is attached to the port after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPortAttach(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port detach process state machine. one device is detached from the port after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPortDetach(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port process. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub interrupt in data process. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessData(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostHubControlCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status); + +/*! + * @brief hub interrupt pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostHubInterruptInCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +static usb_device_handle s_HubDeviceHandle; +static usb_host_interface_handle s_HubInterfaceHandle; +static usb_host_hub_global_t s_HubGlobal; + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance) +{ + if (hubInstance == NULL) + { + return; + } + + /* there is no prime for control or interrupt */ + if (hubInstance->primeStatus != kPrimeNone) + { + return; + } + + /* receive interrupt data */ + if (USB_HostHubInterruptRecv(hubInstance, hubInstance->hubBitmapBuffer, (hubInstance->portCount >> 3) + 1, + USB_HostHubInterruptInCallback, hubInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error in hub interrupt recv\r\n"); +#endif + } + else + { + hubInstance->primeStatus = kPrimeInterrupt; + } +} + +static void USB_HostHubProcess(usb_host_hub_instance_t *hubInstance) +{ + uint8_t needPrimeInterrupt = 0; /* need to prime interrupt in transfer (0 - don't need; 1 - need) */ + uint8_t processSuccess = 0; /* the code excute successfully (0 - fail; 1 - success) */ + uint32_t tmp = 0; + usb_host_hub_descriptor_t *hubDescriptor; + + switch (hubInstance->hubStatus) + { + case kHubRunIdle: + case kHubRunInvalid: + break; + + case kHubRunWaitSetInterface: + hubInstance->hubStatus = kHubRunGetDescriptor7; /* update as next state */ + /* get hub descriptor */ + if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7, USB_HostHubControlCallback, + hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* control transfer is on-going */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("hub get descriptor 7\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("hub get descriptor 7 error\r\n"); +#endif + break; + } + break; + + case kHubRunGetDescriptor7: + hubDescriptor = (usb_host_hub_descriptor_t *)&hubInstance->hubDescriptor[0]; + + /* get the hub think time */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetHubThinkTime, &tmp); + hubInstance->totalThinktime = tmp + (((uint32_t)hubDescriptor->whubcharacteristics[0] & + USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_MASK) >> + USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_SHIFT); + + /* get hub port number */ + hubInstance->portCount = hubDescriptor->bnrports; + if (hubInstance->portCount > USB_HOST_HUB_MAX_PORT) + { +#ifdef HOST_ECHO + usb_echo("port number is bigger than USB_HOST_HUB_MAX_PORT\r\n"); +#endif + return; + } + + hubInstance->hubStatus = kHubRunGetDescriptor; /* update as next state */ + /* get hub descriptor */ + if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7 + (hubInstance->portCount >> 3) + 1, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* control transfer is on-going */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("hub get descriptor\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("hub get descriptor error\r\n"); +#endif + break; + } + break; + + case kHubRunGetDescriptor: + /* malloc port instance for the hub's ports */ + hubInstance->portList = (usb_host_hub_port_instance_t *)USB_OsaMemoryAllocate( + hubInstance->portCount * sizeof(usb_host_hub_port_instance_t)); + if (hubInstance->portList == NULL) + { +#ifdef HOST_ECHO + usb_echo("port list allocate fail\r\n"); +#endif + hubInstance->hubStatus = kHubRunInvalid; + break; + } + /* TODO: port instance status -> can be removed. app_status */ + + hubInstance->hubStatus = kHubRunSetPortPower; /* update as next state */ + hubInstance->portIndex = 0; + + /* there is no significance, just for fixing misra error */ + if (hubInstance->hubStatus != kHubRunSetPortPower) + { + break; + } + + case kHubRunSetPortPower: + /* set PORT_POWER for all ports */ + if (hubInstance->portIndex < hubInstance->portCount) + { + hubInstance->portIndex++; + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portIndex, PORT_POWER, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* update as next state */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("set port feature PORT_POWER\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("set port feature PORT_POWER fail\r\n"); +#endif + needPrimeInterrupt = 1; + break; + } + break; + } + hubInstance->portProcess = 0; + /* reset port information as default */ + for (tmp = 0; tmp < hubInstance->portCount; ++tmp) + { + hubInstance->portList[tmp].deviceHandle = NULL; + hubInstance->portList[tmp].resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + hubInstance->portList[tmp].portStatus = kPortRunWaitPortChange; + } + hubInstance->hubStatus = kHubRunIdle; + needPrimeInterrupt = 1; + break; + + case kHubRunGetStatusDone: /* process hub status change */ + tmp = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS((&hubInstance->hubStatusBuffer[2])); + hubInstance->hubStatus = kHubRunIdle; + if ((1 << C_HUB_LOCAL_POWER) & tmp) /* C_HUB_LOCAL_POWER */ + { + if (USB_HostHubClearFeature(hubInstance, C_HUB_LOCAL_POWER, USB_HostHubControlCallback, hubInstance) == + kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + processSuccess = 1; + } + else + { + needPrimeInterrupt = 1; + } + } + else if ((1 << C_HUB_OVER_CURRENT) & tmp) /* C_HUB_OVER_CURRENT */ + { + if (USB_HostHubClearFeature(hubInstance, C_HUB_OVER_CURRENT, USB_HostHubControlCallback, hubInstance) == + kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + processSuccess = 1; + } + else + { + needPrimeInterrupt = 1; + } + } + else + { + needPrimeInterrupt = 1; + } + break; + + default: + break; + } + + if (needPrimeInterrupt == 1) /* prime interrupt in transfer */ + { + hubInstance->hubStatus = kHubRunIdle; + USB_HostHubGetInterruptStatus(hubInstance); + } + else + { + if (processSuccess == 0) + { + hubInstance->hubStatus = kHubRunInvalid; + } + } +} + +static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + + /* for device attach */ + if (portInstance->deviceHandle == NULL) + { + USB_HostHubProcessPortAttach(hubInstance); + } + else /* for device detach */ + { + USB_HostHubProcessPortDetach(hubInstance); + } +} + +static void USB_HostHubProcessPortAttach(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + uint8_t processSuccess = 0; + uint32_t specStatus; + uint8_t feature; + uint32_t infoValue; + + switch (portInstance->portStatus) + { + case kPortRunIdle: + case kPortRunInvalid: + break; + case kPortRunWaitPortChange: /* (1) port is changed, and get port status */ + portInstance->portStatus = kPortRunCheckCPortConnection; /* update as next state */ + /* send class-specific request to get port status */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckCPortConnection: /* (2) check port status, and clear the status bits */ + feature = 0; + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS((hubInstance->portStatusBuffer)); + if ((1 << C_PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunGetPortConnection; /* update as next state */ + /* clear C_PORT_CONNECTION */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else if ((1 << PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunWaitPortResetDone; /* update as next state */ + /* set PORT_RESET */ + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + if (portInstance->resetCount > 0) + { + portInstance->resetCount--; + } + } + break; + } + else if ((1 << C_PORT_RESET) & specStatus) + { + feature = C_PORT_RESET; /* clear C_PORT_RESET */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_RESET when detached\r\n"); +#endif + } + else if ((1 << C_PORT_ENABLE) & specStatus) + { + feature = C_PORT_ENABLE; /* clear C_PORT_ENABLE */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_ENABLE when detached\r\n"); +#endif + } + else if ((1 << C_PORT_OVER_CURRENT) & specStatus) + { + feature = C_PORT_OVER_CURRENT; /* clear C_PORT_OVER_CURRENT */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_OVER_CURRENT when detached\r\n"); +#endif + } + else + { + } + + if (feature != 0) + { + portInstance->portStatus = kPortRunWaitPortChange; /* update as next state */ + /* clear feature */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, feature, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + } + break; + + case kPortRunGetPortConnection: /* (3) get port status */ + portInstance->portStatus = kPortRunCheckPortConnection; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; /* control transfer is on-going */ + processSuccess = 1; + } + break; + + case kPortRunCheckPortConnection: /* (4) check PORT_CONNECTION bit */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunWaitPortResetDone; /* update as next state */ + /* set PORT_RESET */ + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + if (portInstance->resetCount > 0) + { + portInstance->resetCount--; + } + } + } + break; + + case kPortRunWaitPortResetDone: /* (5) wait port change */ + portInstance->portStatus = kPortRunWaitCPortReset; /* update as next state */ + processSuccess = 1; + /* must wait the enumeration done, then operate the next port */ + USB_HostHubGetInterruptStatus(hubInstance); + break; + + case kPortRunWaitCPortReset: /* (6) get port satus for checking C_PORT_RESET */ + portInstance->portStatus = KPortRunCheckCPortReset; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case KPortRunCheckCPortReset: /* (7) check C_PORT_RESET and clear C_PORT_RESET */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << C_PORT_RESET) & specStatus) + { + if (portInstance->resetCount == 0) + { + portInstance->portStatus = kPortRunPortAttached; /* update as next state */ + /* get port's device speed */ + if (specStatus & (1 << PORT_HIGH_SPEED)) + { + portInstance->speed = USB_SPEED_HIGH; + } + else if (specStatus & (1 << PORT_LOW_SPEED)) + { + portInstance->speed = USB_SPEED_LOW; + } + else + { + portInstance->speed = USB_SPEED_FULL; + } + } + else + { + portInstance->portStatus = kPortRunResetAgain; /* update as next state */ + } + + /* clear C_PORT_RESET */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + } + break; + + case kPortRunResetAgain: /* (8) reset again */ + portInstance->portStatus = kPortRunCheckPortConnection; /* check connection then reset again */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunPortAttached: /* (9) the port have one device attached */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + USB_HostAttachDevice(hubInstance->hostHandle, portInstance->speed, infoValue, hubInstance->portProcess, + hubInstance->hubLevel + 1, &portInstance->deviceHandle); + processSuccess = 1; + hubInstance->portProcess = 0; + s_HubGlobal.hubProcess = NULL; + portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + USB_HostHubGetInterruptStatus(hubInstance); + break; + + default: + break; + } + + if (processSuccess == 0) + { + portInstance->portStatus = kPortRunWaitPortChange; + hubInstance->portProcess = 0; + s_HubGlobal.hubProcess = NULL; + portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +static void USB_HostHubProcessPortDetach(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + uint8_t processSuccess = 0; + uint32_t specStatus; + + switch (portInstance->portStatus) + { + case kPortRunIdle: + case kPortRunInvalid: + break; + + case kPortRunPortAttached: /* (1) port is changed, then get port status */ + portInstance->portStatus = kPortRunCheckPortDetach; + /* get port status */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckPortDetach: /* (2) check port status bits */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + portInstance->portStatus = kPortRunGetConnectionBit; + if ((1 << C_PORT_CONNECTION) & specStatus) /* C_PORT_CONNECTION */ + { + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else if ((1 << C_PORT_ENABLE) & specStatus) /* C_PORT_ENABLE */ + { + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_ENABLE, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else + { + /* don't break to check CONNECTION bit */ + } + + case kPortRunGetConnectionBit: /* (3) get port status */ + portInstance->portStatus = kPortRunCheckConnectionBit; + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckConnectionBit: /* (4) check port connection bit */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_CONNECTION) & specStatus) /* PORT_CONNECTION */ + { + portInstance->portStatus = kPortRunPortAttached; +#ifdef HOST_ECHO + usb_echo("PORT_CONNECTION in attach for detach\r\n"); +#endif + } + else + { + processSuccess = 1; + /* port's device is detached */ + portInstance->portStatus = kPortRunWaitPortChange; + USB_HostDetachDeviceInternal(hubInstance->hostHandle, portInstance->deviceHandle); + portInstance->deviceHandle = NULL; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } + break; + default: + break; + } + + if (processSuccess == 0) + { + portInstance->portStatus = kPortRunPortAttached; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +static void USB_HostHubProcessData(usb_host_hub_instance_t *hubInstance) +{ + uint8_t needPrimeInterrupt = 1; + uint8_t portIndex; + + /* process the port which status change */ + for (portIndex = 0; portIndex <= hubInstance->portCount; ++portIndex) + { + if ((0x01u << (portIndex & 0x07u)) & (hubInstance->hubBitmapBuffer[portIndex >> 3])) + { + if (portIndex == 0) /* hub status change */ + { + if ((s_HubGlobal.hubProcess == NULL) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == 0))) + { + hubInstance->hubStatus = kHubRunGetStatusDone; + if (USB_HostHubGetStatus(hubInstance, hubInstance->hubStatusBuffer, 4, USB_HostHubControlCallback, + hubInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error in usb_class_hub_get_status\r\n"); +#endif + hubInstance->hubStatus = kHubRunIdle; + } + else + { + hubInstance->primeStatus = kPrimeHubControl; + needPrimeInterrupt = 0; + } + } + } + else /* port's status change */ + { + /* process the on-going port or process one new port */ + if ((s_HubGlobal.hubProcess == NULL) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == 0)) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == portIndex))) + { + if (hubInstance->controlTransfer == NULL) + { + s_HubGlobal.hubProcess = hubInstance; + hubInstance->portProcess = portIndex; + needPrimeInterrupt = 0; + USB_HostHubProcessPort(hubInstance); + } + break; /* process the port change in turn */ + } + } + } + } + + if (needPrimeInterrupt == 1) + { + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +void USB_HostHubControlCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->invalid == 1) + { + return; + } + if (status != kStatus_USB_Success) + { + /* if transfer fail, prime a new interrupt in transfer */ + hubInstance->primeStatus = kPrimeNone; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + return; + } + + if (hubInstance->primeStatus == kPrimeHubControl) /* hub related control transfer */ + { + hubInstance->primeStatus = kPrimeNone; + USB_HostHubProcess(hubInstance); + } + else if (hubInstance->primeStatus == kPrimePortControl) /* hub's port related control transfer */ + { + hubInstance->primeStatus = kPrimeNone; + USB_HostHubProcessPort(hubInstance); + } + else + { + } +} + +void USB_HostHubInterruptInCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->invalid == 1) + { + return; + } + /* interrupt data received */ + hubInstance->primeStatus = kPrimeNone; + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("hub interrupt in data callback error\r\n"); +#endif + /* prime nexe interrupt transfer */ + if (hubInstance->controlTransfer == NULL) + { + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } + } + else + { + USB_HostHubProcessData(hubInstance); /* process the interrupt data */ + } +} + +/*! + * @brief host hub callback function. + * + * This function should be called in the host callback function. + * + * @param deviceHandle device handle. + * @param configurationHandle attached device's configuration descriptor information. + * @param event_code callback event code, please reference to enumeration host_event_t. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_NotSupported The configuration don't contain hub interface. + */ +usb_status_t USB_HostHubDeviceEvent(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode) +{ + usb_host_configuration_t *configuration; + usb_host_interface_t *interface; + uint8_t interfaceIndex; + uint8_t id; + usb_status_t status = kStatus_USB_Success; + usb_host_class_handle hubClassHandle; + usb_host_hub_instance_t *hubInstance; + usb_host_hub_instance_t *prevInstance; + uint32_t infoValue; + usb_osa_status_t osaStatus; + + switch (eventCode) + { + case kUSB_HostEventAttach: + /* judge whether is configurationHandle supported */ + configuration = (usb_host_configuration_t *)configurationHandle; + for (interfaceIndex = 0; interfaceIndex < configuration->interfaceCount; ++interfaceIndex) + { + interface = &configuration->interfaceList[interfaceIndex]; + id = interface->interfaceDesc->bInterfaceClass; + if (id != USB_HOST_HUB_CLASS_CODE) + { + continue; + } + id = interface->interfaceDesc->bInterfaceSubClass; + if (id != USB_HOST_HUB_SUBCLASS_CODE_NONE) + { + continue; + } + else + { + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + if (infoValue > 5) + { +#ifdef HOST_ECHO + usb_echo("Host can support max 5 level hubs\r\n"); +#endif + continue; + } + /* the interface is hub */ + s_HubDeviceHandle = deviceHandle; + s_HubInterfaceHandle = interface; + return kStatus_USB_Success; + } + } + status = kStatus_USB_NotSupported; + break; + + case kUSB_HostEventEnumerationDone: + /* the device enumeration is done */ + if ((s_HubDeviceHandle != NULL) && (s_HubInterfaceHandle != NULL)) + { + /* print hub information */ + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + usb_echo("hub attached:level=%d ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + + /* initialize hub mutex */ + if (s_HubGlobal.hubMutex == (usb_osa_mutex_handle)NULL) + { + osaStatus = USB_OsaMutexCreate(&s_HubGlobal.hubMutex); + if (osaStatus != kStatus_USB_OSA_Success) + { + s_HubGlobal.hubMutex = NULL; +#ifdef HOST_ECHO + usb_echo("hub mutex error\r\n"); +#endif + } + } + + /* initialize hub class instance */ + status = USB_HostHubInit(s_HubDeviceHandle, &hubClassHandle); + hubInstance = (usb_host_hub_instance_t *)hubClassHandle; + + /* link hub instance to list */ + USB_HostHubLock(); + hubInstance->next = s_HubGlobal.hubList; + s_HubGlobal.hubList = hubInstance; + USB_HostHubUnlock(); + + /* set hub instance's interface */ + if (status == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + hubInstance->hubStatus = kHubRunWaitSetInterface; + if (USB_HostHubSetInterface(hubClassHandle, s_HubInterfaceHandle, 0, USB_HostHubControlCallback, + hubInstance) != kStatus_USB_Success) + { + hubInstance->hubStatus = kHubRunInvalid; + } + } + } + break; + + case kUSB_HostEventDetach: + /* the device is detached */ + hubInstance = NULL; + + /* get device's hub instance handle */ + USB_HostHubLock(); + prevInstance = s_HubGlobal.hubList; + if (prevInstance->deviceHandle == deviceHandle) + { + hubInstance = prevInstance; + s_HubGlobal.hubList = prevInstance->next; + } + else + { + hubInstance = prevInstance->next; + while (hubInstance != NULL) + { + if (hubInstance->deviceHandle == deviceHandle) + { + prevInstance->next = hubInstance->next; + break; + } + prevInstance = hubInstance; + hubInstance = hubInstance->next; + } + } + USB_HostHubUnlock(); + + if (hubInstance != NULL) + { + if (hubInstance == s_HubGlobal.hubProcess) + { + s_HubGlobal.hubProcess = NULL; + } + /* print hub information */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + usb_echo("hub detached:level=%d ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + hubInstance->invalid = 1; + /* detach hub ports' devices */ + for (uint8_t portIndex = 0; portIndex < hubInstance->portCount; ++portIndex) + { + if ((hubInstance->portList != NULL) && (hubInstance->portList[portIndex].deviceHandle != NULL)) + { + USB_HostDetachDeviceInternal(hubInstance->hostHandle, + hubInstance->portList[portIndex].deviceHandle); + hubInstance->portList[portIndex].deviceHandle = NULL; + } + } + if (hubInstance->portList != NULL) + { + USB_OsaMemoryFree(hubInstance->portList); + } + USB_HostHubDeinit(deviceHandle, hubInstance); /* de-initialize hub instance */ + } + + /* destory hub mutex if there is no hub instance */ + if (s_HubGlobal.hubList == NULL) + { + if (s_HubGlobal.hubMutex != NULL) + { + USB_OsaMutexDestroy(s_HubGlobal.hubMutex); + s_HubGlobal.hubMutex = NULL; + } + } + break; + + default: + break; + } + + return status; +} + +/*! + * @brief remove attached device. called by USB_HostRemoveDevice. + * + * @param hubNumber the device attached hub. + * @param portNumber the device attached port. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostHubRemovePort(uint8_t hubNumber, uint8_t portNumber) +{ + usb_host_hub_instance_t *hubInstance; + uint32_t infoValue; + + /* get hub number's hub instance handle */ + hubInstance = (usb_host_hub_instance_t *)s_HubGlobal.hubList; + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + if (infoValue == hubNumber) + { + break; + } + hubInstance = hubInstance->next; + } + + /* set port's status as default, and reset port */ + if (hubInstance != NULL) + { + hubInstance->portList[portNumber - 1].deviceHandle = NULL; + hubInstance->portList[portNumber - 1].portStatus = kPortRunInvalid; + if (hubInstance->portProcess == portNumber) + { + hubInstance->portProcess = 0; + } + USB_HostHubSendPortReset(hubInstance, portNumber); + } + return kStatus_USB_Error; +} + +/*! + * @brief get device's high-speed hub's address. + * + * @param parent_hub_no device's parent hub's address. + * + * @return hub number. + */ +uint32_t USB_HostHubGetHsHubNumber(uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceInfo; + uint32_t hubNumber; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceInfo); + if (parentHubNo == deviceInfo) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceSpeed, &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */ + { + hubNumber = parentHubNo; + } + else /* parent hub is not HS */ + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceHSHubNumber, + &hubNumber); + } + return hubNumber; + } + return 0; +} + +/*! + * @brief get device's high-speed hub's port number. + * + * @param parent_hub_no device's parent hub's address. + * @param parent_port_no device's parent port no. + * + * @return port number. + */ +uint32_t USB_HostHubGetHsHubPort(uint8_t parentHubNo, uint8_t parentPortNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceInfo; + uint32_t hubPort; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceInfo); + if (parentHubNo == deviceInfo) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceSpeed, &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */ + { + hubPort = parentPortNo; + } + else /* parent hub is not HS */ + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceHSHubNumber, &hubPort); + } + return hubPort; + } + return 0; +} + +/*! + * @brief get device's hub total think time. + * + * @param parent_hub_no device's parent hub's address. + * + * @return think time value. + */ +uint32_t USB_HostHubGetTotalThinkTime(uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceAddress; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceAddress); + if (parentHubNo == deviceAddress) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + return hubInstance->totalThinktime; + } + return 0; +} + +#endif /* USB_HOST_CONFIG_HUB */ -- cgit v1.2.3