summaryrefslogtreecommitdiff
path: root/usb_1.1.0/host/class/usb_host_hub_app.c
diff options
context:
space:
mode:
Diffstat (limited to 'usb_1.1.0/host/class/usb_host_hub_app.c')
-rw-r--r--usb_1.1.0/host/class/usb_host_hub_app.c1106
1 files changed, 1106 insertions, 0 deletions
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 */