]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / UsbPeim.c
index 4a5d8e8bc4265fc143794b051401de9ca05d9aa4..6ea44951627a6241e5553cf4a01dad985b7cd570 100644 (file)
@@ -1,16 +1,9 @@
 /** @file\r
 The module to produce Usb Bus PPI.\r
 \r
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
-  \r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions\r
-of the BSD License which accompanies this distribution.  The\r
-full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\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
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -21,7 +14,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\r
 // UsbIo PPI interface function\r
 //\r
-PEI_USB_IO_PPI         mUsbIoPpi = {\r
+PEI_USB_IO_PPI  mUsbIoPpi = {\r
   PeiUsbControlTransfer,\r
   PeiUsbBulkTransfer,\r
   PeiUsbGetInterfaceDescriptor,\r
@@ -29,7 +22,7 @@ PEI_USB_IO_PPI         mUsbIoPpi = {
   PeiUsbPortReset\r
 };\r
 \r
-EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {\r
+EFI_PEI_PPI_DESCRIPTOR  mUsbIoPpiList = {\r
   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
   &gPeiUsbIoPpiGuid,\r
   NULL\r
@@ -37,7 +30,7 @@ EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {
 \r
 /**\r
   The enumeration routine to detect device change.\r
-  \r
+\r
   @param  PeiServices            Describes the list of possible PEI Services.\r
   @param  UsbHcPpi               The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
   @param  Usb2HcPpi              The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
@@ -49,14 +42,14 @@ EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {
 **/\r
 EFI_STATUS\r
 PeiUsbEnumeration (\r
-  IN EFI_PEI_SERVICES               **PeiServices,\r
-  IN PEI_USB_HOST_CONTROLLER_PPI    *UsbHcPpi,\r
-  IN PEI_USB2_HOST_CONTROLLER_PPI    *Usb2HcPpi\r
+  IN EFI_PEI_SERVICES              **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI   *UsbHcPpi,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI  *Usb2HcPpi\r
   );\r
 \r
 /**\r
   Configure new detected usb device.\r
-  \r
+\r
   @param  PeiServices            Describes the list of possible PEI Services.\r
   @param  PeiUsbDevice           The pointer of PEI_USB_DEVICE instance.\r
   @param  Port                   The port to be configured.\r
@@ -69,15 +62,15 @@ PeiUsbEnumeration (
 **/\r
 EFI_STATUS\r
 PeiConfigureUsbDevice (\r
-  IN     EFI_PEI_SERVICES    **PeiServices,\r
-  IN     PEI_USB_DEVICE      *PeiUsbDevice,\r
-  IN     UINT8               Port,\r
-  IN OUT UINT8               *DeviceAddress\r
+  IN     EFI_PEI_SERVICES  **PeiServices,\r
+  IN     PEI_USB_DEVICE    *PeiUsbDevice,\r
+  IN     UINT8             Port,\r
+  IN OUT UINT8             *DeviceAddress\r
   );\r
 \r
 /**\r
   Get all configurations from a detected usb device.\r
-  \r
+\r
   @param  PeiServices            Describes the list of possible PEI Services.\r
   @param  PeiUsbDevice           The pointer of PEI_USB_DEVICE instance.\r
 \r
@@ -88,13 +81,13 @@ PeiConfigureUsbDevice (
 **/\r
 EFI_STATUS\r
 PeiUsbGetAllConfiguration (\r
-  IN EFI_PEI_SERVICES   **PeiServices,\r
-  IN PEI_USB_DEVICE     *PeiUsbDevice\r
+  IN EFI_PEI_SERVICES  **PeiServices,\r
+  IN PEI_USB_DEVICE    *PeiUsbDevice\r
   );\r
 \r
 /**\r
   Get the start position of next wanted descriptor.\r
-  \r
+\r
   @param  Buffer            Buffer containing data to parse.\r
   @param  Length            Buffer length.\r
   @param  DescType          Descriptor type.\r
@@ -107,16 +100,16 @@ PeiUsbGetAllConfiguration (
 **/\r
 EFI_STATUS\r
 GetExpectedDescriptor (\r
-  IN  UINT8       *Buffer,\r
-  IN  UINTN       Length,\r
-  IN  UINT8       DescType,\r
-  IN  UINT8       DescLength,\r
-  OUT UINTN       *ParsedBytes\r
+  IN  UINT8  *Buffer,\r
+  IN  UINTN  Length,\r
+  IN  UINT8  DescType,\r
+  IN  UINT8  DescLength,\r
+  OUT UINTN  *ParsedBytes\r
   );\r
 \r
 /**\r
   The entrypoint of the module, it will enumerate all HCs.\r
-  \r
+\r
   @param  FileHandle             Handle of the file being invoked.\r
   @param  PeiServices            Describes the list of possible PEI Services.\r
 \r
@@ -128,21 +121,21 @@ GetExpectedDescriptor (
 EFI_STATUS\r
 EFIAPI\r
 PeimInitializeUsb (\r
-  IN EFI_PEI_FILE_HANDLE        FileHandle,\r
-  IN CONST EFI_PEI_SERVICES     **PeiServices\r
+  IN EFI_PEI_FILE_HANDLE     FileHandle,\r
+  IN CONST EFI_PEI_SERVICES  **PeiServices\r
   )\r
 {\r
-  EFI_STATUS                   Status;\r
-  UINTN                        Index;\r
-  PEI_USB_HOST_CONTROLLER_PPI  *UsbHcPpi;\r
-  PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Index;\r
+  PEI_USB_HOST_CONTROLLER_PPI   *UsbHcPpi;\r
+  PEI_USB2_HOST_CONTROLLER_PPI  *Usb2HcPpi;\r
 \r
   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
   //\r
-  // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not \r
+  // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not\r
   // be produced at the same time\r
   //\r
   Index = 0;\r
@@ -154,7 +147,7 @@ PeimInitializeUsb (
                &gPeiUsbHostControllerPpiGuid,\r
                Index,\r
                NULL,\r
-               (VOID **) &UsbHcPpi\r
+               (VOID **)&UsbHcPpi\r
                );\r
     if (EFI_ERROR (Status)) {\r
       //\r
@@ -162,7 +155,8 @@ PeimInitializeUsb (
       //\r
       break;\r
     }\r
-    PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL);\r
+\r
+    PeiUsbEnumeration ((EFI_PEI_SERVICES **)PeiServices, UsbHcPpi, NULL);\r
     Index++;\r
   }\r
 \r
@@ -175,19 +169,20 @@ PeimInitializeUsb (
                  &gPeiUsb2HostControllerPpiGuid,\r
                  Index,\r
                  NULL,\r
-                 (VOID **) &Usb2HcPpi\r
-                 );    \r
+                 (VOID **)&Usb2HcPpi\r
+                 );\r
       if (EFI_ERROR (Status)) {\r
         //\r
         // No more host controller, break out\r
         //\r
         break;\r
-      }   \r
-      PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, NULL, Usb2HcPpi);   \r
+      }\r
+\r
+      PeiUsbEnumeration ((EFI_PEI_SERVICES **)PeiServices, NULL, Usb2HcPpi);\r
       Index++;\r
     }\r
   }\r
-  \r
+\r
   if (Index == 0) {\r
     return EFI_UNSUPPORTED;\r
   }\r
@@ -198,7 +193,7 @@ PeimInitializeUsb (
 /**\r
   The Hub Enumeration just scans the hub ports one time. It also\r
   doesn't support hot-plug.\r
-  \r
+\r
   @param  PeiServices            Describes the list of possible PEI Services.\r
   @param  PeiUsbDevice           The pointer of PEI_USB_DEVICE instance.\r
   @param  CurrentAddress         The DeviceAddress of usb device.\r
@@ -210,9 +205,9 @@ PeimInitializeUsb (
 **/\r
 EFI_STATUS\r
 PeiHubEnumeration (\r
-  IN EFI_PEI_SERVICES               **PeiServices,\r
-  IN PEI_USB_DEVICE                 *PeiUsbDevice,\r
-  IN UINT8                          *CurrentAddress\r
+  IN EFI_PEI_SERVICES  **PeiServices,\r
+  IN PEI_USB_DEVICE    *PeiUsbDevice,\r
+  IN UINT8             *CurrentAddress\r
   )\r
 {\r
   UINTN                 Index;\r
@@ -222,62 +217,53 @@ PeiHubEnumeration (
   UINTN                 MemPages;\r
   EFI_PHYSICAL_ADDRESS  AllocateAddress;\r
   PEI_USB_DEVICE        *NewPeiUsbDevice;\r
+  UINTN                 InterfaceIndex;\r
+  UINTN                 EndpointIndex;\r
 \r
+  UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
 \r
-  UsbIoPpi    = &PeiUsbDevice->UsbIoPpi;\r
+  DEBUG ((DEBUG_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo));\r
 \r
   for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
-\r
     Status = PeiHubGetPortStatus (\r
-              PeiServices,\r
-              UsbIoPpi,\r
-              (UINT8) (Index + 1),\r
-              (UINT32 *) &PortStatus\r
-              );\r
+               PeiServices,\r
+               UsbIoPpi,\r
+               (UINT8)(Index + 1),\r
+               (UINT32 *)&PortStatus\r
+               );\r
 \r
     if (EFI_ERROR (Status)) {\r
       continue;\r
     }\r
 \r
-    if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
-      PeiHubClearPortFeature (\r
-        PeiServices,\r
-        UsbIoPpi,\r
-        (UINT8) (Index + 1),\r
-        EfiUsbPortConnectChange\r
-        );\r
-\r
-      MicroSecondDelay (100 * 1000);\r
-\r
+    DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
+    //\r
+    // Only handle connection/enable/overcurrent/reset change.\r
+    //\r
+    if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
+      continue;\r
+    } else {\r
       if (IsPortConnect (PortStatus.PortStatus)) {\r
-\r
-        PeiHubGetPortStatus (\r
-          PeiServices,\r
-          UsbIoPpi,\r
-          (UINT8) (Index + 1),\r
-          (UINT32 *) &PortStatus\r
-          );\r
-\r
         //\r
         // Begin to deal with the new device\r
         //\r
         MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
-        Status = PeiServicesAllocatePages (\r
-                   EfiBootServicesCode,\r
-                   MemPages,\r
-                   &AllocateAddress\r
-                   );\r
+        Status   = PeiServicesAllocatePages (\r
+                     EfiBootServicesCode,\r
+                     MemPages,\r
+                     &AllocateAddress\r
+                     );\r
         if (EFI_ERROR (Status)) {\r
           return EFI_OUT_OF_RESOURCES;\r
         }\r
 \r
-        NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);\r
+        NewPeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);\r
         ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));\r
 \r
