]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbHub.c
index 5bdf8b544281e084b89664cdfb0d946456d891b7..c7c27a54819f9609f68625f5d5c8939a0e9df7a1 100644 (file)
@@ -2,14 +2,8 @@
 \r
     Unified interface for RootHub and Hub.\r
 \r
-Copyright (c) 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -22,19 +16,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 // bits determine whether hub will report the port in changed\r
 // bit maps.\r
 //\r
-#define USB_HUB_MAP_SIZE  5\r
-\r
-USB_CHANGE_FEATURE_MAP  mHubFeatureMap[USB_HUB_MAP_SIZE] = {\r
+USB_CHANGE_FEATURE_MAP  mHubFeatureMap[] = {\r
   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},\r
   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},\r
   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},\r
   {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},\r
-  {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange},\r
+  {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange}\r
 };\r
 \r
-#define USB_ROOT_HUB_MAP_SIZE 5\r
-\r
-USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[USB_ROOT_HUB_MAP_SIZE] = {\r
+USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[] = {\r
   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},\r
   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},\r
   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},\r
@@ -47,7 +37,38 @@ USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[USB_ROOT_HUB_MAP_SIZE] = {
 // is related to an interface, these requests are sent\r
 // to the control endpoint of the device.\r
 //\r
+/**\r
+  USB hub control transfer to set the hub depth.\r
+\r
+  @param  HubDev                The device of the hub.\r
+  @param  Depth                 The depth to set.\r
+\r
+  @retval EFI_SUCCESS           Depth of the hub is set.\r
+  @retval Others                Failed to set the depth.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHubCtrlSetHubDepth (\r
+  IN  USB_DEVICE          *HubDev,\r
+  IN  UINT16              Depth\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_HUB,\r
+             USB_HUB_REQ_SET_DEPTH,\r
+             Depth,\r
+             0,\r
+             NULL,\r
+             0\r
+             );\r
 \r
+  return Status;\r
+}\r
 \r
 /**\r
   USB hub control transfer to clear the hub feature.\r
@@ -173,9 +194,8 @@ UsbHubCtrlClearTTBuffer (
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  Usb hub control transfer to get the hub descriptor.\r
+  Usb hub control transfer to get the (super speed) hub descriptor.\r
 \r
   @param  HubDev                The hub device.\r
   @param  Buf                   The buffer to hold the descriptor.\r
@@ -193,6 +213,11 @@ UsbHubCtrlGetHubDesc (
   )\r
 {\r
   EFI_STATUS              Status;\r
+  UINT8                   DescType;\r
+\r
+  DescType = (HubDev->Speed == EFI_USB_SPEED_SUPER) ?\r
+             USB_DESC_TYPE_HUB_SUPER_SPEED :\r
+             USB_DESC_TYPE_HUB;\r
 \r
   Status = UsbCtrlRequest (\r
              HubDev,\r
@@ -200,7 +225,7 @@ UsbHubCtrlGetHubDesc (
              USB_REQ_TYPE_CLASS,\r
              USB_HUB_TARGET_HUB,\r
              USB_HUB_REQ_GET_DESC,\r
-             (UINT16) (USB_DESC_TYPE_HUB << 8),\r
+             (UINT16) (DescType << 8),\r
              0,\r
              Buf,\r
              Len\r
@@ -286,74 +311,6 @@ UsbHubCtrlGetPortStatus (
 }\r
 \r
 \r
-/**\r
-  Usb hub control transfer to reset the TT (Transaction Transaltor).\r
-\r
-  @param  HubDev                The hub device.\r
-  @param  Port                  The port of the hub.\r
-\r
-  @retval EFI_SUCCESS           The TT of the hub is reset.\r
-  @retval Others                Failed to reset the port.\r
-\r
-**/\r
-EFI_STATUS\r
-UsbHubCtrlResetTT (\r
-  IN  USB_DEVICE          *HubDev,\r
-  IN  UINT8               Port\r
-  )\r
-{\r
-  EFI_STATUS              Status;\r
-\r
-  Status = UsbCtrlRequest (\r
-             HubDev,\r
-             EfiUsbNoData,\r
-             USB_REQ_TYPE_CLASS,\r
-             USB_HUB_TARGET_HUB,\r
-             USB_HUB_REQ_RESET_TT,\r
-             0,\r
-             (UINT16) (Port + 1),\r
-             NULL,\r
-             0\r
-             );\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-  Usb hub control transfer to set the hub feature.\r
-\r
-  @param  HubDev                The hub device.\r
-  @param  Feature               The feature to set.\r
-\r
-  @retval EFI_SUCESS            The feature is set for the hub.\r
-  @retval Others                Failed to set the feature.\r
-\r
-**/\r
-EFI_STATUS\r
-UsbHubCtrlSetHubFeature (\r
-  IN  USB_DEVICE          *HubDev,\r
-  IN  UINT8               Feature\r
-  )\r
-{\r
-  EFI_STATUS              Status;\r
-\r
-  Status = UsbCtrlRequest (\r
-             HubDev,\r
-             EfiUsbNoData,\r
-             USB_REQ_TYPE_CLASS,\r
-             USB_HUB_TARGET_HUB,\r
-             USB_HUB_REQ_SET_FEATURE,\r
-             Feature,\r
-             0,\r
-             NULL,\r
-             0\r
-             );\r
-\r
-  return Status;\r
-}\r
-\r
-\r
 /**\r
   Usb hub control transfer to set the port feature.\r
 \r
@@ -426,9 +383,7 @@ UsbHubReadDesc (
   //\r
   // Get the whole hub descriptor\r
   //\r
-  Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);\r
-\r
-  return Status;\r
+  return UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);\r
 }\r
 \r
 \r
@@ -516,6 +471,7 @@ UsbIsHubInterface (
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 UsbOnHubInterrupt (\r
   IN  VOID                *Data,\r
   IN  UINTN               DataLength,\r
@@ -620,7 +576,8 @@ UsbHubInit (
   IN USB_INTERFACE        *HubIf\r
   )\r
 {\r
-  EFI_USB_HUB_DESCRIPTOR  HubDesc;\r
+  UINT8                   HubDescBuffer[256];\r
+  EFI_USB_HUB_DESCRIPTOR  *HubDesc;\r
   USB_ENDPOINT_DESC       *EpDesc;\r
   USB_INTERFACE_SETTING   *Setting;\r
   EFI_USB_IO_PROTOCOL     *UsbIo;\r
@@ -628,6 +585,7 @@ UsbHubInit (
   EFI_STATUS              Status;\r
   UINT8                   Index;\r
   UINT8                   NumEndpoints;\r
+  UINT16                  Depth;\r
 \r
   //\r
   // Locate the interrupt endpoint for port change map\r
@@ -654,17 +612,58 @@ UsbHubInit (
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  Status = UsbHubReadDesc (HubDev, &HubDesc);\r
+  //\r
+  // The length field of descriptor is UINT8 type, so the buffer\r
+  // with 256 bytes is enough to hold the descriptor data.\r
+  //\r
+  HubDesc = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer;\r
+  Status = UsbHubReadDesc (HubDev, HubDesc);\r
 \r
   if (EFI_ERROR (Status)) {\r
     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status));\r
     return Status;\r
   }\r
 \r
-  HubIf->NumOfPort = HubDesc.NumPorts;\r
+  HubIf->NumOfPort = HubDesc->NumPorts;\r
 \r
   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));\r
 \r
+  //\r
+  // OK, set IsHub to TRUE. Now usb bus can handle this device\r
+  // as a working HUB. If failed eariler, bus driver will not\r
+  // recognize it as a hub. Other parts of the bus should be able\r
+  // to work.\r
+  //\r
+  HubIf->IsHub  = TRUE;\r
+  HubIf->HubApi = &mUsbHubApi;\r
+  HubIf->HubEp  = EpDesc;\r
+\r
+  if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {\r
+    Depth = (UINT16)(HubIf->Device->Tier - 1);\r
+    DEBUG ((EFI_D_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));\r
+    UsbHubCtrlSetHubDepth (HubIf->Device, Depth);\r
+\r
+    for (Index = 0; Index < HubDesc->NumPorts; Index++) {\r
+      UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);\r
+    }\r
+  } else {\r
+    //\r
+    // Feed power to all the hub ports. It should be ok\r
+    // for both gang/individual powered hubs.\r
+    //\r
+    for (Index = 0; Index < HubDesc->NumPorts; Index++) {\r
+      UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);\r
+    }\r
+\r
+    //\r
+    // Update for the usb hub has no power on delay requirement\r
+    //\r
+    if (HubDesc->PwrOn2PwrGood > 0) {\r
+      gBS->Stall (HubDesc->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
+    }\r
+    UsbHubAckHubStatus (HubIf->Device);\r
+  }\r
+\r
   //\r
   // Create an event to enumerate the hub's port. On\r
   //\r
@@ -711,27 +710,6 @@ UsbHubInit (
     return Status;\r
   }\r
 \r
-  //\r
-  // OK, set IsHub to TRUE. Now usb bus can handle this device\r
-  // as a working HUB. If failed eariler, bus driver will not\r
-  // recognize it as a hub. Other parts of the bus should be able\r
-  // to work.\r
-  //\r
-  HubIf->IsHub  = TRUE;\r
-  HubIf->HubApi = &mUsbHubApi;\r
-  HubIf->HubEp  = EpDesc;\r
-\r
-  //\r
-  // Feed power to all the hub ports. It should be ok\r
-  // for both gang/individual powered hubs.\r
-  //\r
-  for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
-    UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);\r
-  }\r
-\r
-  gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
-  UsbHubAckHubStatus (HubIf->Device);\r
-\r
   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));\r
   return Status;\r
 }\r
@@ -798,7 +776,7 @@ UsbHubClearPortChange (
   // It may lead to extra port state report. USB bus should\r
   // be able to handle this.\r
   //\r
-  for (Index = 0; Index < USB_HUB_MAP_SIZE; Index++) {\r
+  for (Index = 0; Index < ARRAY_SIZE (mHubFeatureMap); Index++) {\r
     Map = &mHubFeatureMap[Index];\r
 \r
     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
@@ -889,22 +867,26 @@ UsbHubResetPort (
   }\r
 \r
   //\r
-  // Drive the reset signal for at least 10ms. Check USB 2.0 Spec\r
+  // Drive the reset signal for worst 20ms. Check USB 2.0 Spec\r
   // section 7.1.7.5 for timing requirements.\r
   //\r
   gBS->Stall (USB_SET_PORT_RESET_STALL);\r
 \r
   //\r
-  // USB hub will clear RESET bit if reset is actually finished.\r
+  // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.\r
   //\r
   ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
 \r
   for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
     Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
 \r
-    if (!EFI_ERROR (Status) &&\r
-        !USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
 \r
+    if (!EFI_ERROR (Status) &&\r
+        USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
+      gBS->Stall (USB_SET_PORT_RECOVERY_STALL);\r
       return EFI_SUCCESS;\r
     }\r
 \r
@@ -1090,7 +1072,7 @@ UsbRootHubClearPortChange (
   // It may lead to extra port state report. USB bus should\r
   // be able to handle this.\r
   //\r
-  for (Index = 0; Index < USB_ROOT_HUB_MAP_SIZE; Index++) {\r
+  for (Index = 0; Index < ARRAY_SIZE (mRootHubFeatureMap); Index++) {\r
     Map = &mRootHubFeatureMap[Index];\r
 \r
     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
@@ -1182,6 +1164,7 @@ UsbRootHubResetPort (
   // should be handled in the EHCI driver.\r
   //\r
   Bus     = RootIf->Device->Bus;\r
+\r
   Status  = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
 \r
   if (EFI_ERROR (Status)) {\r