RT1050_FreeRTOS_USB_Hello/middleware/usb/host/class/usb_host_hub_app.c

1685 lines
65 KiB
C

/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016,2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#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_hci.h"
#include "usb_host_hub_app.h"
#include "usb_host_devices.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define USB_HostHubLockMutexCheck() hubGlobal->hubMutex != NULL
/*! @brief HUB lock */
#define USB_HostHubLock() OSA_MutexLock(hubGlobal->hubMutex, USB_OSA_WAIT_TIMEOUT)
/*! @brief HUB unlock */
#define USB_HostHubUnlock() OSA_MutexUnlock(hubGlobal->hubMutex)
/*******************************************************************************
* 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_global_t *hubGlobal, usb_host_hub_instance_t *hubInstance);
/*!
* @brief hub control pipe transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static 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);
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
static usb_host_hub_instance_t *USB_HostHubGetHubDeviceHandle(usb_host_handle hostHandle, uint8_t parentHubNo);
static usb_status_t USB_HostSendHubRequest(usb_device_handle deviceHandle,
uint8_t requestType,
uint8_t request,
uint16_t wvalue,
uint16_t windex,
host_inner_transfer_callback_t callbackFn,
void *callbackParam);
#endif
/*******************************************************************************
* Variables
******************************************************************************/
static usb_device_handle s_HubDeviceHandle;
static usb_host_interface_handle s_HubInterfaceHandle;
static usb_host_hub_global_t s_HubGlobalArray[USB_HOST_CONFIG_MAX_HOST];
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
static usb_host_configuration_t *s_HubConfiguration;
#endif
/*******************************************************************************
* Code
******************************************************************************/
static usb_host_hub_global_t *USB_HostHubGetHubList(usb_host_handle hostHandle)
{
#if (USB_HOST_CONFIG_MAX_HOST == 1U)
return &s_HubGlobalArray[0];
#else
uint8_t index;
for (index = 0; index < USB_HOST_CONFIG_MAX_HOST; ++index)
{
if (s_HubGlobalArray[index].hostHandle == hostHandle)
{
return &s_HubGlobalArray[index];
}
}
/* There is no used usb_host_hub_global_t instance */
for (index = 0; index < USB_HOST_CONFIG_MAX_HOST; ++index)
{
if (s_HubGlobalArray[index].hostHandle == NULL)
{
s_HubGlobalArray[index].hostHandle = hostHandle;
return &s_HubGlobalArray[index];
}
}
/* Look for the usb_host_hub_global_t instance that is not used any more */
for (index = 0; index < USB_HOST_CONFIG_MAX_HOST; ++index)
{
if (s_HubGlobalArray[index].hubList == NULL)
{
s_HubGlobalArray[index].hostHandle = hostHandle;
return &s_HubGlobalArray[index];
}
}
return NULL;
#endif
}
static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance)
{
uint16_t portNum;
if (hubInstance == NULL)
{
return;
}
/* there is no prime for control or interrupt */
if (hubInstance->primeStatus != (uint8_t)kPrimeNone)
{
return;
}
portNum = (((uint16_t)hubInstance->portCount) >> 3U);
/* receive interrupt data */
if (USB_HostHubInterruptRecv(hubInstance, hubInstance->hubBitmapBuffer, (portNum + 1U),
USB_HostHubInterruptInCallback, hubInstance) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error in hub interrupt recv\r\n");
#endif
}
else
{
hubInstance->primeStatus = (uint8_t)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 execute successfully (0 - fail; 1 - success) */
uint32_t tmp = 0;
usb_host_hub_descriptor_t *hubDescriptor;
void *temp;
usb_host_hub_app_status_t appStatus;
uint16_t portNum;
appStatus = (usb_host_hub_app_status_t)hubInstance->hubStatus;
switch (appStatus)
{
case kHubRunIdle:
case kHubRunInvalid:
break;
case kHubRunWaitSetInterface:
hubInstance->hubStatus = (uint8_t)kHubRunGetDescriptor7; /* update as next state */
/* get hub descriptor */
if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7, USB_HostHubControlCallback,
hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimeHubControl; /* control transfer is on-going */
processSuccess = 1U;
#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:
temp = (void *)&hubInstance->hubDescriptor[0];
hubDescriptor = (usb_host_hub_descriptor_t *)temp;
/* get the hub think time */
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint32_t)kUSB_HostGetHubThinkTime,
&tmp);
hubInstance->totalThinktime = (uint16_t)tmp;
tmp = ((((uint32_t)hubDescriptor->whubcharacteristics[0] &
USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_MASK) >>
USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_SHIFT));
/*
00 - 8 FS bit times;
01 - 16 FS bit times;
10 - 24 FS bit times;
11 - 32 FS bit times;
*/
tmp = (tmp + 1U) << 3U;
hubInstance->totalThinktime += (uint16_t)tmp;
/* 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 = (uint8_t)kHubRunSetPortPower; /* update as next state */
/* get hub descriptor */
portNum = (((uint16_t)hubInstance->portCount) >> 3U);
if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, ((uint16_t)7UL + (portNum) + 1U),
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimeHubControl; /* control transfer is on-going */
processSuccess = 1U;
#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;
/*remove kHubRunGetDescriptor state for misra 16.3*/
case kHubRunSetPortPower:
/* malloc port instance for the hub's ports */
if (NULL == hubInstance->portList)
{
hubInstance->portList = (usb_host_hub_port_instance_t *)OSA_MemoryAllocate(
((uint32_t)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 = (uint8_t)kHubRunInvalid;
break;
}
/* TODO: port instance status -> can be removed. app_status */
hubInstance->portIndex = 0U;
}
/* 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 = (uint8_t)kPrimeHubControl; /* update as next state */
processSuccess = 1U;
#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 = 1U;
break;
}
break;
}
hubInstance->portProcess = 0U;
/* 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 = (uint8_t)kPortRunWaitPortChange;
}
hubInstance->hubStatus = (uint8_t)kHubRunIdle;
needPrimeInterrupt = 1U;
break;
case kHubRunGetStatusDone: /* process hub status change */
tmp = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS((&hubInstance->hubStatusBuffer[2]));
hubInstance->hubStatus = (uint8_t)kHubRunIdle;
if (0U != ((1UL << 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 = (uint8_t)kPrimeHubControl;
hubInstance->hubStatus = (uint8_t)kHubRunClearDone;
processSuccess = 1U;
}
else
{
needPrimeInterrupt = 1U;
}
}
else if (0U != ((1UL << 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 = (uint8_t)kPrimeHubControl;
processSuccess = 1U;
hubInstance->hubStatus = (uint8_t)kHubRunClearDone;
}
else
{
needPrimeInterrupt = 1U;
}
}
else
{
needPrimeInterrupt = 1U;
}
break;
case kHubRunClearDone:
hubInstance->hubStatus = (uint8_t)kHubRunIdle;
needPrimeInterrupt = 1U;
break;
default:
/*no action*/
break;
}
if (needPrimeInterrupt == 1U) /* prime interrupt in transfer */
{
hubInstance->hubStatus = (uint8_t)kHubRunIdle;
USB_HostHubGetInterruptStatus(hubInstance);
}
else
{
if (processSuccess == 0U)
{
hubInstance->hubStatus = (uint8_t)kHubRunInvalid;
}
}
}
static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance)
{
usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1U];
/* 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 - 1U];
uint8_t processSuccess = 0U;
uint32_t specStatus;
uint8_t feature;
uint32_t infoValue;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hubInstance->hostHandle);
usb_host_port_app_status_t appStatus;
if (hubGlobal == NULL)
{
return;
}
appStatus = (usb_host_port_app_status_t)portInstance->portStatus;
switch (appStatus)
{
case kPortRunIdle:
break;
case kPortRunInvalid:
break;
case kPortRunWaitPortChange: /* (1) port is changed, and get port status */
portInstance->portStatus = (uint8_t)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 = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
break;
case kPortRunCheckCPortConnection: /* (2) check port status, and clear the status bits */
feature = 0U;
specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS((hubInstance->portStatusBuffer));
if (0U != ((1UL << C_PORT_CONNECTION) & specStatus))
{
portInstance->portStatus = (uint8_t)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 = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
break;
}
else if (0U != ((1UL << PORT_CONNECTION) & specStatus))
{
portInstance->portStatus = (uint8_t)kPortRunWaitPortResetDone; /* update as next state */
/* set PORT_RESET */
if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
if (portInstance->resetCount > 0U)
{
portInstance->resetCount--;
}
}
break;
}
else if (0U != ((1UL << 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 (0U != ((1UL << 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 (0U != ((1UL << 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
{
/*no action*/
}
if (feature != 0U)
{
portInstance->portStatus = (uint8_t)kPortRunWaitPortChange; /* update as next state */
/* clear feature */
if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, feature,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
}
break;
case kPortRunGetPortConnection: /* (3) get port status */
portInstance->portStatus = (uint8_t)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 = (uint8_t)kPrimePortControl; /* control transfer is on-going */
processSuccess = 1U;
}
break;
case kPortRunCheckPortConnection: /* (4) check PORT_CONNECTION bit */
specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer);
if (0U != ((1UL << PORT_CONNECTION) & specStatus))
{
portInstance->portStatus = (uint8_t)kPortRunWaitPortResetDone; /* update as next state */
/* set PORT_RESET */
if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1;
if (portInstance->resetCount > 0U)
{
portInstance->resetCount--;
}
}
}
break;
case kPortRunWaitPortResetDone: /* (5) wait port change */
portInstance->portStatus = (uint8_t)kPortRunWaitCPortReset; /* update as next state */
processSuccess = 1U;
/* must wait the enumeration done, then operate the next port */
USB_HostHubGetInterruptStatus(hubInstance);
break;
case kPortRunWaitCPortReset: /* (6) get port status for checking C_PORT_RESET */
portInstance->portStatus = (uint8_t)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 = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
break;
case KPortRunCheckCPortReset: /* (7) check C_PORT_RESET and clear C_PORT_RESET */
specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer);
if (0U != ((1UL << C_PORT_RESET) & specStatus))
{
if (portInstance->resetCount == 0U)
{
portInstance->portStatus = (uint8_t)kPortRunPortAttached; /* update as next state */
/* get port's device speed */
if (0U != (specStatus & (1UL << PORT_HIGH_SPEED)))
{
portInstance->speed = USB_SPEED_HIGH;
}
else if (0U != (specStatus & (1UL << PORT_LOW_SPEED)))
{
portInstance->speed = USB_SPEED_LOW;
}
else
{
portInstance->speed = USB_SPEED_FULL;
}
}
else
{
portInstance->portStatus = (uint8_t)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 = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
}
break;
case kPortRunResetAgain: /* (8) reset again */
portInstance->portStatus = (uint8_t)kPortRunCheckPortConnection; /* check connection then reset again */
if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
break;
case kPortRunPortAttached: /* (9) the port have one device attached */
/*zero initilzied for misra 9.1*/
infoValue = 0U;
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint32_t)kUSB_HostGetDeviceAddress,
&infoValue);
(void)USB_HostAttachDevice(hubInstance->hostHandle, portInstance->speed, (uint8_t)infoValue,
hubInstance->portProcess, hubInstance->hubLevel + 1U,
&portInstance->deviceHandle);
processSuccess = 1U;
hubInstance->portProcess = 0U;
hubGlobal->hubProcess = NULL;
portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES;
USB_HostHubGetInterruptStatus(hubInstance);
break;
default:
/*no actino*/
break;
}
if (processSuccess == 0U)
{
portInstance->portStatus = (uint8_t)kPortRunWaitPortChange;
hubInstance->portProcess = 0U;
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 - 1U];
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
usb_host_instance_t *hostPointer = (usb_host_instance_t *)hubInstance->hostHandle;
#endif
uint8_t processSuccess = 0;
uint32_t specStatus;
usb_host_port_app_status_t appStatus;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hubInstance->hostHandle);
if (hubGlobal == NULL)
{
return;
}
appStatus = (usb_host_port_app_status_t)portInstance->portStatus;
switch (appStatus)
{
case kPortRunIdle:
break;
case kPortRunInvalid:
break;
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
case kPortRunPortSuspended:
#endif
case kPortRunPortAttached: /* (1) port is changed, then get port status */
portInstance->portStatus = (uint8_t)kPortRunCheckPortDetach;
/* get port status */
if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4U,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
break;
case kPortRunCheckPortDetach: /* (2) check port status bits */
specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer);
portInstance->portStatus = (uint8_t)kPortRunGetConnectionBit;
if (0U != ((1UL << C_PORT_CONNECTION) & specStatus)) /* C_PORT_CONNECTION */
{
if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
}
else if (0U != ((1UL << C_PORT_ENABLE) & specStatus)) /* C_PORT_ENABLE */
{
if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_ENABLE,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
}
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
else if (0U != ((1UL << C_PORT_SUSPEND) & specStatus))
{
/* clear C_PORT_SUSPEND */
if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_SUSPEND,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
portInstance->portStatus = (uint8_t)kPortRunClearCPortSuspend; /* update as next state */
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
}
#endif
else
{
/*for misra check and make sure hub state machine could keep work*/
portInstance->portStatus = (uint8_t)kPortRunCheckConnectionBit;
if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
}
break;
case kPortRunGetConnectionBit: /* (3) get port status */
portInstance->portStatus = (uint8_t)kPortRunCheckConnectionBit;
if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4,
USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
break;
case kPortRunCheckConnectionBit: /* (4) check port connection bit */
specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer);
if (0U != ((1UL << PORT_CONNECTION) & specStatus)) /* PORT_CONNECTION */
{
portInstance->portStatus = (uint8_t)kPortRunPortAttached;
#ifdef HOST_ECHO
usb_echo("PORT_CONNECTION in attach for detach\r\n");
#endif
}
else
{
processSuccess = 1U;
/* port's device is detached */
portInstance->portStatus = (uint8_t)kPortRunWaitPortChange;
(void)USB_HostDetachDeviceInternal(hubInstance->hostHandle, portInstance->deviceHandle);
portInstance->deviceHandle = NULL;
hubGlobal->hubProcess = NULL;
hubInstance->portProcess = 0U;
USB_HostHubGetInterruptStatus(hubInstance);
}
break;
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
case kPortRunClearCPortSuspend:
portInstance->portStatus = (uint8_t)kPortRunCheckPortSuspend; /* 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 = (uint8_t)kPrimePortControl;
processSuccess = 1U;
}
break;
case kPortRunCheckPortSuspend:
specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer);
if (0U != ((1UL << PORT_SUSPEND) & specStatus))
{
portInstance->portStatus = (uint8_t)kPortRunPortSuspended; /* update as next state */
/* call host callback function, function is initialized in USB_HostInit */
(void)hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
kUSB_HostEventSuspended); /* call host callback function */
}
else
{
portInstance->portStatus = (uint8_t)kPortRunPortAttached; /* update as next state */
/* call host callback function, function is initialized in USB_HostInit */
(void)hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL,
kUSB_HostEventResumed); /* call host callback function */
hostPointer->suspendedDevice = NULL;
}
break;
#endif
default:
/*no action*/
break;
}
if (processSuccess == 0U)
{
portInstance->portStatus = (uint8_t)kPortRunPortAttached;
hubGlobal->hubProcess = NULL;
hubInstance->portProcess = 0U;
USB_HostHubGetInterruptStatus(hubInstance);
}
}
static void USB_HostHubProcessData(usb_host_hub_global_t *hubGlobal, usb_host_hub_instance_t *hubInstance)
{
uint8_t needPrimeInterrupt = 1U;
uint8_t portIndex;
/* process the port which status change */
for (portIndex = 0U; portIndex <= hubInstance->portCount; ++portIndex)
{
if (0U != ((0x01U << (portIndex & 0x07U)) & (hubInstance->hubBitmapBuffer[portIndex >> 3U])))
{
if (portIndex == 0U) /* hub status change */
{
if ((hubGlobal->hubProcess == NULL) ||
((hubGlobal->hubProcess == hubInstance) && (hubInstance->portProcess == 0U)))
{
hubInstance->hubStatus = (uint8_t)kHubRunGetStatusDone;
if (USB_HostHubGetStatus(hubInstance, hubInstance->hubStatusBuffer, 4U, USB_HostHubControlCallback,
hubInstance) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error in usb_class_hub_get_status\r\n");
#endif
hubInstance->hubStatus = (uint8_t)kHubRunIdle;
}
else
{
hubInstance->primeStatus = (uint8_t)kPrimeHubControl;
return; /* return replace break because the misra */
}
}
}
else /* port's status change */
{
/* process the on-going port or process one new port */
if ((hubGlobal->hubProcess == NULL) ||
((hubGlobal->hubProcess == hubInstance) && (hubInstance->portProcess == 0U)) ||
((hubGlobal->hubProcess == hubInstance) && (hubInstance->portProcess == portIndex)))
{
if (hubInstance->controlTransfer == NULL)
{
hubGlobal->hubProcess = hubInstance;
hubInstance->portProcess = portIndex;
needPrimeInterrupt = 0U;
USB_HostHubProcessPort(hubInstance);
}
break; /* process the port change in turn */
}
}
}
}
if (needPrimeInterrupt == 1U)
{
USB_HostHubGetInterruptStatus(hubInstance);
}
}
static 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;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hubInstance->hostHandle);
if (hubGlobal == NULL)
{
return;
}
if (hubInstance->invalid == 1U)
{
return;
}
if (status != kStatus_USB_Success)
{
/* if transfer fail, prime a new interrupt in transfer */
hubInstance->primeStatus = (uint8_t)kPrimeNone;
hubGlobal->hubProcess = NULL;
hubInstance->portProcess = 0U;
USB_HostHubGetInterruptStatus(hubInstance);
return;
}
if (hubInstance->primeStatus == (uint8_t)kPrimeHubControl) /* hub related control transfer */
{
hubInstance->primeStatus = (uint8_t)kPrimeNone;
USB_HostHubProcess(hubInstance);
}
else if (hubInstance->primeStatus == (uint8_t)kPrimePortControl) /* hub's port related control transfer */
{
hubInstance->primeStatus = (uint8_t)kPrimeNone;
USB_HostHubProcessPort(hubInstance);
}
else
{
/*no action*/
}
}
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
/*!
* @brief get device's hub device instance.
*
* @param parent_hub_no device's parent hub instance.
*
* @return think time value.
*/
static usb_host_hub_instance_t *USB_HostHubGetHubDeviceHandle(usb_host_handle hostHandle, uint8_t parentHubNo)
{
usb_host_hub_instance_t *hubInstance;
uint32_t deviceAddress;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle);
if (hubGlobal == NULL)
{
return NULL;
}
hubInstance = hubGlobal->hubList;
/* get parentHubNo's hub instance handle */
while (hubInstance != NULL)
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint32_t)kUSB_HostGetDeviceAddress,
&deviceAddress);
if (parentHubNo == deviceAddress)
{
break;
}
hubInstance = hubInstance->next;
}
if (hubInstance != NULL)
{
return hubInstance;
}
return (usb_host_hub_instance_t *)NULL;
}
static void USB_HostSetHubRequestCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
usb_host_instance_t *hostInstance = (usb_host_instance_t *)param;
(void)USB_HostFreeTransfer(param, transfer);
if (kStatus_USB_Success == status)
{
/* call host callback function, function is initialized in USB_HostInit */
(void)hostInstance->deviceCallback(hostInstance->suspendedDevice, NULL,
kUSB_HostEventSuspended); /* call host callback function */
}
else
{
/* call host callback function, function is initialized in USB_HostInit */
(void)hostInstance->deviceCallback(hostInstance->suspendedDevice, NULL,
kUSB_HostEventNotSuspended); /* call host callback function */
}
}
static void USB_HostClearHubRequestCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
(void)USB_HostFreeTransfer(param, transfer);
if (kStatus_USB_Success == status)
{
}
}
static void USB_HostHubRemoteWakeupCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
usb_host_hub_instance_t *hubInstance;
usb_host_instance_t *hostInstance;
usb_host_device_instance_t *deviceInstance;
if (NULL == param)
{
return;
}
hubInstance = (usb_host_hub_instance_t *)param;
hostInstance = (usb_host_instance_t *)hubInstance->hostHandle;
if (NULL == hostInstance)
{
return;
}
(void)USB_HostFreeTransfer(hostInstance, transfer);
if (kStatus_USB_Success != status)
{
(void)usb_echo("Transfer failed to set remote wakeup request to HUB.\r\n");
}
if (kStatus_USB_Success == status)
{
hubInstance->controlRetry = USB_HOST_HUB_REMOTE_WAKEUP_TIMES;
hubInstance = hubInstance->next;
while (NULL != hubInstance)
{
hubInstance->controlRetry = USB_HOST_HUB_REMOTE_WAKEUP_TIMES;
if (0U != hubInstance->supportRemoteWakeup)
{
(void)usb_echo("Set HUB remote wakeup feature: level %d, address %d.\r\n",
((usb_host_device_instance_t *)hubInstance->deviceHandle)->level,
((usb_host_device_instance_t *)hubInstance->deviceHandle)->setAddress);
status = USB_HostSendHubRequest(
hubInstance->deviceHandle,
USB_REQUEST_TYPE_RECIPIENT_DEVICE | USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_STANDARD,
USB_REQUEST_STANDARD_SET_FEATURE, USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP, 0,
USB_HostHubRemoteWakeupCallback, hubInstance);
if (kStatus_USB_Success != status)
{
(void)usb_echo("Send set remote wakeup request to HUB failed.\r\n");
}
break;
}
hubInstance = hubInstance->next;
}
}
else
{
if (0U != hubInstance->controlRetry)
{
hubInstance->controlRetry--;
(void)usb_echo("Retry...\r\n", ((usb_host_device_instance_t *)hubInstance->deviceHandle)->level,
((usb_host_device_instance_t *)hubInstance->deviceHandle)->setAddress);
status = USB_HostSendHubRequest(
hubInstance->deviceHandle,
USB_REQUEST_TYPE_RECIPIENT_DEVICE | USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_STANDARD,
USB_REQUEST_STANDARD_SET_FEATURE, USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP, 0,
USB_HostHubRemoteWakeupCallback, hubInstance);
if (kStatus_USB_Success != status)
{
(void)usb_echo("Send set remote wakeup request to HUB failed.\r\n");
}
}
else
{
(void)usb_echo("Transfer failed to set remote wakeup request to HUB.\r\n");
}
}
if (kStatus_USB_Success != status)
{
/* call host callback function, function is initialized in USB_HostInit */
(void)hostInstance->deviceCallback(hostInstance->suspendedDevice, NULL, kUSB_HostEventNotSuspended);
return;
}
if (NULL == hubInstance)
{
status = kStatus_USB_Error;
deviceInstance = (usb_host_device_instance_t *)hostInstance->suspendedDevice;
if (NULL == deviceInstance)
{
usb_host_bus_control_t type = kUSB_HostBusSuspend;
/* the callbackFn is initialized in USB_HostGetControllerInterface */
status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl,
&type);
if (kStatus_USB_Success != status)
{
(void)usb_echo("Suspend USB BUS failed.\r\n");
}
}
else
{
usb_host_hub_instance_t *hubInstance4Device =
USB_HostHubGetHubDeviceHandle(hostInstance, deviceInstance->hubNumber);
if (NULL != hubInstance4Device)
{
status = USB_HostSendHubRequest(
hubInstance4Device->deviceHandle,
USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER,
USB_REQUEST_STANDARD_SET_FEATURE, PORT_SUSPEND, deviceInstance->portNumber,
USB_HostSetHubRequestCallback, hostInstance);
if (kStatus_USB_Success != status)
{
(void)usb_echo("Send suspend request to HUB is failed.\r\n");
}
}
else
{
(void)usb_echo("Invalid HUB instance of device.\r\n");
}
}
if (kStatus_USB_Success != status)
{
/* call host callback function, function is initialized in USB_HostInit */
(void)hostInstance->deviceCallback(hostInstance->suspendedDevice, NULL, kUSB_HostEventNotSuspended);
return;
}
}
}
static usb_status_t USB_HostSendHubRequest(usb_device_handle deviceHandle,
uint8_t requestType,
uint8_t request,
uint16_t wvalue,
uint16_t windex,
host_inner_transfer_callback_t callbackFn,
void *callbackParam)
{
usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle;
usb_host_transfer_t *transfer;
/* get transfer */
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;
}
/* initialize transfer */
transfer->transferBuffer = NULL;
transfer->transferLength = 0U;
transfer->callbackFn = callbackFn;
transfer->callbackParam = callbackParam;
transfer->setupPacket->bmRequestType = requestType;
transfer->setupPacket->bRequest = request;
transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(wvalue);
transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(windex);
transfer->setupPacket->wLength = USB_SHORT_TO_LITTLE_ENDIAN(0U);
/* send transfer */
if (USB_HostSendSetup(deviceInstance->hostHandle, deviceInstance->controlPipe, transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("Error in sending hub set report!\r\n");
#endif
(void)USB_HostFreeTransfer(deviceInstance->hostHandle, transfer);
return kStatus_USB_Error;
}
return kStatus_USB_Success;
}
#endif
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;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hubInstance->hostHandle);
if (hubGlobal == NULL)
{
return;
}
if (hubInstance->invalid == 1U)
{
return;
}
/* interrupt data received */
hubInstance->primeStatus = (uint8_t)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)
{
hubGlobal->hubProcess = NULL;
hubInstance->portProcess = 0;
USB_HostHubGetInterruptStatus(hubInstance);
}
}
else
{
USB_HostHubProcessData(hubGlobal, hubInstance); /* process the interrupt data */
}
}
/*!
* @brief host hub callback function.
*
* This function should be called in the host callback function.
*
* @param hostHandle host handle.
* @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_host_handle hostHandle,
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 = 0U;
osa_status_t osaStatus;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle);
usb_host_event_t hostEventCode = (usb_host_event_t)eventCode;
if (hubGlobal == NULL)
{
return kStatus_USB_Error;
}
switch (hostEventCode)
{
case kUSB_HostEventAttach:
/* judge whether is configurationHandle supported */
configuration = (usb_host_configuration_t *)configurationHandle;
for (interfaceIndex = 0U; 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
{
(void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetDeviceLevel,
&infoValue);
if (infoValue > 5U)
{
#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST))
(void)usb_echo("Host can support max 5 level hubs\r\n");
#endif
continue;
}
/* the interface is hub */
s_HubDeviceHandle = deviceHandle;
s_HubInterfaceHandle = interface;
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
s_HubConfiguration = configuration;
#endif
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 */
(void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetDeviceLevel,
&infoValue);
(void)usb_echo("hub attached:level=%u ", infoValue);
(void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetDeviceAddress,
&infoValue);
(void)usb_echo("address=%u\r\n", infoValue);
/* initialize hub mutex */
if (hubGlobal->hubMutex == (osa_mutex_handle_t)NULL)
{
hubGlobal->hubMutex = (osa_mutex_handle_t)(&hubGlobal->mutexBuffer[0]);
osaStatus = OSA_MutexCreate(hubGlobal->hubMutex);
if (osaStatus != KOSA_StatusSuccess)
{
hubGlobal->hubMutex = NULL;
#ifdef HOST_ECHO
(void)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 */
if (USB_HostHubLockMutexCheck())
{
(void)USB_HostHubLock();
}
hubInstance->next = hubGlobal->hubList;
hubGlobal->hubList = hubInstance;
if (USB_HostHubLockMutexCheck())
{
(void)USB_HostHubUnlock();
}
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
hubInstance->supportRemoteWakeup = 0U;
hubInstance->controlRetry = USB_HOST_HUB_REMOTE_WAKEUP_TIMES;
if (0U != (s_HubConfiguration->configurationDesc->bmAttributes &
USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_MASK))
{
hubInstance->supportRemoteWakeup = 1U;
}
#endif
/* set hub instance's interface */
if (status == kStatus_USB_Success)
{
hubInstance->primeStatus = (uint8_t)kPrimeHubControl;
hubInstance->hubStatus = (uint8_t)kHubRunWaitSetInterface;
if (USB_HostHubSetInterface(hubClassHandle, s_HubInterfaceHandle, 0, USB_HostHubControlCallback,
hubInstance) != kStatus_USB_Success)
{
hubInstance->hubStatus = (uint8_t)kHubRunInvalid;
}
}
}
break;
case kUSB_HostEventDetach:
/* the device is detached */
hubInstance = NULL;
/* get device's hub instance handle */
if (USB_HostHubLockMutexCheck())
{
(void)USB_HostHubLock();
}
prevInstance = hubGlobal->hubList;
if (prevInstance->deviceHandle == deviceHandle)
{
hubInstance = prevInstance;
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;
}
}
if (USB_HostHubLockMutexCheck())
{
(void)USB_HostHubUnlock();
}
if (hubInstance != NULL)
{
if (hubInstance == hubGlobal->hubProcess)
{
hubGlobal->hubProcess = NULL;
}
/* print hub information */
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle,
(uint32_t)kUSB_HostGetDeviceLevel, &infoValue);
(void)usb_echo("hub detached:level=%u ", infoValue);
(void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetDeviceAddress,
&infoValue);
(void)usb_echo("address=%u\r\n", infoValue);
hubInstance->invalid = 1U;
/* detach hub ports' devices */
for (uint8_t portIndex = 0U; portIndex < hubInstance->portCount; ++portIndex)
{
if ((hubInstance->portList != NULL) && (hubInstance->portList[portIndex].deviceHandle != NULL))
{
(void)USB_HostDetachDeviceInternal(hubInstance->hostHandle,
hubInstance->portList[portIndex].deviceHandle);
hubInstance->portList[portIndex].deviceHandle = NULL;
}
}
if (hubInstance->portList != NULL)
{
(void)OSA_MemoryFree(hubInstance->portList);
}
(void)USB_HostHubDeinit(deviceHandle, hubInstance); /* de-initialize hub instance */
}
/* destroy hub mutex if there is no hub instance */
if (hubGlobal->hubList == NULL)
{
if (hubGlobal->hubMutex != NULL)
{
(void)OSA_MutexDestroy(hubGlobal->hubMutex);
hubGlobal->hubMutex = NULL;
}
}
status = kStatus_USB_Success;
break;
default:
/*action*/
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(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber)
{
usb_host_hub_instance_t *hubInstance;
uint32_t infoValue;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle);
if (hubGlobal == NULL)
{
return kStatus_USB_Error;
}
/* get hub number's hub instance handle */
hubInstance = (usb_host_hub_instance_t *)hubGlobal->hubList;
while (hubInstance != NULL)
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint8_t)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 - 1U].deviceHandle = NULL;
hubInstance->portList[portNumber - 1U].portStatus = (uint8_t)kPortRunInvalid;
if (hubInstance->portProcess == portNumber)
{
hubInstance->portProcess = 0U;
}
(void)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(usb_host_handle hostHandle, uint8_t parentHubNo)
{
usb_host_hub_instance_t *hubInstance;
uint32_t deviceInfo;
uint32_t hubNumber = 0U;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle);
if (hubGlobal == NULL)
{
return 0U;
}
hubInstance = hubGlobal->hubList;
/* get parentHubNo's hub instance handle */
while (hubInstance != NULL)
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint32_t)kUSB_HostGetDeviceAddress,
&deviceInfo);
if (parentHubNo == deviceInfo)
{
break;
}
hubInstance = hubInstance->next;
}
if (hubInstance != NULL)
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint32_t)kUSB_HostGetDeviceSpeed,
&deviceInfo);
if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */
{
hubNumber = parentHubNo;
}
else /* parent hub is not HS */
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle,
(uint32_t)kUSB_HostGetDeviceHSHubNumber, &hubNumber);
}
return hubNumber;
}
return 0U;
}
/*!
* @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(usb_host_handle hostHandle, uint8_t parentHubNo, uint8_t parentPortNo)
{
usb_host_hub_instance_t *hubInstance;
uint32_t deviceInfo = 0U;
uint32_t hubPort = 0U;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle);
if (hubGlobal == NULL)
{
return 0U;
}
hubInstance = hubGlobal->hubList;
/* get parentHubNo's hub instance handle */
while (hubInstance != NULL)
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint32_t)kUSB_HostGetDeviceAddress,
&deviceInfo);
if (parentHubNo == deviceInfo)
{
break;
}
hubInstance = hubInstance->next;
}
if (hubInstance != NULL)
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint32_t)kUSB_HostGetDeviceSpeed,
&deviceInfo);
if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */
{
hubPort = parentPortNo;
}
else /* parent hub is not HS */
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle,
(uint32_t)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(usb_host_handle hostHandle, uint8_t parentHubNo)
{
usb_host_hub_instance_t *hubInstance;
uint32_t deviceAddress;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle);
if (hubGlobal == NULL)
{
return 0U;
}
hubInstance = hubGlobal->hubList;
/* get parentHubNo's hub instance handle */
while (hubInstance != NULL)
{
(void)USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, (uint32_t)kUSB_HostGetDeviceAddress,
&deviceAddress);
if (parentHubNo == deviceAddress)
{
break;
}
hubInstance = hubInstance->next;
}
if (hubInstance != NULL)
{
return hubInstance->totalThinktime;
}
return 0;
}
#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U))
/*!
* @brief Suspend the device.
*
* @param hostHandle Host instance.
*
* @return kStatus_USB_Success or error codes.
*
*/
usb_status_t USB_HostHubSuspendDevice(usb_host_handle hostHandle)
{
usb_host_instance_t *hostInstance;
usb_host_hub_instance_t *hubInstance;
usb_status_t status = kStatus_USB_Error;
usb_host_hub_global_t *hubGlobal = USB_HostHubGetHubList(hostHandle);
if (hubGlobal == NULL)
{
return kStatus_USB_Error;
}
hubInstance = hubGlobal->hubList;
if (NULL == hostHandle)
{
return kStatus_USB_InvalidHandle;
}
hostInstance = (usb_host_instance_t *)hostHandle;
if (NULL == hubInstance)
{
usb_host_bus_control_t type = kUSB_HostBusSuspend;
/* the callbackFn is initialized in USB_HostGetControllerInterface */
status =
hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, &type);
if (kStatus_USB_Success != status)
{
(void)usb_echo("Suspend USB BUS failed.\r\n");
}
return status;
}
/* Scan HUB instance handle */
while (hubInstance != NULL)
{
hubInstance->controlRetry = USB_HOST_HUB_REMOTE_WAKEUP_TIMES;
if (0U != hubInstance->supportRemoteWakeup)
{
(void)usb_echo("Set HUB remote wakeup feature: level %d, address %d.\r\n",
((usb_host_device_instance_t *)hubInstance->deviceHandle)->level,
((usb_host_device_instance_t *)hubInstance->deviceHandle)->setAddress);
status = USB_HostSendHubRequest(
hubInstance->deviceHandle,
USB_REQUEST_TYPE_RECIPIENT_DEVICE | USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_STANDARD,
USB_REQUEST_STANDARD_SET_FEATURE, USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP, 0,
USB_HostHubRemoteWakeupCallback, hubInstance);
break;
}
hubInstance = hubInstance->next;
}
if (NULL == hubInstance)
{
usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)hostInstance->suspendedDevice;
if (NULL == deviceInstance)
{
usb_host_bus_control_t type = kUSB_HostBusSuspend;
/* the callbackFn is initialized in USB_HostGetControllerInterface */
status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl,
&type);
if (kStatus_USB_Success != status)
{
(void)usb_echo("Suspend USB BUS failed.\r\n");
}
}
else
{
usb_host_hub_instance_t *hubInstance4Device =
USB_HostHubGetHubDeviceHandle(hostHandle, deviceInstance->hubNumber);
if (NULL != hubInstance4Device)
{
status = USB_HostSendHubRequest(
hubInstance4Device->deviceHandle,
USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER,
USB_REQUEST_STANDARD_SET_FEATURE, PORT_SUSPEND, deviceInstance->portNumber,
USB_HostSetHubRequestCallback, hostInstance);
if (kStatus_USB_Success != status)
{
(void)usb_echo("Send suspend request to HUB is failed.\r\n");
}
}
else
{
(void)usb_echo("Invalid HUB instance of device.\r\n");
}
}
}
return status;
}
/*!
* @brief Resume the device.
*
* @param hostHandle Host instance.
*
* @return kStatus_USB_Success or error codes.
*
*/
usb_status_t USB_HostHubResumeDevice(usb_host_handle hostHandle)
{
usb_host_instance_t *hostInstance;
usb_host_device_instance_t *deviceInstance;
usb_host_hub_instance_t *hubInstance = NULL;
usb_status_t status = kStatus_USB_Error;
if (NULL == hostHandle)
{
return kStatus_USB_InvalidHandle;
}
hostInstance = (usb_host_instance_t *)hostHandle;
deviceInstance = (usb_host_device_instance_t *)hostInstance->suspendedDevice;
if (NULL == deviceInstance)
{
return kStatus_USB_InvalidHandle;
}
hubInstance = USB_HostHubGetHubDeviceHandle(hostHandle, deviceInstance->hubNumber);
if (NULL != hubInstance)
{
status = USB_HostSendHubRequest(
hubInstance->deviceHandle,
USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER,
USB_REQUEST_STANDARD_CLEAR_FEATURE, PORT_SUSPEND, deviceInstance->portNumber,
USB_HostClearHubRequestCallback, hostInstance);
}
return status;
}
#endif
#endif /* USB_HOST_CONFIG_HUB */