-        NewPeiUsbDevice->Signature        = PEI_USB_DEVICE_SIGNATURE;\r
-        NewPeiUsbDevice->DeviceAddress    = 0;\r
-        NewPeiUsbDevice->MaxPacketSize0   = 8;\r
-        NewPeiUsbDevice->DataToggle       = 0;\r
+        NewPeiUsbDevice->Signature      = PEI_USB_DEVICE_SIGNATURE;\r
+        NewPeiUsbDevice->DeviceAddress  = 0;\r
+        NewPeiUsbDevice->MaxPacketSize0 = 8;\r
+        NewPeiUsbDevice->DataToggle     = 0;\r
         CopyMem (\r
           &(NewPeiUsbDevice->UsbIoPpi),\r
           &mUsbIoPpi,\r
@@ -289,50 +275,78 @@ PeiHubEnumeration (
           sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
           );\r
         NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;\r
-        NewPeiUsbDevice->AllocateAddress  = (UINTN) AllocateAddress;\r
+        NewPeiUsbDevice->AllocateAddress  = (UINTN)AllocateAddress;\r
         NewPeiUsbDevice->UsbHcPpi         = PeiUsbDevice->UsbHcPpi;\r
         NewPeiUsbDevice->Usb2HcPpi        = PeiUsbDevice->Usb2HcPpi;\r
+        NewPeiUsbDevice->Tier             = (UINT8)(PeiUsbDevice->Tier + 1);\r
         NewPeiUsbDevice->IsHub            = 0x0;\r
         NewPeiUsbDevice->DownStreamPortNo = 0x0;\r
 \r
-        PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+        if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||\r
+            ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0))\r
+        {\r
+          //\r
+          // If the port already has reset change flag and is connected and enabled, skip the port reset logic.\r
+          //\r
+          PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+\r
+          PeiHubGetPortStatus (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            (UINT8)(Index + 1),\r
+            (UINT32 *)&PortStatus\r
+            );\r
+        } else {\r
+          PeiHubClearPortFeature (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            (UINT8)(Index + 1),\r
+            EfiUsbPortResetChange\r
+            );\r
+        }\r
 \r
-        PeiHubGetPortStatus (\r
-           PeiServices,\r
-           UsbIoPpi,\r
-           (UINT8) (Index + 1),\r
-           (UINT32 *) &PortStatus\r
-           );\r
+        NewPeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus);\r
+        DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));\r
 \r
