]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbEnumer.c
index fc0007dd11cbe418ab0f21327fb6b8576b2138ee..0cded1eea7436254733d230a27d76e722f7410d2 100644 (file)
@@ -1,37 +1,21 @@
 /** @file\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
-\r
-  Module Name:\r
-\r
-    UsbEnumer.c\r
-\r
-  Abstract:\r
-\r
-    Usb bus enumeration support\r
-\r
-  Revision History\r
+    Usb bus enumeration support.\r
 \r
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "UsbBus.h"\r
 \r
-\r
 /**\r
-  Return the endpoint descriptor in this interface\r
+  Return the endpoint descriptor in this interface.\r
 \r
-  @param  UsbIf                 The interface to search in\r
-  @param  EpAddr                The address of the endpoint to return\r
+  @param  UsbIf                 The interface to search in.\r
+  @param  EpAddr                The address of the endpoint to return.\r
 \r
-  @return The endpoint descriptor or NULL\r
+  @return The endpoint descriptor or NULL.\r
 \r
 **/\r
 USB_ENDPOINT_DESC *\r
@@ -41,9 +25,12 @@ UsbGetEndpointDesc (
   )\r
 {\r
   USB_ENDPOINT_DESC       *EpDesc;\r
-  UINTN                   Index;\r
+  UINT8                   Index;\r
+  UINT8                   NumEndpoints;\r
+\r
+  NumEndpoints = UsbIf->IfSetting->Desc.NumEndpoints;\r
 \r
-  for (Index = 0; Index < UsbIf->IfSetting->Desc.NumEndpoints; Index++) {\r
+  for (Index = 0; Index < NumEndpoints; Index++) {\r
     EpDesc = UsbIf->IfSetting->Endpoints[Index];\r
 \r
     if (EpDesc->Desc.EndpointAddress == EpAddr) {\r
@@ -56,35 +43,37 @@ UsbGetEndpointDesc (
 \r
 \r
 /**\r
-  Free the resource used by USB interface\r
+  Free the resource used by USB interface.\r
 \r
-  @param  UsbIf                 The USB interface to free\r
-\r
-  @return None\r
+  @param  UsbIf                 The USB interface to free.\r
 \r
+  @retval EFI_ACCESS_DENIED     The interface is still occupied.\r
+  @retval EFI_SUCCESS           The interface is freed.\r
 **/\r
-STATIC\r
-VOID\r
+EFI_STATUS\r
 UsbFreeInterface (\r
   IN USB_INTERFACE        *UsbIf\r
   )\r
 {\r
-  UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);\r
+  EFI_STATUS              Status;\r
 \r
-  gBS->UninstallMultipleProtocolInterfaces (\r
-         UsbIf->Handle,\r
-         &gEfiDevicePathProtocolGuid,\r
-         UsbIf->DevicePath,\r
-         &gEfiUsbIoProtocolGuid,\r
-         &UsbIf->UsbIo,\r
-         NULL\r
-         );\r
+  UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);\r
 \r
-  if (UsbIf->DevicePath != NULL) {\r
-    gBS->FreePool (UsbIf->DevicePath);\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  UsbIf->Handle,\r
+                  &gEfiDevicePathProtocolGuid, UsbIf->DevicePath,\r
+                  &gEfiUsbIoProtocolGuid,      &UsbIf->UsbIo,\r
+                  NULL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    if (UsbIf->DevicePath != NULL) {\r
+      FreePool (UsbIf->DevicePath);\r
+    }\r
+    FreePool (UsbIf);\r
+  } else {\r
+    UsbOpenHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);\r
   }\r
-\r
-  gBS->FreePool (UsbIf);\r
+  return Status;\r
 }\r
 \r
 \r
@@ -92,13 +81,12 @@ UsbFreeInterface (
   Create an interface for the descriptor IfDesc. Each\r
   device's configuration can have several interfaces.\r
 \r
-  @param  Device                The device has the interface descriptor\r
-  @param  IfDesc                The interface descriptor\r
+  @param  Device                The device has the interface descriptor.\r
+  @param  IfDesc                The interface descriptor.\r
 \r
   @return The created USB interface for the descriptor, or NULL.\r
 \r
 **/\r
-STATIC\r
 USB_INTERFACE *\r
 UsbCreateInterface (\r
   IN USB_DEVICE           *Device,\r
@@ -119,8 +107,14 @@ UsbCreateInterface (
   UsbIf->Signature  = USB_INTERFACE_SIGNATURE;\r
   UsbIf->Device     = Device;\r
   UsbIf->IfDesc     = IfDesc;\r
+  ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);\r
   UsbIf->IfSetting  = IfDesc->Settings[IfDesc->ActiveIndex];\r
-  UsbIf->UsbIo      = mUsbIoProtocol;\r
+\r
+  CopyMem (\r
+    &(UsbIf->UsbIo),\r
+    &mUsbIoProtocol,\r
+    sizeof (EFI_USB_IO_PROTOCOL)\r
+    );\r
 \r
   //\r
   // Install protocols for USBIO and device path\r
@@ -138,7 +132,7 @@ UsbCreateInterface (
   UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);\r
 \r
   if (UsbIf->DevicePath == NULL) {\r
-    USB_ERROR (("UsbCreateInterface: failed to create device path\n"));\r
+    DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to create device path\n"));\r
 \r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ON_ERROR;\r
@@ -154,7 +148,7 @@ UsbCreateInterface (
                   );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbCreateInterface: failed to install UsbIo - %r\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to install UsbIo - %r\n", Status));\r
     goto ON_ERROR;\r
   }\r
 \r
@@ -173,31 +167,28 @@ UsbCreateInterface (
            NULL\r
            );\r
 \r
-    USB_ERROR (("UsbCreateInterface: failed to open host for child - %r\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to open host for child - %r\n", Status));\r
     goto ON_ERROR;\r
   }\r
 \r
   return UsbIf;\r
 \r
 ON_ERROR:\r
-  if (UsbIf->DevicePath) {\r
-    gBS->FreePool (UsbIf->DevicePath);\r
+  if (UsbIf->DevicePath != NULL) {\r
+    FreePool (UsbIf->DevicePath);\r
   }\r
 \r
-  gBS->FreePool (UsbIf);\r
+  FreePool (UsbIf);\r
   return NULL;\r
 }\r
 \r
 \r
 /**\r
-  Free the resource used by this USB device\r
-\r
-  @param  Device                The USB device to free\r
+  Free the resource used by this USB device.\r
 \r
-  @return None\r
+  @param  Device                The USB device to free.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 UsbFreeDevice (\r
   IN USB_DEVICE           *Device\r
@@ -214,13 +205,12 @@ UsbFreeDevice (
 /**\r
   Create a device which is on the parent's ParentPort port.\r
 \r
-  @param  ParentIf              The parent HUB interface\r
-  @param  ParentPort            The port on the HUB this device is connected to\r
+  @param  ParentIf              The parent HUB interface.\r
+  @param  ParentPort            The port on the HUB this device is connected to.\r
 \r
-  @return Created USB device\r
+  @return Created USB device, Or NULL.\r
 \r
 **/\r
-STATIC\r
 USB_DEVICE *\r
 UsbCreateDevice (\r
   IN USB_INTERFACE        *ParentIf,\r
@@ -242,21 +232,21 @@ UsbCreateDevice (
   Device->ParentAddr  = ParentIf->Device->Address;\r
   Device->ParentIf    = ParentIf;\r
   Device->ParentPort  = ParentPort;\r
+  Device->Tier        = (UINT8)(ParentIf->Device->Tier + 1);\r
   return Device;\r
 }\r
 \r
 \r
 /**\r
   Connect the USB interface with its driver. EFI USB bus will\r
-  create a USB interface for each seperate interface descriptor.\r
+  create a USB interface for each separate interface descriptor.\r
 \r
-  @param  UsbIf                 The interface to connect driver to\r
+  @param  UsbIf             The interface to connect driver to.\r
 \r
-  @return EFI_SUCCESS : Interface is managed by some driver\r
-  @return Others      : Failed to locate a driver for this interface\r
+  @return EFI_SUCCESS       Interface is managed by some driver.\r
+  @return Others            Failed to locate a driver for this interface.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 UsbConnectDriver (\r
   IN USB_INTERFACE        *UsbIf\r
@@ -272,7 +262,7 @@ UsbConnectDriver (
   // connect drivers with this interface\r
   //\r
   if (UsbIsHubInterface (UsbIf)) {\r
-    USB_DEBUG (("UsbConnectDriver: found a hub device\n"));\r
+    DEBUG ((EFI_D_INFO, "UsbConnectDriver: found a hub device\n"));\r
     Status = mUsbHubApi.Init (UsbIf);\r
 \r
   } else {\r
@@ -283,18 +273,24 @@ UsbConnectDriver (
     // twisted TPL used. It should be no problem for us to connect\r
     // or disconnect at CALLBACK.\r
     //\r
-    OldTpl            = UsbGetCurrentTpl ();\r
-    USB_DEBUG (("UsbConnectDriver: TPL before connect is %d\n", OldTpl));\r
 \r
-    gBS->RestoreTPL (TPL_CALLBACK);\r
+    //\r
+    // Only recursively wanted usb child device\r
+    //\r
+    if (UsbBusIsWantedUsbIO (UsbIf->Device->Bus, UsbIf)) {\r
+      OldTpl            = UsbGetCurrentTpl ();\r
+      DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));\r
 \r
-    Status            = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);\r
-    UsbIf->IsManaged  = (BOOLEAN)!EFI_ERROR (Status);\r
+      gBS->RestoreTPL (TPL_CALLBACK);\r
 \r
-    USB_DEBUG (("UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl()));\r
-    ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
+      Status            = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);\r
+      UsbIf->IsManaged  = (BOOLEAN)!EFI_ERROR (Status);\r
 \r
-    gBS->RaiseTPL (OldTpl);\r
+      DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl()));\r
+      ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
+\r
+      gBS->RaiseTPL (OldTpl);\r
+    }\r
   }\r
 \r
   return Status;\r
@@ -307,10 +303,10 @@ UsbConnectDriver (
   settings. Only one setting is active. It will\r
   also reset its endpoints' toggle to zero.\r
 \r
-  @param  IfDesc                The interface descriptor to set\r
-  @param  Alternate             The alternate setting number to locate\r
+  @param  IfDesc                The interface descriptor to set.\r
+  @param  Alternate             The alternate setting number to locate.\r
 \r
-  @retval EFI_NOT_FOUND         There is no setting with this alternate index\r
+  @retval EFI_NOT_FOUND         There is no setting with this alternate index.\r
   @retval EFI_SUCCESS           The interface is set to Alternate setting.\r
 \r
 **/\r
@@ -321,7 +317,7 @@ UsbSelectSetting (
   )\r
 {\r
   USB_INTERFACE_SETTING   *Setting;\r
-  UINT8                   Index;\r
+  UINTN                   Index;\r
 \r
   //\r
   // Locate the active alternate setting\r
@@ -329,6 +325,7 @@ UsbSelectSetting (
   Setting = NULL;\r
 \r
   for (Index = 0; Index < IfDesc->NumOfSetting; Index++) {\r
+    ASSERT (Index < USB_MAX_INTERFACE_SETTING);\r
     Setting = IfDesc->Settings[Index];\r
 \r
     if (Setting->Desc.AlternateSetting == Alternate) {\r
@@ -342,7 +339,8 @@ UsbSelectSetting (
 \r
   IfDesc->ActiveIndex = Index;\r
 \r
-  USB_DEBUG (("UsbSelectSetting: setting %d selected for interface %d\n",\r
+  ASSERT (Setting != NULL);\r
+  DEBUG ((EFI_D_INFO, "UsbSelectSetting: setting %d selected for interface %d\n",\r
               Alternate, Setting->Desc.InterfaceNumber));\r
 \r
   //\r
@@ -360,11 +358,11 @@ UsbSelectSetting (
   Select a new configuration for the device. Each\r
   device may support several configurations.\r
 \r
-  @param  Device                The device to select configuration\r
-  @param  ConfigValue           The index of the configuration ( != 0)\r
+  @param  Device                The device to select configuration.\r
+  @param  ConfigValue           The index of the configuration ( != 0).\r
 \r
-  @retval EFI_NOT_FOUND         There is no configuration with the index\r
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource\r
+  @retval EFI_NOT_FOUND         There is no configuration with the index.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource.\r
   @retval EFI_SUCCESS           The configuration is selected.\r
 \r
 **/\r
@@ -401,7 +399,7 @@ UsbSelectConfig (
 \r
   Device->ActiveConfig = ConfigDesc;\r
 \r
-  USB_DEBUG (("UsbSelectConfig: config %d selected for device %d\n",\r
+  DEBUG ((EFI_D_INFO, "UsbSelectConfig: config %d selected for device %d\n",\r
               ConfigValue, Device->Address));\r
 \r
   //\r
@@ -421,9 +419,11 @@ UsbSelectConfig (
     UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);\r
 \r
     if (UsbIf == NULL) {\r
+      Device->NumOfInterface = Index;\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
+    ASSERT (Index < USB_MAX_INTERFACE);\r
     Device->Interfaces[Index] = UsbIf;\r
 \r
     //\r
@@ -434,7 +434,11 @@ UsbSelectConfig (
     Status = UsbConnectDriver (UsbIf);\r
 \r
     if (EFI_ERROR (Status)) {\r
-      USB_ERROR (("UsbSelectConfig: failed to connect driver %r, ignored\n", Status));\r
+      DEBUG ((\r
+        DEBUG_WARN,\r
+        "UsbSelectConfig: failed to connect driver %r, ignored\n",\r
+        Status\r
+        ));\r
     }\r
   }\r
 \r
@@ -444,29 +448,27 @@ UsbSelectConfig (
 }\r
 \r
 \r
-\r
 /**\r
   Disconnect the USB interface with its driver.\r
 \r
-  @param  UsbIf                 The interface to disconnect driver from\r
-\r
-  @return None\r
+  @param  UsbIf                 The interface to disconnect driver from.\r
 \r
 **/\r
-STATIC\r
-VOID\r
+EFI_STATUS\r
 UsbDisconnectDriver (\r
   IN USB_INTERFACE        *UsbIf\r
   )\r
 {\r
   EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
 \r
   //\r
   // Release the hub if it's a hub controller, otherwise\r
   // disconnect the driver if it is managed by other drivers.\r
   //\r
+  Status = EFI_SUCCESS;\r
   if (UsbIf->IsHub) {\r
-    UsbIf->HubApi->Release (UsbIf);\r
+    Status = UsbIf->HubApi->Release (UsbIf);\r
 \r
   } else if (UsbIf->IsManaged) {\r
     //\r
@@ -477,65 +479,79 @@ UsbDisconnectDriver (
     // or disconnect at CALLBACK.\r
     //\r
     OldTpl           = UsbGetCurrentTpl ();\r
-    USB_DEBUG (("UsbDisconnectDriver: old TPL is %d\n", OldTpl));\r
+    DEBUG ((EFI_D_INFO, "UsbDisconnectDriver: old TPL is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));\r
 \r
     gBS->RestoreTPL (TPL_CALLBACK);\r
 \r
-    gBS->DisconnectController (UsbIf->Handle, NULL, NULL);\r
-    UsbIf->IsManaged = FALSE;\r
+    Status = gBS->DisconnectController (UsbIf->Handle, NULL, NULL);\r
+    if (!EFI_ERROR (Status)) {\r
+      UsbIf->IsManaged = FALSE;\r
+    }\r
 \r
-    USB_DEBUG (("UsbDisconnectDriver: TPL after disconnect is %d\n", UsbGetCurrentTpl()));\r
+    DEBUG (( EFI_D_INFO, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32)UsbGetCurrentTpl(), Status));\r
     ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
 \r
     gBS->RaiseTPL (OldTpl);\r
   }\r
-}\r
 \r
+  return Status;\r
+}\r
 \r
 \r
 /**\r
-  Remove the current device configuration\r
-\r
-  @param  Device                The USB device to remove configuration from\r
+  Remove the current device configuration.\r
 \r
-  @return None\r
+  @param  Device                The USB device to remove configuration from.\r
 \r
 **/\r
-VOID\r
+EFI_STATUS\r
 UsbRemoveConfig (\r
   IN USB_DEVICE           *Device\r
   )\r
 {\r
   USB_INTERFACE           *UsbIf;\r
   UINTN                   Index;\r
+  EFI_STATUS              Status;\r
+  EFI_STATUS              ReturnStatus;\r
 \r
   //\r
   // Remove each interface of the device\r
   //\r
+  ReturnStatus = EFI_SUCCESS;\r
   for (Index = 0; Index < Device->NumOfInterface; Index++) {\r
+    ASSERT (Index < USB_MAX_INTERFACE);\r
     UsbIf = Device->Interfaces[Index];\r
 \r
     if (UsbIf == NULL) {\r
       continue;\r
     }\r
 \r
-    UsbDisconnectDriver (UsbIf);\r
-    UsbFreeInterface (UsbIf);\r
-    Device->Interfaces[Index] = NULL;\r
+    Status = UsbDisconnectDriver (UsbIf);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = UsbFreeInterface (UsbIf);\r
+      if (EFI_ERROR (Status)) {\r
+        UsbConnectDriver (UsbIf);\r
+      }\r
+    }\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      Device->Interfaces[Index] = NULL;\r
+    } else {\r
+      ReturnStatus = Status;\r
+    }\r
   }\r
 \r
   Device->ActiveConfig    = NULL;\r
-  Device->NumOfInterface  = 0;\r
+  return ReturnStatus;\r
 }\r
 \r
 \r
-\r
 /**\r
   Remove the device and all its children from the bus.\r
 \r
-  @param  Device                The device to remove\r
+  @param  Device                The device to remove.\r
 \r
-  @retval EFI_SUCCESS           The device is removed\r
+  @retval EFI_SUCCESS           The device is removed.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -546,7 +562,8 @@ UsbRemoveDevice (
   USB_BUS                 *Bus;\r
   USB_DEVICE              *Child;\r
   EFI_STATUS              Status;\r
-  UINT8                   Index;\r
+  EFI_STATUS              ReturnStatus;\r
+  UINTN                   Index;\r
 \r
   Bus = Device->Bus;\r
 \r
@@ -554,7 +571,8 @@ UsbRemoveDevice (
   // Remove all the devices on its downstream ports. Search from devices[1].\r
   // Devices[0] is the root hub.\r
   //\r
-  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
+  ReturnStatus = EFI_SUCCESS;\r
+  for (Index = 1; Index < Bus->MaxDevices; Index++) {\r
     Child = Bus->Devices[Index];\r
 \r
     if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {\r
@@ -563,33 +581,43 @@ UsbRemoveDevice (
 \r
     Status = UsbRemoveDevice (Child);\r
 \r
-    if (EFI_ERROR (Status)) {\r
-      USB_ERROR (("UsbRemoveDevice: failed to remove child, ignore error\n"));\r
+    if (!EFI_ERROR (Status)) {\r
       Bus->Devices[Index] = NULL;\r
+    } else {\r
+      Bus->Devices[Index]->DisconnectFail = TRUE;\r
+      ReturnStatus = Status;\r
+      DEBUG ((EFI_D_INFO, "UsbRemoveDevice: failed to remove child %p at parent %p\n", Child, Device));\r
     }\r
   }\r
 \r
-  UsbRemoveConfig (Device);\r
+  if (EFI_ERROR (ReturnStatus)) {\r
+    return ReturnStatus;\r
+  }\r
 \r
-  USB_DEBUG (("UsbRemoveDevice: device %d removed\n", Device->Address));\r
+  Status = UsbRemoveConfig (Device);\r
 \r
-  Bus->Devices[Device->Address] = NULL;\r
-  UsbFreeDevice (Device);\r
+  if (!EFI_ERROR (Status)) {\r
+    DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));\r
 \r
-  return EFI_SUCCESS;\r
+    ASSERT (Device->Address < Bus->MaxDevices);\r
+    Bus->Devices[Device->Address] = NULL;\r
+    UsbFreeDevice (Device);\r
+  } else {\r
+    Bus->Devices[Device->Address]->DisconnectFail = TRUE;\r
+  }\r
+  return Status;\r
 }\r
 \r
 \r
 /**\r
-  Find the child device on the hub's port\r
+  Find the child device on the hub's port.\r
 \r
-  @param  HubIf                 The hub interface\r
-  @param  Port                  The port of the hub this child is connected to\r
+  @param  HubIf                 The hub interface.\r
+  @param  Port                  The port of the hub this child is connected to.\r
 \r
-  @return The device on the hub's port, or NULL if there is none\r
+  @return The device on the hub's port, or NULL if there is none.\r
 \r
 **/\r
-STATIC\r
 USB_DEVICE *\r
 UsbFindChild (\r
   IN USB_INTERFACE        *HubIf,\r
@@ -605,7 +633,7 @@ UsbFindChild (
   //\r
   // Start checking from device 1, device 0 is the root hub\r
   //\r
-  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
+  for (Index = 1; Index < Bus->MaxDevices; Index++) {\r
     Device = Bus->Devices[Index];\r
 \r
     if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&\r
@@ -619,23 +647,23 @@ UsbFindChild (
 }\r
 \r
 \r
-\r
 /**\r
   Enumerate and configure the new device on the port of this HUB interface.\r
 \r
-  @param  HubIf                 The HUB that has the device connected\r
-  @param  Port                  The port index of the hub (started with zero)\r
+  @param  HubIf                 The HUB that has the device connected.\r
+  @param  Port                  The port index of the hub (started with zero).\r
+  @param  ResetIsNeeded         The boolean to control whether skip the reset of the port.\r
 \r
-  @retval EFI_SUCCESS           The device is enumerated (added or removed)\r
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device\r
-  @retval Others                Failed to enumerate the device\r
+  @retval EFI_SUCCESS           The device is enumerated (added or removed).\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device.\r
+  @retval Others                Failed to enumerate the device.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 UsbEnumerateNewDev (\r
   IN USB_INTERFACE        *HubIf,\r
-  IN UINT8                Port\r
+  IN UINT8                Port,\r
+  IN BOOLEAN              ResetIsNeeded\r
   )\r
 {\r
   USB_BUS                 *Bus;\r
@@ -643,20 +671,16 @@ UsbEnumerateNewDev (
   USB_DEVICE              *Child;\r
   USB_DEVICE              *Parent;\r
   EFI_USB_PORT_STATUS     PortState;\r
-  UINT8                   Address;\r
+  UINTN                   Address;\r
   UINT8                   Config;\r
   EFI_STATUS              Status;\r
 \r
-  Address = USB_MAX_DEVICES;\r
   Parent  = HubIf->Device;\r
   Bus     = Parent->Bus;\r
   HubApi  = HubIf->HubApi;\r
+  Address = Bus->MaxDevices;\r
 \r
-\r
-  //\r
-  // Wait at least 100 ms for the power on port to stable\r
-  //\r
-  gBS->Stall (100 * USB_STALL_1_MS);\r
+  gBS->Stall (USB_WAIT_PORT_STABLE_STALL);\r
 \r
   //\r
   // Hub resets the device for at least 10 milliseconds.\r
@@ -664,16 +688,18 @@ UsbEnumerateNewDev (
   // and the hub is a EHCI root hub, ResetPort will release\r
   // the device to its companion UHCI and return an error.\r
   //\r
-  Status = HubApi->ResetPort (HubIf, Port);\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));\r
+  if (ResetIsNeeded) {\r
+    Status = HubApi->ResetPort (HubIf, Port);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));\r
 \r
-    return Status;\r
+      return Status;\r
+    }\r
+    DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d is reset\n", Port));\r
+  } else {\r
+    DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d reset is skipped\n", Port));\r
   }\r
 \r
-  USB_DEBUG (("UsbEnumerateNewDev: hub port %d is reset\n", Port));\r
-\r
   Child = UsbCreateDevice (HubIf, Port);\r
 \r
   if (Child == NULL) {\r
@@ -687,104 +713,107 @@ UsbEnumerateNewDev (
   Status = HubApi->GetPortStatus (HubIf, Port, &PortState);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbEnumerateNewDev: failed to get speed of port %d\n", Port));\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port));\r
     goto ON_ERROR;\r
   }\r
 \r
-  if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
-    Child->Speed = EFI_USB_SPEED_LOW;\r
-\r
+  if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: No device present at port %d\n", Port));\r
+    goto ON_ERROR;\r
+  } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_SUPER_SPEED)){\r
+    Child->Speed      = EFI_USB_SPEED_SUPER;\r
+    Child->MaxPacket0 = 512;\r
   } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {\r
-    Child->Speed = EFI_USB_SPEED_HIGH;\r
-\r
+    Child->Speed      = EFI_USB_SPEED_HIGH;\r
+    Child->MaxPacket0 = 64;\r
+  } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
+    Child->Speed      = EFI_USB_SPEED_LOW;\r
+    Child->MaxPacket0 = 8;\r
   } else {\r
-    Child->Speed = EFI_USB_SPEED_FULL;\r
+    Child->Speed      = EFI_USB_SPEED_FULL;\r
+    Child->MaxPacket0 = 8;\r
   }\r
 \r
-  USB_DEBUG (("UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));\r
+  DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));\r
 \r
-  if (Child->Speed != EFI_USB_SPEED_HIGH) {\r
+  if (((Child->Speed == EFI_USB_SPEED_LOW) || (Child->Speed == EFI_USB_SPEED_FULL)) &&\r
+      (Parent->Speed == EFI_USB_SPEED_HIGH)) {\r
     //\r
-    // If the child isn't a high speed device, it is necessary to\r
-    // set the transaction translator. This is quite simple:\r
+    // If the child is a low or full speed device, it is necessary to\r
+    // set the transaction translator. Port TT is 1-based.\r
+    // This is quite simple:\r
     //  1. if parent is of high speed, then parent is our translator\r
     //  2. otherwise use parent's translator.\r
     //\r
-    if (Parent->Speed == EFI_USB_SPEED_HIGH) {\r
-      Child->Translator.TranslatorHubAddress  = Parent->Address;\r
-      Child->Translator.TranslatorPortNumber  = Port;\r
-\r
-    } else {\r
-      Child->Translator = Parent->Translator;\r
-    }\r
-\r
-    USB_DEBUG (("UsbEnumerateNewDev: device uses translator (%d, %d)\n",\r
-                Child->Translator.TranslatorHubAddress,\r
-                Child->Translator.TranslatorPortNumber));\r
+    Child->Translator.TranslatorHubAddress  = Parent->Address;\r
+    Child->Translator.TranslatorPortNumber  = (UINT8) (Port + 1);\r
+  } else {\r
+    Child->Translator = Parent->Translator;\r
   }\r
+  DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device uses translator (%d, %d)\n",\r
+           Child->Translator.TranslatorHubAddress,\r
+           Child->Translator.TranslatorPortNumber));\r
 \r
   //\r
   // After port is reset, hub establishes a signal path between\r
-  // the device and host (DEFALUT state). Device¡¯s registers are\r
+  // the device and host (DEFALUT state). Device's registers are\r
   // reset, use default address 0 (host enumerates one device at\r
   // a time) , and ready to respond to control transfer at EP 0.\r
   //\r
 \r
-  //\r
-  // Host sends a Get_Descriptor request to learn the max packet\r
-  // size of default pipe (only part of the device¡¯s descriptor).\r
-  //\r
-  Status = UsbGetMaxPacketSize0 (Child);\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));\r
-    goto ON_ERROR;\r
-  }\r
-\r
-  USB_DEBUG (("UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));\r
-\r
   //\r
   // Host assigns an address to the device. Device completes the\r
   // status stage with default address, then switches to new address.\r
   // ADDRESS state. Address zero is reserved for root hub.\r
   //\r
-  for (Address = 1; Address < USB_MAX_DEVICES; Address++) {\r
+  ASSERT (Bus->MaxDevices <= 256);\r
+  for (Address = 1; Address < Bus->MaxDevices; Address++) {\r
     if (Bus->Devices[Address] == NULL) {\r
       break;\r
     }\r
   }\r
 \r
-  if (Address == USB_MAX_DEVICES) {\r
-    USB_ERROR (("UsbEnumerateNewDev: address pool is full for port %d\n", Port));\r
+  if (Address >= Bus->MaxDevices) {\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));\r
 \r
     Status = EFI_ACCESS_DENIED;\r
     goto ON_ERROR;\r
   }\r
 \r
+  Status                = UsbSetAddress (Child, (UINT8)Address);\r
+  Child->Address        = (UINT8)Address;\r
   Bus->Devices[Address] = Child;\r
-  Status                = UsbSetAddress (Child, Address);\r
-  Child->Address        = Address;\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbEnumerateNewDev: failed to set device address - %r\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));\r
     goto ON_ERROR;\r
   }\r
 \r
+  gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);\r
+\r
+  DEBUG ((EFI_D_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));\r
+\r
   //\r
-  // Wait 20ms for set address to complete\r
+  // Host sends a Get_Descriptor request to learn the max packet\r
+  // size of default pipe (only part of the device's descriptor).\r
   //\r
-  gBS->Stall (20 * USB_STALL_1_MS);\r
+  Status = UsbGetMaxPacketSize0 (Child);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));\r
+    goto ON_ERROR;\r
+  }\r
 \r
-  USB_DEBUG (("UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));\r
+  DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));\r
 \r
   //\r
-  // Host learns about the device¡¯s abilities by requesting device's\r
+  // Host learns about the device's abilities by requesting device's\r
   // entire descriptions.\r
   //\r
   Status = UsbBuildDescTable (Child);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));\r
     goto ON_ERROR;\r
   }\r
 \r
@@ -796,11 +825,11 @@ UsbEnumerateNewDev (
   Status = UsbSetConfig (Child, Config);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));\r
     goto ON_ERROR;\r
   }\r
 \r
-  USB_DEBUG (("UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));\r
+  DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));\r
 \r
   //\r
   // Host assigns and loads a device driver.\r
@@ -808,38 +837,50 @@ UsbEnumerateNewDev (
   Status = UsbSelectConfig (Child, Config);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));\r
     goto ON_ERROR;\r
   }\r
 \r
+  //\r
+  // Report Status Code to indicate USB device has been detected by hotplug\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG),\r
+    Bus->DevicePath\r
+    );\r
   return EFI_SUCCESS;\r
 \r
 ON_ERROR:\r
-  if (Address != USB_MAX_DEVICES) {\r
-    Bus->Devices[Address] = NULL;\r
-  }\r
-\r
-  if (Child != NULL) {\r
-    UsbFreeDevice (Child);\r
-  }\r
-\r
+  //\r
+  // If reach here, it means the enumeration process on a given port is interrupted due to error.\r
+  // The s/w resources, including the assigned address(Address) and the allocated usb device data\r
+  // structure(Bus->Devices[Address]), will NOT be freed here. These resources will be freed when\r
+  // the device is unplugged from the port or DriverBindingStop() is invoked.\r
+  //\r
+  // This way is used to co-work with the lower layer EDKII UHCI/EHCI/XHCI host controller driver.\r
+  // It's mainly because to keep UEFI spec unchanged EDKII XHCI driver have to maintain a state machine\r
+  // to keep track of the mapping between actual address and request address. If the request address\r
+  // (Address) is freed here, the Address value will be used by next enumerated device. Then EDKII XHCI\r
+  // host controller driver will have wrong information, which will cause further transaction error.\r
+  //\r
+  // EDKII UHCI/EHCI doesn't get impacted as it's make sense to reserve s/w resource till it gets unplugged.\r
+  //\r
   return Status;\r
 }\r
 \r
 \r
-\r
 /**\r
   Process the events on the port.\r
 \r
-  @param  HubIf                 The HUB that has the device connected\r
-  @param  Port                  The port index of the hub (started with zero)\r
+  @param  HubIf                 The HUB that has the device connected.\r
+  @param  Port                  The port index of the hub (started with zero).\r
 \r
-  @retval EFI_SUCCESS           The device is enumerated (added or removed)\r
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device\r
-  @retval Others                Failed to enumerate the device\r
+  @retval EFI_SUCCESS           The device is enumerated (added or removed).\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device.\r
+  @retval Others                Failed to enumerate the device.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 UsbEnumeratePort (\r
   IN USB_INTERFACE        *HubIf,\r
@@ -860,54 +901,90 @@ UsbEnumeratePort (
   Status = HubApi->GetPortStatus (HubIf, Port, &PortState);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbEnumeratePort: failed to get state of port %d\n", Port));\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));\r
     return Status;\r
   }\r
 \r
-  if (PortState.PortChangeStatus == 0) {\r
+  //\r
+  // Only handle connection/enable/overcurrent/reset change.\r
+  // Usb super speed hub may report other changes, such as warm reset change. Ignore them.\r
+  //\r
+  if ((PortState.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  USB_DEBUG (("UsbEnumeratePort: port %d state - %x, change - %x\n",\r
-              Port, PortState.PortStatus, PortState.PortChangeStatus));\r
+  DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",\r
+              Port, PortState.PortStatus, PortState.PortChangeStatus, HubIf));\r
 \r
   //\r
   // This driver only process two kinds of events now: over current and\r
   // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.\r
   // ENABLE/RESET is used to reset port. SUSPEND isn't supported.\r
   //\r
-  Status = EFI_SUCCESS;\r
 \r
   if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {\r
+\r
+    if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {\r
+      //\r
+      // Case1:\r
+      //   Both OverCurrent and OverCurrentChange set, means over current occurs,\r
+      //   which probably is caused by short circuit. It has to wait system hardware\r
+      //   to perform recovery.\r
+      //\r
+      DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));\r
+      return EFI_DEVICE_ERROR;\r
+\r
+    }\r
     //\r
-    // If overcurrent condition is cleared, enable the port again\r
+    // Case2:\r
+    //   Only OverCurrentChange set, means system has been recoveried from\r
+    //   over current. As a result, all ports are nearly power-off, so\r
+    //   it's necessary to detach and enumerate all ports again.\r
     //\r
-    if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {\r
-      HubApi->SetPortFeature (HubIf, Port, USB_HUB_PORT_POWER);\r
-    }\r
+    DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port));\r
+  }\r
 \r
-  } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {\r
+  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {\r
     //\r
-    // Device connected or disconnected. Either way, if there is\r
-    // already a device present in the bus, need to remove it.\r
+    // Case3:\r
+    //   1.1 roothub port reg doesn't reflect over-current state, while its counterpart\r
+    //   on 2.0 roothub does. When over-current has influence on 1.1 device, the port\r
+    //   would be disabled, so it's also necessary to detach and enumerate again.\r
     //\r
-    Child = UsbFindChild (HubIf, Port);\r
+    DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port));\r
+  }\r
 \r
-    if (Child != NULL) {\r
-      USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port));\r
-      UsbRemoveDevice (Child);\r
-    }\r
+  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {\r
+    //\r
+    // Case4:\r
+    //   Device connected or disconnected normally.\r
+    //\r
+    DEBUG ((EFI_D_INFO, "UsbEnumeratePort: Device Connect/Disconnect Normally\n", Port));\r
+  }\r
 \r
-    if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
-      //\r
-      // Now, new device connected, enumerate and configure the device\r
-      //\r
-      USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port));\r
-      Status = UsbEnumerateNewDev (HubIf, Port);\r
+  //\r
+  // Following as the above cases, it's safety to remove and create again.\r
+  //\r
+  Child = UsbFindChild (HubIf, Port);\r
 \r
+  if (Child != NULL) {\r
+    DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from root hub %p\n", Port, HubIf));\r
+    UsbRemoveDevice (Child);\r
+  }\r
+\r
+  if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
+    //\r
+    // Now, new device connected, enumerate and configure the device\r
+    //\r
+    DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));\r
+    if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {\r
+      Status = UsbEnumerateNewDev (HubIf, Port, FALSE);\r
     } else {\r
-      USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port));\r
+      Status = UsbEnumerateNewDev (HubIf, Port, TRUE);\r
     }\r
+\r
+  } else {\r
+    DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));\r
   }\r
 \r
   HubApi->ClearPortChange (HubIf, Port);\r
@@ -916,15 +993,14 @@ UsbEnumeratePort (
 \r
 \r
 /**\r
-  Enumerate all the changed hub ports\r
-\r
-  @param  Event                 The event that is triggered\r
-  @param  Context               The context to the event\r
+  Enumerate all the changed hub ports.\r
 \r
-  @return None\r
+  @param  Event                 The event that is triggered.\r
+  @param  Context               The context to the event.\r
 \r
 **/\r
 VOID\r
+EFIAPI\r
 UsbHubEnumeration (\r
   IN EFI_EVENT            Event,\r
   IN VOID                 *Context\r
@@ -934,11 +1010,20 @@ UsbHubEnumeration (
   UINT8                   Byte;\r
   UINT8                   Bit;\r
   UINT8                   Index;\r
+  USB_DEVICE              *Child;\r
 \r
-  ASSERT (Context);\r
+  ASSERT (Context != NULL);\r
 \r
   HubIf = (USB_INTERFACE *) Context;\r
 \r
+  for (Index = 0; Index < HubIf->NumOfPort; Index++) {\r
+    Child = UsbFindChild (HubIf, Index);\r
+    if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {\r
+      DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index, HubIf));\r
+      UsbRemoveDevice (Child);\r
+    }\r
+  }\r
+\r
   if (HubIf->ChangeMap == NULL) {\r
     return ;\r
   }\r
@@ -966,15 +1051,14 @@ UsbHubEnumeration (
 \r
 \r
 /**\r
-  Enumerate all the changed hub ports\r
-\r
-  @param  Event                 The event that is triggered\r
-  @param  Context               The context to the event\r
+  Enumerate all the changed hub ports.\r
 \r
-  @return None\r
+  @param  Event                 The event that is triggered.\r
+  @param  Context               The context to the event.\r
 \r
 **/\r
 VOID\r
+EFIAPI\r
 UsbRootHubEnumeration (\r
   IN EFI_EVENT            Event,\r
   IN VOID                 *Context\r
@@ -982,10 +1066,17 @@ UsbRootHubEnumeration (
 {\r
   USB_INTERFACE           *RootHub;\r
   UINT8                   Index;\r
+  USB_DEVICE              *Child;\r
 \r
   RootHub = (USB_INTERFACE *) Context;\r
 \r
   for (Index = 0; Index < RootHub->NumOfPort; Index++) {\r
+    Child = UsbFindChild (RootHub, Index);\r
+    if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {\r
+      DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index, RootHub));\r
+      UsbRemoveDevice (Child);\r
+    }\r
+\r
     UsbEnumeratePort (RootHub, Index);\r
   }\r
 }\r