]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
MdeModulePkg: Add PEI USB drivers and related PPIs
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / UsbPeim.c
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c
new file mode 100644 (file)
index 0000000..4a5d8e8
--- /dev/null
@@ -0,0 +1,1041 @@
+/** @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
+\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
+**/\r
+\r
+#include "UsbPeim.h"\r
+#include "HubPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+//\r
+// UsbIo PPI interface function\r
+//\r
+PEI_USB_IO_PPI         mUsbIoPpi = {\r
+  PeiUsbControlTransfer,\r
+  PeiUsbBulkTransfer,\r
+  PeiUsbGetInterfaceDescriptor,\r
+  PeiUsbGetEndpointDescriptor,\r
+  PeiUsbPortReset\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {\r
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+  &gPeiUsbIoPpiGuid,\r
+  NULL\r
+};\r
+\r
+/**\r
+  The enumeration routine to detect device change.\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
+\r
+  @retval EFI_SUCCESS            The usb is enumerated successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+  @retval Others                 Other failure occurs.\r
+\r
+**/\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
+  );\r
+\r
+/**\r
+  Configure new detected usb device.\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
+  @param  DeviceAddress          The device address to be configured.\r
+\r
+  @retval EFI_SUCCESS            The new detected usb device is configured successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+  @retval Others                 Other failure occurs.\r
+\r
+**/\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
+  );\r
+\r
+/**\r
+  Get all configurations from a detected usb device.\r
+  \r
+  @param  PeiServices            Describes the list of possible PEI Services.\r
+  @param  PeiUsbDevice           The pointer of PEI_USB_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS            The new detected usb device is configured successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+  @retval Others                 Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetAllConfiguration (\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
+  @param  Buffer            Buffer containing data to parse.\r
+  @param  Length            Buffer length.\r
+  @param  DescType          Descriptor type.\r
+  @param  DescLength        Descriptor length.\r
+  @param  ParsedBytes       Bytes has been parsed.\r
+\r
+  @retval EFI_SUCCESS       Get wanted descriptor successfully.\r
+  @retval EFI_DEVICE_ERROR  Error occurred.\r
+\r
+**/\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
+  );\r
+\r
+/**\r
+  The entrypoint of the module, it will enumerate all HCs.\r
+  \r
+  @param  FileHandle             Handle of the file being invoked.\r
+  @param  PeiServices            Describes the list of possible PEI Services.\r
+\r
+  @retval EFI_SUCCESS            Usb initialization is done successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+  @retval EFI_UNSUPPORTED        Can't find required PPI.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeUsb (\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
+\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not \r
+  // be produced at the same time\r
+  //\r
+  Index = 0;\r
+  while (TRUE) {\r
+    //\r
+    // Get UsbHcPpi at first.\r
+    //\r
+    Status = PeiServicesLocatePpi (\r
+               &gPeiUsbHostControllerPpiGuid,\r
+               Index,\r
+               NULL,\r
+               (VOID **) &UsbHcPpi\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // No more host controller, break out\r
+      //\r
+      break;\r
+    }\r
+    PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL);\r
+    Index++;\r
+  }\r
+\r
+  if (Index == 0) {\r
+    //\r
+    // Then try to get Usb2HcPpi.\r
+    //\r
+    while (TRUE) {\r
+      Status = PeiServicesLocatePpi (\r
+                 &gPeiUsb2HostControllerPpiGuid,\r
+                 Index,\r
+                 NULL,\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
+      Index++;\r
+    }\r
+  }\r
+  \r
+  if (Index == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The Hub Enumeration just scans the hub ports one time. It also\r
+  doesn't support hot-plug.\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
+\r
+  @retval EFI_SUCCESS            The usb hub is enumerated successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+  @retval Others                 Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubEnumeration (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_DEVICE                 *PeiUsbDevice,\r
+  IN UINT8                          *CurrentAddress\r
+  )\r
+{\r
+  UINTN                 Index;\r
+  EFI_STATUS            Status;\r
+  PEI_USB_IO_PPI        *UsbIoPpi;\r
+  EFI_USB_PORT_STATUS   PortStatus;\r
+  UINTN                 MemPages;\r
+  EFI_PHYSICAL_ADDRESS  AllocateAddress;\r
+  PEI_USB_DEVICE        *NewPeiUsbDevice;\r
+\r
+\r
+  UsbIoPpi    = &PeiUsbDevice->UsbIoPpi;\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
+\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
+      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
+        if (EFI_ERROR (Status)) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+\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
+        CopyMem (\r
+          &(NewPeiUsbDevice->UsbIoPpi),\r
+          &mUsbIoPpi,\r
+          sizeof (PEI_USB_IO_PPI)\r
+          );\r
+        CopyMem (\r
+          &(NewPeiUsbDevice->UsbIoPpiList),\r
+          &mUsbIoPpiList,\r
+          sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+          );\r
+        NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;\r
+        NewPeiUsbDevice->AllocateAddress  = (UINTN) AllocateAddress;\r
+        NewPeiUsbDevice->UsbHcPpi         = PeiUsbDevice->UsbHcPpi;\r
+        NewPeiUsbDevice->Usb2HcPpi        = PeiUsbDevice->Usb2HcPpi;\r
+        NewPeiUsbDevice->IsHub            = 0x0;\r
+        NewPeiUsbDevice->DownStreamPortNo = 0x0;\r
+\r
+        PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+\r
+        PeiHubGetPortStatus (\r
+           PeiServices,\r
+           UsbIoPpi,\r
+           (UINT8) (Index + 1),\r
+           (UINT32 *) &PortStatus\r
+           );\r
+\r
+        NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\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
+          }\r
+       }\r
+\r
+        //\r
+        // Configure that Usb Device\r
+        //\r
+        Status = PeiConfigureUsbDevice (\r
+                  PeiServices,\r
+                  NewPeiUsbDevice,\r
+                  (UINT8) (Index + 1),\r
+                  CurrentAddress\r
+                  );\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          continue;\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
+  @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
+\r
+  @retval EFI_SUCCESS            The usb is enumerated successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+  @retval Others                 Other failure occurs.\r
+\r
+**/\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
+  )\r
+{\r
+  UINT8                 NumOfRootPort;\r
+  EFI_STATUS            Status;\r
+  UINT8                 Index;\r
+  EFI_USB_PORT_STATUS   PortStatus;\r
+  PEI_USB_DEVICE        *PeiUsbDevice;\r
+  UINTN                 MemPages;\r
+  EFI_PHYSICAL_ADDRESS  AllocateAddress;\r
+  UINT8                 CurrentAddress;\r
+\r
+\r
+  CurrentAddress = 0;\r
+  if (Usb2HcPpi != NULL){\r
+    Usb2HcPpi->GetRootHubPortNumber (\r
+                PeiServices,\r
+                Usb2HcPpi,\r
+                (UINT8 *) &NumOfRootPort\r
+                );    \r
+  } else {\r
+    UsbHcPpi->GetRootHubPortNumber (\r
+                PeiServices,\r
+                UsbHcPpi,\r
+                (UINT8 *) &NumOfRootPort\r
+                );\r
+  }\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
+    } else {\r
+      UsbHcPpi->GetRootHubPortStatus (\r
+                  PeiServices,\r
+                  UsbHcPpi,\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
+      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
+        if (EFI_ERROR (Status)) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+\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
+        CopyMem (\r
+          &(PeiUsbDevice->UsbIoPpi),\r
+          &mUsbIoPpi,\r
+          sizeof (PEI_USB_IO_PPI)\r
+          );\r
+        CopyMem (\r
+          &(PeiUsbDevice->UsbIoPpiList),\r
+          &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
+\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
+        PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
+        DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));\r
+\r
+        //\r
+        // Configure that Usb Device\r
+        //\r
+        Status = PeiConfigureUsbDevice (\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
+        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
+      } else {\r
+        //\r
+        // Disconnect change happen, currently we don't support\r
+        //\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Configure new detected usb device.\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
+  @param  DeviceAddress          The device address to be configured.\r
+\r
+  @retval EFI_SUCCESS            The new detected usb device is configured successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+  @retval Others                 Other failure occurs.\r
+\r
+**/\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
+  )\r
+{\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
+  ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR));\r
+  //\r
+  // Get USB device descriptor\r
+  //\r
+\r
+  for (Retry = 0; Retry < 3; Retry ++) {\r
+\r
+    PeiUsbDevice->MaxPacketSize0 = 8;\r
+\r
+    Status = PeiUsbGetDescriptor (\r
+               PeiServices,\r
+               UsbIoPpi,\r
+               (USB_DT_DEVICE << 8),\r
+               0,\r
+               8,\r
+               &DeviceDescriptor\r
+               );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry));\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Retry == 3) {\r
+    DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry));\r
+    return Status;\r
+  }\r
+\r
+  PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;\r
+\r
+  (*DeviceAddress) ++;\r
+\r
+  Status = PeiUsbSetDeviceAddress (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            *DeviceAddress\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n"));\r
+    return Status;\r
+  }\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
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n"));\r
+    return Status;\r
+  }\r
+  //\r
+  // Get its default configuration and its first interface\r
+  //\r
+  Status = PeiUsbGetAllConfiguration (\r
+            PeiServices,\r
+            PeiUsbDevice\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = PeiUsbSetConfiguration (\r
+            PeiServices,\r
+            UsbIoPpi\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get all configurations from a detected usb device.\r
+  \r
+  @param  PeiServices            Describes the list of possible PEI Services.\r
+  @param  PeiUsbDevice           The pointer of PEI_USB_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS            The new detected usb device is configured successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+  @retval Others                 Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetAllConfiguration (\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
+\r
+  UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+\r
+  //\r
+  // 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
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_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
+\r
+  //\r
+  // Then we get the total descriptors for this configuration\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 ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));\r
+    return Status;\r
+  }\r
+  //\r
+  // Parse this configuration descriptor\r
+  // First get the current config descriptor;\r
+  //\r
+  Status = GetExpectedDescriptor (\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                       = 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
+  //\r
+  Status = GetExpectedDescriptor (\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->InterfaceDesc = (EFI_USB_INTERFACE_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
+\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
+    PeiUsbDevice->EndpointDesc[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
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get the start position of next wanted descriptor.\r
+  \r
+  @param  Buffer            Buffer containing data to parse.\r
+  @param  Length            Buffer length.\r
+  @param  DescType          Descriptor type.\r
+  @param  DescLength        Descriptor length.\r
+  @param  ParsedBytes       Bytes has been parsed.\r
+\r
+  @retval EFI_SUCCESS       Get wanted descriptor successfully.\r
+  @retval EFI_DEVICE_ERROR  Error occurred.\r
+\r
+**/\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
+  )\r
+{\r
+  UINT16  DescriptorHeader;\r
+  UINT8   Len;\r
+  UINT8   *Ptr;\r
+  UINTN   Parsed;\r
+\r
+  Parsed  = 0;\r
+  Ptr     = Buffer;\r
+\r
+  while (TRUE) {\r
+    //\r
+    // Buffer length should not less than Desc length\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
+\r
+    //\r
+    // Check to see if it is a start of expected descriptor\r
+    //\r
+    if (DescriptorHeader == ((DescType << 8) | DescLength)) {\r
+      break;\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
+    //\r
+    if (Len < 2) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    if (Len > Length) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    //\r
+    // Skip this mismatch descriptor\r
+    //\r
+    Length -= Len;\r
+    Ptr += Len;\r
+    Parsed += Len;\r
+  }\r
+\r
+  *ParsedBytes = Parsed;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send reset signal over the given root hub port.\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
+  @param  PortNum           The port to be reset.\r
+  @param  RetryIndex        The retry times.\r
+\r
+**/\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
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+\r
+\r
+  if (Usb2HcPpi != NULL) {\r
+    MicroSecondDelay (200 * 1000);\r
+    \r
+    //\r
+    // reset root port\r
+    //\r
+    Status = Usb2HcPpi->SetRootHubPortFeature (\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
+      return;\r
+    }\r
+    \r
+    MicroSecondDelay (200 * 1000);\r
+    \r
+    //\r
+    // clear reset root port\r
+    //\r
+    Status = Usb2HcPpi->ClearRootHubPortFeature (\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
+      return;\r
+    }\r
+    \r
+    MicroSecondDelay (1 * 1000);\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->ClearRootHubPortFeature (\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
+    // reset root port\r
+    //\r
+    Status = UsbHcPpi->SetRootHubPortFeature (\r
+                         PeiServices,\r
+                         UsbHcPpi,\r
+                         PortNum,\r
+                         EfiUsbPortReset\r
+                         );\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+      return;\r
+    }\r
+    \r
+    MicroSecondDelay (200 * 1000);\r
+    \r
+    //\r
+    // clear reset root port\r
+    //\r
+    Status = UsbHcPpi->ClearRootHubPortFeature (\r
+                         PeiServices,\r
+                         UsbHcPpi,\r
+                         PortNum,\r
+                         EfiUsbPortReset\r
+                         );\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+      return;\r
+    }\r
+    \r
+    MicroSecondDelay (1 * 1000);\r
+    \r
+    UsbHcPpi->ClearRootHubPortFeature (\r
+                PeiServices,\r
+                UsbHcPpi,\r
+                PortNum,\r
+                EfiUsbPortConnectChange\r
+                );\r
+    \r
+    //\r
+    // Set port enable\r
+    //\r
+    UsbHcPpi->SetRootHubPortFeature(\r
+                PeiServices,\r
+                UsbHcPpi,\r
+                PortNum,\r
+                EfiUsbPortEnable\r
+                );\r
+    \r
+    UsbHcPpi->ClearRootHubPortFeature (\r
+                PeiServices,\r
+                UsbHcPpi,\r
+                PortNum,\r
+                EfiUsbPortEnableChange\r
+                );\r
+    \r
+    MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);\r
+  }\r
+  return;\r
+}\r
+\r
+\r