-        NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
+        if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {\r
+          NewPeiUsbDevice->MaxPacketSize0 = 512;\r
+        } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {\r
+          NewPeiUsbDevice->MaxPacketSize0 = 64;\r
+        } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
+          NewPeiUsbDevice->MaxPacketSize0 = 8;\r
+        } else {\r
+          NewPeiUsbDevice->MaxPacketSize0 = 8;\r
+        }\r
 \r
-        if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {\r
-           if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
-             NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index;\r
-             NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress;\r
-           } else {\r
-               CopyMem(&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof(EFI_USB2_HC_TRANSACTION_TRANSLATOR));\r
+        if (NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {\r
+          if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+            NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index;\r
+            NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress;\r
+          } else {\r
+            CopyMem (&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof (EFI_USB2_HC_TRANSACTION_TRANSLATOR));\r
           }\r
-       }\r
+        }\r
 \r
         //\r
         // Configure that Usb Device\r
         //\r
         Status = PeiConfigureUsbDevice (\r
-                  PeiServices,\r
-                  NewPeiUsbDevice,\r
-                  (UINT8) (Index + 1),\r
-                  CurrentAddress\r
-                  );\r
+                   PeiServices,\r
+                   NewPeiUsbDevice,\r
+                   (UINT8)(Index + 1),\r
+                   CurrentAddress\r
+                   );\r
 \r
         if (EFI_ERROR (Status)) {\r
           continue;\r
         }\r
 \r
+        DEBUG ((DEBUG_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n"));\r
+\r
         Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);\r
 \r
         if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {\r
-          NewPeiUsbDevice->IsHub  = 0x1;\r
+          NewPeiUsbDevice->IsHub = 0x1;\r
 \r
           Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);\r
           if (EFI_ERROR (Status)) {\r
@@ -341,18 +355,53 @@ PeiHubEnumeration (
 \r
           PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);\r
         }\r
-      }\r
 \r
+        for (InterfaceIndex = 1; InterfaceIndex < NewPeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {\r
+          //\r
+          // Begin to deal with the new device\r
+          //\r
+          MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
+          Status   = PeiServicesAllocatePages (\r
+                       EfiBootServicesCode,\r
+                       MemPages,\r
+                       &AllocateAddress\r
+                       );\r
+          if (EFI_ERROR (Status)) {\r
+            return EFI_OUT_OF_RESOURCES;\r
+          }\r
+\r
+          CopyMem ((VOID *)(UINTN)AllocateAddress, NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));\r
+          NewPeiUsbDevice                   = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);\r
+          NewPeiUsbDevice->AllocateAddress  = (UINTN)AllocateAddress;\r
+          NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;\r
+          NewPeiUsbDevice->InterfaceDesc    = NewPeiUsbDevice->InterfaceDescList[InterfaceIndex];\r
+          for (EndpointIndex = 0; EndpointIndex < NewPeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {\r
+            NewPeiUsbDevice->EndpointDesc[EndpointIndex] = NewPeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];\r
+          }\r
+\r
+          Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);\r
+\r
+          if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {\r
+            NewPeiUsbDevice->IsHub = 0x1;\r
+\r
+            Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);\r
+            if (EFI_ERROR (Status)) {\r
+              return Status;\r
+            }\r
+\r
+            PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);\r
+          }\r
+        }\r
+      }\r
     }\r
   }\r
 \r
-\r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
   The enumeration routine to detect device change.\r
-  \r
+\r
   @param  PeiServices            Describes the list of possible PEI Services.\r
   @param  UsbHcPpi               The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
   @param  Usb2HcPpi              The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
@@ -364,9 +413,9 @@ PeiHubEnumeration (
 **/\r
 EFI_STATUS\r
 PeiUsbEnumeration (\r
-  IN EFI_PEI_SERVICES               **PeiServices,\r
-  IN PEI_USB_HOST_CONTROLLER_PPI    *UsbHcPpi,\r
-  IN PEI_USB2_HOST_CONTROLLER_PPI   *Usb2HcPpi\r
+  IN EFI_PEI_SERVICES              **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI   *UsbHcPpi,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI  *Usb2HcPpi\r
   )\r
 {\r
   UINT8                 NumOfRootPort;\r
@@ -377,101 +426,74 @@ PeiUsbEnumeration (
   UINTN                 MemPages;\r
   EFI_PHYSICAL_ADDRESS  AllocateAddress;\r
   UINT8                 CurrentAddress;\r
-\r
+  UINTN                 InterfaceIndex;\r
+  UINTN                 EndpointIndex;\r
 \r
   CurrentAddress = 0;\r
-  if (Usb2HcPpi != NULL){\r
+  if (Usb2HcPpi != NULL) {\r
     Usb2HcPpi->GetRootHubPortNumber (\r
-                PeiServices,\r
-                Usb2HcPpi,\r
-                (UINT8 *) &NumOfRootPort\r
-                );    \r
-  } else {\r
+                 PeiServices,\r
+                 Usb2HcPpi,\r
+                 (UINT8 *)&NumOfRootPort\r
+                 );\r
+  } else if (UsbHcPpi != NULL) {\r
     UsbHcPpi->GetRootHubPortNumber (\r
                 PeiServices,\r
                 UsbHcPpi,\r
-                (UINT8 *) &NumOfRootPort\r
+                (UINT8 *)&NumOfRootPort\r
                 );\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));\r
+\r
   for (Index = 0; Index < NumOfRootPort; Index++) {\r
     //\r
     // First get root port status to detect changes happen\r
     //\r
     if (Usb2HcPpi != NULL) {\r
       Usb2HcPpi->GetRootHubPortStatus (\r
-                  PeiServices,\r
-                  Usb2HcPpi,\r
-                  (UINT8) Index,\r
-                  &PortStatus\r
-                  );      \r
+                   PeiServices,\r
+                   Usb2HcPpi,\r
+                   (UINT8)Index,\r
+                   &PortStatus\r
+                   );\r
     } else {\r
       UsbHcPpi->GetRootHubPortStatus (\r
                   PeiServices,\r
                   UsbHcPpi,\r
-                  (UINT8) Index,\r
+                  (UINT8)Index,\r
                   &PortStatus\r
                   );\r
     }\r
-    DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
-    if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
-      //\r
-      // Changes happen, first clear this change status\r
-      //\r
-      if (Usb2HcPpi != NULL) {\r
-        Usb2HcPpi->ClearRootHubPortFeature (\r
-                    PeiServices,\r
-                    Usb2HcPpi,\r
-                    (UINT8) Index,\r
-                    EfiUsbPortConnectChange\r
-                    );        \r
-      } else {\r
-        UsbHcPpi->ClearRootHubPortFeature (\r
-                    PeiServices,\r
-                    UsbHcPpi,\r
-                    (UINT8) Index,\r
-                    EfiUsbPortConnectChange\r
-                    );\r
-      }\r
-      MicroSecondDelay (100 * 1000);\r
 \r
+    DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
+    //\r
+    // Only handle connection/enable/overcurrent/reset change.\r
+    //\r
+    if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
+      continue;\r
+    } else {\r
       if (IsPortConnect (PortStatus.PortStatus)) {\r
-        if (Usb2HcPpi != NULL) {\r
-          Usb2HcPpi->GetRootHubPortStatus (\r
-                      PeiServices,\r
-                      Usb2HcPpi,\r
-                      (UINT8) Index,\r
-                      &PortStatus\r
-                      );\r
-        } else {\r
-          UsbHcPpi->GetRootHubPortStatus (\r
-                      PeiServices,\r
-                      UsbHcPpi,\r
-                      (UINT8) Index,\r
-                      &PortStatus\r
-                      );\r
-        }\r
-\r
-        //\r
-        // Connect change happen\r
-        //\r
         MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
-        Status = PeiServicesAllocatePages (\r
-                   EfiBootServicesCode,\r
-                   MemPages,\r
-                   &AllocateAddress\r
-                   );\r
+        Status   = PeiServicesAllocatePages (\r
+                     EfiBootServicesCode,\r
+                     MemPages,\r
+                     &AllocateAddress\r
+                     );\r
         if (EFI_ERROR (Status)) {\r
           return EFI_OUT_OF_RESOURCES;\r
         }\r
 \r
-        PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);\r
+        PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);\r
         ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));\r
 \r
-        PeiUsbDevice->Signature         = PEI_USB_DEVICE_SIGNATURE;\r
-        PeiUsbDevice->DeviceAddress     = 0;\r
-        PeiUsbDevice->MaxPacketSize0    = 8;\r
-        PeiUsbDevice->DataToggle        = 0;\r
+        PeiUsbDevice->Signature      = PEI_USB_DEVICE_SIGNATURE;\r
+        PeiUsbDevice->DeviceAddress  = 0;\r
+        PeiUsbDevice->MaxPacketSize0 = 8;\r
+        PeiUsbDevice->DataToggle     = 0;\r
         CopyMem (\r
           &(PeiUsbDevice->UsbIoPpi),\r
           &mUsbIoPpi,\r
@@ -482,54 +504,88 @@ PeiUsbEnumeration (
           &mUsbIoPpiList,\r
           sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
           );\r
-        PeiUsbDevice->UsbIoPpiList.Ppi  = &PeiUsbDevice->UsbIoPpi;\r
-        PeiUsbDevice->AllocateAddress   = (UINTN) AllocateAddress;\r
-        PeiUsbDevice->UsbHcPpi          = UsbHcPpi;\r
-        PeiUsbDevice->Usb2HcPpi         = Usb2HcPpi;\r
-        PeiUsbDevice->IsHub             = 0x0;\r
-        PeiUsbDevice->DownStreamPortNo  = 0x0;\r
-\r
-        ResetRootPort (\r
-          PeiServices,\r
-          PeiUsbDevice->UsbHcPpi,\r
-          PeiUsbDevice->Usb2HcPpi,\r
-          Index,\r
-          0\r
-          );\r
+        PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;\r
+        PeiUsbDevice->AllocateAddress  = (UINTN)AllocateAddress;\r
+        PeiUsbDevice->UsbHcPpi         = UsbHcPpi;\r
+        PeiUsbDevice->Usb2HcPpi        = Usb2HcPpi;\r
+        PeiUsbDevice->IsHub            = 0x0;\r
+        PeiUsbDevice->DownStreamPortNo = 0x0;\r
+\r
+        if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||\r
+            ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0))\r
+        {\r
+          //\r
+          // If the port already has reset change flag and is connected and enabled, skip the port reset logic.\r
+          //\r
+          ResetRootPort (\r
+            PeiServices,\r
+            PeiUsbDevice->UsbHcPpi,\r
+            PeiUsbDevice->Usb2HcPpi,\r
+            Index,\r
+            0\r
+            );\r
 \r
-        if (Usb2HcPpi != NULL) {\r
-          Usb2HcPpi->GetRootHubPortStatus (\r
-                      PeiServices,\r
-                      Usb2HcPpi,\r
-                      (UINT8) Index,\r
-                      &PortStatus\r
-                      );\r
+          if (Usb2HcPpi != NULL) {\r
+            Usb2HcPpi->GetRootHubPortStatus (\r
+                         PeiServices,\r
+                         Usb2HcPpi,\r
+                         (UINT8)Index,\r
+                         &PortStatus\r
+                         );\r
+          } else {\r
+            UsbHcPpi->GetRootHubPortStatus (\r
+                        PeiServices,\r
+                        UsbHcPpi,\r
+                        (UINT8)Index,\r
+                        &PortStatus\r
+                        );\r
+          }\r
         } else {\r
-          UsbHcPpi->GetRootHubPortStatus (\r
-                      PeiServices,\r
-                      UsbHcPpi,\r
-                      (UINT8) Index,\r
-                      &PortStatus\r
-                      );\r
+          if (Usb2HcPpi != NULL) {\r
+            Usb2HcPpi->ClearRootHubPortFeature (\r
+                         PeiServices,\r
+                         Usb2HcPpi,\r
+                         (UINT8)Index,\r
+                         EfiUsbPortResetChange\r
+                         );\r
+          } else {\r
+            UsbHcPpi->ClearRootHubPortFeature (\r
+                        PeiServices,\r
+                        UsbHcPpi,\r
+                        (UINT8)Index,\r
+                        EfiUsbPortResetChange\r
+                        );\r
+          }\r
         }\r
 \r
-        PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
-        DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));\r
+        PeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus);\r
+        DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));\r
+\r
+        if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {\r
+          PeiUsbDevice->MaxPacketSize0 = 512;\r
+        } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {\r
+          PeiUsbDevice->MaxPacketSize0 = 64;\r
+        } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
+          PeiUsbDevice->MaxPacketSize0 = 8;\r
+        } else {\r
+          PeiUsbDevice->MaxPacketSize0 = 8;\r
+        }\r
 \r
         //\r
         // Configure that Usb Device\r
         //\r
         Status = PeiConfigureUsbDevice (\r
-                  PeiServices,\r
-                  PeiUsbDevice,\r
-                  Index,\r
-                  &CurrentAddress\r
-                  );\r
+                   PeiServices,\r
+                   PeiUsbDevice,\r
+                   Index,\r
+                   &CurrentAddress\r
+                   );\r
 \r
         if (EFI_ERROR (Status)) {\r
           continue;\r
         }\r
-        DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n"));\r
+\r
+        DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));\r
 \r
         Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);\r
 \r
@@ -543,6 +599,43 @@ PeiUsbEnumeration (
 \r
           PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);\r
         }\r
+\r
+        for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {\r
+          //\r
+          // Begin to deal with the new device\r
+          //\r
+          MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
+          Status   = PeiServicesAllocatePages (\r
+                       EfiBootServicesCode,\r
+                       MemPages,\r
+                       &AllocateAddress\r
+                       );\r
+          if (EFI_ERROR (Status)) {\r
+            return EFI_OUT_OF_RESOURCES;\r
+          }\r
+\r
+          CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE));\r
+          PeiUsbDevice                   = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);\r
+          PeiUsbDevice->AllocateAddress  = (UINTN)AllocateAddress;\r
+          PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;\r
+          PeiUsbDevice->InterfaceDesc    = PeiUsbDevice->InterfaceDescList[InterfaceIndex];\r
+          for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {\r
+            PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];\r
+          }\r
+\r
+          Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);\r
+\r
+          if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {\r
+            PeiUsbDevice->IsHub = 0x1;\r
+\r
+            Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);\r
+            if (EFI_ERROR (Status)) {\r
+              return Status;\r
+            }\r
+\r
+            PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);\r
+          }\r
+        }\r
       } else {\r
         //\r
         // Disconnect change happen, currently we don't support\r
@@ -556,7 +649,7 @@ PeiUsbEnumeration (
 \r
 /**\r
   Configure new detected usb device.\r
-  \r
+\r
   @param  PeiServices            Describes the list of possible PEI Services.\r
   @param  PeiUsbDevice           The pointer of PEI_USB_DEVICE instance.\r
   @param  Port                   The port to be configured.\r
@@ -569,16 +662,16 @@ PeiUsbEnumeration (
 **/\r
 EFI_STATUS\r
 PeiConfigureUsbDevice (\r
-  IN EFI_PEI_SERVICES   **PeiServices,\r
-  IN PEI_USB_DEVICE     *PeiUsbDevice,\r
-  IN UINT8              Port,\r
-  IN OUT UINT8          *DeviceAddress\r
+  IN EFI_PEI_SERVICES  **PeiServices,\r
+  IN PEI_USB_DEVICE    *PeiUsbDevice,\r
+  IN UINT8             Port,\r
+  IN OUT UINT8         *DeviceAddress\r
   )\r
 {\r
-  EFI_USB_DEVICE_DESCRIPTOR   DeviceDescriptor;\r
-  EFI_STATUS                  Status;\r
-  PEI_USB_IO_PPI              *UsbIoPpi;\r
-  UINT8                       Retry;\r
+  EFI_USB_DEVICE_DESCRIPTOR  DeviceDescriptor;\r
+  EFI_STATUS                 Status;\r
+  PEI_USB_IO_PPI             *UsbIoPpi;\r
+  UINT8                      Retry;\r
 \r
   UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
   Status   = EFI_SUCCESS;\r
@@ -587,10 +680,7 @@ PeiConfigureUsbDevice (
   // Get USB device descriptor\r
   //\r
 \r
-  for (Retry = 0; Retry < 3; Retry ++) {\r
-\r
-    PeiUsbDevice->MaxPacketSize0 = 8;\r
-\r
+  for (Retry = 0; Retry < 3; Retry++) {\r
     Status = PeiUsbGetDescriptor (\r
                PeiServices,\r
                UsbIoPpi,\r
@@ -601,65 +691,73 @@ PeiConfigureUsbDevice (
                );\r
 \r
     if (!EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry));\r
+      DEBUG ((DEBUG_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry));\r
       break;\r
     }\r
   }\r
 \r
   if (Retry == 3) {\r
-    DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry));\r
+    DEBUG ((DEBUG_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status));\r
     return Status;\r
   }\r
 \r
-  PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;\r
+  if ((DeviceDescriptor.BcdUSB >= 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) {\r
+    PeiUsbDevice->MaxPacketSize0 = 1 << 9;\r
+  } else {\r
+    PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;\r
+  }\r
 \r
-  (*DeviceAddress) ++;\r
+  (*DeviceAddress)++;\r
 \r
   Status = PeiUsbSetDeviceAddress (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            *DeviceAddress\r
-            );\r
+             PeiServices,\r
+             UsbIoPpi,\r
+             *DeviceAddress\r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n"));\r
+    DEBUG ((DEBUG_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status));\r
     return Status;\r
   }\r
 \r
+  MicroSecondDelay (USB_SET_DEVICE_ADDRESS_STALL);\r
+\r
   PeiUsbDevice->DeviceAddress = *DeviceAddress;\r
 \r
   //\r
   // Get whole USB device descriptor\r
   //\r
   Status = PeiUsbGetDescriptor (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            (USB_DT_DEVICE << 8),\r
-            0,\r
-            (UINT16) sizeof (EFI_USB_DEVICE_DESCRIPTOR),\r
-            &DeviceDescriptor\r
-            );\r
+             PeiServices,\r
+             UsbIoPpi,\r
+             (USB_DT_DEVICE << 8),\r
+             0,\r
+             (UINT16)sizeof (EFI_USB_DEVICE_DESCRIPTOR),\r
+             &DeviceDescriptor\r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n"));\r
+    DEBUG ((DEBUG_ERROR, "PeiUsbGetDescriptor First Failed\n"));\r
     return Status;\r
   }\r
+\r
   //\r
   // Get its default configuration and its first interface\r
   //\r
   Status = PeiUsbGetAllConfiguration (\r
-            PeiServices,\r
-            PeiUsbDevice\r
-            );\r
-\r
+             PeiServices,\r
+             PeiUsbDevice\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
+  MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL);\r
+\r
   Status = PeiUsbSetConfiguration (\r
-            PeiServices,\r
-            UsbIoPpi\r
-            );\r
+             PeiServices,\r
+             UsbIoPpi\r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -670,7 +768,7 @@ PeiConfigureUsbDevice (
 \r
 /**\r
   Get all configurations from a detected usb device.\r
-  \r
+\r
   @param  PeiServices            Describes the list of possible PEI Services.\r
   @param  PeiUsbDevice           The pointer of PEI_USB_DEVICE instance.\r
 \r
@@ -681,19 +779,20 @@ PeiConfigureUsbDevice (
 **/\r
 EFI_STATUS\r
 PeiUsbGetAllConfiguration (\r
-  IN EFI_PEI_SERVICES   **PeiServices,\r
-  IN PEI_USB_DEVICE     *PeiUsbDevice\r
+  IN EFI_PEI_SERVICES  **PeiServices,\r
+  IN PEI_USB_DEVICE    *PeiUsbDevice\r
   )\r
 {\r
-  EFI_STATUS                Status;\r
-  EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;\r
-  PEI_USB_IO_PPI            *UsbIoPpi;\r
-  UINT16                    ConfigDescLength;\r
-  UINT8                     *Ptr;\r
-  UINTN                     SkipBytes;\r
-  UINTN                     LengthLeft;\r
-  UINTN                     Index;\r
-  UINTN                     NumOfEndpoint;\r
+  EFI_STATUS                 Status;\r
+  EFI_USB_CONFIG_DESCRIPTOR  *ConfigDesc;\r
+  PEI_USB_IO_PPI             *UsbIoPpi;\r
+  UINT16                     ConfigDescLength;\r
+  UINT8                      *Ptr;\r
+  UINTN                      SkipBytes;\r
+  UINTN                      LengthLeft;\r
+  UINTN                      InterfaceIndex;\r
+  UINTN                      Index;\r
+  UINTN                      NumOfEndpoint;\r
 \r
   UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
 \r
@@ -701,110 +800,137 @@ PeiUsbGetAllConfiguration (
   // First get its 4-byte configuration descriptor\r
   //\r
   Status = PeiUsbGetDescriptor (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            (USB_DT_CONFIG << 8), // Value\r
-            0,      // Index\r
-            4,      // Length\r
-            PeiUsbDevice->ConfigurationData\r
-            );\r
+             PeiServices,\r
+             UsbIoPpi,\r
+             (USB_DT_CONFIG << 8), // Value\r
+             0,                    // Index\r
+             4,                    // Length\r
+             PeiUsbDevice->ConfigurationData\r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));\r
+    DEBUG ((DEBUG_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));\r
     return Status;\r
   }\r
 \r
-  ConfigDesc        = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData;\r
-  ConfigDescLength  = ConfigDesc->TotalLength;\r
+  MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL);\r
+\r
+  ConfigDesc       = (EFI_USB_CONFIG_DESCRIPTOR *)PeiUsbDevice->ConfigurationData;\r
+  ConfigDescLength = ConfigDesc->TotalLength;\r
 \r
   //\r
-  // Then we get the total descriptors for this configuration\r
+  // Reject if TotalLength even cannot cover itself.\r
   //\r
-  Status = PeiUsbGetDescriptor (\r
-            PeiServices,\r
-            UsbIoPpi,\r
-            (USB_DT_CONFIG << 8),\r
-            0,\r
-            ConfigDescLength,\r
-            PeiUsbDevice->ConfigurationData\r
-            );\r
+  if (ConfigDescLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (ConfigDesc->TotalLength)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));\r
-    return Status;\r
+  //\r
+  // Reject if TotalLength exceeds the PeiUsbDevice->ConfigurationData.\r
+  //\r
+  if (ConfigDescLength > sizeof (PeiUsbDevice->ConfigurationData)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
+\r
   //\r
-  // Parse this configuration descriptor\r
-  // First get the current config descriptor;\r
+  // Then we get the total descriptors for this configuration\r
   //\r
-  Status = GetExpectedDescriptor (\r
-            PeiUsbDevice->ConfigurationData,\r
-            ConfigDescLength,\r
-            USB_DT_CONFIG,\r
-            (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR),\r
-            &SkipBytes\r
-            );\r
+  Status = PeiUsbGetDescriptor (\r
+             PeiServices,\r
+             UsbIoPpi,\r
+             (USB_DT_CONFIG << 8),\r
+             0,\r
+             ConfigDescLength,\r
+             PeiUsbDevice->ConfigurationData\r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));\r
     return Status;\r
   }\r
 \r
-  Ptr                       = PeiUsbDevice->ConfigurationData + SkipBytes;\r
-  PeiUsbDevice->ConfigDesc  = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr;\r
-\r
-  Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
-  LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
-\r
   //\r
-  // Get the first interface descriptor\r
+  // Parse this configuration descriptor\r
+  // First get the current config descriptor;\r
   //\r
   Status = GetExpectedDescriptor (\r
-            Ptr,\r
-            LengthLeft,\r
-            USB_DT_INTERFACE,\r
-            (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR),\r
-            &SkipBytes\r
-            );\r
+             PeiUsbDevice->ConfigurationData,\r
+             ConfigDescLength,\r
+             USB_DT_CONFIG,\r
+             (UINT8)sizeof (EFI_USB_CONFIG_DESCRIPTOR),\r
+             &SkipBytes\r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Ptr += SkipBytes;\r
-  PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;\r
+  Ptr                      = PeiUsbDevice->ConfigurationData + SkipBytes;\r
+  PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *)Ptr;\r
 \r
-  Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
-  LengthLeft -= SkipBytes;\r
-  LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
-\r
-  //\r
-  // Parse all the endpoint descriptor within this interface\r
-  //\r
-  NumOfEndpoint = PeiUsbDevice->InterfaceDesc->NumEndpoints;\r
-  ASSERT (NumOfEndpoint <= MAX_ENDPOINT);\r
+  Ptr       += sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
+  LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
 \r
-  for (Index = 0; Index < NumOfEndpoint; Index++) {\r
+  for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {\r
     //\r
-    // Get the endpoint descriptor\r
+    // Get the interface descriptor\r
     //\r
     Status = GetExpectedDescriptor (\r
-              Ptr,\r
-              LengthLeft,\r
-              USB_DT_ENDPOINT,\r
-              (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),\r
-              &SkipBytes\r
-              );\r
+               Ptr,\r
+               LengthLeft,\r
+               USB_DT_INTERFACE,\r
+               (UINT8)sizeof (EFI_USB_INTERFACE_DESCRIPTOR),\r
+               &SkipBytes\r
+               );\r
 \r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
 \r
     Ptr += SkipBytes;\r
-    PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;\r
+    if (InterfaceIndex == 0) {\r
+      PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *)Ptr;\r
+    }\r
+\r
+    PeiUsbDevice->InterfaceDescList[InterfaceIndex] = (EFI_USB_INTERFACE_DESCRIPTOR *)Ptr;\r
 \r
-    Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+    Ptr        += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
     LengthLeft -= SkipBytes;\r
-    LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+    LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
+\r
+    //\r
+    // Parse all the endpoint descriptor within this interface\r
+    //\r
+    NumOfEndpoint = PeiUsbDevice->InterfaceDescList[InterfaceIndex]->NumEndpoints;\r
+    ASSERT (NumOfEndpoint <= MAX_ENDPOINT);\r
+\r
+    for (Index = 0; Index < NumOfEndpoint; Index++) {\r
+      //\r
+      // Get the endpoint descriptor\r
+      //\r
+      Status = GetExpectedDescriptor (\r
+                 Ptr,\r
+                 LengthLeft,\r
+                 USB_DT_ENDPOINT,\r
+                 (UINT8)sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),\r
+                 &SkipBytes\r
+                 );\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      Ptr += SkipBytes;\r
+      if (InterfaceIndex == 0) {\r
+        PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *)Ptr;\r
+      }\r
+\r
+      PeiUsbDevice->EndpointDescList[InterfaceIndex][Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *)Ptr;\r
+\r
+      Ptr        += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+      LengthLeft -= SkipBytes;\r
+      LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+    }\r
   }\r
 \r
   return EFI_SUCCESS;\r
@@ -812,7 +938,7 @@ PeiUsbGetAllConfiguration (
 \r
 /**\r
   Get the start position of next wanted descriptor.\r
-  \r
+\r
   @param  Buffer            Buffer containing data to parse.\r
   @param  Length            Buffer length.\r
   @param  DescType          Descriptor type.\r
@@ -825,72 +951,77 @@ PeiUsbGetAllConfiguration (
 **/\r
 EFI_STATUS\r
 GetExpectedDescriptor (\r
-  IN  UINT8       *Buffer,\r
-  IN  UINTN       Length,\r
-  IN  UINT8       DescType,\r
-  IN  UINT8       DescLength,\r
-  OUT UINTN       *ParsedBytes\r
+  IN  UINT8  *Buffer,\r
+  IN  UINTN  Length,\r
+  IN  UINT8  DescType,\r
+  IN  UINT8  DescLength,\r
+  OUT UINTN  *ParsedBytes\r
   )\r
 {\r
-  UINT16  DescriptorHeader;\r
-  UINT8   Len;\r
-  UINT8   *Ptr;\r
-  UINTN   Parsed;\r
+  USB_DESC_HEAD  *Head;\r
+  UINTN          Offset;\r
 \r
-  Parsed  = 0;\r
-  Ptr     = Buffer;\r
+  //\r
+  // Total length is too small that cannot hold the single descriptor header plus data.\r
+  //\r
+  if (Length <= sizeof (USB_DESC_HEAD)) {\r
+    DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, total length = %d!\n", Length));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
-  while (TRUE) {\r
+  //\r
+  // All the descriptor has a common LTV (Length, Type, Value)\r
+  // format. Skip the descriptor that isn't of this Type\r
+  //\r
+  Offset = 0;\r
+  Head   = (USB_DESC_HEAD *)Buffer;\r
+  while (Offset < Length - sizeof (USB_DESC_HEAD)) {\r
     //\r
-    // Buffer length should not less than Desc length\r
+    // Above condition make sure Head->Len and Head->Type are safe to access\r
     //\r
-    if (Length < DescLength) {\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
-\r
-    DescriptorHeader  = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8));\r
-\r
-    Len               = Buffer[0];\r
+    Head = (USB_DESC_HEAD *)&Buffer[Offset];\r
 \r
-    //\r
-    // Check to see if it is a start of expected descriptor\r
-    //\r
-    if (DescriptorHeader == ((DescType << 8) | DescLength)) {\r
-      break;\r
+    if (Head->Len == 0) {\r
+      DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = 0!\n"));\r
+      return EFI_DEVICE_ERROR;\r
     }\r
 \r
-    if ((UINT8) (DescriptorHeader >> 8) == DescType) {\r
-      if (Len > DescLength) {\r
-        return EFI_DEVICE_ERROR;\r
-      }\r
-    }\r
     //\r
-    // Descriptor length should be at least 2\r
-    // and should not exceed the buffer length\r
+    // Make sure no overflow when adding Head->Len to Offset.\r
     //\r
-    if (Len < 2) {\r
+    if (Head->Len > MAX_UINTN - Offset) {\r
+      DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = %d!\n", Head->Len));\r
       return EFI_DEVICE_ERROR;\r
     }\r
 \r
-    if (Len > Length) {\r
-      return EFI_DEVICE_ERROR;\r
+    if (Head->Type == DescType) {\r
+      break;\r
     }\r
-    //\r
-    // Skip this mismatch descriptor\r
-    //\r
-    Length -= Len;\r
-    Ptr += Len;\r
-    Parsed += Len;\r
+\r
+    Offset += Head->Len;\r
+  }\r
+\r
+  //\r
+  // Head->Len is invalid resulting data beyond boundary, or\r
+  // Descriptor cannot be found: No such type.\r
+  //\r
+  if (Length < Offset) {\r
+    DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Length));\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  *ParsedBytes = Parsed;\r
+  if ((Head->Type != DescType) || (Head->Len < DescLength)) {\r
+    DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
+  *ParsedBytes = Offset;\r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
   Send reset signal over the given root hub port.\r
-  \r
+\r
   @param  PeiServices       Describes the list of possible PEI Services.\r
   @param  UsbHcPpi          The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
   @param  Usb2HcPpi         The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
@@ -900,81 +1031,122 @@ GetExpectedDescriptor (
 **/\r
 VOID\r
 ResetRootPort (\r
-  IN EFI_PEI_SERVICES               **PeiServices,\r
-  IN PEI_USB_HOST_CONTROLLER_PPI    *UsbHcPpi,\r
-  IN PEI_USB2_HOST_CONTROLLER_PPI   *Usb2HcPpi,\r
-  IN UINT8                          PortNum,\r
-  IN UINT8                          RetryIndex\r
+  IN EFI_PEI_SERVICES              **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI   *UsbHcPpi,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI  *Usb2HcPpi,\r
+  IN UINT8                         PortNum,\r
+  IN UINT8                         RetryIndex\r
   )\r
 {\r
-  EFI_STATUS             Status;\r
-\r
+  EFI_STATUS           Status;\r
+  UINTN                Index;\r
+  EFI_USB_PORT_STATUS  PortStatus;\r
 \r
   if (Usb2HcPpi != NULL) {\r
     MicroSecondDelay (200 * 1000);\r
-    \r
+\r
     //\r
     // reset root port\r
     //\r
     Status = Usb2HcPpi->SetRootHubPortFeature (\r
-                         PeiServices,\r
-                         Usb2HcPpi,\r
-                         PortNum,\r
-                         EfiUsbPortReset\r
-                         );\r
-    \r
+                          PeiServices,\r
+                          Usb2HcPpi,\r
+                          PortNum,\r
+                          EfiUsbPortReset\r
+                          );\r
+\r
     if (EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+      DEBUG ((DEBUG_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
       return;\r
     }\r
-    \r
-    MicroSecondDelay (200 * 1000);\r
-    \r
+\r
+    //\r
+    // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
+    // section 7.1.7.5 for timing requirements.\r
+    //\r
+    MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);\r
+\r
     //\r
     // clear reset root port\r
     //\r
     Status = Usb2HcPpi->ClearRootHubPortFeature (\r
-                         PeiServices,\r
-                         Usb2HcPpi,\r
-                         PortNum,\r
-                         EfiUsbPortReset\r
-                         );\r
-    \r
+                          PeiServices,\r
+                          Usb2HcPpi,\r
+                          PortNum,\r
+                          EfiUsbPortReset\r
+                          );\r
+\r
     if (EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+      DEBUG ((DEBUG_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+      return;\r
+    }\r
+\r
+    MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);\r
+\r
+    //\r
+    // USB host controller won't clear the RESET bit until\r
+    // reset is actually finished.\r
+    //\r
+    ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+    for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
+      Status = Usb2HcPpi->GetRootHubPortStatus (\r
+                            PeiServices,\r
+                            Usb2HcPpi,\r
+                            PortNum,\r
+                            &PortStatus\r
+                            );\r
+      if (EFI_ERROR (Status)) {\r
+        return;\r
+      }\r
+\r
+      if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {\r
+        break;\r
+      }\r
+\r
+      MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);\r
+    }\r
+\r
+    if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
+      DEBUG ((DEBUG_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));\r
       return;\r
     }\r
-    \r
-    MicroSecondDelay (1 * 1000);\r
-    \r
+\r
     Usb2HcPpi->ClearRootHubPortFeature (\r
-                PeiServices,\r
-                Usb2HcPpi,\r
-                PortNum,\r
-                EfiUsbPortConnectChange\r
-                );\r
-    \r
+                 PeiServices,\r
+                 Usb2HcPpi,\r
+                 PortNum,\r
+                 EfiUsbPortResetChange\r
+                 );\r
+\r
+    Usb2HcPpi->ClearRootHubPortFeature (\r
+                 PeiServices,\r
+                 Usb2HcPpi,\r
+                 PortNum,\r
+                 EfiUsbPortConnectChange\r
+                 );\r
+\r
     //\r
     // Set port enable\r
     //\r
-    Usb2HcPpi->SetRootHubPortFeature(\r
-                PeiServices,\r
-                Usb2HcPpi,\r
-                PortNum,\r
-                EfiUsbPortEnable\r
-                );\r
-    \r
+    Usb2HcPpi->SetRootHubPortFeature (\r
+                 PeiServices,\r
+                 Usb2HcPpi,\r
+                 PortNum,\r
+                 EfiUsbPortEnable\r
+                 );\r
+\r
     Usb2HcPpi->ClearRootHubPortFeature (\r
-                PeiServices,\r
-                Usb2HcPpi,\r
-                PortNum,\r
-                EfiUsbPortEnableChange\r
-                );\r
-    \r
+                 PeiServices,\r
+                 Usb2HcPpi,\r
+                 PortNum,\r
+                 EfiUsbPortEnableChange\r
+                 );\r
+\r
     MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);\r
   } else {\r
     MicroSecondDelay (200 * 1000);\r
-    \r
+\r
     //\r
     // reset root port\r
     //\r
@@ -984,14 +1156,18 @@ ResetRootPort (
                          PortNum,\r
                          EfiUsbPortReset\r
                          );\r
-    \r
+\r
     if (EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+      DEBUG ((DEBUG_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
       return;\r
     }\r
-    \r
-    MicroSecondDelay (200 * 1000);\r
-    \r
+\r
+    //\r
+    // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
+    // section 7.1.7.5 for timing requirements.\r
+    //\r
+    MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL);\r
+\r
     //\r
     // clear reset root port\r
     //\r
@@ -1001,41 +1177,76 @@ ResetRootPort (
                          PortNum,\r
                          EfiUsbPortReset\r
                          );\r
-    \r
+\r
     if (EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+      DEBUG ((DEBUG_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+      return;\r
+    }\r
+\r
+    MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL);\r
+\r
+    //\r
+    // USB host controller won't clear the RESET bit until\r
+    // reset is actually finished.\r
+    //\r
+    ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+    for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {\r
+      Status = UsbHcPpi->GetRootHubPortStatus (\r
+                           PeiServices,\r
+                           UsbHcPpi,\r
+                           PortNum,\r
+                           &PortStatus\r
+                           );\r
+      if (EFI_ERROR (Status)) {\r
+        return;\r
+      }\r
+\r
+      if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) {\r
+        break;\r
+      }\r
+\r
+      MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL);\r
+    }\r
+\r
+    if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {\r
+      DEBUG ((DEBUG_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum));\r
       return;\r
     }\r
-    \r
-    MicroSecondDelay (1 * 1000);\r
-    \r
+\r
+    UsbHcPpi->ClearRootHubPortFeature (\r
+                PeiServices,\r
+                UsbHcPpi,\r
+                PortNum,\r
+                EfiUsbPortResetChange\r
+                );\r
+\r
     UsbHcPpi->ClearRootHubPortFeature (\r
                 PeiServices,\r
                 UsbHcPpi,\r
                 PortNum,\r
                 EfiUsbPortConnectChange\r
                 );\r
-    \r
+\r
     //\r
     // Set port enable\r
     //\r
-    UsbHcPpi->SetRootHubPortFeature(\r
+    UsbHcPpi->SetRootHubPortFeature (\r
                 PeiServices,\r
                 UsbHcPpi,\r
                 PortNum,\r
                 EfiUsbPortEnable\r
                 );\r
-    \r
+\r
     UsbHcPpi->ClearRootHubPortFeature (\r
                 PeiServices,\r
                 UsbHcPpi,\r
                 PortNum,\r
                 EfiUsbPortEnableChange\r
                 );\r
-    \r
+\r
     MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);\r
   }\r
+\r
   return;\r
 }\r
-\r
-\r