]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Add PEI USB drivers and related PPIs
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 27 Jun 2011 23:30:55 +0000 (23:30 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 27 Jun 2011 23:30:55 +0000 (23:30 +0000)
Signed-off-by: jljusten
Reviewed-by: mdkinney
Reviewed-by: geekboy15a
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11901 6f19259b-4bc3-4df7-8a09-765794883524

36 files changed:
MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/EhciReg.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/EhciSched.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/EhciSched.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h [new file with mode: 0644]
MdeModulePkg/Include/Ppi/Usb2HostController.h [new file with mode: 0644]
MdeModulePkg/Include/Ppi/UsbController.h [new file with mode: 0644]
MdeModulePkg/Include/Ppi/UsbHostController.h [new file with mode: 0644]
MdeModulePkg/Include/Ppi/UsbIo.h [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c b/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.c
new file mode 100644 (file)
index 0000000..6c179b0
--- /dev/null
@@ -0,0 +1,1248 @@
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 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 "EhcPeim.h"\r
+\r
+//\r
+// Two arrays used to translate the EHCI port state (change)\r
+// to the UEFI protocol's port state (change).\r
+//\r
+USB_PORT_STATE_MAP  mUsbPortStateMap[] = {\r
+  {PORTSC_CONN,     USB_PORT_STAT_CONNECTION},\r
+  {PORTSC_ENABLED,  USB_PORT_STAT_ENABLE},\r
+  {PORTSC_SUSPEND,  USB_PORT_STAT_SUSPEND},\r
+  {PORTSC_OVERCUR,  USB_PORT_STAT_OVERCURRENT},\r
+  {PORTSC_RESET,    USB_PORT_STAT_RESET},\r
+  {PORTSC_POWER,    USB_PORT_STAT_POWER},\r
+  {PORTSC_OWNER,    USB_PORT_STAT_OWNER}\r
+};\r
+\r
+USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {\r
+  {PORTSC_CONN_CHANGE,    USB_PORT_STAT_C_CONNECTION},\r
+  {PORTSC_ENABLE_CHANGE,  USB_PORT_STAT_C_ENABLE},\r
+  {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}\r
+};\r
+\r
+/**\r
+  Read Ehc Operation register.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Offset    The operation register offset.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+EhcReadOpReg (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
\r
+  ASSERT (Ehc->CapLen != 0);\r
+\r
+  Data = MmioRead32 (Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset);\r
+  \r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write the data to the EHCI operation register.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Offset    EHCI operation register offset.\r
+  @param  Data      The data to write.\r
+\r
+**/\r
+VOID\r
+EhcWriteOpReg (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+\r
+  ASSERT (Ehc->CapLen != 0);\r
+\r
+  MmioWrite32(Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset, Data);\r
+\r
+}\r
+\r
+/**\r
+  Set one bit of the operational register while keeping other bits.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Offset    The offset of the operational register.\r
+  @param  Bit       The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+EhcSetOpRegBit (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  Data  = EhcReadOpReg (Ehc, Offset);\r
+  Data |= Bit;\r
+  EhcWriteOpReg (Ehc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Clear one bit of the operational register while keeping other bits.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Offset    The offset of the operational register.\r
+  @param  Bit       The bit mask of the register to clear.\r
+\r
+**/\r
+VOID\r
+EhcClearOpRegBit (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  Data  = EhcReadOpReg (Ehc, Offset);\r
+  Data &= ~Bit;\r
+  EhcWriteOpReg (Ehc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Wait the operation register's bit as specified by Bit \r
+  to become set (or clear).\r
+  \r
+  @param  Ehc           The EHCI device.\r
+  @param  Offset        The offset of the operational register.\r
+  @param  Bit           The bit mask of the register to wait for.\r
+  @param  WaitToSet     Wait the bit to set or clear.\r
+  @param  Timeout       The time to wait before abort (in millisecond).\r
+\r
+  @retval EFI_SUCCESS   The bit successfully changed by host controller.\r
+  @retval EFI_TIMEOUT   The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcWaitOpRegBit (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit,\r
+  IN BOOLEAN              WaitToSet,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  UINT32                  Index;\r
+\r
+  for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) {\r
+    if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    MicroSecondDelay (EHC_SYNC_POLL_INTERVAL);\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Read EHCI capability register.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Offset    Capability register address.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+EhcReadCapRegister (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  \r
+  Data = MmioRead32(Ehc->UsbHostControllerBaseAddress + Offset);\r
+  \r
+  return Data;\r
+}\r
+\r
+/**\r
+  Set door bell and wait it to be ACKed by host controller.\r
+  This function is used to synchronize with the hardware.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Timeout   The time to wait before abort (in millisecond, ms).\r
+\r
+  @retval EFI_TIMEOUT       Time out happened while waiting door bell to set.\r
+  @retval EFI_SUCCESS       Synchronized with the hardware.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcSetAndWaitDoorBell (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  UINT32              Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT32                  Data;\r
+\r
+  EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);\r
+\r
+  Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);\r
+\r
+  //\r
+  // ACK the IAA bit in USBSTS register. Make sure other\r
+  // interrupt bits are not ACKed. These bits are WC (Write Clean).\r
+  //\r
+  Data  = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);\r
+  Data &= ~USBSTS_INTACK_MASK;\r
+  Data |= USBSTS_IAA;\r
+\r
+  EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Clear all the interrutp status bits, these bits \r
+  are Write-Clean.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhcAckAllInterrupt (\r
+  IN  PEI_USB2_HC_DEV         *Ehc\r
+  )\r
+{\r
+  EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);\r
+}\r
+\r
+/**\r
+  Enable the periodic schedule then wait EHC to \r
+  actually enable it.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Timeout   The time to wait before abort (in millisecond, ms).\r
+\r
+  @retval EFI_TIMEOUT       Time out happened while enabling periodic schedule.\r
+  @retval EFI_SUCCESS       The periodical schedule is enabled.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcEnablePeriodSchd (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);\r
+\r
+  Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Enable asynchrounous schedule.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Timeout   Time to wait before abort.\r
+\r
+  @retval EFI_SUCCESS       The EHCI asynchronous schedule is enabled.\r
+  @retval Others            Failed to enable the asynchronous scheudle.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcEnableAsyncSchd (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);\r
+\r
+  Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check whether Ehc is halted.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+\r
+  @retval TRUE      The controller is halted.\r
+  @retval FALSE     The controller isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsHalt (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+{\r
+  return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);\r
+}\r
+\r
+/**\r
+  Check whether system error occurred.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+\r
+  @retval TRUE      System error happened.\r
+  @retval FALSE     No system error.\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsSysError (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+{\r
+  return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);\r
+}\r
+\r
+/**\r
+  Reset the host controller.\r
+  \r
+  @param  Ehc             The EHCI device.\r
+  @param  Timeout         Time to wait before abort (in millisecond, ms).\r
+\r
+  @retval EFI_TIMEOUT     The transfer failed due to time out.\r
+  @retval Others          Failed to reset the host.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcResetHC (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Host can only be reset when it is halt. If not so, halt it\r
+  //\r
+  if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
+    Status = EhcHaltHC (Ehc, Timeout);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);\r
+  Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Halt the host controller.\r
+  \r
+  @param  Ehc             The EHCI device.\r
+  @param  Timeout         Time to wait before abort.\r
+\r
+  @retval EFI_TIMEOUT     Failed to halt the controller before Timeout.\r
+  @retval EFI_SUCCESS     The EHCI is halt.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcHaltHC (\r
+  IN PEI_USB2_HC_DEV     *Ehc,\r
+  IN UINT32              Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+  Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the EHCI to run.\r
+  \r
+  @param  Ehc             The EHCI device.\r
+  @param  Timeout         Time to wait before abort.\r
+\r
+  @retval EFI_SUCCESS     The EHCI is running.\r
+  @retval Others          Failed to set the EHCI to run.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcRunHC (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+  Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initialize the HC hardware. \r
+  EHCI spec lists the five things to do to initialize the hardware.\r
+  1. Program CTRLDSSEGMENT.\r
+  2. Set USBINTR to enable interrupts.\r
+  3. Set periodic list base.\r
+  4. Set USBCMD, interrupt threshold, frame list size etc.\r
+  5. Write 1 to CONFIGFLAG to route all ports to EHCI.\r
+  \r
+  @param  Ehc             The EHCI device.\r
+\r
+  @retval EFI_SUCCESS     The EHCI has come out of halt state.\r
+  @retval EFI_TIMEOUT     Time out happened.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitHC (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_PHYSICAL_ADDRESS        TempPtr;\r
+  UINTN               PageNumber;\r
+  \r
+  ASSERT (EhcIsHalt (Ehc));\r
+\r
+  //\r
+  // Allocate the periodic frame and associated memeory\r
+  // management facilities if not already done.\r
+  //\r
+  if (Ehc->PeriodFrame != NULL) {\r
+    EhcFreeSched (Ehc);\r
+  }\r
+  PageNumber =  sizeof(PEI_URB)/PAGESIZE +1;\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             PageNumber,\r
+             &TempPtr\r
+             );\r
+  Ehc->Urb = (PEI_URB *) ((UINTN) TempPtr);\r
+  if (Ehc->Urb  == NULL) {\r
+    return Status;\r
+  }\r
+  \r
+  Status = EhcInitSched (Ehc);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr\r
+  //\r
+  EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);\r
+\r
+  //\r
+  // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling\r
+  //\r
+  EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);\r
+\r
+  //\r
+  // 3. Program periodic frame list, already done in EhcInitSched\r
+  // 4. Start the Host Controller\r
+  //\r
+  EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+\r
+  //\r
+  // 5. Set all ports routing to EHC\r
+  //\r
+  EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);\r
+\r
+  //\r
+  // Wait roothub port power stable\r
+  //\r
+  MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);\r
+\r
+  Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param  DeviceAddress         Target device address.\r
+  @param  EndPointAddress       Endpoint number and its direction in bit 7.\r
+  @param  DeviceSpeed           Device speed, Low speed device doesn't support \r
+                                bulk transfer.\r
+  @param  MaximumPacketLength   Maximum packet size the endpoint is capable of \r
+                                sending or receiving.\r
+  @param  Data                  Array of pointers to the buffers of data to transmit \r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  DataToggle            On input, the initial data toggle for the transfer;\r
+                                On output, it is updated to to next data toggle to use of \r
+                                the subsequent bulk transfer.\r
+  @param  TimeOut               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+  @param  Translator            A pointr to the transaction translator data.                                \r
+  @param  TransferResult        A pointer to the detailed result information of the\r
+                                bulk transfer.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcBulkTransfer (\r
+  IN EFI_PEI_SERVICES                     **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI         *This,\r
+  IN  UINT8                               DeviceAddress,\r
+  IN  UINT8                               EndPointAddress,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINTN                               MaximumPacketLength,\r
+  IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+  IN  OUT UINTN                           *DataLength,\r
+  IN  OUT UINT8                           *DataToggle,\r
+  IN  UINTN                               TimeOut,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *TransferResult\r
+  )\r
+{\r
+  PEI_USB2_HC_DEV         *Ehc;\r
+  PEI_URB                 *Urb;\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Validate the parameters\r
+  //\r
+  if ((DataLength == NULL) || (*DataLength == 0) || \r
+      (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
+      ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+      ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ehc =PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_DEVICE_ERROR;\r
+\r
+  if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+    EhcAckAllInterrupt (Ehc);\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EhcAckAllInterrupt (Ehc);\r
+\r
+  //\r
+  // Create a new URB, insert it into the asynchronous\r
+  // schedule list, then poll the execution status.\r
+  //\r
+  Urb = EhcCreateUrb (\r
+          Ehc,\r
+          DeviceAddress,\r
+          EndPointAddress,\r
+          DeviceSpeed,\r
+          *DataToggle,\r
+          MaximumPacketLength,\r
+          Translator,\r
+          EHC_BULK_TRANSFER,\r
+          NULL,\r
+          Data[0],\r
+          *DataLength,\r
+          NULL,\r
+          NULL,\r
+          1\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EhcLinkQhToAsync (Ehc, Urb->Qh);\r
+  Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
+  EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
+\r
+  *TransferResult = Urb->Result;\r
+  *DataLength     = Urb->Completed;\r
+  *DataToggle     = Urb->DataToggle;\r
+\r
+  if (*TransferResult == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  EhcAckAllInterrupt (Ehc);\r
+  EhcFreeUrb (Ehc, Urb);\r
+\r
+ON_EXIT:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the number of root hub ports.\r
+\r
+  @param[in]  PeiServices   The pointer to the PEI Services Table.\r
+  @param[in]  This          The pointer to this instance of the \r
+                            PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param[out] PortNumber    The pointer to the number of the root hub ports.                                \r
+                                \r
+  @retval EFI_SUCCESS           The port number was retrieved successfully.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetRootHubPortNumber (\r
+  IN EFI_PEI_SERVICES                       **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI           *This,\r
+  OUT UINT8                                 *PortNumber\r
+  )\r
+{\r
+\r
+  PEI_USB2_HC_DEV             *EhcDev;\r
+  EhcDev = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);\r
+  \r
+  if (PortNumber == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }  \r
+  \r
+  *PortNumber = (UINT8)(EhcDev->HcStructParams & HCSP_NPORTS);\r
+  return EFI_SUCCESS;\r
+  \r
+}\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param  PortNumber            Specifies the root hub port whose feature\r
+                                is requested to be cleared.\r
+  @param  PortFeature           Indicates the feature selector associated with the\r
+                                feature clear request.\r
+\r
+  @retval EFI_SUCCESS            The feature specified by PortFeature was cleared \r
+                                 for the USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcClearRootHubPortFeature (\r
+  IN EFI_PEI_SERVICES                       **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI           *This,\r
+  IN  UINT8                 PortNumber,\r
+  IN  EFI_USB_PORT_FEATURE  PortFeature\r
+  )\r
+{\r
+  PEI_USB2_HC_DEV         *Ehc;\r
+  UINT32                  Offset;\r
+  UINT32                  State;\r
+  UINT32                  TotalPort;\r
+  EFI_STATUS              Status;\r
+\r
+  Ehc       = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);\r
+  Status    = EFI_SUCCESS;\r
+\r
+  TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+  if (PortNumber >= TotalPort) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Offset  = EHC_PORT_STAT_OFFSET + (4 * PortNumber);\r
+  State   = EhcReadOpReg (Ehc, Offset);\r
+  State &= ~PORTSC_CHANGE_MASK;\r
+\r
+  switch (PortFeature) {\r
+  case EfiUsbPortEnable:\r
+    //\r
+    // Clear PORT_ENABLE feature means disable port.\r
+    //\r
+    State &= ~PORTSC_ENABLED;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortSuspend:\r
+    //\r
+    // A write of zero to this bit is ignored by the host\r
+    // controller. The host controller will unconditionally\r
+    // set this bit to a zero when:\r
+    //   1. software sets the Forct Port Resume bit to a zero from a one.\r
+    //   2. software sets the Port Reset bit to a one frome a zero.\r
+    //\r
+    State &= ~PORSTSC_RESUME;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortReset:\r
+    //\r
+    // Clear PORT_RESET means clear the reset signal.\r
+    //\r
+    State &= ~PORTSC_RESET;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortOwner:\r
+    //\r
+    // Clear port owner means this port owned by EHC\r
+    //\r
+    State &= ~PORTSC_OWNER;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortConnectChange:\r
+    //\r
+    // Clear connect status change\r
+    //\r
+    State |= PORTSC_CONN_CHANGE;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortEnableChange:\r
+    //\r
+    // Clear enable status change\r
+    //\r
+    State |= PORTSC_ENABLE_CHANGE;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortOverCurrentChange:\r
+    //\r
+    // Clear PortOverCurrent change\r
+    //\r
+    State |= PORTSC_OVERCUR_CHANGE;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortPower:\r
+  case EfiUsbPortSuspendChange:\r
+  case EfiUsbPortResetChange:\r
+    //\r
+    // Not supported or not related operation\r
+    //\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+    break;\r
+  }\r
+\r
+ON_EXIT:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sets a feature for the specified root hub port.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES\r
+  @param  This                  The pointer of PEI_USB2_HOST_CONTROLLER_PPI\r
+  @param  PortNumber            Root hub port to set.\r
+  @param  PortFeature           Feature to set.\r
+\r
+  @retval EFI_SUCCESS            The feature specified by PortFeature was set.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_TIMEOUT            The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcSetRootHubPortFeature (\r
+  IN EFI_PEI_SERVICES                       **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI           *This,\r
+  IN UINT8                                  PortNumber,\r
+  IN EFI_USB_PORT_FEATURE                   PortFeature\r
+  )\r
+{\r
+  PEI_USB2_HC_DEV         *Ehc;\r
+  UINT32                  Offset;\r
+  UINT32                  State;\r
+  UINT32                  TotalPort;\r
+  EFI_STATUS              Status;\r
+\r
+  Ehc       = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);\r
+  Status    = EFI_SUCCESS;\r
+\r
+  TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+  if (PortNumber >= TotalPort) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Offset  = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
+  State   = EhcReadOpReg (Ehc, Offset);\r
+\r
+  //\r
+  // Mask off the port status change bits, these bits are\r
+  // write clean bit\r
+  //\r
+  State &= ~PORTSC_CHANGE_MASK;\r
+\r
+  switch (PortFeature) {\r
+  case EfiUsbPortEnable:\r
+    //\r
+    // Sofeware can't set this bit, Port can only be enable by\r
+    // EHCI as a part of the reset and enable\r
+    //\r
+    State |= PORTSC_ENABLED;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortSuspend:\r
+    State |= PORTSC_SUSPEND;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortReset:\r
+    //\r
+    // Make sure Host Controller not halt before reset it\r
+    //\r
+    if (EhcIsHalt (Ehc)) {\r
+      Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+    }\r
+    \r
+    //\r
+    // Set one to PortReset bit must also set zero to PortEnable bit\r
+    //\r
+    State |= PORTSC_RESET;\r
+    State &= ~PORTSC_ENABLED;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortPower:\r
+    //\r
+    // Not supported, ignore the operation\r
+    //\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  case EfiUsbPortOwner:\r
+    State |= PORTSC_OWNER;\r
+    EhcWriteOpReg (Ehc, Offset, State);\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+ON_EXIT:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param  PortNumber             The root hub port to retrieve the state from.  \r
+  @param  PortStatus             Variable to receive the port state.\r
+\r
+  @retval EFI_SUCCESS            The status of the USB root hub port specified.\r
+                                 by PortNumber was returned in PortStatus.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetRootHubPortStatus (\r
+  IN EFI_PEI_SERVICES                       **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI           *This,\r
+  IN  UINT8                                 PortNumber,\r
+  OUT EFI_USB_PORT_STATUS                   *PortStatus\r
+  )\r
+{\r
+  PEI_USB2_HC_DEV         *Ehc;\r
+  UINT32                  Offset;\r
+  UINT32                  State;\r
+  UINT32                  TotalPort;\r
+  UINTN                   Index;\r
+  UINTN                   MapSize;\r
+  EFI_STATUS              Status;\r
+\r
+  if (PortStatus == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ehc       =  PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);\r
+  Status    = EFI_SUCCESS;\r
+\r
+  TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+  if (PortNumber >= TotalPort) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Offset                        = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
+  PortStatus->PortStatus        = 0;\r
+  PortStatus->PortChangeStatus  = 0;\r
+\r
+  State                         = EhcReadOpReg (Ehc, Offset);\r
+\r
+  //\r
+  // Identify device speed. If in K state, it is low speed.\r
+  // If the port is enabled after reset, the device is of \r
+  // high speed. The USB bus driver should retrieve the actual\r
+  // port speed after reset. \r
+  //\r
+  if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+\r
+  } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+  }\r
+  \r
+  //\r
+  // Convert the EHCI port/port change state to UEFI status\r
+  //\r
+  MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+  for (Index = 0; Index < MapSize; Index++) {\r
+    if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
+      PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
+    }\r
+  }\r
+\r
+  MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+  for (Index = 0; Index < MapSize; Index++) {\r
+    if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
+      PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param  DeviceAddress          The target device address.\r
+  @param  DeviceSpeed            Target device speed.\r
+  @param  MaximumPacketLength    Maximum packet size the default control transfer \r
+                                 endpoint is capable of sending or receiving.\r
+  @param  Request                USB device request to send.\r
+  @param  TransferDirection      Specifies the data direction for the data stage.\r
+  @param  Data                   Data buffer to be transmitted or received from USB device.\r
+  @param  DataLength             The size (in bytes) of the data buffer.\r
+  @param  TimeOut                Indicates the maximum timeout, in millisecond.\r
+  @param  Translator             Transaction translator to be used by this device.\r
+  @param  TransferResult         Return the result of this control transfer.\r
+\r
+  @retval EFI_SUCCESS            Transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.\r
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcControlTransfer (\r
+  IN  EFI_PEI_SERVICES                    **PeiServices,\r
+  IN  PEI_USB2_HOST_CONTROLLER_PPI        *This,\r
+  IN  UINT8                               DeviceAddress,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINTN                               MaximumPacketLength,\r
+  IN  EFI_USB_DEVICE_REQUEST              *Request,\r
+  IN  EFI_USB_DATA_DIRECTION              TransferDirection,\r
+  IN  OUT VOID                            *Data,\r
+  IN  OUT UINTN                           *DataLength,\r
+  IN  UINTN                               TimeOut,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *TransferResult\r
+  )\r
+{\r
+  PEI_USB2_HC_DEV         *Ehc;\r
+  PEI_URB                 *Urb;\r
+  UINT8                   Endpoint;\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Validate parameters\r
+  //\r
+  if ((Request == NULL) || (TransferResult == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((TransferDirection != EfiUsbDataIn) &&\r
+      (TransferDirection != EfiUsbDataOut) &&\r
+      (TransferDirection != EfiUsbNoData)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((TransferDirection == EfiUsbNoData) && \r
+      ((Data != NULL) || (*DataLength != 0))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((TransferDirection != EfiUsbNoData) && \r
+     ((Data == NULL) || (*DataLength == 0))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((MaximumPacketLength != 8)  && (MaximumPacketLength != 16) &&\r
+      (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+\r
+  if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
+      ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+      ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ehc             = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);\r
+\r
+  Status          = EFI_DEVICE_ERROR;\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+\r
+  if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+    EhcAckAllInterrupt (Ehc);\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EhcAckAllInterrupt (Ehc);\r
+\r
+  //\r
+  // Create a new URB, insert it into the asynchronous\r
+  // schedule list, then poll the execution status.\r
+  //\r
+  //\r
+  // Encode the direction in address, although default control\r
+  // endpoint is bidirectional. EhcCreateUrb expects this\r
+  // combination of Ep addr and its direction.\r
+  //\r
+  Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
+  Urb = EhcCreateUrb (\r
+          Ehc,\r
+          DeviceAddress,\r
+          Endpoint,\r
+          DeviceSpeed,\r
+          0,\r
+          MaximumPacketLength,\r
+          Translator,\r
+          EHC_CTRL_TRANSFER,\r
+          Request,\r
+          Data,\r
+          *DataLength,\r
+          NULL,\r
+          NULL,\r
+          1\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EhcLinkQhToAsync (Ehc, Urb->Qh);\r
+  Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
+  EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
+\r
+  //\r
+  // Get the status from URB. The result is updated in EhcCheckUrbResult\r
+  // which is called by EhcExecTransfer\r
+  //\r
+  *TransferResult = Urb->Result;\r
+  *DataLength     = Urb->Completed;\r
+\r
+  if (*TransferResult == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  EhcAckAllInterrupt (Ehc);\r
+  EhcFreeUrb (Ehc, Urb);\r
+\r
+ON_EXIT:\r
+  return Status;\r
+}\r
+\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            PPI successfully installed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcPeimEntry (\r
+  IN EFI_PEI_FILE_HANDLE     FileHandle,\r
+  IN CONST EFI_PEI_SERVICES  **PeiServices\r
+  )\r
+{\r
+  PEI_USB_CONTROLLER_PPI      *ChipSetUsbControllerPpi;\r
+  EFI_STATUS                  Status;\r
+  UINT8                       Index;\r
+  UINTN                       ControllerType;\r
+  UINTN                       BaseAddress;\r
+  UINTN                       MemPages;\r
+  PEI_USB2_HC_DEV             *EhcDev;\r
+  EFI_PHYSICAL_ADDRESS        TempPtr;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = PeiServicesLocatePpi (\r
+             &gPeiUsbControllerPpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **) &ChipSetUsbControllerPpi\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Index = 0;\r
+  while (TRUE) {\r
+    Status = ChipSetUsbControllerPpi->GetUsbController (\r
+                                        (EFI_PEI_SERVICES **) PeiServices,\r
+                                        ChipSetUsbControllerPpi,\r
+                                        Index,\r
+                                        &ControllerType,\r
+                                        &BaseAddress\r
+                                        );\r
+    //\r
+    // When status is error, meant no controller is found\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    \r
+    //\r
+    // This PEIM is for UHC type controller.\r
+    //\r
+    if (ControllerType != PEI_EHCI_CONTROLLER) {\r
+      Index++;\r
+      continue;\r
+    }\r
+\r
+    MemPages = sizeof (PEI_USB2_HC_DEV) / PAGESIZE + 1;\r
+    Status = PeiServicesAllocatePages (\r
+               EfiBootServicesCode,\r
+               MemPages,\r
+               &TempPtr\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);\r
+    EhcDev = (PEI_USB2_HC_DEV *) ((UINTN) TempPtr);\r
+\r
+    EhcDev->Signature = USB2_HC_DEV_SIGNATURE;\r
+\r
+    EhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
+\r
+\r
+    EhcDev->HcStructParams = EhcReadCapRegister (EhcDev, EHC_HCSPARAMS_OFFSET);\r
+    EhcDev->HcCapParams    = EhcReadCapRegister (EhcDev, EHC_HCCPARAMS_OFFSET);\r
+    EhcDev->CapLen         = EhcReadCapRegister (EhcDev, EHC_CAPLENGTH_OFFSET) & 0x0FF;\r
+    //\r
+    // Initialize Uhc's hardware\r
+    //\r
+    Status = InitializeUsbHC (EhcDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    EhcDev->Usb2HostControllerPpi.ControlTransfer          = EhcControlTransfer;\r
+    EhcDev->Usb2HostControllerPpi.BulkTransfer             = EhcBulkTransfer;\r
+    EhcDev->Usb2HostControllerPpi.GetRootHubPortNumber     = EhcGetRootHubPortNumber;\r
+    EhcDev->Usb2HostControllerPpi.GetRootHubPortStatus     = EhcGetRootHubPortStatus;\r
+    EhcDev->Usb2HostControllerPpi.SetRootHubPortFeature    = EhcSetRootHubPortFeature;\r
+    EhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature  = EhcClearRootHubPortFeature;\r
+\r
+    EhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+    EhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;\r
+    EhcDev->PpiDescriptor.Ppi = &EhcDev->Usb2HostControllerPpi;\r
+\r
+    Status = PeiServicesInstallPpi (&EhcDev->PpiDescriptor);\r
+    if (EFI_ERROR (Status)) {\r
+      Index++;\r
+      continue;\r
+    }\r
+\r
+    Index++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  @param  EhcDev                 EHCI Device.\r
+\r
+  @retval EFI_SUCCESS            EHCI successfully initialized.\r
+  @retval EFI_ABORTED            EHCI was failed to be initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+  IN PEI_USB2_HC_DEV      *EhcDev  \r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+       \r
+  EhcResetHC (EhcDev, EHC_RESET_TIMEOUT);\r
+\r
+  Status = EhcInitHC (EhcDev);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_ABORTED;      \r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.h b/MdeModulePkg/Bus/Pci/EhciPei/EhcPeim.h
new file mode 100644 (file)
index 0000000..fa1671b
--- /dev/null
@@ -0,0 +1,227 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 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
+#ifndef _RECOVERY_EHC_H_\r
+#define _RECOVERY_EHC_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbController.h>\r
+#include <Ppi/Usb2HostController.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/IoLib.h>\r
+\r
+typedef struct _PEI_USB2_HC_DEV PEI_USB2_HC_DEV;\r
+\r
+#define EFI_LIST_ENTRY LIST_ENTRY\r
+\r
+#include "UsbHcMem.h"\r
+#include "EhciReg.h"\r
+#include "EhciUrb.h"\r
+#include "EhciSched.h"\r
+\r
+#define EFI_USB_SPEED_FULL 0x0000\r
+#define EFI_USB_SPEED_LOW  0x0001\r
+#define EFI_USB_SPEED_HIGH 0x0002\r
+\r
+#define PAGESIZE           4096\r
+\r
+#define EHC_1_MICROSECOND            1\r
+#define EHC_1_MILLISECOND            (1000 * EHC_1_MICROSECOND)\r
+#define EHC_1_SECOND                 (1000 * EHC_1_MILLISECOND)\r
+\r
+//\r
+// EHCI register operation timeout, set by experience\r
+//\r
+#define EHC_RESET_TIMEOUT            (1 * EHC_1_SECOND)\r
+#define EHC_GENERIC_TIMEOUT          (10 * EHC_1_MILLISECOND)\r
+\r
+\r
+//\r
+// Wait for roothub port power stable, refers to Spec[EHCI1.0-2.3.9]\r
+//\r
+#define EHC_ROOT_PORT_RECOVERY_STALL (20 * EHC_1_MILLISECOND)\r
+\r
+//\r
+// Sync and Async transfer polling interval, set by experience, \r
+// and the unit of Async is 100us, means 50ms as interval.\r
+//\r
+#define EHC_SYNC_POLL_INTERVAL       (6 * EHC_1_MILLISECOND)\r
+\r
+#define EHC_ASYNC_POLL_INTERVAL      (50 * 10000U)\r
+\r
+//\r
+//Iterate through the doule linked list. NOT delete safe\r
+//\r
+#define EFI_LIST_FOR_EACH(Entry, ListHead)    \\r
+  for(Entry = (ListHead)->ForwardLink; Entry != (ListHead); Entry = Entry->ForwardLink)\r
+\r
+//\r
+//Iterate through the doule linked list. This is delete-safe.\r
+//Don't touch NextEntry\r
+//\r
+#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead)            \\r
+  for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\\r
+      Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink)\r
+\r
+#define EFI_LIST_CONTAINER(Entry, Type, Field) BASE_CR(Entry, Type, Field)\r
+\r
+\r
+#define EHC_LOW_32BIT(Addr64)     ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))\r
+#define EHC_HIGH_32BIT(Addr64)    ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+#define EHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+#define EHC_REG_BIT_IS_SET(Ehc, Offset, Bit) \\r
+          (EHC_BIT_IS_SET(EhcReadOpReg ((Ehc), (Offset)), (Bit)))\r
+\r
+#define USB2_HC_DEV_SIGNATURE  SIGNATURE_32 ('e', 'h', 'c', 'i')\r
+\r
+struct _PEI_USB2_HC_DEV {\r
+  UINTN                               Signature;\r
+  PEI_USB2_HOST_CONTROLLER_PPI        Usb2HostControllerPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR              PpiDescriptor;                    \r
+  UINT32                              UsbHostControllerBaseAddress;\r
+  PEI_URB                             *Urb;\r
+  USBHC_MEM_POOL                      *MemPool;\r
+\r
+  //\r
+  // Schedule data shared between asynchronous and periodic\r
+  // transfers:\r
+  // ShortReadStop, as its name indicates, is used to terminate\r
+  // the short read except the control transfer. EHCI follows\r
+  // the alternative next QTD point when a short read happens.\r
+  // For control transfer, even the short read happens, try the\r
+  // status stage.\r
+  //\r
+  PEI_EHC_QTD                         *ShortReadStop;\r
+  EFI_EVENT                           PollTimer;\r
+  \r
+  //\r
+  // Asynchronous(bulk and control) transfer schedule data: \r
+  // ReclaimHead is used as the head of the asynchronous transfer\r
+  // list. It acts as the reclamation header. \r
+  //\r
+  PEI_EHC_QH                          *ReclaimHead;\r
+  \r
+  //\r
+  // Peroidic (interrupt) transfer schedule data:\r
+  //\r
+  VOID                                *PeriodFrame;     // Mapped as common buffer \r
+  VOID                                *PeriodFrameHost;\r
+  VOID                                *PeriodFrameMap;\r
+                                      \r
+  PEI_EHC_QH                          *PeriodOne;\r
+  EFI_LIST_ENTRY                      AsyncIntTransfers;\r
+\r
+  //\r
+  // EHCI configuration data\r
+  //\r
+  UINT32                              HcStructParams; // Cache of HC structure parameter, EHC_HCSPARAMS_OFFSET\r
+  UINT32                              HcCapParams;    // Cache of HC capability parameter, HCCPARAMS\r
+  UINT32                              CapLen;         // Capability length\r
+  UINT32                              High32bitAddr;\r
+};\r
+\r
+#define PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(a)  CR (a, PEI_USB2_HC_DEV, Usb2HostControllerPpi, USB2_HC_DEV_SIGNATURE)\r
+\r
+/**\r
+  @param  EhcDev                 EHCI Device.\r
+\r
+  @retval EFI_SUCCESS            EHCI successfully initialized.\r
+  @retval EFI_ABORTED            EHCI was failed to be initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+  IN PEI_USB2_HC_DEV      *EhcDev  \r
+  );\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+  \r
+  @param  Ehc                   The EHCI device.\r
+  @param  Check4G               Whether the host controller requires allocated memory \r
+                                from one 4G address space.\r
+  @param  Which4G               The 4G memory area each memory allocated should be from.\r
+\r
+  @retval EFI_SUCCESS           The memory pool is initialized.\r
+  @retval EFI_OUT_OF_RESOURCE   Fail to init the memory pool.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN BOOLEAN              Check4G,\r
+  IN UINT32               Which4G\r
+  )\r
+;\r
+            \r
+/**\r
+  Release the memory management pool.\r
+  \r
+  @param  Pool                  The USB memory pool to free.\r
+\r
+  @retval EFI_DEVICE_ERROR      Fail to free the memory pool.\r
+  @retval EFI_SUCCESS           The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+  IN USBHC_MEM_POOL       *Pool\r
+  )\r
+;\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Pool      The host controller's memory pool.\r
+  @param  Size      Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN  USBHC_MEM_POOL      *Pool,\r
+  IN  UINTN               Size\r
+  )\r
+;\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool           The memory pool of the host controller.\r
+  @param  Mem            The memory to free.\r
+  @param  Size           The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+  IN USBHC_MEM_POOL       *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf b/MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf
new file mode 100644 (file)
index 0000000..f10ad49
--- /dev/null
@@ -0,0 +1,66 @@
+## @file\r
+# Component description file for EhcPeim PEIM to produce gPeiUsb2HostControllerPpiGuid \r
+# based on gPeiUsbControllerPpiGuid which is used to enable recovery function from USB Drivers.\r
+#\r
+# Copyright (c) 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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = EhciPei\r
+  FILE_GUID                      = BAB4F20F-0981-4b5f-A047-6EF83BEEAB3C\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = EhcPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  EhcPeim.c\r
+  EhcPeim.h\r
+  EhciUrb.c\r
+  EhciSched.c\r
+  UsbHcMem.c\r
+  EhciReg.h\r
+  EhciSched.h\r
+  EhciUrb.h\r
+  UsbHcMem.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  IoLib\r
+  TimerLib\r
+  BaseMemoryLib\r
+  PeimEntryPoint\r
+  PeiServicesLib\r
+\r
+\r
+[Ppis]\r
+  gPeiUsb2HostControllerPpiGuid                 # PPI ALWAYS_PRODUCED\r
+  gPeiUsbControllerPpiGuid                      # PPI ALWAYS_CONSUMED\r
+\r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhciReg.h b/MdeModulePkg/Bus/Pci/EhciPei/EhciReg.h
new file mode 100644 (file)
index 0000000..34c61d8
--- /dev/null
@@ -0,0 +1,310 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 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
+#ifndef _EFI_EHCI_REG_H_\r
+#define _EFI_EHCI_REG_H_\r
+\r
+\r
+\r
+//\r
+// Capability register offset\r
+//\r
+#define EHC_CAPLENGTH_OFFSET    0    // Capability register length offset\r
+#define EHC_HCSPARAMS_OFFSET    0x04 // Structural Parameters 04-07h\r
+#define EHC_HCCPARAMS_OFFSET    0x08 // Capability parameters offset\r
+\r
+//\r
+// Capability register bit definition\r
+//\r
+#define HCSP_NPORTS             0x0F // Number of root hub port\r
+#define HCCP_64BIT              0x01 // 64-bit addressing capability\r
+\r
+//\r
+// Operational register offset\r
+//\r
+#define EHC_USBCMD_OFFSET       0x0  // USB command register offset\r
+#define EHC_USBSTS_OFFSET       0x04 // Statue register offset\r
+#define EHC_USBINTR_OFFSET      0x08 // USB interrutp offset\r
+#define EHC_FRINDEX_OFFSET      0x0C // Frame index offset\r
+#define EHC_CTRLDSSEG_OFFSET    0x10 // Control data structure segment offset\r
+#define EHC_FRAME_BASE_OFFSET   0x14 // Frame list base address offset\r
+#define EHC_ASYNC_HEAD_OFFSET   0x18 // Next asynchronous list address offset\r
+#define EHC_CONFIG_FLAG_OFFSET  0x40 // Configure flag register offset\r
+#define EHC_PORT_STAT_OFFSET    0x44 // Port status/control offset\r
+\r
+#define EHC_FRAME_LEN           1024\r
+\r
+//\r
+// Register bit definition\r
+//\r
+#define CONFIGFLAG_ROUTE_EHC    0x01 // Route port to EHC\r
+\r
+#define USBCMD_RUN              0x01   // Run/stop\r
+#define USBCMD_RESET            0x02   // Start the host controller reset\r
+#define USBCMD_ENABLE_PERIOD    0x10   // Enable periodic schedule\r
+#define USBCMD_ENABLE_ASYNC     0x20   // Enable asynchronous schedule\r
+#define USBCMD_IAAD             0x40   // Interrupt on async advance doorbell\r
+\r
+#define USBSTS_IAA              0x20   // Interrupt on async advance\r
+#define USBSTS_PERIOD_ENABLED   0x4000 // Periodic schedule status\r
+#define USBSTS_ASYNC_ENABLED    0x8000 // Asynchronous schedule status\r
+#define USBSTS_HALT             0x1000 // Host controller halted\r
+#define USBSTS_SYS_ERROR        0x10   // Host system error\r
+#define USBSTS_INTACK_MASK      0x003F // Mask for the interrupt ACK, the WC\r
+                                       // (write clean) bits in USBSTS register\r
+\r
+#define PORTSC_CONN             0x01   // Current Connect Status\r
+#define PORTSC_CONN_CHANGE      0x02   // Connect Status Change\r
+#define PORTSC_ENABLED          0x04   // Port Enable / Disable\r
+#define PORTSC_ENABLE_CHANGE    0x08   // Port Enable / Disable Change\r
+#define PORTSC_OVERCUR          0x10   // Over current Active\r
+#define PORTSC_OVERCUR_CHANGE   0x20   // Over current Change\r
+#define PORSTSC_RESUME          0x40   // Force Port Resume\r
+#define PORTSC_SUSPEND          0x80   // Port Suspend State\r
+#define PORTSC_RESET            0x100  // Port Reset\r
+#define PORTSC_LINESTATE_K      0x400  // Line Status K-state\r
+#define PORTSC_LINESTATE_J      0x800  // Line Status J-state\r
+#define PORTSC_POWER            0x1000 // Port Power\r
+#define PORTSC_OWNER            0x2000 // Port Owner\r
+#define PORTSC_CHANGE_MASK      0x2A   // Mask of the port change bits,\r
+                                       // they are WC (write clean)\r
+//\r
+// PCI Configuration Registers\r
+//\r
+#define EHC_BAR_INDEX           0      // how many bytes away from USB_BASE to 0x10\r
+\r
+#define EHC_LINK_TERMINATED(Link) (((Link) & 0x01) != 0)\r
+\r
+#define EHC_ADDR(High, QhHw32)   \\r
+        ((VOID *) (UINTN) (LShiftU64 ((High), 32) | ((QhHw32) & 0xFFFFFFF0)))\r
+\r
+#define EHCI_IS_DATAIN(EndpointAddr) EHC_BIT_IS_SET((EndpointAddr), 0x80)\r
+\r
+//\r
+// Structure to map the hardware port states to the \r
+// UEFI's port states. \r
+//\r
+typedef struct {\r
+  UINT16                  HwState;\r
+  UINT16                  UefiState;\r
+} USB_PORT_STATE_MAP;\r
+\r
+//\r
+// Ehci Data and Ctrl Structures\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8                   Pi;\r
+  UINT8                   SubClassCode;\r
+  UINT8                   BaseCode;\r
+} USB_CLASSC;\r
+#pragma pack()\r
+\r
+\r
+/**\r
+  Read EHCI capability register.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Offset    Capability register address.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+EhcReadCapRegister (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  UINT32              Offset\r
+  )\r
+;\r
+\r
+/**\r
+  Read Ehc Operation register.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Offset    The operation register offset.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+EhcReadOpReg (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  UINT32              Offset\r
+  )\r
+;\r
+\r
+/**\r
+  Write the data to the EHCI operation register.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Offset    EHCI operation register offset.\r
+  @param  Data      The data to write.\r
+\r
+**/\r
+VOID\r
+EhcWriteOpReg (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+;\r
+\r
+/**\r
+  Stop the legacy USB SMI support.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhcClearLegacySupport (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+;\r
+\r
+/**\r
+  Set door bell and wait it to be ACKed by host controller.\r
+  This function is used to synchronize with the hardware.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Timeout   The time to wait before abort (in millisecond, ms).\r
+\r
+  @retval EFI_TIMEOUT       Time out happened while waiting door bell to set.\r
+  @retval EFI_SUCCESS       Synchronized with the hardware.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcSetAndWaitDoorBell (\r
+  IN  PEI_USB2_HC_DEV      *Ehc,\r
+  IN  UINT32               Timeout\r
+  )\r
+;\r
+\r
+/**\r
+  Clear all the interrutp status bits, these bits \r
+  are Write-Clean.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhcAckAllInterrupt (\r
+  IN  PEI_USB2_HC_DEV     *Ehc\r
+  )\r
+;\r
+\r
+/**\r
+  Check whether Ehc is halted.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+\r
+  @retval TRUE      The controller is halted.\r
+  @retval FALSE     The controller isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsHalt (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+;\r
+\r
+/**\r
+  Check whether system error occurred.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+\r
+  @retval TRUE      System error happened.\r
+  @retval FALSE     No system error.\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsSysError (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+;\r
+\r
+/**\r
+  Reset the host controller.\r
+  \r
+  @param  Ehc             The EHCI device.\r
+  @param  Timeout         Time to wait before abort (in millisecond, ms).\r
+\r
+  @retval EFI_TIMEOUT     The transfer failed due to time out.\r
+  @retval Others          Failed to reset the host.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcResetHC (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+;\r
+\r
+/**\r
+  Halt the host controller.\r
+  \r
+  @param  Ehc             The EHCI device.\r
+  @param  Timeout         Time to wait before abort.\r
+\r
+  @retval EFI_TIMEOUT     Failed to halt the controller before Timeout.\r
+  @retval EFI_SUCCESS     The EHCI is halt.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcHaltHC (\r
+  IN PEI_USB2_HC_DEV     *Ehc,\r
+  IN UINT32              Timeout\r
+  )\r
+;\r
+\r
+/**\r
+  Set the EHCI to run\r
+  \r
+  @param  Ehc             The EHCI device.\r
+  @param  Timeout         Time to wait before abort.\r
+\r
+  @retval EFI_SUCCESS     The EHCI is running.\r
+  @retval Others          Failed to set the EHCI to run.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcRunHC (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+;\r
+\r
+/**\r
+  Initialize the HC hardware. \r
+  EHCI spec lists the five things to do to initialize the hardware.\r
+  1. Program CTRLDSSEGMENT.\r
+  2. Set USBINTR to enable interrupts.\r
+  3. Set periodic list base.\r
+  4. Set USBCMD, interrupt threshold, frame list size etc.\r
+  5. Write 1 to CONFIGFLAG to route all ports to EHCI.\r
+  \r
+  @param  Ehc             The EHCI device.\r
+\r
+  @retval EFI_SUCCESS     The EHCI has come out of halt state.\r
+  @retval EFI_TIMEOUT     Time out happened.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitHC (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.c b/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.c
new file mode 100644 (file)
index 0000000..d153aa3
--- /dev/null
@@ -0,0 +1,873 @@
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 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 "EhcPeim.h"\r
+\r
+/**\r
+  Create helper QTD/QH for the EHCI device.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for helper QTD/QH.\r
+  @retval EFI_SUCCESS           Helper QH/QTD are created.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcCreateHelpQ (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+{\r
+  USB_ENDPOINT            Ep;\r
+  PEI_EHC_QH              *Qh;\r
+  QH_HW                   *QhHw;\r
+  PEI_EHC_QTD             *Qtd;\r
+\r
+  //\r
+  // Create an inactive Qtd to terminate the short packet read.\r
+  //\r
+  Qtd = EhcCreateQtd (Ehc, NULL, 0, QTD_PID_INPUT, 0, 64);\r
+\r
+  if (Qtd == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Qtd->QtdHw.Status   = QTD_STAT_HALTED;\r
+  Ehc->ShortReadStop  = Qtd;\r
+\r
+  //\r
+  // Create a QH to act as the EHC reclamation header.\r
+  // Set the header to loopback to itself.\r
+  //\r
+  Ep.DevAddr    = 0;\r
+  Ep.EpAddr     = 1;\r
+  Ep.Direction  = EfiUsbDataIn;\r
+  Ep.DevSpeed   = EFI_USB_SPEED_HIGH;\r
+  Ep.MaxPacket  = 64;\r
+  Ep.HubAddr    = 0;\r
+  Ep.HubPort    = 0;\r
+  Ep.Toggle     = 0;\r
+  Ep.Type       = EHC_BULK_TRANSFER;\r
+  Ep.PollRate   = 1;\r
+\r
+  Qh            = EhcCreateQh (Ehc, &Ep);\r
+\r
+  if (Qh == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  QhHw              = &Qh->QhHw;\r
+  QhHw->HorizonLink = QH_LINK (QhHw, EHC_TYPE_QH, FALSE);\r
+  QhHw->Status      = QTD_STAT_HALTED;\r
+  QhHw->ReclaimHead = 1;\r
+  Ehc->ReclaimHead  = Qh;\r
+\r
+  //\r
+  // Create a dummy QH to act as the terminator for periodical schedule\r
+  //\r
+  Ep.EpAddr   = 2;\r
+  Ep.Type     = EHC_INT_TRANSFER_SYNC;\r
+\r
+  Qh          = EhcCreateQh (Ehc, &Ep);\r
+\r
+  if (Qh == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Qh->QhHw.Status = QTD_STAT_HALTED;\r
+  Ehc->PeriodOne  = Qh;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize the schedule data structure such as frame list.\r
+  \r
+  @param  Ehc                   The EHCI device to init schedule data for.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to init schedule data.\r
+  @retval EFI_SUCCESS           The schedule data is initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitSched (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  PhyAddr;\r
+  VOID                  *Map;\r
+  UINTN                 Index;\r
+  UINT32                *Desc;\r
+  EFI_STATUS            Status;\r
+\r
+  //\r
+  // First initialize the periodical schedule data:\r
+  // 1. Allocate and map the memory for the frame list\r
+  // 2. Create the help QTD/QH\r
+  // 3. Initialize the frame entries\r
+  // 4. Set the frame list register\r
+  //\r
+  //\r
+  // The Frame List ocupies 4K bytes,\r
+  // and must be aligned on 4-Kbyte boundaries.\r
+  //\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             1,\r
+             &PhyAddr\r
+             );\r
+\r
+  Map = NULL;\r
+  Ehc->PeriodFrameHost  = (VOID *)(UINTN)PhyAddr;\r
+  Ehc->PeriodFrame      = (VOID *)(UINTN)PhyAddr;\r
+  Ehc->PeriodFrameMap   = Map;\r
+  Ehc->High32bitAddr    = EHC_HIGH_32BIT (PhyAddr);\r
+\r
+  //\r
+  // Init memory pool management then create the helper\r
+  // QTD/QH. If failed, previously allocated resources\r
+  // will be freed by EhcFreeSched\r
+  //\r
+  Ehc->MemPool = UsbHcInitMemPool (\r
+                   Ehc,\r
+                   EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT),\r
+                   Ehc->High32bitAddr\r
+                   );\r
+\r
+  if (Ehc->MemPool == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = EhcCreateHelpQ (Ehc);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Initialize the frame list entries then set the registers\r
+  //\r
+  Desc = (UINT32 *) Ehc->PeriodFrame;\r
+\r
+  for (Index = 0; Index < EHC_FRAME_LEN; Index++) {\r
+    Desc[Index] = QH_LINK (Ehc->PeriodOne, EHC_TYPE_QH, FALSE);\r
+  }\r
+\r
+  EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (Ehc->PeriodFrame));\r
+\r
+  //\r
+  // Second initialize the asynchronous schedule:\r
+  // Only need to set the AsynListAddr register to\r
+  // the reclamation header\r
+  //\r
+  EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (Ehc->ReclaimHead));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free the schedule data. It may be partially initialized.\r
+  \r
+  @param  Ehc   The EHCI device. \r
+\r
+**/\r
+VOID\r
+EhcFreeSched (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+{\r
+  EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0);\r
+  EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0);\r
+\r
+  if (Ehc->PeriodOne != NULL) {\r
+    UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (PEI_EHC_QH));\r
+    Ehc->PeriodOne = NULL;\r
+  }\r
+\r
+  if (Ehc->ReclaimHead != NULL) {\r
+    UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (PEI_EHC_QH));\r
+    Ehc->ReclaimHead = NULL;\r
+  }\r
+\r
+  if (Ehc->ShortReadStop != NULL) {\r
+    UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (PEI_EHC_QTD));\r
+    Ehc->ShortReadStop = NULL;\r
+  }\r
+\r
+  if (Ehc->MemPool != NULL) {\r
+    UsbHcFreeMemPool (Ehc->MemPool);\r
+    Ehc->MemPool = NULL;\r
+  }\r
+\r
+  if (Ehc->PeriodFrame != NULL) {\r
+    Ehc->PeriodFrame = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+  Link the queue head to the asynchronous schedule list.\r
+  UEFI only supports one CTRL/BULK transfer at a time\r
+  due to its interfaces. This simplifies the AsynList\r
+  management: A reclamation header is always linked to\r
+  the AsyncListAddr, the only active QH is appended to it.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+  @param  Qh    The queue head to link.\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToAsync (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_EHC_QH           *Qh\r
+  )\r
+{\r
+  PEI_EHC_QH               *Head;\r
+\r
+  //\r
+  // Append the queue head after the reclaim header, then\r
+  // fix the hardware visiable parts (EHCI R1.0 page 72).\r
+  // ReclaimHead is always linked to the EHCI's AsynListAddr.\r
+  //\r
+  Head                    = Ehc->ReclaimHead;\r
+\r
+  Qh->NextQh              = Head->NextQh;\r
+  Head->NextQh            = Qh;\r
+\r
+  Qh->QhHw.HorizonLink    = QH_LINK (Head, EHC_TYPE_QH, FALSE);;\r
+  Head->QhHw.HorizonLink  = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+}\r
+\r
+/**\r
+  Unlink a queue head from the asynchronous schedule list.\r
+  Need to synchronize with hardware.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+  @param  Qh    The queue head to unlink.\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromAsync (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_EHC_QH           *Qh\r
+  )\r
+{\r
+  PEI_EHC_QH              *Head;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Ehc->ReclaimHead->NextQh == Qh);\r
+\r
+  //\r
+  // Remove the QH from reclamation head, then update the hardware\r
+  // visiable part: Only need to loopback the ReclaimHead. The Qh\r
+  // is pointing to ReclaimHead (which is staill in the list).\r
+  //\r
+  Head                    = Ehc->ReclaimHead;\r
+\r
+  Head->NextQh            = Qh->NextQh;\r
+  Qh->NextQh              = NULL;\r
+\r
+  Head->QhHw.HorizonLink  = QH_LINK (Head, EHC_TYPE_QH, FALSE);\r
+\r
+  //\r
+  // Set and wait the door bell to synchronize with the hardware\r
+  //\r
+  Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIMEOUT);\r
+  \r
+  return;\r
+}\r
+\r
+/**\r
+  Link a queue head for interrupt transfer to the periodic\r
+  schedule frame list. This code is very much the same as\r
+  that in UHCI.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+  @param  Qh    The queue head to link.\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToPeriod (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_EHC_QH           *Qh\r
+  )\r
+{\r
+  UINT32                  *Frames;\r
+  UINTN                   Index;\r
+  PEI_EHC_QH              *Prev;\r
+  PEI_EHC_QH              *Next;\r
+\r
+  Frames = Ehc->PeriodFrame;\r
+\r
+  for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {\r
+    //\r
+    // First QH can't be NULL because we always keep PeriodOne\r
+    // heads on the frame list\r
+    //\r
+    ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));\r
+    Next  = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);\r
+    Prev  = NULL;\r
+\r
+    //\r
+    // Now, insert the queue head (Qh) into this frame:\r
+    // 1. Find a queue head with the same poll interval, just insert\r
+    //    Qh after this queue head, then we are done.\r
+    //\r
+    // 2. Find the position to insert the queue head into:\r
+    //      Previous head's interval is bigger than Qh's\r
+    //      Next head's interval is less than Qh's\r
+    //    Then, insert the Qh between then\r
+    //\r
+    while (Next->Interval > Qh->Interval) {\r
+      Prev  = Next;\r
+      Next  = Next->NextQh;\r
+    }\r
+\r
+    ASSERT (Next != NULL);\r
+\r
+    //\r
+    // The entry may have been linked into the frame by early insertation.\r
+    // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh\r
+    // with Qh.Interval == 8 on the frame. If so, we are done with this frame.\r
+    // It isn't necessary to compare all the QH with the same interval to\r
+    // Qh. This is because if there is other QH with the same interval, Qh\r
+    // should has been inserted after that at Frames[0] and at Frames[0] it is\r
+    // impossible for (Next == Qh)\r
+    //\r
+    if (Next == Qh) {\r
+      continue;\r
+    }\r
+\r
+    if (Next->Interval == Qh->Interval) {\r
+      //\r
+      // If there is a QH with the same interval, it locates at\r
+      // Frames[0], and we can simply insert it after this QH. We\r
+      // are all done.\r
+      //\r
+      ASSERT ((Index == 0) && (Qh->NextQh == NULL));\r
+\r
+      Prev                    = Next;\r
+      Next                    = Next->NextQh;\r
+\r
+      Qh->NextQh              = Next;\r
+      Prev->NextQh            = Qh;\r
+\r
+      Qh->QhHw.HorizonLink    = Prev->QhHw.HorizonLink;\r
+      Prev->QhHw.HorizonLink  = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+      break;\r
+    }\r
+    \r
+    //\r
+    // OK, find the right position, insert it in. If Qh's next\r
+    // link has already been set, it is in position. This is\r
+    // guarranted by 2^n polling interval.\r
+    //\r
+    if (Qh->NextQh == NULL) {\r
+      Qh->NextQh              = Next;\r
+      Qh->QhHw.HorizonLink    = QH_LINK (Next, EHC_TYPE_QH, FALSE);\r
+    }\r
+\r
+    if (Prev == NULL) {\r
+      Frames[Index] = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+    } else {\r
+      Prev->NextQh            = Qh;\r
+      Prev->QhHw.HorizonLink  = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Unlink an interrupt queue head from the periodic \r
+  schedule frame list.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+  @param  Qh    The queue head to unlink.\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromPeriod (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_EHC_QH           *Qh\r
+  )\r
+{\r
+  UINT32                  *Frames;\r
+  UINTN                   Index;\r
+  PEI_EHC_QH              *Prev;\r
+  PEI_EHC_QH              *This;\r
+\r
+  Frames = Ehc->PeriodFrame;\r
+\r
+  for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {\r
+    //\r
+    // Frame link can't be NULL because we always keep PeroidOne\r
+    // on the frame list\r
+    //\r
+    ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));\r
+    This  = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);\r
+    Prev  = NULL;\r
+\r
+    //\r
+    // Walk through the frame's QH list to find the\r
+    // queue head to remove\r
+    //\r
+    while ((This != NULL) && (This != Qh)) {\r
+      Prev  = This;\r
+      This  = This->NextQh;\r
+    }\r
+    \r
+    //\r
+    // Qh may have already been unlinked from this frame\r
+    // by early action. See the comments in EhcLinkQhToPeriod.\r
+    //\r
+    if (This == NULL) {\r
+      continue;\r
+    }\r
+\r
+    if (Prev == NULL) {\r
+      //\r
+      // Qh is the first entry in the frame\r
+      //\r
+      Frames[Index] = Qh->QhHw.HorizonLink;\r
+    } else {\r
+      Prev->NextQh            = Qh->NextQh;\r
+      Prev->QhHw.HorizonLink  = Qh->QhHw.HorizonLink;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Check the URB's execution result and update the URB's\r
+  result accordingly. \r
+\r
+  @param Ehc   The EHCI device.\r
+  @param Urb   The URB to check result.\r
+\r
+  @retval TRUE    URB transfer is finialized.\r
+  @retval FALSE   URB transfer is not finialized.\r
+\r
+**/\r
+BOOLEAN\r
+EhcCheckUrbResult (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  PEI_URB             *Urb\r
+  )\r
+{\r
+  EFI_LIST_ENTRY          *Entry;\r
+  PEI_EHC_QTD             *Qtd;\r
+  QTD_HW                  *QtdHw;\r
+  UINT8                   State;\r
+  BOOLEAN                 Finished;\r
+\r
+  ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));\r
+\r
+  Finished        = TRUE;\r
+  Urb->Completed  = 0;\r
+\r
+  Urb->Result     = EFI_USB_NOERROR;\r
+\r
+  if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+    Urb->Result |= EFI_USB_ERR_SYSTEM;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {\r
+    Qtd   = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);\r
+    QtdHw = &Qtd->QtdHw;\r
+    State = (UINT8) QtdHw->Status;\r
+\r
+    if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {\r
+      //\r
+      // EHCI will halt the queue head when met some error.\r
+      // If it is halted, the result of URB is finialized.\r
+      //\r
+      if ((State & QTD_STAT_ERR_MASK) == 0) {\r
+        Urb->Result |= EFI_USB_ERR_STALL;\r
+      }\r
+\r
+      if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {\r
+        Urb->Result |= EFI_USB_ERR_BABBLE;\r
+      }\r
+\r
+      if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {\r
+        Urb->Result |= EFI_USB_ERR_BUFFER;\r
+      }\r
+\r
+      if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) {\r
+        Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
+      }\r
+\r
+      Finished = TRUE;\r
+      goto ON_EXIT;\r
+      \r
+    } else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {\r
+      //\r
+      // The QTD is still active, no need to check furthur.\r
+      //\r
+      Urb->Result |= EFI_USB_ERR_NOTEXECUTE;\r
+      \r
+      Finished = FALSE;\r
+      goto ON_EXIT;\r
+\r
+    } else {\r
+      //\r
+      // This QTD is finished OK or met short packet read. Update the\r
+      // transfer length if it isn't a setup.\r
+      //\r
+      if (QtdHw->Pid != QTD_PID_SETUP) {\r
+        Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes;\r
+      }\r
+\r
+      if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {\r
+        //EHC_DUMP_QH ((Urb->Qh, "Short packet read", FALSE));\r
+\r
+        //\r
+        // Short packet read condition. If it isn't a setup transfer,\r
+        // no need to check furthur: the queue head will halt at the\r
+        // ShortReadStop. If it is a setup transfer, need to check the\r
+        // Status Stage of the setup transfer to get the finial result\r
+        //\r
+        if (QtdHw->AltNext == QTD_LINK (Ehc->ShortReadStop, FALSE)) {\r
+          \r
+          Finished = TRUE;\r
+          goto ON_EXIT;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+  //\r
+  // Return the data toggle set by EHCI hardware, bulk and interrupt\r
+  // transfer will use this to initialize the next transaction. For\r
+  // Control transfer, it always start a new data toggle sequence for\r
+  // new transfer.\r
+  //\r
+  // NOTICE: don't move DT update before the loop, otherwise there is\r
+  // a race condition that DT is wrong.\r
+  //\r
+  Urb->DataToggle = (UINT8) Urb->Qh->QhHw.DataToggle;\r
+\r
+  return Finished;\r
+}\r
+\r
+/**\r
+  Execute the transfer by polling the URB. This is a synchronous operation.\r
+  \r
+  @param  Ehc               The EHCI device.\r
+  @param  Urb               The URB to execute.\r
+  @param  TimeOut           The time to wait before abort, in millisecond.\r
+\r
+  @retval EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @retval EFI_TIMEOUT       The transfer failed due to time out.\r
+  @retval EFI_SUCCESS       The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcExecTransfer (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  PEI_URB             *Urb,\r
+  IN  UINTN               TimeOut\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   Index;\r
+  UINTN                   Loop;\r
+  BOOLEAN                 Finished;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  Loop      = (TimeOut * EHC_1_MILLISECOND / EHC_SYNC_POLL_INTERVAL) + 1;\r
+  Finished  = FALSE;\r
+\r
+  for (Index = 0; Index < Loop; Index++) {\r
+    Finished = EhcCheckUrbResult (Ehc, Urb);\r
+\r
+    if (Finished) {\r
+      break;\r
+    }\r
+\r
+    MicroSecondDelay (EHC_SYNC_POLL_INTERVAL);\r
+  }\r
+\r
+  if (!Finished) {\r
+    Status = EFI_TIMEOUT;\r
+  } else if (Urb->Result != EFI_USB_NOERROR) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Delete a single asynchronous interrupt transfer for\r
+  the device and endpoint.\r
+  \r
+  @param  Ehc               The EHCI device.\r
+  @param  DevAddr           The address of the target device.\r
+  @param  EpNum             The endpoint of the target.\r
+  @param  DataToggle        Return the next data toggle to use.\r
+\r
+  @retval EFI_NOT_FOUND     No transfer for the device is found.\r
+  @retval EFI_SUCCESS       An asynchronous transfer is removed.\r
+\r
+**/\r
+EFI_STATUS\r
+EhciDelAsyncIntTransfer (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               EpNum,  \r
+  OUT UINT8               *DataToggle\r
+  )\r
+{\r
+  EFI_LIST_ENTRY          *Entry;\r
+  EFI_LIST_ENTRY          *Next;\r
+  PEI_URB                 *Urb;\r
+  EFI_USB_DATA_DIRECTION  Direction;\r
+\r
+  Direction = (((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
+  EpNum    &= 0x0F;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, PEI_URB, UrbList);\r
+\r
+    if ((Urb->Ep.DevAddr == DevAddr) && (Urb->Ep.EpAddr == EpNum) && \r
+        (Urb->Ep.Direction == Direction)) {\r
+      //\r
+      // Check the URB status to retrieve the next data toggle\r
+      // from the associated queue head.\r
+      //\r
+      EhcCheckUrbResult (Ehc, Urb);\r
+      *DataToggle = Urb->DataToggle;\r
+\r
+      EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
+      RemoveEntryList (&Urb->UrbList);\r
+\r
+      EhcFreeUrb (Ehc, Urb);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Remove all the asynchronous interrutp transfers.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhciDelAllAsyncIntTransfers (\r
+  IN PEI_USB2_HC_DEV      *Ehc\r
+  )\r
+{\r
+  EFI_LIST_ENTRY          *Entry;\r
+  EFI_LIST_ENTRY          *Next;\r
+  PEI_URB                 *Urb;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, PEI_URB, UrbList);\r
+\r
+    EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
+    RemoveEntryList (&Urb->UrbList);\r
+\r
+    EhcFreeUrb (Ehc, Urb);\r
+  }\r
+}\r
+\r
+/**\r
+  Flush data from PCI controller specific address to mapped system \r
+  memory address.\r
+  \r
+  @param  Ehc               The EHCI device.\r
+  @param  Urb               The URB to unmap.\r
+\r
+  @retval EFI_DEVICE_ERROR  Fail to flush data to mapped system memory.\r
+  @retval EFI_SUCCESS       Success to flush data to mapped system memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcFlushAsyncIntMap (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  PEI_URB             *Urb\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+\r
+  Urb->DataMap  = NULL;\r
+  PhyAddr       =  (EFI_PHYSICAL_ADDRESS) (UINTN) Urb->Data;\r
+  Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Update the queue head for next round of asynchronous transfer.\r
+\r
+  @param Urb   The URB to update.\r
+\r
+**/\r
+VOID\r
+EhcUpdateAsyncRequest (\r
+  IN PEI_URB              *Urb\r
+  )\r
+{\r
+  EFI_LIST_ENTRY          *Entry;\r
+  PEI_EHC_QTD             *FirstQtd;\r
+  QH_HW                   *QhHw;\r
+  PEI_EHC_QTD             *Qtd;\r
+  QTD_HW                  *QtdHw;\r
+  UINTN                   Index;\r
+\r
+  Qtd = NULL;\r
+\r
+  if (Urb->Result == EFI_USB_NOERROR) {\r
+    FirstQtd = NULL;\r
+\r
+    EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {\r
+      Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);\r
+\r
+      if (FirstQtd == NULL) {\r
+        FirstQtd = Qtd;\r
+      }\r
+      \r
+      //\r
+      // Update the QTD for next round of transfer. Host control\r
+      // may change dt/Total Bytes to Transfer/C_Page/Cerr/Status/\r
+      // Current Offset. These fields need to be updated. DT isn't\r
+      // used by interrupt transfer. It uses DT in queue head.\r
+      // Current Offset is in Page[0], only need to reset Page[0]\r
+      // to initial data buffer.\r
+      //\r
+      QtdHw             = &Qtd->QtdHw;\r
+      QtdHw->Status     = QTD_STAT_ACTIVE;\r
+      QtdHw->ErrCnt     = QTD_MAX_ERR;\r
+      QtdHw->CurPage    = 0;\r
+      QtdHw->TotalBytes = (UINT32) Qtd->DataLen;\r
+      QtdHw->Page[0]    = EHC_LOW_32BIT (Qtd->Data);\r
+    }\r
+    \r
+    //\r
+    // Update QH for next round of transfer. Host control only\r
+    // touch the fields in transfer overlay area. Only need to\r
+    // zero out the overlay area and set NextQtd to the first\r
+    // QTD. DateToggle bit is left untouched.\r
+    //\r
+    QhHw              = &Urb->Qh->QhHw;\r
+    QhHw->CurQtd      = QTD_LINK (0, TRUE);\r
+    QhHw->AltQtd      = 0;\r
+\r
+    QhHw->Status      = 0;\r
+    QhHw->Pid         = 0;\r
+    QhHw->ErrCnt      = 0;\r
+    QhHw->CurPage     = 0;\r
+    QhHw->Ioc         = 0;\r
+    QhHw->TotalBytes  = 0;\r
+\r
+    for (Index = 0; Index < 5; Index++) {\r
+      QhHw->Page[Index]     = 0;\r
+      QhHw->PageHigh[Index] = 0;\r
+    }\r
+\r
+    QhHw->NextQtd = QTD_LINK (FirstQtd, FALSE);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Remove all the asynchronous interrutp transfers.\r
+  \r
+  @param  Event         Interrupt event.\r
+  @param  Context       Pointer to PEI_USB2_HC_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EhcMoniteAsyncRequests (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+{\r
+  PEI_USB2_HC_DEV         *Ehc;\r
+  EFI_LIST_ENTRY          *Entry;\r
+  EFI_LIST_ENTRY          *Next;\r
+  BOOLEAN                 Finished;\r
+  UINT8                   *ProcBuf;\r
+  PEI_URB                 *Urb;\r
+  EFI_STATUS              Status;\r
+  UINTN               PageNumber;\r
+\r
+  Ehc     = (PEI_USB2_HC_DEV *) Context;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, PEI_URB, UrbList);\r
+\r
+    //\r
+    // Check the result of URB execution. If it is still\r
+    // active, check the next one.\r
+    //\r
+    Finished = EhcCheckUrbResult (Ehc, Urb);\r
+\r
+    if (!Finished) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Flush any PCI posted write transactions from a PCI host \r
+    // bridge to system memory.\r
+    //\r
+    Status = EhcFlushAsyncIntMap (Ehc, Urb);\r
+    \r
+    //\r
+    // Allocate a buffer then copy the transferred data for user.\r
+    // If failed to allocate the buffer, update the URB for next\r
+    // round of transfer. Ignore the data of this round.\r
+    //\r
+    ProcBuf = NULL;\r
+\r
+    if (Urb->Result == EFI_USB_NOERROR) {\r
+      ASSERT (Urb->Completed <= Urb->DataLen);\r
+      PageNumber =  Urb->Completed/PAGESIZE +1;\r
+      Status = PeiServicesAllocatePages (\r
+                 EfiBootServicesCode,\r
+                 PageNumber,\r
+                 (EFI_PHYSICAL_ADDRESS *)ProcBuf\r
+                 );\r
+      if (ProcBuf == NULL) {\r
+        EhcUpdateAsyncRequest (Urb);\r
+        continue;\r
+      }\r
+\r
+      CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
+    }\r
+\r
+    EhcUpdateAsyncRequest (Urb);\r
+\r
+    //\r
+    // Leave error recovery to its related device driver. A\r
+    // common case of the error recovery is to re-submit the\r
+    // interrupt transfer which is linked to the head of the\r
+    // list. This function scans from head to tail. So the\r
+    // re-submitted interrupt transfer's callback function\r
+    // will not be called again in this round. Don't touch this\r
+    // URB after the callback, it may have been removed by the\r
+    // callback.\r
+    //\r
+    if (Urb->Callback != NULL) {\r
+      (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
+    }\r
+\r
+    if (ProcBuf != NULL) {\r
+    }\r
+  }\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.h b/MdeModulePkg/Bus/Pci/EhciPei/EhciSched.h
new file mode 100644 (file)
index 0000000..0eb90f8
--- /dev/null
@@ -0,0 +1,180 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 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
+#ifndef _EFI_EHCI_SCHED_H_\r
+#define _EFI_EHCI_SCHED_H_\r
+\r
+/**\r
+  Initialize the schedule data structure such as frame list.\r
+  \r
+  @param  Ehc   The EHCI device to init schedule data for.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to init schedule data.\r
+  @retval EFI_SUCCESS           The schedule data is initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitSched (\r
+  IN PEI_USB2_HC_DEV          *Ehc\r
+  )\r
+;\r
+\r
+/**\r
+  Free the schedule data. It may be partially initialized.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhcFreeSched (\r
+  IN PEI_USB2_HC_DEV          *Ehc\r
+  )\r
+;\r
+\r
+/**\r
+  Link the queue head to the asynchronous schedule list.\r
+  UEFI only supports one CTRL/BULK transfer at a time\r
+  due to its interfaces. This simplifies the AsynList\r
+  management: A reclamation header is always linked to\r
+  the AsyncListAddr, the only active QH is appended to it.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+  @param  Qh    The queue head to link.\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToAsync (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_EHC_QH           *Qh\r
+  )\r
+;\r
+\r
+/**\r
+  Unlink a queue head from the asynchronous schedule list.\r
+  Need to synchronize with hardware.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+  @param  Qh    The queue head to unlink.\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromAsync (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_EHC_QH           *Qh\r
+  )\r
+;\r
+\r
+/**\r
+  Link a queue head for interrupt transfer to the periodic\r
+  schedule frame list. This code is very much the same as\r
+  that in UHCI.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+  @param  Qh    The queue head to link.\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToPeriod (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_EHC_QH           *Qh\r
+  )\r
+;\r
+\r
+/**\r
+  Unlink an interrupt queue head from the periodic \r
+  schedule frame list.\r
+  \r
+  @param  Ehc   The EHCI device.\r
+  @param  Qh    The queue head to unlink.\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromPeriod (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_EHC_QH           *Qh\r
+  )\r
+;\r
+\r
+/**\r
+  Execute the transfer by polling the URB. This is a synchronous operation.\r
+  \r
+  @param  Ehc               The EHCI device.\r
+  @param  Urb               The URB to execute.\r
+  @param  TimeOut           The time to wait before abort, in millisecond.\r
+\r
+  @retval EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @retval EFI_TIMEOUT       The transfer failed due to time out.\r
+  @retval EFI_SUCCESS       The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcExecTransfer (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  PEI_URB             *Urb,\r
+  IN  UINTN               TimeOut\r
+  )\r
+;\r
+\r
+/**\r
+  Delete a single asynchronous interrupt transfer for\r
+  the device and endpoint.\r
+  \r
+  @param  Ehc               The EHCI device.\r
+  @param  DevAddr           The address of the target device.\r
+  @param  EpNum             The endpoint of the target.\r
+  @param  DataToggle        Return the next data toggle to use.\r
+\r
+  @retval EFI_NOT_FOUND     No transfer for the device is found.\r
+  @retval EFI_SUCCESS       An asynchronous transfer is removed.\r
+\r
+**/\r
+EFI_STATUS\r
+EhciDelAsyncIntTransfer (\r
+  IN  PEI_USB2_HC_DEV     *Ehc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               EpNum,  \r
+  OUT UINT8               *DataToggle\r
+  )\r
+;\r
+\r
+/**\r
+  Remove all the asynchronous interrutp transfers.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhciDelAllAsyncIntTransfers (\r
+  IN PEI_USB2_HC_DEV          *Ehc\r
+  )\r
+;\r
+\r
+/**\r
+  Remove all the asynchronous interrutp transfers.\r
+  \r
+  @param  Event         Interrupt event.\r
+  @param  Context       Pointer to PEI_USB2_HC_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EhcMoniteAsyncRequests (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c b/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c
new file mode 100644 (file)
index 0000000..597a494
--- /dev/null
@@ -0,0 +1,610 @@
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 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 "EhcPeim.h"\r
+\r
+/**\r
+  Delete a single asynchronous interrupt transfer for\r
+  the device and endpoint.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+  @param  Data        Current data not associated with a QTD.\r
+  @param  DataLen     The length of the data.\r
+  @param  PktId       Packet ID to use in the QTD.\r
+  @param  Toggle      Data toggle to use in the QTD.\r
+  @param  MaxPacket   Maximu packet length of the endpoint.\r
+\r
+  @retval the pointer to the created QTD or NULL if failed to create one.\r
+\r
+**/\r
+PEI_EHC_QTD *\r
+EhcCreateQtd (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT8                *Data,\r
+  IN UINTN                DataLen,\r
+  IN UINT8                PktId,\r
+  IN UINT8                Toggle,\r
+  IN UINTN                MaxPacket\r
+  )\r
+{\r
+  PEI_EHC_QTD             *Qtd;\r
+  QTD_HW                  *QtdHw;\r
+  UINTN                   Index;\r
+  UINTN                   Len;\r
+  UINTN                   ThisBufLen;\r
+\r
+  ASSERT (Ehc != NULL);\r
+\r
+  Qtd = UsbHcAllocateMem (Ehc, Ehc->MemPool, sizeof (PEI_EHC_QTD));\r
+\r
+  if (Qtd == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Qtd->Signature    = EHC_QTD_SIG;\r
+  Qtd->Data         = Data;\r
+  Qtd->DataLen      = 0;\r
+\r
+  InitializeListHead (&Qtd->QtdList);\r
+\r
+  QtdHw             = &Qtd->QtdHw;\r
+  QtdHw->NextQtd    = QTD_LINK (NULL, TRUE);\r
+  QtdHw->AltNext    = QTD_LINK (NULL, TRUE);\r
+  QtdHw->Status     = QTD_STAT_ACTIVE;\r
+  QtdHw->Pid        = PktId;\r
+  QtdHw->ErrCnt     = QTD_MAX_ERR;\r
+  QtdHw->Ioc        = 0;\r
+  QtdHw->TotalBytes = 0;\r
+  QtdHw->DataToggle = Toggle;\r
+\r
+  //\r
+  // Fill in the buffer points\r
+  //\r
+  if (Data != NULL) {\r
+    Len = 0;\r
+\r
+    for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {\r
+      //\r
+      // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to\r
+      // compute the offset and clear Reserved fields. This is already\r
+      // done in the data point.\r
+      //\r
+      QtdHw->Page[Index]      = EHC_LOW_32BIT (Data);\r
+      QtdHw->PageHigh[Index]  = EHC_HIGH_32BIT (Data);\r
+\r
+      ThisBufLen              = QTD_BUF_LEN - (EHC_LOW_32BIT (Data) & QTD_BUF_MASK);\r
+\r
+      if (Len + ThisBufLen >= DataLen) {\r
+        Len = DataLen;\r
+        break;\r
+      }\r
+\r
+      Len += ThisBufLen;\r
+      Data += ThisBufLen;\r
+    }\r
+    \r
+    //\r
+    // Need to fix the last pointer if the Qtd can't hold all the\r
+    // user's data to make sure that the length is in the unit of\r
+    // max packets. If it can hold all the data, there is no such\r
+    // need.\r
+    //\r
+    if (Len < DataLen) {\r
+      Len = Len - Len % MaxPacket;\r
+    }\r
+\r
+    QtdHw->TotalBytes = (UINT32) Len;\r
+    Qtd->DataLen      = Len;\r
+  }\r
+\r
+  return Qtd;\r
+}\r
+\r
+/**\r
+  Initialize the queue head for interrupt transfer,\r
+  that is, initialize the following three fields:\r
+    1. SplitXState in the Status field.\r
+    2. Microframe S-mask.\r
+    3. Microframe C-mask.\r
+  \r
+  @param  Ep    The queue head's related endpoint.\r
+  @param  QhHw  The queue head to initialize.\r
+\r
+**/\r
+VOID\r
+EhcInitIntQh (\r
+  IN USB_ENDPOINT         *Ep,\r
+  IN QH_HW                *QhHw\r
+  )\r
+{\r
+  //\r
+  // Because UEFI interface can't utilitize an endpoint with\r
+  // poll rate faster than 1ms, only need to set one bit in\r
+  // the queue head. simple. But it may be changed later. If\r
+  // sub-1ms interrupt is supported, need to update the S-Mask\r
+  // here\r
+  //\r
+  if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {\r
+    QhHw->SMask = QH_MICROFRAME_0;\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // For low/full speed device, the transfer must go through\r
+  // the split transaction. Need to update three fields\r
+  // 1. SplitXState in the status\r
+  // 2. Microframe S-Mask\r
+  // 3. Microframe C-Mask\r
+  // UEFI USB doesn't exercise admission control. It simplely\r
+  // schedule the high speed transactions in microframe 0, and\r
+  // full/low speed transactions at microframe 1. This also\r
+  // avoid the use of FSTN.\r
+  //\r
+  QhHw->SMask = QH_MICROFRAME_1;\r
+  QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;\r
+}\r
+\r
+/**\r
+  Allocate and initialize a EHCI queue head.\r
+  \r
+  @param  Ehci      The EHCI device.\r
+  @param  Ep        The endpoint to create queue head for.\r
+\r
+  @retval the pointer to the created queue head or NULL if failed to create one.\r
+\r
+**/\r
+PEI_EHC_QH *\r
+EhcCreateQh (\r
+  IN PEI_USB2_HC_DEV      *Ehci,\r
+  IN USB_ENDPOINT         *Ep\r
+  )\r
+{\r
+  PEI_EHC_QH              *Qh;\r
+  QH_HW                   *QhHw;\r
+\r
+  Qh = UsbHcAllocateMem (Ehci, Ehci->MemPool, sizeof (PEI_EHC_QH));\r
+\r
+  if (Qh == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Qh->Signature       = EHC_QH_SIG;\r
+  Qh->NextQh          = NULL;\r
+  Qh->Interval        = Ep->PollRate;\r
+  \r
+  InitializeListHead (&Qh->Qtds);\r
+\r
+  QhHw                = &Qh->QhHw;\r
+  QhHw->HorizonLink   = QH_LINK (NULL, 0, TRUE);\r
+  QhHw->DeviceAddr    = Ep->DevAddr;\r
+  QhHw->Inactive      = 0;\r
+  QhHw->EpNum         = Ep->EpAddr;\r
+  QhHw->EpSpeed       = Ep->DevSpeed;\r
+  QhHw->DtCtrl        = 0;\r
+  QhHw->ReclaimHead   = 0;\r
+  QhHw->MaxPacketLen  = (UINT32) Ep->MaxPacket;\r
+  QhHw->CtrlEp        = 0;\r
+  QhHw->NakReload     = QH_NAK_RELOAD;\r
+  QhHw->HubAddr       = Ep->HubAddr;\r
+  QhHw->PortNum       = Ep->HubPort;\r
+  QhHw->Multiplier    = 1;\r
+  QhHw->DataToggle    = Ep->Toggle;\r
+\r
+  if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r
+    QhHw->Status |= QTD_STAT_DO_SS;\r
+  }\r
+\r
+  switch (Ep->Type) {\r
+  case EHC_CTRL_TRANSFER:\r
+    //\r
+    // Special initialization for the control transfer:\r
+    // 1. Control transfer initialize data toggle from each QTD\r
+    // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.\r
+    //\r
+    QhHw->DtCtrl = 1;\r
+\r
+    if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r
+      QhHw->CtrlEp = 1;\r
+    }\r
+    break;\r
+\r
+  case EHC_INT_TRANSFER_ASYNC:\r
+  case EHC_INT_TRANSFER_SYNC:\r
+    //\r
+    // Special initialization for the interrupt transfer\r
+    // to set the S-Mask and C-Mask\r
+    //\r
+    QhHw->NakReload = 0;\r
+    EhcInitIntQh (Ep, QhHw);\r
+    break;\r
+\r
+  case EHC_BULK_TRANSFER:\r
+    if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {\r
+      QhHw->Status |= QTD_STAT_DO_PING;\r
+    }\r
+\r
+    break;\r
+  }\r
+\r
+  return Qh;\r
+}\r
+\r
+/**\r
+  Convert the poll interval from application to that\r
+  be used by EHCI interface data structure. Only need\r
+  to get the max 2^n that is less than interval. UEFI\r
+  can't support high speed endpoint with a interval less\r
+  than 8 microframe because interval is specified in\r
+  the unit of ms (millisecond).\r
+  \r
+  @param Interval       The interval to convert.\r
+\r
+  @retval The converted interval.\r
+\r
+**/\r
+UINTN\r
+EhcConvertPollRate (\r
+  IN  UINTN               Interval\r
+  )\r
+{\r
+  UINTN                   BitCount;\r
+\r
+  if (Interval == 0) {\r
+    return 1;\r
+  }\r
+  \r
+  //\r
+  // Find the index (1 based) of the highest non-zero bit\r
+  //\r
+  BitCount = 0;\r
+\r
+  while (Interval != 0) {\r
+    Interval >>= 1;\r
+    BitCount++;\r
+  }\r
+\r
+  return (UINTN)1 << (BitCount - 1);\r
+}\r
+\r
+/**\r
+  Free a list of QTDs.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+  @param  Qtds        The list head of the QTD.\r
+\r
+**/\r
+VOID\r
+EhcFreeQtds (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN EFI_LIST_ENTRY       *Qtds\r
+  )\r
+{\r
+  EFI_LIST_ENTRY          *Entry;\r
+  EFI_LIST_ENTRY          *Next;\r
+  PEI_EHC_QTD             *Qtd;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {\r
+    Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);\r
+\r
+    RemoveEntryList (&Qtd->QtdList);\r
+    UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (PEI_EHC_QTD));\r
+  }\r
+}\r
+\r
+/**\r
+  Free an allocated URB. It is possible for it to be partially inited.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+  @param  Urb         The URB to free.\r
+\r
+**/\r
+VOID\r
+EhcFreeUrb (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_URB              *Urb\r
+  )\r
+{\r
+  if (Urb->Qh != NULL) {\r
+    //\r
+    // Ensure that this queue head has been unlinked from the\r
+    // schedule data structures. Free all the associated QTDs\r
+    //\r
+    EhcFreeQtds (Ehc, &Urb->Qh->Qtds);\r
+    UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (PEI_EHC_QH));\r
+  }\r
+}\r
+\r
+/**\r
+  Create a list of QTDs for the URB.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+  @param  Urb         The URB to create QTDs for.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate resource for QTD.\r
+  @retval EFI_SUCCESS             The QTDs are allocated for the URB.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcCreateQtds (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_URB              *Urb\r
+  )\r
+{\r
+  USB_ENDPOINT            *Ep;\r
+  PEI_EHC_QH              *Qh;\r
+  PEI_EHC_QTD             *Qtd;\r
+  PEI_EHC_QTD             *StatusQtd;\r
+  PEI_EHC_QTD             *NextQtd;\r
+  EFI_LIST_ENTRY          *Entry;\r
+  UINT32                  AlterNext;\r
+  UINT8                   Toggle;\r
+  UINTN                   Len;\r
+  UINT8                   Pid;\r
+\r
+  ASSERT ((Urb != NULL) && (Urb->Qh != NULL));\r
+\r
+  //\r
+  // EHCI follows the alternet next QTD pointer if it meets\r
+  // a short read and the AlterNext pointer is valid. UEFI\r
+  // EHCI driver should terminate the transfer except the\r
+  // control transfer.\r
+  //\r
+  Toggle    = 0;\r
+  Qh        = Urb->Qh;\r
+  Ep        = &Urb->Ep;\r
+  StatusQtd = NULL;\r
+  AlterNext = QTD_LINK (NULL, TRUE);\r
+\r
+  if (Ep->Direction == EfiUsbDataIn) {\r
+    AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE);\r
+  }\r
+  \r
+  //\r
+  // Build the Setup and status packets for control transfer\r
+  //\r
+  if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {\r
+    Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
+    Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);\r
+\r
+    if (Qtd == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
+\r
+    //\r
+    // Create the status packet now. Set the AlterNext to it. So, when\r
+    // EHCI meets a short control read, it can resume at the status stage.\r
+    // Use the opposite direction of the data stage, or IN if there is\r
+    // no data stage.\r
+    //\r
+    if (Ep->Direction == EfiUsbDataIn) {\r
+      Pid = QTD_PID_OUTPUT;\r
+    } else {\r
+      Pid = QTD_PID_INPUT;\r
+    }\r
+\r
+    StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket);\r
+\r
+    if (StatusQtd == NULL) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    if (Ep->Direction == EfiUsbDataIn) {\r
+      AlterNext = QTD_LINK (StatusQtd, FALSE);\r
+    }\r
+\r
+    Toggle = 1;\r
+  }\r
+\r
+  //\r
+  // Build the data packets for all the transfers\r
+  //\r
+  if (Ep->Direction == EfiUsbDataIn) {\r
+    Pid = QTD_PID_INPUT;\r
+  } else {\r
+    Pid = QTD_PID_OUTPUT;\r
+  }\r
+\r
+  Qtd = NULL;\r
+  Len = 0;\r
+\r
+  while (Len < Urb->DataLen) {\r
+    Qtd = EhcCreateQtd (\r
+            Ehc,\r
+            (UINT8 *) Urb->DataPhy + Len,\r
+            Urb->DataLen - Len,\r
+            Pid,\r
+            Toggle,\r
+            Ep->MaxPacket\r
+            );\r
+\r
+    if (Qtd == NULL) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Qtd->QtdHw.AltNext = AlterNext;\r
+    InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
+\r
+    //\r
+    // Switch the Toggle bit if odd number of packets are included in the QTD.\r
+    //\r
+    if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {\r
+      Toggle = (UINT8) (1 - Toggle);\r
+    }\r
+\r
+    Len += Qtd->DataLen;\r
+  }\r
+  \r
+  //\r
+  // Insert the status packet for control transfer\r
+  //\r
+  if (Ep->Type == EHC_CTRL_TRANSFER) {\r
+    InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);\r
+  }\r
+\r
+  //\r
+  // OK, all the QTDs needed are created. Now, fix the NextQtd point\r
+  //\r
+  EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r
+    Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);\r
+\r
+    //\r
+    // break if it is the last entry on the list\r
+    //\r
+    if (Entry->ForwardLink == &Qh->Qtds) {\r
+      break;\r
+    }\r
+\r
+    NextQtd             = EFI_LIST_CONTAINER (Entry->ForwardLink, PEI_EHC_QTD, QtdList);\r
+    Qtd->QtdHw.NextQtd  = QTD_LINK (NextQtd, FALSE);\r
+  }\r
+\r
+  //\r
+  // Link the QTDs to the queue head\r
+  //\r
+  NextQtd           = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, PEI_EHC_QTD, QtdList);\r
+  Qh->QhHw.NextQtd  = QTD_LINK (NextQtd, FALSE);\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  EhcFreeQtds (Ehc, &Qh->Qtds);\r
+  return EFI_OUT_OF_RESOURCES;\r
+}\r
+\r
+/**\r
+  Create a new URB and its associated QTD.\r
+  \r
+  @param  Ehc               The EHCI device.\r
+  @param  DevAddr           The device address.\r
+  @param  EpAddr            Endpoint addrress & its direction.\r
+  @param  DevSpeed          The device speed.\r
+  @param  Toggle            Initial data toggle to use.\r
+  @param  MaxPacket         The max packet length of the endpoint.\r
+  @param  Hub               The transaction translator to use.\r
+  @param  Type              The transaction type.\r
+  @param  Request           The standard USB request for control transfer.\r
+  @param  Data              The user data to transfer.\r
+  @param  DataLen           The length of data buffer.\r
+  @param  Callback          The function to call when data is transferred.\r
+  @param  Context           The context to the callback.\r
+  @param  Interval          The interval for interrupt transfer.\r
+\r
+  @retval the pointer to the created URB or NULL.\r
+\r
+**/\r
+PEI_URB *\r
+EhcCreateUrb (\r
+  IN PEI_USB2_HC_DEV                    *Ehc,\r
+  IN UINT8                              DevAddr,\r
+  IN UINT8                              EpAddr,  \r
+  IN UINT8                              DevSpeed,\r
+  IN UINT8                              Toggle,\r
+  IN UINTN                              MaxPacket,\r
+  IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
+  IN UINTN                              Type,\r
+  IN EFI_USB_DEVICE_REQUEST             *Request,\r
+  IN VOID                               *Data,\r
+  IN UINTN                              DataLen,\r
+  IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,\r
+  IN VOID                               *Context,\r
+  IN UINTN                              Interval\r
+  )\r
+{\r
+  USB_ENDPOINT                  *Ep;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Len;\r
+  PEI_URB                       *Urb;\r
+  VOID                          *Map;\r
+\r
+    \r
+  Map = NULL;\r
+  \r
+  Urb = Ehc->Urb;\r
+  Urb->Signature  = EHC_URB_SIG;\r
+  InitializeListHead (&Urb->UrbList);\r
+\r
+  Ep              = &Urb->Ep;\r
+  Ep->DevAddr     = DevAddr;\r
+  Ep->EpAddr      = (UINT8) (EpAddr & 0x0F);\r
+  Ep->Direction   = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
+  Ep->DevSpeed    = DevSpeed;\r
+  Ep->MaxPacket   = MaxPacket;\r
+\r
+  Ep->HubAddr     = 0;\r
+  Ep->HubPort     = 0;\r
+\r
+  if (DevSpeed != EFI_USB_SPEED_HIGH) {\r
+    ASSERT (Hub != NULL);\r
+\r
+    Ep->HubAddr   = Hub->TranslatorHubAddress;\r
+    Ep->HubPort   = Hub->TranslatorPortNumber;\r
+  }\r
+\r
+  Ep->Toggle      = Toggle;\r
+  Ep->Type        = Type;\r
+  Ep->PollRate    = EhcConvertPollRate (Interval);\r
+\r
+  Urb->Request    = Request;\r
+  Urb->Data       = Data;\r
+  Urb->DataLen    = DataLen;\r
+  Urb->Callback   = Callback;\r
+  Urb->Context    = Context;\r
+  Urb->Qh         = EhcCreateQh (Ehc, &Urb->Ep);\r
+\r
+  if (Urb->Qh == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+  \r
+  //\r
+  // Map the request and user data\r
+  //\r
+  if (Request != NULL) {\r
+    Len     = sizeof (EFI_USB_DEVICE_REQUEST);\r
+    PhyAddr =  (EFI_PHYSICAL_ADDRESS) (UINTN) Request ;\r
+    if ( (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);\r
+    Urb->RequestMap = Map;\r
+  }\r
+\r
+  if (Data != NULL) {\r
+    Len      = DataLen;\r
+    PhyAddr  =  (EFI_PHYSICAL_ADDRESS) (UINTN) Data ;\r
+    if ( (Len != DataLen)) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);\r
+    Urb->DataMap  = Map;\r
+  }\r
+\r
+  Status = EhcCreateQtds (Ehc, Urb);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  return Urb;\r
+\r
+ON_ERROR:\r
+  EhcFreeUrb (Ehc, Urb);\r
+  return NULL;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.h b/MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.h
new file mode 100644 (file)
index 0000000..3fe93fb
--- /dev/null
@@ -0,0 +1,331 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 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
+#ifndef _EFI_EHCI_URB_H_\r
+#define _EFI_EHCI_URB_H_\r
+\r
+typedef struct _PEI_EHC_QTD PEI_EHC_QTD;\r
+typedef struct _PEI_EHC_QH  PEI_EHC_QH;\r
+typedef struct _PEI_URB     PEI_URB;\r
+\r
+#define EHC_CTRL_TRANSFER       0x01\r
+#define EHC_BULK_TRANSFER       0x02\r
+#define EHC_INT_TRANSFER_SYNC   0x04\r
+#define EHC_INT_TRANSFER_ASYNC  0x08\r
+\r
+#define EHC_QTD_SIG             SIGNATURE_32 ('U', 'S', 'B', 'T')\r
+#define EHC_QH_SIG              SIGNATURE_32 ('U', 'S', 'B', 'H')\r
+#define EHC_URB_SIG             SIGNATURE_32 ('U', 'S', 'B', 'R')\r
+\r
+//\r
+// Hardware related bit definitions\r
+//\r
+#define EHC_TYPE_ITD            0x00\r
+#define EHC_TYPE_QH             0x02\r
+#define EHC_TYPE_SITD           0x04\r
+#define EHC_TYPE_FSTN           0x06\r
+\r
+#define QH_NAK_RELOAD           3\r
+#define QH_HSHBW_MULTI          1\r
+\r
+#define QTD_MAX_ERR             3\r
+#define QTD_PID_OUTPUT          0x00\r
+#define QTD_PID_INPUT           0x01\r
+#define QTD_PID_SETUP           0x02\r
+\r
+#define QTD_STAT_DO_OUT         0\r
+#define QTD_STAT_DO_SS          0\r
+#define QTD_STAT_DO_PING        0x01\r
+#define QTD_STAT_DO_CS          0x02\r
+#define QTD_STAT_TRANS_ERR      0x08\r
+#define QTD_STAT_BABBLE_ERR     0x10\r
+#define QTD_STAT_BUFF_ERR       0x20\r
+#define QTD_STAT_HALTED         0x40\r
+#define QTD_STAT_ACTIVE         0x80\r
+#define QTD_STAT_ERR_MASK       (QTD_STAT_TRANS_ERR | QTD_STAT_BABBLE_ERR | QTD_STAT_BUFF_ERR)\r
+\r
+#define QTD_MAX_BUFFER          4\r
+#define QTD_BUF_LEN             4096\r
+#define QTD_BUF_MASK            0x0FFF\r
+\r
+#define QH_MICROFRAME_0         0x01\r
+#define QH_MICROFRAME_1         0x02\r
+#define QH_MICROFRAME_2         0x04\r
+#define QH_MICROFRAME_3         0x08\r
+#define QH_MICROFRAME_4         0x10\r
+#define QH_MICROFRAME_5         0x20\r
+#define QH_MICROFRAME_6         0x40\r
+#define QH_MICROFRAME_7         0x80\r
+\r
+#define USB_ERR_SHORT_PACKET    0x200\r
+\r
+//\r
+// Fill in the hardware link point: pass in a EHC_QH/QH_HW \r
+// pointer to QH_LINK; A EHC_QTD/QTD_HW pointer to QTD_LINK\r
+//\r
+#define QH_LINK(Addr, Type, Term) \\r
+          ((UINT32) ((EHC_LOW_32BIT (Addr) & 0xFFFFFFE0) | (Type) | ((Term) ? 1 : 0)))\r
+\r
+#define QTD_LINK(Addr, Term)      QH_LINK((Addr), 0, (Term))\r
+\r
+//\r
+// The defination of EHCI hardware used data structure for \r
+// little endian architecture. The QTD and QH structures \r
+// are required to be 32 bytes aligned. Don't add members \r
+// to the head of the associated software strucuture.\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT32                  NextQtd;\r
+  UINT32                  AltNext;\r
+  \r
+  UINT32                  Status       : 8;\r
+  UINT32                  Pid          : 2;\r
+  UINT32                  ErrCnt       : 2;\r
+  UINT32                  CurPage      : 3;\r
+  UINT32                  Ioc          : 1;\r
+  UINT32                  TotalBytes   : 15;\r
+  UINT32                  DataToggle   : 1;\r
+\r
+  UINT32                  Page[5];\r
+  UINT32                  PageHigh[5];\r
+} QTD_HW;\r
+\r
+typedef struct {\r
+  UINT32                  HorizonLink;  \r
+  //\r
+  // Endpoint capabilities/Characteristics DWord 1 and DWord 2\r
+  //\r
+  UINT32                  DeviceAddr   : 7;\r
+  UINT32                  Inactive     : 1;\r
+  UINT32                  EpNum        : 4;\r
+  UINT32                  EpSpeed      : 2;\r
+  UINT32                  DtCtrl       : 1;\r
+  UINT32                  ReclaimHead  : 1;\r
+  UINT32                  MaxPacketLen : 11;\r
+  UINT32                  CtrlEp       : 1;\r
+  UINT32                  NakReload    : 4;\r
+\r
+  UINT32                  SMask        : 8;\r
+  UINT32                  CMask        : 8;\r
+  UINT32                  HubAddr      : 7;\r
+  UINT32                  PortNum      : 7;\r
+  UINT32                  Multiplier   : 2;\r
+\r
+  //\r
+  // Transaction execution overlay area\r
+  //\r
+  UINT32                  CurQtd;\r
+  UINT32                  NextQtd;\r
+  UINT32                  AltQtd;\r
+  \r
+  UINT32                  Status       : 8;\r
+  UINT32                  Pid          : 2;\r
+  UINT32                  ErrCnt       : 2;\r
+  UINT32                  CurPage      : 3;\r
+  UINT32                  Ioc          : 1;\r
+  UINT32                  TotalBytes   : 15;\r
+  UINT32                  DataToggle   : 1;\r
+\r
+  UINT32                  Page[5];\r
+  UINT32                  PageHigh[5];\r
+} QH_HW;\r
+#pragma pack()\r
+\r
+\r
+//\r
+// Endpoint address and its capabilities\r
+//\r
+typedef struct _USB_ENDPOINT {\r
+  UINT8                   DevAddr;\r
+  UINT8                   EpAddr;     // Endpoint address, no direction encoded in\r
+  EFI_USB_DATA_DIRECTION  Direction;\r
+  UINT8                   DevSpeed;\r
+  UINTN                   MaxPacket;\r
+  UINT8                   HubAddr;\r
+  UINT8                   HubPort;\r
+  UINT8                   Toggle;     // Data toggle, not used for control transfer\r
+  UINTN                   Type;\r
+  UINTN                   PollRate;   // Polling interval used by EHCI\r
+} USB_ENDPOINT;\r
+\r
+//\r
+// Software QTD strcture, this is used to manage all the \r
+// QTD generated from a URB. Don't add fields before QtdHw.\r
+//\r
+struct _PEI_EHC_QTD {\r
+  QTD_HW                  QtdHw;\r
+  UINT32                  Signature;\r
+  EFI_LIST_ENTRY          QtdList;   // The list of QTDs to one end point\r
+  UINT8                   *Data;     // Buffer of the original data\r
+  UINTN                   DataLen;   // Original amount of data in this QTD\r
+};\r
+\r
+\r
+\r
+//\r
+// Software QH structure. All three different transaction types \r
+// supported by UEFI USB, that is the control/bulk/interrupt \r
+// transfers use the queue head and queue token strcuture. \r
+//\r
+// Interrupt QHs are linked to periodic frame list in the reversed\r
+// 2^N tree. Each interrupt QH is linked to the list starting at \r
+// frame 0. There is a dummy interrupt QH linked to each frame as\r
+// a sentinental whose polling interval is 1. Synchronous interrupt\r
+// transfer is linked after this dummy QH. \r
+// \r
+// For control/bulk transfer, only synchronous (in the sense of UEFI) \r
+// transfer is supported. A dummy QH is linked to EHCI AsyncListAddr\r
+// as the reclamation header. New transfer is inserted after this QH.\r
+//\r
+struct _PEI_EHC_QH {\r
+  QH_HW                   QhHw;\r
+  UINT32                  Signature;\r
+  PEI_EHC_QH              *NextQh;    // The queue head pointed to by horizontal link\r
+  EFI_LIST_ENTRY          Qtds;       // The list of QTDs to this queue head\r
+  UINTN                   Interval; \r
+};\r
+\r
+//\r
+// URB (Usb Request Block) contains information for all kinds of \r
+// usb requests.\r
+//\r
+struct _PEI_URB {\r
+  UINT32                          Signature;\r
+  EFI_LIST_ENTRY                  UrbList;\r
+  \r
+  //\r
+  // Transaction information\r
+  //\r
+  USB_ENDPOINT                    Ep;\r
+  EFI_USB_DEVICE_REQUEST          *Request;     // Control transfer only\r
+  VOID                            *RequestPhy;  // Address of the mapped request\r
+  VOID                            *RequestMap;\r
+  VOID                            *Data;\r
+  UINTN                           DataLen;\r
+  VOID                            *DataPhy;     // Address of the mapped user data\r
+  VOID                            *DataMap;\r
+  EFI_ASYNC_USB_TRANSFER_CALLBACK Callback; \r
+  VOID                            *Context;\r
+\r
+  //\r
+  // Schedule data\r
+  //\r
+  PEI_EHC_QH                      *Qh;\r
+  \r
+  //\r
+  // Transaction result\r
+  //\r
+  UINT32                          Result;\r
+  UINTN                           Completed;    // completed data length\r
+  UINT8                           DataToggle;\r
+};\r
+\r
+/**\r
+  Delete a single asynchronous interrupt transfer for\r
+  the device and endpoint.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+  @param  Data        Current data not associated with a QTD.\r
+  @param  DataLen     The length of the data.\r
+  @param  PktId       Packet ID to use in the QTD.\r
+  @param  Toggle      Data toggle to use in the QTD.\r
+  @param  MaxPacket   Maximu packet length of the endpoint.\r
+\r
+  @retval the pointer to the created QTD or NULL if failed to create one.\r
+\r
+**/\r
+PEI_EHC_QTD *\r
+EhcCreateQtd (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN UINT8                *Data,\r
+  IN UINTN                DataLen,\r
+  IN UINT8                PktId,\r
+  IN UINT8                Toggle,\r
+  IN UINTN                MaxPacket\r
+  )\r
+;\r
+\r
+/**\r
+  Allocate and initialize a EHCI queue head.\r
+  \r
+  @param  Ehci      The EHCI device.\r
+  @param  Ep        The endpoint to create queue head for.\r
+\r
+  @retval the pointer to the created queue head or NULL if failed to create one.\r
+\r
+**/\r
+PEI_EHC_QH *\r
+EhcCreateQh (\r
+  IN PEI_USB2_HC_DEV      *Ehci,\r
+  IN USB_ENDPOINT         *Ep\r
+  )\r
+;\r
+\r
+/**\r
+  Free an allocated URB. It is possible for it to be partially inited.\r
+  \r
+  @param  Ehc         The EHCI device.\r
+  @param  Urb         The URB to free.\r
+\r
+**/\r
+VOID\r
+EhcFreeUrb (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN PEI_URB              *Urb\r
+  )\r
+;\r
+\r
+/**\r
+  Create a new URB and its associated QTD.\r
+  \r
+  @param  Ehc               The EHCI device.\r
+  @param  DevAddr           The device address.\r
+  @param  EpAddr            Endpoint addrress & its direction.\r
+  @param  DevSpeed          The device speed.\r
+  @param  Toggle            Initial data toggle to use.\r
+  @param  MaxPacket         The max packet length of the endpoint.\r
+  @param  Hub               The transaction translator to use.\r
+  @param  Type              The transaction type.\r
+  @param  Request           The standard USB request for control transfer.\r
+  @param  Data              The user data to transfer.\r
+  @param  DataLen           The length of data buffer.\r
+  @param  Callback          The function to call when data is transferred.\r
+  @param  Context           The context to the callback.\r
+  @param  Interval          The interval for interrupt transfer.\r
+\r
+  @retval the pointer to the created URB or NULL.\r
+\r
+**/\r
+PEI_URB *\r
+EhcCreateUrb (\r
+  IN PEI_USB2_HC_DEV                    *Ehc,\r
+  IN UINT8                              DevAddr,\r
+  IN UINT8                              EpAddr,  \r
+  IN UINT8                              DevSpeed,\r
+  IN UINT8                              Toggle,\r
+  IN UINTN                              MaxPacket,\r
+  IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
+  IN UINTN                              Type,\r
+  IN EFI_USB_DEVICE_REQUEST             *Request,\r
+  IN VOID                               *Data,\r
+  IN UINTN                              DataLen,\r
+  IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,\r
+  IN VOID                               *Context,\r
+  IN UINTN                              Interval\r
+  )\r
+;\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.c b/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.c
new file mode 100644 (file)
index 0000000..6b37558
--- /dev/null
@@ -0,0 +1,493 @@
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 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 "EhcPeim.h"\r
+\r
+/**\r
+  Allocate a block of memory to be used by the buffer pool.\r
+\r
+  @param  Ehc            The EHCI device.\r
+  @param  Pool           The buffer pool to allocate memory for.\r
+  @param  Pages          How many pages to allocate.\r
+\r
+  @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN  USBHC_MEM_POOL      *Pool,\r
+  IN  UINTN               Pages\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK         *Block;\r
+  VOID                    *BufHost;\r
+  VOID                    *Mapping;\r
+  EFI_PHYSICAL_ADDRESS    MappedAddr;\r
+  EFI_STATUS              Status;\r
+  UINTN               PageNumber;\r
+  EFI_PHYSICAL_ADDRESS        TempPtr;\r
+\r
+  Mapping = NULL;\r
+  PageNumber =  sizeof(USBHC_MEM_BLOCK)/PAGESIZE +1;\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             PageNumber,\r
+             &TempPtr\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+      return NULL;\r
+  }\r
+  ZeroMem ((VOID   *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);\r
+  \r
+  //\r
+  // each bit in the bit array represents USBHC_MEM_UNIT\r
+  // bytes of memory in the memory block.\r
+  //\r
+  ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+  \r
+  Block = (USBHC_MEM_BLOCK*)(UINTN)TempPtr;\r
+  Block->BufLen   = EFI_PAGES_TO_SIZE (Pages);\r
+  Block->BitsLen  = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+  \r
+  PageNumber =  (Block->BitsLen)/PAGESIZE +1;\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             PageNumber,\r
+             &TempPtr\r
+             );\r
+  \r
+    if (EFI_ERROR (Status)) {\r
+      return NULL;\r
+    }\r
+  ZeroMem ((VOID   *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);        \r
+\r
+  Block->Bits  = (UINT8 *)(UINTN)TempPtr;\r
+\r
+  \r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             Pages,\r
+             &TempPtr\r
+             );\r
+  ZeroMem ((VOID   *)(UINTN)TempPtr, Pages*EFI_PAGE_SIZE);\r
+\r
+  BufHost  = (VOID *)(UINTN)TempPtr;\r
+  MappedAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) BufHost;\r
+  //\r
+  // Check whether the data structure used by the host controller\r
+  // should be restricted into the same 4G\r
+  //\r
+  if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
+      return NULL;\r
+  }\r
+\r
+  Block->BufHost  = BufHost;\r
+  Block->Buf      = (UINT8 *) ((UINTN) MappedAddr);\r
+  Block->Mapping  = Mapping;\r
+  Block->Next      = NULL;\r
+\r
+  return Block;\r
+\r
+}\r
+\r
+/**\r
+  Free the memory block from the memory pool.\r
+\r
+  @param  Pool           The memory pool to free the block from.\r
+  @param  Block          The memory block to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMemBlock (\r
+  IN USBHC_MEM_POOL       *Pool,\r
+  IN USBHC_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  ASSERT ((Pool != NULL) && (Block != NULL));\r
+}\r
+\r
+/**\r
+  Alloc some memory from the block.\r
+\r
+  @param  Block          The memory block to allocate memory from.\r
+  @param  Units          Number of memory units to allocate.\r
+\r
+  @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+          the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocMemFromBlock (\r
+  IN  USBHC_MEM_BLOCK     *Block,\r
+  IN  UINTN               Units\r
+  )\r
+{\r
+  UINTN                   Byte;\r
+  UINT8                   Bit;\r
+  UINTN                   StartByte;\r
+  UINT8                   StartBit;\r
+  UINTN                   Available;\r
+  UINTN                   Count;\r
+\r
+  ASSERT ((Block != 0) && (Units != 0));\r
+\r
+  StartByte  = 0;\r
+  StartBit   = 0;\r
+  Available  = 0;\r
+\r
+  for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+    //\r
+    // If current bit is zero, the corresponding memory unit is\r
+    // available, otherwise we need to restart our searching.\r
+    // Available counts the consective number of zero bit.\r
+    //\r
+    if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+      Available++;\r
+\r
+      if (Available >= Units) {\r
+        break;\r
+      }\r
+\r
+      NEXT_BIT (Byte, Bit);\r
+\r
+    } else {\r
+      NEXT_BIT (Byte, Bit);\r
+\r
+      Available  = 0;\r
+      StartByte  = Byte;\r
+      StartBit   = Bit;\r
+    }\r
+  }\r
+\r
+  if (Available < Units) {\r
+    return NULL;\r
+  }\r
+  \r
+  //\r
+  // Mark the memory as allocated\r
+  //\r
+  Byte  = StartByte;\r
+  Bit   = StartBit;\r
+\r
+  for (Count = 0; Count < Units; Count++) {\r
+    ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+    Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));\r
+    NEXT_BIT (Byte, Bit);\r
+  }\r
+\r
+  return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
+}\r
+\r
+/**\r
+  Insert the memory block to the pool's list of the blocks.\r
+\r
+  @param  Head           The head of the memory pool's block list.\r
+  @param  Block          The memory block to insert.\r
+\r
+**/\r
+VOID\r
+UsbHcInsertMemBlockToPool (\r
+  IN USBHC_MEM_BLOCK      *Head,\r
+  IN USBHC_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  ASSERT ((Head != NULL) && (Block != NULL));\r
+  Block->Next = Head->Next;\r
+  Head->Next  = Block;\r
+}\r
+\r
+/**\r
+  Is the memory block empty?\r
+\r
+  @param  Block   The memory block to check.\r
+\r
+  @retval TRUE    The memory block is empty.\r
+  @retval FALSE   The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+UsbHcIsMemBlockEmpty (\r
+  IN USBHC_MEM_BLOCK     *Block\r
+  )\r
+{\r
+  UINTN                   Index;\r
+\r
+  \r
+  for (Index = 0; Index < Block->BitsLen; Index++) {\r
+    if (Block->Bits[Index] != 0) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Unlink the memory block from the pool's list.\r
+\r
+  @param  Head           The block list head of the memory's pool.\r
+  @param  BlockToUnlink  The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+UsbHcUnlinkMemBlock (\r
+  IN USBHC_MEM_BLOCK      *Head,\r
+  IN USBHC_MEM_BLOCK      *BlockToUnlink\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK         *Block;\r
+\r
+  ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    if (Block->Next == BlockToUnlink) {\r
+      Block->Next         = BlockToUnlink->Next;\r
+      BlockToUnlink->Next = NULL;\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+  \r
+  @param  Ehc                   The EHCI device.\r
+  @param  Check4G               Whether the host controller requires allocated memory.\r
+                                from one 4G address space.\r
+  @param  Which4G               The 4G memory area each memory allocated should be from.\r
+\r
+  @retval EFI_SUCCESS           The memory pool is initialized.\r
+  @retval EFI_OUT_OF_RESOURCE   Fail to init the memory pool.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN BOOLEAN              Check4G,\r
+  IN UINT32               Which4G\r
+  )\r
+{\r
+  USBHC_MEM_POOL          *Pool;\r
+  UINTN               PageNumber;\r
+  EFI_STATUS              Status;\r
+  EFI_PHYSICAL_ADDRESS        TempPtr;\r
+  \r
+  PageNumber =  sizeof(USBHC_MEM_POOL)/PAGESIZE +1;\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             PageNumber,\r
+              &TempPtr\r
+             );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return NULL;\r
+    }\r
+  ZeroMem ((VOID   *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);        \r
+\r
+  Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr); \r
+\r
+  Pool->Check4G = Check4G;\r
+  Pool->Which4G = Which4G;\r
+  Pool->Head    = UsbHcAllocMemBlock (Ehc, Pool, USBHC_MEM_DEFAULT_PAGES);\r
+\r
+  if (Pool->Head == NULL) {\r
+    Pool = NULL;\r
+  }\r
+\r
+  return Pool;\r
+}\r
+\r
+/**\r
+  Release the memory management pool.\r
+  \r
+  @param  Pool                  The USB memory pool to free.\r
+\r
+  @retval EFI_DEVICE_ERROR      Fail to free the memory pool.\r
+  @retval EFI_SUCCESS           The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+  IN USBHC_MEM_POOL       *Pool\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK *Block;\r
+\r
+  ASSERT (Pool->Head != NULL);\r
+\r
+  //\r
+  // Unlink all the memory blocks from the pool, then free them.\r
+  // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
+  // first block.\r
+  //\r
+  for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+    UsbHcFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  UsbHcFreeMemBlock (Pool, Pool->Head);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+  \r
+  @param  Ehc       The EHCI device.\r
+  @param  Pool      The host controller's memory pool.\r
+  @param  Size      Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+  IN PEI_USB2_HC_DEV      *Ehc,\r
+  IN  USBHC_MEM_POOL      *Pool,\r
+  IN  UINTN               Size\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK         *Head;\r
+  USBHC_MEM_BLOCK         *Block;\r
+  USBHC_MEM_BLOCK         *NewBlock;\r
+  VOID                    *Mem;\r
+  UINTN                   AllocSize;\r
+  UINTN                   Pages;\r
+\r
+  Mem       = NULL;\r
+  AllocSize = USBHC_MEM_ROUND (Size);\r
+  Head      = Pool->Head;\r
+  ASSERT (Head != NULL);\r
+\r
+  //\r
+  // First check whether current memory blocks can satisfy the allocation.\r
+  //\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
+\r
+    if (Mem != NULL) {\r
+      ZeroMem (Mem, Size);\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Mem != NULL) {\r
+    return Mem;\r
+  }\r
+\r
+  //\r
+  // Create a new memory block if there is not enough memory\r
+  // in the pool. If the allocation size is larger than the\r
+  // default page number, just allocate a large enough memory\r
+  // block. Otherwise allocate default pages.\r
+  //\r
+  if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
+    Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+  } else {\r
+    Pages = USBHC_MEM_DEFAULT_PAGES;\r
+  }\r
+  NewBlock = UsbHcAllocMemBlock (Ehc,Pool, Pages);\r
+\r
+  if (NewBlock == NULL) {\r
+    return NULL;\r
+  }\r
+  \r
+  //\r
+  // Add the new memory block to the pool, then allocate memory from it\r
+  //\r
+  UsbHcInsertMemBlockToPool (Head, NewBlock);\r
+  Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
+\r
+  if (Mem != NULL) {\r
+    ZeroMem (Mem, Size);\r
+  }\r
+\r
+  return Mem;\r
+}\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool           The memory pool of the host controller.\r
+  @param  Mem            The memory to free.\r
+  @param  Size           The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+  IN USBHC_MEM_POOL       *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK         *Head;\r
+  USBHC_MEM_BLOCK         *Block;\r
+  UINT8                   *ToFree;\r
+  UINTN                   AllocSize;\r
+  UINTN                   Byte;\r
+  UINTN                   Bit;\r
+  UINTN                   Count;\r
+\r
+  Head      = Pool->Head;\r
+  AllocSize = USBHC_MEM_ROUND (Size);\r
+  ToFree    = (UINT8 *) Mem;\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    //\r
+    // scan the memory block list for the memory block that\r
+    // completely contains the memory to free.\r
+    //\r
+    if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+      //\r
+      // compute the start byte and bit in the bit array\r
+      //\r
+      Byte  = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
+      Bit   = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
+\r
+      //\r
+      // reset associated bits in bit arry\r
+      //\r
+      for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
+        ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+        Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
+        NEXT_BIT (Byte, Bit);\r
+      }\r
+\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If Block == NULL, it means that the current memory isn't\r
+  // in the host controller's pool. This is critical because\r
+  // the caller has passed in a wrong memory point\r
+  //\r
+  ASSERT (Block != NULL);\r
+\r
+  //\r
+  // Release the current memory block if it is empty and not the head\r
+  //\r
+  if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
+    UsbHcFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  return ;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.h b/MdeModulePkg/Bus/Pci/EhciPei/UsbHcMem.h
new file mode 100644 (file)
index 0000000..586d12a
--- /dev/null
@@ -0,0 +1,77 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 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
+#ifndef _EFI_EHCI_MEM_H_\r
+#define _EFI_EHCI_MEM_H_\r
+\r
+#include <Uefi.h>\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+#define USB_HC_BIT(a)                  ((UINTN)(1 << (a)))\r
+\r
+#define USB_HC_BIT_IS_SET(Data, Bit)   \\r
+          ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))\r
+\r
+#define USB_HC_HIGH_32BIT(Addr64)    \\r
+          ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+\r
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;\r
+\r
+struct _USBHC_MEM_BLOCK {\r
+  UINT8                   *Bits;    // Bit array to record which unit is allocated\r
+  UINTN                   BitsLen; \r
+  UINT8                   *Buf;\r
+  UINT8                   *BufHost;\r
+  UINTN                   BufLen;   // Memory size in bytes\r
+  VOID                    *Mapping;     \r
+  USBHC_MEM_BLOCK         *Next;\r
+};\r
+\r
+//\r
+// USBHC_MEM_POOL is used to manage the memory used by USB \r
+// host controller. EHCI requires the control memory and transfer\r
+// data to be on the same 4G memory. \r
+//\r
+typedef struct _USBHC_MEM_POOL {\r
+  BOOLEAN                 Check4G;      \r
+  UINT32                  Which4G;      \r
+  USBHC_MEM_BLOCK         *Head;\r
+} USBHC_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, must be 2^n, n>4\r
+//\r
+#define USBHC_MEM_UNIT           64\r
+\r
+#define USBHC_MEM_UNIT_MASK      (USBHC_MEM_UNIT - 1)\r
+#define USBHC_MEM_DEFAULT_PAGES  16\r
+\r
+#define USBHC_MEM_ROUND(Len)  (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define NEXT_BIT(Byte, Bit)   \\r
+          do {                \\r
+            (Bit)++;          \\r
+            if ((Bit) > 7) {  \\r
+              (Byte)++;       \\r
+              (Bit) = 0;      \\r
+            }                 \\r
+          } while (0)       \r
+\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c b/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c
new file mode 100644 (file)
index 0000000..f58b694
--- /dev/null
@@ -0,0 +1,3196 @@
+/** @file\r
+PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\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 "UhcPeim.h"\r
+\r
+/**\r
+  Initializes Usb Host Controller.\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            PPI successfully installed.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcPeimEntry (\r
+  IN EFI_PEI_FILE_HANDLE        FileHandle,\r
+  IN CONST EFI_PEI_SERVICES     **PeiServices\r
+  )\r
+{\r
+  PEI_USB_CONTROLLER_PPI      *ChipSetUsbControllerPpi;\r
+  EFI_STATUS                  Status;\r
+  UINT8                       Index;\r
+  UINTN                       ControllerType;\r
+  UINTN                       BaseAddress;\r
+  UINTN                       MemPages;\r
+  USB_UHC_DEV                 *UhcDev;\r
+  EFI_PHYSICAL_ADDRESS        TempPtr;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = PeiServicesLocatePpi (\r
+             &gPeiUsbControllerPpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **) &ChipSetUsbControllerPpi\r
+             );\r
+  //\r
+  // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.\r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Index = 0;\r
+  while (TRUE) {\r
+    Status = ChipSetUsbControllerPpi->GetUsbController (\r
+                                        (EFI_PEI_SERVICES **) PeiServices,\r
+                                        ChipSetUsbControllerPpi,\r
+                                        Index,\r
+                                        &ControllerType,\r
+                                        &BaseAddress\r
+                                        );\r
+    //\r
+    // When status is error, meant no controller is found\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // This PEIM is for UHC type controller.\r
+    //\r
+    if (ControllerType != PEI_UHCI_CONTROLLER) {\r
+      Index++;\r
+      continue;\r
+    }\r
+\r
+    MemPages = sizeof (USB_UHC_DEV) / EFI_PAGE_SIZE + 1;\r
+\r
+    Status = PeiServicesAllocatePages (\r
+               EfiBootServicesData,\r
+               MemPages,\r
+               &TempPtr\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);\r
+    UhcDev->Signature   = USB_UHC_DEV_SIGNATURE;\r
+    UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
+\r
+    //\r
+    // Init local memory management service\r
+    //\r
+    Status = InitializeMemoryManagement (UhcDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Initialize Uhc's hardware\r
+    //\r
+    Status = InitializeUsbHC (UhcDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    UhcDev->UsbHostControllerPpi.ControlTransfer          = UhcControlTransfer;\r
+    UhcDev->UsbHostControllerPpi.BulkTransfer             = UhcBulkTransfer;\r
+    UhcDev->UsbHostControllerPpi.GetRootHubPortNumber     = UhcGetRootHubPortNumber;\r
+    UhcDev->UsbHostControllerPpi.GetRootHubPortStatus     = UhcGetRootHubPortStatus;\r
+    UhcDev->UsbHostControllerPpi.SetRootHubPortFeature    = UhcSetRootHubPortFeature;\r
+    UhcDev->UsbHostControllerPpi.ClearRootHubPortFeature  = UhcClearRootHubPortFeature;\r
+\r
+    UhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+    UhcDev->PpiDescriptor.Guid  = &gPeiUsbHostControllerPpiGuid;\r
+    UhcDev->PpiDescriptor.Ppi   = &UhcDev->UsbHostControllerPpi;\r
+\r
+    Status = PeiServicesInstallPpi (&UhcDev->PpiDescriptor);\r
+    if (EFI_ERROR (Status)) {\r
+      Index++;\r
+      continue;\r
+    }\r
+\r
+    Index++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param  DeviceAddress          The target device address.\r
+  @param  DeviceSpeed            Target device speed.\r
+  @param  MaximumPacketLength    Maximum packet size the default control transfer \r
+                                 endpoint is capable of sending or receiving.\r
+  @param  Request                USB device request to send.\r
+  @param  TransferDirection      Specifies the data direction for the data stage.\r
+  @param  Data                   Data buffer to be transmitted or received from USB device.\r
+  @param  DataLength             The size (in bytes) of the data buffer.\r
+  @param  TimeOut                Indicates the maximum timeout, in millisecond.\r
+  @param  TransferResult         Return the result of this control transfer.\r
+\r
+  @retval EFI_SUCCESS            Transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.\r
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcControlTransfer (\r
+  IN     EFI_PEI_SERVICES               **PeiServices,\r
+  IN     PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN     UINT8                          DeviceAddress,\r
+  IN     UINT8                          DeviceSpeed,\r
+  IN     UINT8                          MaximumPacketLength,\r
+  IN     EFI_USB_DEVICE_REQUEST         *Request,\r
+  IN     EFI_USB_DATA_DIRECTION         TransferDirection,\r
+  IN OUT VOID                           *Data                 OPTIONAL,\r
+  IN OUT UINTN                          *DataLength           OPTIONAL,\r
+  IN     UINTN                          TimeOut,\r
+  OUT    UINT32                         *TransferResult\r
+  )\r
+{\r
+  USB_UHC_DEV *UhcDev;\r
+  UINT32      StatusReg;\r
+  UINT8       PktID;\r
+  QH_STRUCT   *PtrQH;\r
+  TD_STRUCT   *PtrTD;\r
+  TD_STRUCT   *PtrPreTD;\r
+  TD_STRUCT   *PtrSetupTD;\r
+  TD_STRUCT   *PtrStatusTD;\r
+  EFI_STATUS  Status;\r
+  UINT32      DataLen;\r
+  UINT8       *PtrDataSource;\r
+  UINT8       *Ptr;\r
+  UINT8       DataToggle;\r
+\r
+  UhcDev      = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+\r
+  StatusReg   = UhcDev->UsbHostControllerBaseAddress + USBSTS;\r
+\r
+  PktID       = INPUT_PACKET_ID;\r
+\r
+  if (Request == NULL || TransferResult == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // if errors exist that cause host controller halt,\r
+  // then return EFI_DEVICE_ERROR.\r
+  //\r
+\r
+  if (!IsStatusOK (UhcDev, StatusReg)) {\r
+    ClearStatusReg (UhcDev, StatusReg);\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ClearStatusReg (UhcDev, StatusReg);\r
+\r
+  //\r
+  // generate Setup Stage TD\r
+  //\r
+\r
+  PtrQH = UhcDev->ConfigQH;\r
+\r
+  GenSetupStageTD (\r
+    UhcDev,\r
+    DeviceAddress,\r
+    0,\r
+    DeviceSpeed,\r
+    (UINT8 *) Request,\r
+    (UINT8) sizeof (EFI_USB_DEVICE_REQUEST),\r
+    &PtrSetupTD\r
+    );\r
+\r
+  //\r
+  // link setup TD structures to QH structure\r
+  //\r
+  LinkTDToQH (PtrQH, PtrSetupTD);\r
+\r
+  PtrPreTD = PtrSetupTD;\r
+\r
+  //\r
+  //  Data Stage of Control Transfer\r
+  //\r
+  switch (TransferDirection) {\r
+\r
+  case EfiUsbDataIn:\r
+    PktID         = INPUT_PACKET_ID;\r
+    PtrDataSource = Data;\r
+    DataLen       = (UINT32) *DataLength;\r
+    Ptr           = PtrDataSource;\r
+    break;\r
+\r
+  case EfiUsbDataOut:\r
+    PktID         = OUTPUT_PACKET_ID;\r
+    PtrDataSource = Data;\r
+    DataLen       = (UINT32) *DataLength;\r
+    Ptr           = PtrDataSource;\r
+    break;\r
+\r
+  //\r
+  // no data stage\r
+  //\r
+  case EfiUsbNoData:\r
+    if (*DataLength != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    PktID         = OUTPUT_PACKET_ID;\r
+    PtrDataSource = NULL;\r
+    DataLen       = 0;\r
+    Ptr           = NULL;\r
+    break;\r
+\r
+  default:\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  DataToggle  = 1;\r
+\r
+  PtrTD       = PtrSetupTD;\r
+  while (DataLen > 0) {\r
+    //\r
+    // create TD structures and link together\r
+    //\r
+    UINT8 PacketSize;\r
+\r
+    //\r
+    // PacketSize is the data load size of each TD carries.\r
+    //\r
+    PacketSize = (UINT8) DataLen;\r
+    if (DataLen > MaximumPacketLength) {\r
+      PacketSize = MaximumPacketLength;\r
+    }\r
+\r
+    GenDataTD (\r
+      UhcDev,\r
+      DeviceAddress,\r
+      0,\r
+      Ptr,\r
+      PacketSize,\r
+      PktID,\r
+      DataToggle,\r
+      DeviceSpeed,\r
+      &PtrTD\r
+      );\r
+\r
+    //\r
+    // Link two TDs in vertical depth\r
+    //\r
+    LinkTDToTD (PtrPreTD, PtrTD);\r
+    PtrPreTD = PtrTD;\r
+\r
+    DataToggle ^= 1;\r
+    Ptr += PacketSize;\r
+    DataLen -= PacketSize;\r
+  }\r
+\r
+  //\r
+  // PtrPreTD points to the last TD before the Setup-Stage TD.\r
+  //\r
+  PtrPreTD = PtrTD;\r
+\r
+  //\r
+  // Status Stage of Control Transfer\r
+  //\r
+  if (PktID == OUTPUT_PACKET_ID) {\r
+    PktID = INPUT_PACKET_ID;\r
+  } else {\r
+    PktID = OUTPUT_PACKET_ID;\r
+  }\r
+  //\r
+  // create Status Stage TD structure\r
+  //\r
+  CreateStatusTD (\r
+    UhcDev,\r
+    DeviceAddress,\r
+    0,\r
+    PktID,\r
+    DeviceSpeed,\r
+    &PtrStatusTD\r
+    );\r
+\r
+  LinkTDToTD (PtrPreTD, PtrStatusTD);\r
+\r
+  //\r
+  // Poll QH-TDs execution and get result.\r
+  // detail status is returned\r
+  //\r
+  Status = ExecuteControlTransfer (\r
+            UhcDev,\r
+            PtrSetupTD,\r
+            DataLength,\r
+            TimeOut,\r
+            TransferResult\r
+            );\r
+\r
+  //\r
+  // TRUE means must search other framelistindex\r
+  //\r
+  SetQHVerticalValidorInvalid(PtrQH, FALSE);\r
+  DeleteQueuedTDs (UhcDev, PtrSetupTD);\r
+\r
+  //\r
+  // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
+  //\r
+  if (!IsStatusOK (UhcDev, StatusReg)) {\r
+\r
+    ClearStatusReg (UhcDev, StatusReg);\r
+    *TransferResult |= EFI_USB_ERR_SYSTEM;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ClearStatusReg (UhcDev, StatusReg);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param  DeviceAddress         Target device address.\r
+  @param  EndPointAddress       Endpoint number and its direction in bit 7.\r
+  @param  MaximumPacketLength   Maximum packet size the endpoint is capable of \r
+                                sending or receiving.\r
+  @param  Data                  Array of pointers to the buffers of data to transmit \r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  DataToggle            On input, the initial data toggle for the transfer;\r
+                                On output, it is updated to to next data toggle to use of \r
+                                the subsequent bulk transfer.\r
+  @param  TimeOut               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+  @param  TransferResult        A pointer to the detailed result information of the\r
+                                bulk transfer.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcBulkTransfer (\r
+  IN     EFI_PEI_SERVICES               **PeiServices,\r
+  IN     PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN     UINT8                          DeviceAddress,\r
+  IN     UINT8                          EndPointAddress,\r
+  IN     UINT8                          MaximumPacketLength,\r
+  IN OUT VOID                           *Data,\r
+  IN OUT UINTN                          *DataLength,\r
+  IN OUT UINT8                          *DataToggle,\r
+  IN     UINTN                          TimeOut,\r
+  OUT    UINT32                         *TransferResult\r
+  )\r
+{\r
+  USB_UHC_DEV             *UhcDev;\r
+  UINT32                  StatusReg;\r
+\r
+  UINT32                  DataLen;\r
+\r
+  QH_STRUCT               *PtrQH;\r
+  TD_STRUCT               *PtrFirstTD;\r
+  TD_STRUCT               *PtrTD;\r
+  TD_STRUCT               *PtrPreTD;\r
+\r
+  UINT8                   PktID;\r
+  UINT8                   *PtrDataSource;\r
+  UINT8                   *Ptr;\r
+\r
+  BOOLEAN                 IsFirstTD;\r
+\r
+  EFI_STATUS              Status;\r
+\r
+  EFI_USB_DATA_DIRECTION  TransferDirection;\r
+\r
+  BOOLEAN                 ShortPacketEnable;\r
+\r
+  UINT16                  CommandContent;\r
+\r
+  UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+\r
+  //\r
+  // Enable the maximum packet size (64bytes)\r
+  // that can be used for full speed bandwidth reclamation\r
+  // at the end of a frame.\r
+  //\r
+  CommandContent = USBReadPortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD);\r
+  if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {\r
+    CommandContent |= USBCMD_MAXP;\r
+    USBWritePortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD, CommandContent);\r
+  }\r
+\r
+  StatusReg   = UhcDev->UsbHostControllerBaseAddress + USBSTS;\r
+\r
+  //\r
+  // these code lines are added here per complier's strict demand\r
+  //\r
+  PktID             = INPUT_PACKET_ID;\r
+  PtrTD             = NULL;\r
+  PtrFirstTD        = NULL;\r
+  PtrPreTD          = NULL;\r
+  DataLen           = 0;\r
+  Ptr               = NULL;\r
+\r
+  ShortPacketEnable = FALSE;\r
+\r
+  if ((DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MaximumPacketLength != 8 && MaximumPacketLength != 16\r
+      && MaximumPacketLength != 32 && MaximumPacketLength != 64) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
+  //\r
+  if (!IsStatusOK (UhcDev, StatusReg)) {\r
+\r
+    ClearStatusReg (UhcDev, StatusReg);\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ClearStatusReg (UhcDev, StatusReg);\r
+\r
+  if ((EndPointAddress & 0x80) != 0) {\r
+    TransferDirection = EfiUsbDataIn;\r
+  } else {\r
+    TransferDirection = EfiUsbDataOut;\r
+  }\r
+\r
+  switch (TransferDirection) {\r
+\r
+  case EfiUsbDataIn:\r
+    ShortPacketEnable = TRUE;\r
+    PktID             = INPUT_PACKET_ID;\r
+    PtrDataSource     = Data;\r
+    DataLen           = (UINT32) *DataLength;\r
+    Ptr               = PtrDataSource;\r
+    break;\r
+\r
+  case EfiUsbDataOut:\r
+    PktID         = OUTPUT_PACKET_ID;\r
+    PtrDataSource = Data;\r
+    DataLen       = (UINT32) *DataLength;\r
+    Ptr           = PtrDataSource;\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  PtrQH = UhcDev->BulkQH;\r
+\r
+  IsFirstTD = TRUE;\r
+  while (DataLen > 0) {\r
+    //\r
+    // create TD structures and link together\r
+    //\r
+    UINT8 PacketSize;\r
+\r
+    PacketSize = (UINT8) DataLen;\r
+    if (DataLen > MaximumPacketLength) {\r
+      PacketSize = MaximumPacketLength;\r
+    }\r
+\r
+    GenDataTD (\r
+      UhcDev,\r
+      DeviceAddress,\r
+      EndPointAddress,\r
+      Ptr,\r
+      PacketSize,\r
+      PktID,\r
+      *DataToggle,\r
+      USB_FULL_SPEED_DEVICE,\r
+      &PtrTD\r
+      );\r
+\r
+    //\r
+    // Enable short packet detection.\r
+    // (default action is disabling short packet detection)\r
+    //\r
+    if (ShortPacketEnable) {\r
+      EnableorDisableTDShortPacket (PtrTD, TRUE);\r
+    }\r
+\r
+    if (IsFirstTD) {\r
+      PtrFirstTD            = PtrTD;\r
+      PtrFirstTD->PtrNextTD = NULL;\r
+      IsFirstTD             = FALSE;\r
+    } else {\r
+      //\r
+      // Link two TDs in vertical depth\r
+      //\r
+      LinkTDToTD (PtrPreTD, PtrTD);\r
+    }\r
+\r
+    PtrPreTD = PtrTD;\r
+\r
+    *DataToggle ^= 1;\r
+    Ptr += PacketSize;\r
+    DataLen -= PacketSize;\r
+  }\r
+  //\r
+  // link TD structures to QH structure\r
+  //\r
+  LinkTDToQH (PtrQH, PtrFirstTD);\r
+\r
+  //\r
+  // Execute QH-TD and get result\r
+  //\r
+  //\r
+  // detail status is put into the Result field in the pIRP\r
+  // the Data Toggle value is also re-updated to the value\r
+  // of the last successful TD\r
+  //\r
+  Status = ExecBulkTransfer (\r
+            UhcDev,\r
+            PtrFirstTD,\r
+            DataLength,\r
+            DataToggle,\r
+            TimeOut,\r
+            TransferResult\r
+            );\r
+\r
+  //\r
+  // Delete Bulk transfer TD structure\r
+  //\r
+  DeleteQueuedTDs (UhcDev, PtrFirstTD);\r
+\r
+  //\r
+  // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
+  //\r
+  if (!IsStatusOK (UhcDev, StatusReg)) {\r
+\r
+    ClearStatusReg (UhcDev, StatusReg);\r
+    *TransferResult |= EFI_USB_ERR_SYSTEM;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  ClearStatusReg (UhcDev, StatusReg);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the number of root hub ports.\r
+\r
+  @param[in]  PeiServices   The pointer to the PEI Services Table.\r
+  @param[in]  This          The pointer to this instance of the \r
+                            PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param[out] PortNumber    The pointer to the number of the root hub ports.                                \r
+                                \r
+  @retval EFI_SUCCESS           The port number was retrieved successfully.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcGetRootHubPortNumber (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  OUT UINT8                         *PortNumber\r
+  )\r
+{\r
+  USB_UHC_DEV *UhcDev;\r
+  UINT32      PSAddr;\r
+  UINT16      RHPortControl;\r
+  UINT32      Index;\r
+\r
+  UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+\r
+  if (PortNumber == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *PortNumber = 0;\r
+\r
+  for (Index = 0; Index < 2; Index++) {\r
+    PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + Index * 2;\r
+    RHPortControl = USBReadPortW (UhcDev, PSAddr);\r
+    //\r
+    // Port Register content is valid\r
+    //\r
+    if (RHPortControl != 0xff) {\r
+      (*PortNumber)++;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param  PortNumber             The root hub port to retrieve the state from.  \r
+  @param  PortStatus             Variable to receive the port state.\r
+\r
+  @retval EFI_SUCCESS            The status of the USB root hub port specified.\r
+                                 by PortNumber was returned in PortStatus.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcGetRootHubPortStatus (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN  UINT8                         PortNumber,\r
+  OUT EFI_USB_PORT_STATUS           *PortStatus\r
+  )\r
+{\r
+  USB_UHC_DEV *UhcDev;\r
+  UINT32      PSAddr;\r
+  UINT16      RHPortStatus;\r
+  UINT8       TotalPortNumber;\r
+\r
+  if (PortStatus == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);\r
+  if (PortNumber > TotalPortNumber) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UhcDev                        = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+  PSAddr                        = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;\r
+\r
+  PortStatus->PortStatus        = 0;\r
+  PortStatus->PortChangeStatus  = 0;\r
+\r
+  RHPortStatus = USBReadPortW (UhcDev, PSAddr);\r
+\r
+  //\r
+  // Current Connect Status\r
+  //\r
+  if ((RHPortStatus & USBPORTSC_CCS) != 0) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
+  }\r
+  //\r
+  // Port Enabled/Disabled\r
+  //\r
+  if ((RHPortStatus & USBPORTSC_PED) != 0) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
+  }\r
+  //\r
+  // Port Suspend\r
+  //\r
+  if ((RHPortStatus & USBPORTSC_SUSP) != 0) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+  }\r
+  //\r
+  // Port Reset\r
+  //\r
+  if ((RHPortStatus & USBPORTSC_PR) != 0) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
+  }\r
+  //\r
+  // Low Speed Device Attached\r
+  //\r
+  if ((RHPortStatus & USBPORTSC_LSDA) != 0) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+  }\r
+  //\r
+  //   Fill Port Status Change bits\r
+  //\r
+  //\r
+  // Connect Status Change\r
+  //\r
+  if ((RHPortStatus & USBPORTSC_CSC) != 0) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
+  }\r
+  //\r
+  // Port Enabled/Disabled Change\r
+  //\r
+  if ((RHPortStatus & USBPORTSC_PEDC) != 0) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sets a feature for the specified root hub port.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES\r
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI\r
+  @param  PortNumber            Root hub port to set.\r
+  @param  PortFeature           Feature to set.\r
+\r
+  @retval EFI_SUCCESS            The feature specified by PortFeature was set.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_TIMEOUT            The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcSetRootHubPortFeature (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN UINT8                          PortNumber,\r
+  IN EFI_USB_PORT_FEATURE           PortFeature\r
+  )\r
+{\r
+  USB_UHC_DEV *UhcDev;\r
+  UINT32      PSAddr;\r
+  UINT32      CommandRegAddr;\r
+  UINT16      RHPortControl;\r
+  UINT8       TotalPortNumber;\r
+\r
+  UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);\r
+  if (PortNumber > TotalPortNumber) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UhcDev          = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+  PSAddr          = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;\r
+  CommandRegAddr  = UhcDev->UsbHostControllerBaseAddress + USBCMD;\r
+\r
+  RHPortControl = USBReadPortW (UhcDev, PSAddr);\r
+\r
+  switch (PortFeature) {\r
+\r
+  case EfiUsbPortSuspend:\r
+    if ((USBReadPortW (UhcDev, CommandRegAddr) & USBCMD_EGSM) == 0) {\r
+      //\r
+      // if global suspend is not active, can set port suspend\r
+      //\r
+      RHPortControl &= 0xfff5;\r
+      RHPortControl |= USBPORTSC_SUSP;\r
+    }\r
+    break;\r
+\r
+  case EfiUsbPortReset:\r
+    RHPortControl &= 0xfff5;\r
+    RHPortControl |= USBPORTSC_PR;\r
+    //\r
+    // Set the reset bit\r
+    //\r
+    break;\r
+\r
+  case EfiUsbPortPower:\r
+    break;\r
+\r
+  case EfiUsbPortEnable:\r
+    RHPortControl &= 0xfff5;\r
+    RHPortControl |= USBPORTSC_PED;\r
+    break;\r
+\r
+  default:\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  USBWritePortW (UhcDev, PSAddr, RHPortControl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param  PortNumber            Specifies the root hub port whose feature\r
+                                is requested to be cleared.\r
+  @param  PortFeature           Indicates the feature selector associated with the\r
+                                feature clear request.\r
+\r
+  @retval EFI_SUCCESS            The feature specified by PortFeature was cleared \r
+                                 for the USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcClearRootHubPortFeature (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN UINT8                          PortNumber,\r
+  IN EFI_USB_PORT_FEATURE           PortFeature\r
+  )\r
+{\r
+  USB_UHC_DEV *UhcDev;\r
+  UINT32      PSAddr;\r
+  UINT16      RHPortControl;\r
+  UINT8       TotalPortNumber;\r
+\r
+  UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);\r
+\r
+  if (PortNumber > TotalPortNumber) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UhcDev  = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+  PSAddr  = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;\r
+\r
+  RHPortControl = USBReadPortW (UhcDev, PSAddr);\r
+\r
+  switch (PortFeature) {\r
+  //\r
+  // clear PORT_ENABLE feature means disable port.\r
+  //\r
+  case EfiUsbPortEnable:\r
+    RHPortControl &= 0xfff5;\r
+    RHPortControl &= ~USBPORTSC_PED;\r
+    break;\r
+\r
+  //\r
+  // clear PORT_SUSPEND feature means resume the port.\r
+  // (cause a resume on the specified port if in suspend mode)\r
+  //\r
+  case EfiUsbPortSuspend:\r
+    RHPortControl &= 0xfff5;\r
+    RHPortControl &= ~USBPORTSC_SUSP;\r
+    break;\r
+\r
+  //\r
+  // no operation\r
+  //\r
+  case EfiUsbPortPower:\r
+    break;\r
+\r
+  //\r
+  // clear PORT_RESET means clear the reset signal.\r
+  //\r
+  case EfiUsbPortReset:\r
+    RHPortControl &= 0xfff5;\r
+    RHPortControl &= ~USBPORTSC_PR;\r
+    break;\r
+\r
+  //\r
+  // clear connect status change\r
+  //\r
+  case EfiUsbPortConnectChange:\r
+    RHPortControl &= 0xfff5;\r
+    RHPortControl |= USBPORTSC_CSC;\r
+    break;\r
+\r
+  //\r
+  // clear enable/disable status change\r
+  //\r
+  case EfiUsbPortEnableChange:\r
+    RHPortControl &= 0xfff5;\r
+    RHPortControl |= USBPORTSC_PEDC;\r
+    break;\r
+\r
+  //\r
+  // root hub does not support this request\r
+  //\r
+  case EfiUsbPortSuspendChange:\r
+    break;\r
+\r
+  //\r
+  // root hub does not support this request\r
+  //\r
+  case EfiUsbPortOverCurrentChange:\r
+    break;\r
+\r
+  //\r
+  // root hub does not support this request\r
+  //\r
+  case EfiUsbPortResetChange:\r
+    break;\r
+\r
+  default:\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  USBWritePortW (UhcDev, PSAddr, RHPortControl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UHCI.\r
+\r
+  @param  UhcDev                 UHCI Device.\r
+\r
+  @retval EFI_SUCCESS            UHCI successfully initialized.\r
+  @retval EFI_OUT_OF_RESOURCES   Resource can not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+  IN USB_UHC_DEV          *UhcDev\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      FrameListBaseAddrReg;\r
+  UINT32      CommandReg;\r
+  UINT16      Command;\r
+\r
+  //\r
+  // Create and Initialize Frame List For the Host Controller.\r
+  //\r
+  Status = CreateFrameList (UhcDev);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FrameListBaseAddrReg  = UhcDev->UsbHostControllerBaseAddress + USBFLBASEADD;\r
+  CommandReg            = UhcDev->UsbHostControllerBaseAddress + USBCMD;\r
+\r
+  //\r
+  // Set Frame List Base Address to the specific register to inform the hardware.\r
+  //\r
+  SetFrameListBaseAddress (UhcDev, FrameListBaseAddrReg, (UINT32) (UINTN) (UhcDev->FrameListEntry));\r
+\r
+  Command = USBReadPortW (UhcDev, CommandReg);\r
+  Command |= USBCMD_GRESET;\r
+  USBWritePortW (UhcDev, CommandReg, Command);\r
+\r
+  MicroSecondDelay (50 * 1000);\r
+\r
+\r
+  Command &= ~USBCMD_GRESET;\r
+\r
+  USBWritePortW (UhcDev, CommandReg, Command);\r
+\r
+  //\r
+  //UHCI spec page120 reset recovery time\r
+  //\r
+  MicroSecondDelay (20 * 1000);\r
+\r
+  //\r
+  // Set Run/Stop bit to 1.\r
+  //\r
+  Command = USBReadPortW (UhcDev, CommandReg);\r
+  Command |= USBCMD_RS | USBCMD_MAXP;\r
+  USBWritePortW (UhcDev, CommandReg, Command);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create Frame List Structure.\r
+\r
+  @param  UhcDev                 UHCI device.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateFrameList (\r
+  USB_UHC_DEV             *UhcDev\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  FrameListBaseAddr;\r
+  FRAMELIST_ENTRY       *FrameListPtr;\r
+  UINTN                 Index;\r
+\r
+  //\r
+  // The Frame List ocupies 4K bytes,\r
+  // and must be aligned on 4-Kbyte boundaries.\r
+  //\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesData,\r
+             1,\r
+             &FrameListBaseAddr\r
+             );\r
+\r
+  if (Status != EFI_SUCCESS) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  //Create Control QH and Bulk QH and link them into Framelist Entry\r
+  //\r
+  Status = CreateQH(UhcDev, &UhcDev->ConfigQH);\r
+  if (Status != EFI_SUCCESS) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  Status = CreateQH(UhcDev, &UhcDev->BulkQH);\r
+  if (Status != EFI_SUCCESS) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  //Set the corresponding QH pointer \r
+  //\r
+  SetQHHorizontalLinkPtr(UhcDev->ConfigQH, UhcDev->BulkQH);\r
+  SetQHHorizontalQHorTDSelect (UhcDev->ConfigQH, TRUE);\r
+  SetQHHorizontalValidorInvalid (UhcDev->ConfigQH, TRUE);\r
+\r
+  UhcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) FrameListBaseAddr);\r
+\r
+  FrameListPtr = UhcDev->FrameListEntry;\r
+\r
+  for (Index = 0; Index < 1024; Index++) {\r
+    FrameListPtr->FrameListPtrTerminate = 0;\r
+    FrameListPtr->FrameListPtr          = (UINT32)(UINTN)UhcDev->ConfigQH >> 4;\r
+    FrameListPtr->FrameListPtrQSelect   = 1;\r
+    FrameListPtr->FrameListRsvd         = 0;\r
+    FrameListPtr ++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Read a 16bit width data from Uhc HC IO space register.\r
+  \r
+  @param  UhcDev  The UHCI device.\r
+  @param  Port    The IO space address of the register.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT16\r
+USBReadPortW (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        Port\r
+  )\r
+{\r
+  return IoRead16 (Port);\r
+}\r
+\r
+/**\r
+  Write a 16bit width data into Uhc HC IO space register.\r
+  \r
+  @param  UhcDev  The UHCI device.\r
+  @param  Port    The IO space address of the register.\r
+  @param  Data    The data written into the register.\r
+\r
+**/\r
+VOID\r
+USBWritePortW (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        Port,\r
+  IN  UINT16        Data\r
+  )\r
+{\r
+  IoWrite16 (Port, Data);\r
+}\r
+\r
+/**\r
+  Write a 32bit width data into Uhc HC IO space register.\r
+  \r
+  @param  UhcDev  The UHCI device.\r
+  @param  Port    The IO space address of the register.\r
+  @param  Data    The data written into the register.\r
+\r
+**/\r
+VOID\r
+USBWritePortDW (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        Port,\r
+  IN  UINT32        Data\r
+  )\r
+{\r
+  IoWrite32 (Port, Data);\r
+}\r
+\r
+/**\r
+  Clear the content of UHCI's Status Register.\r
+  \r
+  @param  UhcDev       The UHCI device.\r
+  @param  StatusAddr   The IO space address of the register.\r
+\r
+**/\r
+VOID\r
+ClearStatusReg (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        StatusAddr\r
+  )\r
+{\r
+  //\r
+  // Clear the content of UHCI's Status Register\r
+  //\r
+  USBWritePortW (UhcDev, StatusAddr, 0x003F);\r
+}\r
+\r
+/**\r
+  Check whether the host controller operates well.\r
+\r
+  @param  UhcDev        The UHCI device.\r
+  @param  StatusRegAddr The io address of status register.\r
+\r
+  @retval TRUE          Host controller is working.\r
+  @retval FALSE         Host controller is halted or system error.\r
+\r
+**/\r
+BOOLEAN\r
+IsStatusOK (\r
+  IN USB_UHC_DEV     *UhcDev,\r
+  IN UINT32          StatusRegAddr\r
+  )\r
+{\r
+  UINT16  StatusValue;\r
+\r
+  StatusValue = USBReadPortW (UhcDev, StatusRegAddr);\r
+\r
+  if ((StatusValue & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+}\r
+\r
+/**\r
+  Get Current Frame Number.\r
+\r
+  @param  UhcDev          The UHCI device.\r
+  @param  FrameNumberAddr The address of frame list register.\r
+\r
+  @retval The content of the frame list register.\r
+\r
+**/\r
+UINT16\r
+GetCurrentFrameNumber (\r
+  IN USB_UHC_DEV   *UhcDev,\r
+  IN UINT32        FrameNumberAddr\r
+  )\r
+{\r
+  //\r
+  // Gets value in the USB frame number register.\r
+  //\r
+  return (UINT16) (USBReadPortW (UhcDev, FrameNumberAddr) & 0x03FF);\r
+}\r
+\r
+/**\r
+  Set Frame List Base Address.\r
+\r
+  @param  UhcDev           The UHCI device.\r
+  @param  FrameListRegAddr The address of frame list register.\r
+  @param  Addr             The address of frame list table.\r
+\r
+**/\r
+VOID\r
+SetFrameListBaseAddress (\r
+  IN USB_UHC_DEV   *UhcDev,\r
+  IN UINT32        FrameListRegAddr,\r
+  IN UINT32        Addr\r
+  )\r
+{\r
+  //\r
+  // Sets value in the USB Frame List Base Address register.\r
+  //\r
+  USBWritePortDW (UhcDev, FrameListRegAddr, (UINT32) (Addr & 0xFFFFF000));\r
+}\r
+\r
+/**\r
+  Create QH and initialize.\r
+\r
+  @param  UhcDev               The UHCI device.\r
+  @param  PtrQH                Place to store QH_STRUCT pointer.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+  @retval EFI_SUCCESS        Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateQH (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  OUT QH_STRUCT     **PtrQH\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // allocate align memory for QH_STRUCT\r
+  //\r
+  Status = AllocateTDorQHStruct (UhcDev, sizeof(QH_STRUCT), (void **)PtrQH);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // init each field of the QH_STRUCT\r
+  //\r
+  SetQHHorizontalValidorInvalid (*PtrQH, FALSE);\r
+  SetQHVerticalValidorInvalid (*PtrQH, FALSE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set the horizontal link pointer in QH.\r
+\r
+  @param  PtrQH               Place to store QH_STRUCT pointer.\r
+  @param  PtrNext             Place to the next QH_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalLinkPtr (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN VOID       *PtrNext\r
+  )\r
+{\r
+  //\r
+  // Since the QH_STRUCT is aligned on 16-byte boundaries,\r
+  // Only the highest 28bit of the address is valid\r
+  // (take 32bit address as an example).\r
+  //\r
+  PtrQH->QueueHead.QHHorizontalPtr = (UINT32) (UINTN) PtrNext >> 4;\r
+}\r
+\r
+/**\r
+  Get the horizontal link pointer in QH.\r
+\r
+  @param  PtrQH     Place to store QH_STRUCT pointer.\r
+\r
+  @retval The horizontal link pointer in QH.\r
+\r
+**/\r
+VOID *\r
+GetQHHorizontalLinkPtr (\r
+  IN QH_STRUCT  *PtrQH\r
+  )\r
+{\r
+  //\r
+  // Restore the 28bit address to 32bit address\r
+  // (take 32bit address as an example)\r
+  //\r
+  return (VOID *) (UINTN) ((PtrQH->QueueHead.QHHorizontalPtr) << 4);\r
+}\r
+\r
+/**\r
+  Set a QH or TD horizontally to be connected with a specific QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+  @param  IsQH       Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalQHorTDSelect (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN BOOLEAN    IsQH\r
+  )\r
+{\r
+  //\r
+  // if QH is connected, the specified bit is set,\r
+  // if TD is connected, the specified bit is cleared.\r
+  //\r
+  PtrQH->QueueHead.QHHorizontalQSelect = IsQH ? 1 : 0;\r
+}\r
+\r
+/**\r
+  Set the horizontal validor bit in QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+  @param  IsValid    Specify the horizontal linker is valid or not.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalValidorInvalid (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN BOOLEAN    IsValid\r
+  )\r
+{\r
+  //\r
+  // Valid means the horizontal link pointer is valid,\r
+  // else, it's invalid.\r
+  //\r
+  PtrQH->QueueHead.QHHorizontalTerminate = IsValid ? 0 : 1;\r
+}\r
+\r
+/**\r
+  Set the vertical link pointer in QH.\r
+\r
+  @param  PtrQH       Place to store QH_STRUCT pointer.\r
+  @param  PtrNext     Place to the next QH_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalLinkPtr (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN VOID       *PtrNext\r
+  )\r
+{\r
+  //\r
+  // Since the QH_STRUCT is aligned on 16-byte boundaries,\r
+  // Only the highest 28bit of the address is valid\r
+  // (take 32bit address as an example).\r
+  //\r
+  PtrQH->QueueHead.QHVerticalPtr = (UINT32) (UINTN) PtrNext >> 4;\r
+}\r
+\r
+/**\r
+  Set a QH or TD vertically to be connected with a specific QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+  @param  IsQH       Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalQHorTDSelect (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN BOOLEAN    IsQH\r
+  )\r
+{\r
+  //\r
+  // Set the specified bit if the Vertical Link Pointer pointing to a QH,\r
+  // Clear the specified bit if the Vertical Link Pointer pointing to a TD.\r
+  //\r
+  PtrQH->QueueHead.QHVerticalQSelect = IsQH ? 1 : 0;\r
+}\r
+\r
+/**\r
+  Set the vertical validor bit in QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+  @param  IsValid    Specify the vertical linker is valid or not.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalValidorInvalid (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN BOOLEAN    IsValid\r
+  )\r
+{\r
+  //\r
+  // If TRUE, meaning the Vertical Link Pointer field is valid,\r
+  // else, the field is invalid.\r
+  //\r
+  PtrQH->QueueHead.QHVerticalTerminate = IsValid ? 0 : 1;\r
+}\r
+\r
+/**\r
+  Get the vertical validor bit in QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+\r
+  @retval The vertical linker is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+GetQHHorizontalValidorInvalid (\r
+  IN QH_STRUCT  *PtrQH\r
+  )\r
+{\r
+  //\r
+  // If TRUE, meaning the Horizontal Link Pointer field is valid,\r
+  // else, the field is invalid.\r
+  //\r
+  return (BOOLEAN) (!(PtrQH->QueueHead.QHHorizontalTerminate));\r
+}\r
+\r
+/**\r
+  Allocate TD or QH Struct.\r
+\r
+  @param  UhcDev                 The UHCI device.\r
+  @param  Size                   The size of allocation.\r
+  @param  PtrStruct              Place to store TD_STRUCT pointer.\r
+\r
+  @return EFI_SUCCESS            Allocate successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocateTDorQHStruct (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  IN  UINT32          Size,\r
+  OUT VOID            **PtrStruct\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status      = EFI_SUCCESS;\r
+  *PtrStruct  = NULL;\r
+\r
+  Status = UhcAllocatePool (\r
+            UhcDev,\r
+            (UINT8 **) PtrStruct,\r
+            Size\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ZeroMem (*PtrStruct, Size);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Create a TD Struct.\r
+\r
+  @param  UhcDev                 The UHCI device.\r
+  @param  PtrTD                  Place to store TD_STRUCT pointer.\r
+\r
+  @return EFI_SUCCESS            Allocate successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateTD (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  OUT TD_STRUCT       **PtrTD\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  //\r
+  // create memory for TD_STRUCT, and align the memory.\r
+  //\r
+  Status = AllocateTDorQHStruct (UhcDev, sizeof(TD_STRUCT), (void **)PtrTD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Make TD ready.\r
+  //\r
+  SetTDLinkPtrValidorInvalid (*PtrTD, FALSE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Generate Setup Stage TD.\r
+\r
+  @param  UhcDev       The UHCI device.\r
+  @param  DevAddr      Device address.\r
+  @param  Endpoint     Endpoint number.\r
+  @param  DeviceSpeed  Device Speed.\r
+  @param  DevRequest   Device reuquest.\r
+  @param  RequestLen   Request length.\r
+  @param  PtrTD        TD_STRUCT generated.\r
+\r
+  @return EFI_SUCCESS            Generate setup stage TD successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GenSetupStageTD (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  IN  UINT8           DevAddr,\r
+  IN  UINT8           Endpoint,\r
+  IN  UINT8           DeviceSpeed,\r
+  IN  UINT8           *DevRequest,\r
+  IN  UINT8           RequestLen,\r
+  OUT TD_STRUCT       **PtrTD\r
+  )\r
+{\r
+  TD_STRUCT   *TdStruct;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = CreateTD (UhcDev, &TdStruct);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SetTDLinkPtr (TdStruct, NULL);\r
+\r
+  //\r
+  // Depth first fashion\r
+  //\r
+  SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);\r
+\r
+  //\r
+  // initialize as the last TD in the QH context,\r
+  // this field will be updated in the TD linkage process.\r
+  //\r
+  SetTDLinkPtrValidorInvalid (TdStruct, FALSE);\r
+\r
+  //\r
+  // Disable Short Packet Detection by default\r
+  //\r
+  EnableorDisableTDShortPacket (TdStruct, FALSE);\r
+\r
+  //\r
+  // Max error counter is 3, retry 3 times when error encountered.\r
+  //\r
+  SetTDControlErrorCounter (TdStruct, 3);\r
+\r
+  //\r
+  // set device speed attribute\r
+  // (TRUE - Slow Device; FALSE - Full Speed Device)\r
+  //\r
+  switch (DeviceSpeed) {\r
+  case USB_SLOW_SPEED_DEVICE:\r
+    SetTDLoworFullSpeedDevice (TdStruct, TRUE);\r
+    break;\r
+\r
+  case USB_FULL_SPEED_DEVICE:\r
+    SetTDLoworFullSpeedDevice (TdStruct, FALSE);\r
+    break;\r
+  }\r
+  //\r
+  // Non isochronous transfer TD\r
+  //\r
+  SetTDControlIsochronousorNot (TdStruct, FALSE);\r
+\r
+  //\r
+  // Interrupt On Complete bit be set to zero,\r
+  // Disable IOC interrupt.\r
+  //\r
+  SetorClearTDControlIOC (TdStruct, FALSE);\r
+\r
+  //\r
+  // Set TD Active bit\r
+  //\r
+  SetTDStatusActiveorInactive (TdStruct, TRUE);\r
+\r
+  SetTDTokenMaxLength (TdStruct, RequestLen);\r
+\r
+  SetTDTokenDataToggle0 (TdStruct);\r
+\r
+  SetTDTokenEndPoint (TdStruct, Endpoint);\r
+\r
+  SetTDTokenDeviceAddress (TdStruct, DevAddr);\r
+\r
+  SetTDTokenPacketID (TdStruct, SETUP_PACKET_ID);\r
+\r
+  TdStruct->PtrTDBuffer      = (UINT8 *) DevRequest;\r
+  TdStruct->TDBufferLength = RequestLen;\r
+  SetTDDataBuffer (TdStruct);\r
+\r
+  *PtrTD = TdStruct;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Generate Data Stage TD.\r
+\r
+  @param  UhcDev       The UHCI device.\r
+  @param  DevAddr      Device address.\r
+  @param  Endpoint     Endpoint number.\r
+  @param  PtrData      Data buffer.\r
+  @param  Len          Data length.\r
+  @param  PktID        PacketID.\r
+  @param  Toggle       Data toggle value.\r
+  @param  DeviceSpeed  Device Speed.\r
+  @param  PtrTD        TD_STRUCT generated.\r
+\r
+  @return EFI_SUCCESS            Generate data stage TD successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GenDataTD (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  IN  UINT8           DevAddr,\r
+  IN  UINT8           Endpoint,\r
+  IN  UINT8           *PtrData,\r
+  IN  UINT8           Len,\r
+  IN  UINT8           PktID,\r
+  IN  UINT8           Toggle,\r
+  IN  UINT8           DeviceSpeed,\r
+  OUT TD_STRUCT       **PtrTD\r
+  )\r
+{\r
+  TD_STRUCT   *TdStruct;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = CreateTD (UhcDev, &TdStruct);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SetTDLinkPtr (TdStruct, NULL);\r
+\r
+  //\r
+  // Depth first fashion\r
+  //\r
+  SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);\r
+\r
+  //\r
+  // Link pointer pointing to TD struct\r
+  //\r
+  SetTDLinkPtrQHorTDSelect (TdStruct, FALSE);\r
+\r
+  //\r
+  // initialize as the last TD in the QH context,\r
+  // this field will be updated in the TD linkage process.\r
+  //\r
+  SetTDLinkPtrValidorInvalid (TdStruct, FALSE);\r
+\r
+  //\r
+  // Disable short packet detect\r
+  //\r
+  EnableorDisableTDShortPacket (TdStruct, FALSE);\r
+  //\r
+  // Max error counter is 3\r
+  //\r
+  SetTDControlErrorCounter (TdStruct, 3);\r
+\r
+  //\r
+  // set device speed attribute\r
+  // (TRUE - Slow Device; FALSE - Full Speed Device)\r
+  //\r
+  switch (DeviceSpeed) {\r
+  case USB_SLOW_SPEED_DEVICE:\r
+    SetTDLoworFullSpeedDevice (TdStruct, TRUE);\r
+    break;\r
+\r
+  case USB_FULL_SPEED_DEVICE:\r
+    SetTDLoworFullSpeedDevice (TdStruct, FALSE);\r
+    break;\r
+  }\r
+  //\r
+  // Non isochronous transfer TD\r
+  //\r
+  SetTDControlIsochronousorNot (TdStruct, FALSE);\r
+\r
+  //\r
+  // Disable Interrupt On Complete\r
+  // Disable IOC interrupt.\r
+  //\r
+  SetorClearTDControlIOC (TdStruct, FALSE);\r
+\r
+  //\r
+  // Set Active bit\r
+  //\r
+  SetTDStatusActiveorInactive (TdStruct, TRUE);\r
+\r
+  SetTDTokenMaxLength (TdStruct, Len);\r
+\r
+  if (Toggle != 0) {\r
+    SetTDTokenDataToggle1 (TdStruct);\r
+  } else {\r
+    SetTDTokenDataToggle0 (TdStruct);\r
+  }\r
+\r
+  SetTDTokenEndPoint (TdStruct, Endpoint);\r
+\r
+  SetTDTokenDeviceAddress (TdStruct, DevAddr);\r
+\r
+  SetTDTokenPacketID (TdStruct, PktID);\r
+\r
+  TdStruct->PtrTDBuffer      = (UINT8 *) PtrData;\r
+  TdStruct->TDBufferLength = Len;\r
+  SetTDDataBuffer (TdStruct);\r
+\r
+  *PtrTD = TdStruct;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Generate Status Stage TD.\r
+\r
+  @param  UhcDev       The UHCI device.\r
+  @param  DevAddr      Device address.\r
+  @param  Endpoint     Endpoint number.\r
+  @param  PktID        PacketID.\r
+  @param  DeviceSpeed  Device Speed.\r
+  @param  PtrTD        TD_STRUCT generated.\r
+\r
+  @return EFI_SUCCESS            Generate status stage TD successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateStatusTD (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  IN  UINT8           DevAddr,\r
+  IN  UINT8           Endpoint,\r
+  IN  UINT8           PktID,\r
+  IN  UINT8           DeviceSpeed,\r
+  OUT TD_STRUCT       **PtrTD\r
+  )\r
+{\r
+  TD_STRUCT   *PtrTDStruct;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = CreateTD (UhcDev, &PtrTDStruct);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SetTDLinkPtr (PtrTDStruct, NULL);\r
+\r
+  //\r
+  // Depth first fashion\r
+  //\r
+  SetTDLinkPtrDepthorBreadth (PtrTDStruct, TRUE);\r
+\r
+  //\r
+  // initialize as the last TD in the QH context,\r
+  // this field will be updated in the TD linkage process.\r
+  //\r
+  SetTDLinkPtrValidorInvalid (PtrTDStruct, FALSE);\r
+\r
+  //\r
+  // Disable short packet detect\r
+  //\r
+  EnableorDisableTDShortPacket (PtrTDStruct, FALSE);\r
+\r
+  //\r
+  // Max error counter is 3\r
+  //\r
+  SetTDControlErrorCounter (PtrTDStruct, 3);\r
+\r
+  //\r
+  // set device speed attribute\r
+  // (TRUE - Slow Device; FALSE - Full Speed Device)\r
+  //\r
+  switch (DeviceSpeed) {\r
+  case USB_SLOW_SPEED_DEVICE:\r
+    SetTDLoworFullSpeedDevice (PtrTDStruct, TRUE);\r
+    break;\r
+\r
+  case USB_FULL_SPEED_DEVICE:\r
+    SetTDLoworFullSpeedDevice (PtrTDStruct, FALSE);\r
+    break;\r
+  }\r
+  //\r
+  // Non isochronous transfer TD\r
+  //\r
+  SetTDControlIsochronousorNot (PtrTDStruct, FALSE);\r
+\r
+  //\r
+  // Disable Interrupt On Complete\r
+  // Disable IOC interrupt.\r
+  //\r
+  SetorClearTDControlIOC (PtrTDStruct, FALSE);\r
+\r
+  //\r
+  // Set TD Active bit\r
+  //\r
+  SetTDStatusActiveorInactive (PtrTDStruct, TRUE);\r
+\r
+  SetTDTokenMaxLength (PtrTDStruct, 0);\r
+\r
+  SetTDTokenDataToggle1 (PtrTDStruct);\r
+\r
+  SetTDTokenEndPoint (PtrTDStruct, Endpoint);\r
+\r
+  SetTDTokenDeviceAddress (PtrTDStruct, DevAddr);\r
+\r
+  SetTDTokenPacketID (PtrTDStruct, PktID);\r
+\r
+  PtrTDStruct->PtrTDBuffer      = NULL;\r
+  PtrTDStruct->TDBufferLength = 0;\r
+  SetTDDataBuffer (PtrTDStruct);\r
+\r
+  *PtrTD = PtrTDStruct;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set the link pointer validor bit in TD.\r
+\r
+  @param  PtrTDStruct  Place to store TD_STRUCT pointer.\r
+  @param  IsValid      Specify the linker pointer is valid or not.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrValidorInvalid (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsValid\r
+  )\r
+{\r
+  //\r
+  // Valid means the link pointer is valid,\r
+  // else, it's invalid.\r
+  //\r
+  PtrTDStruct->TDData.TDLinkPtrTerminate = (IsValid ? 0 : 1);\r
+}\r
+\r
+/**\r
+  Set the Link Pointer pointing to a QH or TD.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  IsQH          Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrQHorTDSelect (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsQH\r
+  )\r
+{\r
+  //\r
+  // Indicate whether the Link Pointer pointing to a QH or TD\r
+  //\r
+  PtrTDStruct->TDData.TDLinkPtrQSelect = (IsQH ? 1 : 0);\r
+}\r
+\r
+/**\r
+  Set the traverse is depth-first or breadth-first.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  IsDepth       Specify the traverse is depth-first or breadth-first.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrDepthorBreadth (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsDepth\r
+  )\r
+{\r
+  //\r
+  // If TRUE, indicating the host controller should process in depth first fashion,\r
+  // else, the host controller should process in breadth first fashion\r
+  //\r
+  PtrTDStruct->TDData.TDLinkPtrDepthSelect = (IsDepth ? 1 : 0);\r
+}\r
+\r
+/**\r
+  Set TD Link Pointer in TD.\r
+\r
+  @param  PtrTDStruct  Place to store TD_STRUCT pointer.\r
+  @param  PtrNext      Place to the next TD_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtr (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  VOID      *PtrNext\r
+  )\r
+{\r
+  //\r
+  // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,\r
+  // only the highest 28 bits are valid. (if take 32bit address as an example)\r
+  //\r
+  PtrTDStruct->TDData.TDLinkPtr = (UINT32) (UINTN) PtrNext >> 4;\r
+}\r
+\r
+/**\r
+  Get TD Link Pointer.\r
+\r
+  @param  PtrTDStruct     Place to store TD_STRUCT pointer.\r
+\r
+  @retval Get TD Link Pointer in TD.\r
+\r
+**/\r
+VOID *\r
+GetTDLinkPtr (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  //\r
+  // Get TD Link Pointer. Restore it back to 32bit\r
+  // (if take 32bit address as an example)\r
+  //\r
+  return (VOID *) (UINTN) ((PtrTDStruct->TDData.TDLinkPtr) << 4);\r
+}\r
+\r
+/**\r
+  Get the information about whether the Link Pointer field pointing to\r
+  a QH or a TD.\r
+\r
+  @param  PtrTDStruct     Place to store TD_STRUCT pointer.\r
+\r
+  @retval whether the Link Pointer field pointing to a QH or a TD.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDLinkPtrQHOrTD (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  //\r
+  // Get the information about whether the Link Pointer field pointing to\r
+  // a QH or a TD.\r
+  //\r
+  return (BOOLEAN) (PtrTDStruct->TDData.TDLinkPtrQSelect);\r
+}\r
+\r
+/**\r
+  Enable/Disable short packet detection mechanism.\r
+\r
+  @param  PtrTDStruct  Place to store TD_STRUCT pointer.\r
+  @param  IsEnable     Enable or disable short packet detection mechanism.\r
+\r
+**/\r
+VOID\r
+EnableorDisableTDShortPacket (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsEnable\r
+  )\r
+{\r
+  //\r
+  // TRUE means enable short packet detection mechanism.\r
+  //\r
+  PtrTDStruct->TDData.TDStatusSPD = (IsEnable ? 1 : 0);\r
+}\r
+\r
+/**\r
+  Set the max error counter in TD.\r
+\r
+  @param  PtrTDStruct  Place to store TD_STRUCT pointer.\r
+  @param  MaxErrors    The number of allowable error.\r
+\r
+**/\r
+VOID\r
+SetTDControlErrorCounter (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINT8     MaxErrors\r
+  )\r
+{\r
+  //\r
+  // valid value of MaxErrors is 0,1,2,3\r
+  //\r
+  if (MaxErrors > 3) {\r
+    MaxErrors = 3;\r
+  }\r
+\r
+  PtrTDStruct->TDData.TDStatusErr = MaxErrors;\r
+}\r
+\r
+/**\r
+  Set the TD is targeting a low-speed device or not.\r
+\r
+  @param  PtrTDStruct       Place to store TD_STRUCT pointer.\r
+  @param  IsLowSpeedDevice  Whether The device is low-speed.\r
+\r
+**/\r
+VOID\r
+SetTDLoworFullSpeedDevice (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsLowSpeedDevice\r
+  )\r
+{\r
+  //\r
+  // TRUE means the TD is targeting at a Low-speed device\r
+  //\r
+  PtrTDStruct->TDData.TDStatusLS = (IsLowSpeedDevice ? 1 : 0);\r
+}\r
+\r
+/**\r
+  Set the TD is isochronous transfer type or not.\r
+\r
+  @param  PtrTDStruct       Place to store TD_STRUCT pointer.\r
+  @param  IsIsochronous     Whether the transaction isochronous transfer type.\r
+\r
+**/\r
+VOID\r
+SetTDControlIsochronousorNot (\r
+  IN  TD_STRUCT   *PtrTDStruct,\r
+  IN  BOOLEAN     IsIsochronous\r
+  )\r
+{\r
+  //\r
+  // TRUE means the TD belongs to Isochronous transfer type.\r
+  //\r
+  PtrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);\r
+}\r
+\r
+/**\r
+  Set if UCHI should issue an interrupt on completion of the frame\r
+  in which this TD is executed\r
+\r
+  @param  PtrTDStruct       Place to store TD_STRUCT pointer.\r
+  @param  IsSet             Whether HC should issue an interrupt on completion.\r
+\r
+**/\r
+VOID\r
+SetorClearTDControlIOC (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsSet\r
+  )\r
+{\r
+  //\r
+  // If this bit is set, it indicates that the host controller should issue\r
+  // an interrupt on completion of the frame in which this TD is executed.\r
+  //\r
+  PtrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;\r
+}\r
+\r
+/**\r
+  Set if the TD is active and can be executed.\r
+\r
+  @param  PtrTDStruct       Place to store TD_STRUCT pointer.\r
+  @param  IsActive          Whether the TD is active and can be executed.\r
+\r
+**/\r
+VOID\r
+SetTDStatusActiveorInactive (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsActive\r
+  )\r
+{\r
+  //\r
+  // If this bit is set, it indicates that the TD is active and can be\r
+  // executed.\r
+  //\r
+  if (IsActive) {\r
+    PtrTDStruct->TDData.TDStatus |= 0x80;\r
+  } else {\r
+    PtrTDStruct->TDData.TDStatus &= 0x7F;\r
+  }\r
+}\r
+\r
+/**\r
+  Specifies the maximum number of data bytes allowed for the transfer.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  MaxLen        The maximum number of data bytes allowed.\r
+\r
+  @retval The allowed maximum number of data.\r
+**/\r
+UINT16\r
+SetTDTokenMaxLength (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINT16    MaxLen\r
+  )\r
+{\r
+  //\r
+  // Specifies the maximum number of data bytes allowed for the transfer.\r
+  // the legal value extent is 0 ~ 0x500.\r
+  //\r
+  if (MaxLen > 0x500) {\r
+    MaxLen = 0x500;\r
+  }\r
+\r
+  PtrTDStruct->TDData.TDTokenMaxLen = MaxLen - 1;\r
+\r
+  return MaxLen;\r
+}\r
+\r
+/**\r
+  Set the data toggle bit to DATA1.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDataToggle1 (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  //\r
+  // Set the data toggle bit to DATA1\r
+  //\r
+  PtrTDStruct->TDData.TDTokenDataToggle = 1;\r
+}\r
+\r
+/**\r
+  Set the data toggle bit to DATA0.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDataToggle0 (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  //\r
+  // Set the data toggle bit to DATA0\r
+  //\r
+  PtrTDStruct->TDData.TDTokenDataToggle = 0;\r
+}\r
+\r
+/**\r
+  Set EndPoint Number the TD is targeting at.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  EndPoint      The Endport number of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenEndPoint (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINTN     EndPoint\r
+  )\r
+{\r
+  //\r
+  // Set EndPoint Number the TD is targeting at.\r
+  //\r
+  PtrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;\r
+}\r
+\r
+/**\r
+  Set Device Address the TD is targeting at.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  DevAddr       The Device Address of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDeviceAddress (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINTN     DevAddr\r
+  )\r
+{\r
+  //\r
+  // Set Device Address the TD is targeting at.\r
+  //\r
+  PtrTDStruct->TDData.TDTokenDevAddr = (UINT8) DevAddr;\r
+}\r
+\r
+/**\r
+  Set Packet Identification the TD is targeting at.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  PacketID      The Packet Identification of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenPacketID (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINT8     PacketID\r
+  )\r
+{\r
+  //\r
+  // Set the Packet Identification to be used for this transaction.\r
+  //\r
+  PtrTDStruct->TDData.TDTokenPID = PacketID;\r
+}\r
+\r
+/**\r
+  Set the beginning address of the data buffer that will be used\r
+  during the transaction.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDDataBuffer (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  //\r
+  // Set the beginning address of the data buffer that will be used\r
+  // during the transaction.\r
+  //\r
+  PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer);\r
+}\r
+\r
+/**\r
+  Detect whether the TD is active.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The TD is active or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusActive (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  UINT8 TDStatus;\r
+\r
+  //\r
+  // Detect whether the TD is active.\r
+  //\r
+  TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+  return (BOOLEAN) (TDStatus & 0x80);\r
+}\r
+\r
+/**\r
+  Detect whether the TD is stalled.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The TD is stalled or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusStalled (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  UINT8 TDStatus;\r
+\r
+  //\r
+  // Detect whether the device/endpoint addressed by this TD is stalled.\r
+  //\r
+  TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+  return (BOOLEAN) (TDStatus & 0x40);\r
+}\r
+\r
+/**\r
+  Detect whether Data Buffer Error is happened.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The Data Buffer Error is happened or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBufferError (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  UINT8 TDStatus;\r
+\r
+  //\r
+  // Detect whether Data Buffer Error is happened.\r
+  //\r
+  TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+  return (BOOLEAN) (TDStatus & 0x20);\r
+}\r
+\r
+/**\r
+  Detect whether Babble Error is happened.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The Babble Error is happened or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBabbleError (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  UINT8 TDStatus;\r
+\r
+  //\r
+  // Detect whether Babble Error is happened.\r
+  //\r
+  TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+  return (BOOLEAN) (TDStatus & 0x10);\r
+}\r
+\r
+/**\r
+  Detect whether NAK is received.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The NAK is received or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusNAKReceived (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  UINT8 TDStatus;\r
+\r
+  //\r
+  // Detect whether NAK is received.\r
+  //\r
+  TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+  return (BOOLEAN) (TDStatus & 0x08);\r
+}\r
+\r
+/**\r
+  Detect whether CRC/Time Out Error is encountered.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The CRC/Time Out Error is encountered or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusCRCTimeOutError (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  UINT8 TDStatus;\r
+\r
+  //\r
+  // Detect whether CRC/Time Out Error is encountered.\r
+  //\r
+  TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+  return (BOOLEAN) (TDStatus & 0x04);\r
+}\r
+\r
+/**\r
+  Detect whether Bitstuff Error is received.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The Bitstuff Error is received or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBitStuffError (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  UINT8 TDStatus;\r
+\r
+  //\r
+  // Detect whether Bitstuff Error is received.\r
+  //\r
+  TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+  return (BOOLEAN) (TDStatus & 0x02);\r
+}\r
+\r
+/**\r
+  Retrieve the actual number of bytes that were tansferred.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The actual number of bytes that were tansferred.\r
+\r
+**/\r
+UINT16\r
+GetTDStatusActualLength (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  //\r
+  // Retrieve the actual number of bytes that were tansferred.\r
+  // the value is encoded as n-1. so return the decoded value.\r
+  //\r
+  return (UINT16) ((PtrTDStruct->TDData.TDStatusActualLength) + 1);\r
+}\r
+\r
+/**\r
+  Retrieve the information of whether the Link Pointer field is valid or not.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The linker pointer field is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+GetTDLinkPtrValidorInvalid (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  )\r
+{\r
+  //\r
+  // Retrieve the information of whether the Link Pointer field\r
+  // is valid or not.\r
+  //\r
+  if ((PtrTDStruct->TDData.TDLinkPtrTerminate & BIT0) != 0) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Count TD Number from PtrFirstTD.\r
+\r
+  @param  PtrFirstTD   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The queued TDs number.\r
+\r
+**/\r
+UINTN\r
+CountTDsNumber (\r
+  IN  TD_STRUCT *PtrFirstTD\r
+  )\r
+{\r
+  UINTN     Number;\r
+  TD_STRUCT *Ptr;\r
+\r
+  //\r
+  // Count the queued TDs number.\r
+  //\r
+  Number  = 0;\r
+  Ptr     = PtrFirstTD;\r
+  while (Ptr != 0) {\r
+    Ptr = (TD_STRUCT *) Ptr->PtrNextTD;\r
+    Number++;\r
+  }\r
+\r
+  return Number;\r
+}\r
+\r
+/**\r
+  Link TD To QH.\r
+\r
+  @param  PtrQH   Place to store QH_STRUCT pointer.\r
+  @param  PtrTD   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+LinkTDToQH (\r
+  IN  QH_STRUCT *PtrQH,\r
+  IN  TD_STRUCT *PtrTD\r
+  )\r
+{\r
+  if (PtrQH == NULL || PtrTD == NULL) {\r
+    return ;\r
+  }\r
+  //\r
+  //  Validate QH Vertical Ptr field\r
+  //\r
+  SetQHVerticalValidorInvalid (PtrQH, TRUE);\r
+\r
+  //\r
+  //  Vertical Ptr pointing to TD structure\r
+  //\r
+  SetQHVerticalQHorTDSelect (PtrQH, FALSE);\r
+\r
+  SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);\r
+\r
+  PtrQH->PtrDown = (VOID *) PtrTD;\r
+}\r
+\r
+/**\r
+  Link TD To TD.\r
+\r
+  @param  PtrPreTD  Place to store TD_STRUCT pointer.\r
+  @param  PtrTD     Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+LinkTDToTD (\r
+  IN  TD_STRUCT *PtrPreTD,\r
+  IN  TD_STRUCT *PtrTD\r
+  )\r
+{\r
+  if (PtrPreTD == NULL || PtrTD == NULL) {\r
+    return ;\r
+  }\r
+  //\r
+  // Depth first fashion\r
+  //\r
+  SetTDLinkPtrDepthorBreadth (PtrPreTD, TRUE);\r
+\r
+  //\r
+  // Link pointer pointing to TD struct\r
+  //\r
+  SetTDLinkPtrQHorTDSelect (PtrPreTD, FALSE);\r
+\r
+  //\r
+  // Validate the link pointer valid bit\r
+  //\r
+  SetTDLinkPtrValidorInvalid (PtrPreTD, TRUE);\r
+\r
+  SetTDLinkPtr (PtrPreTD, PtrTD);\r
+\r
+  PtrPreTD->PtrNextTD = (VOID *) PtrTD;\r
+\r
+  PtrTD->PtrNextTD    = NULL;\r
+}\r
+\r
+/**\r
+  Execute Control Transfer.\r
+\r
+  @param  UhcDev            The UCHI device.\r
+  @param  PtrTD             A pointer to TD_STRUCT data.\r
+  @param  ActualLen         Actual transfer Length.\r
+  @param  TimeOut           TimeOut value.\r
+  @param  TransferResult    Transfer Result.\r
+\r
+  @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @return EFI_TIMEOUT       The transfer failed due to time out.\r
+  @return EFI_SUCCESS       The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecuteControlTransfer (\r
+  IN  USB_UHC_DEV *UhcDev,\r
+  IN  TD_STRUCT   *PtrTD,\r
+  OUT UINTN       *ActualLen,\r
+  IN  UINTN       TimeOut,\r
+  OUT UINT32      *TransferResult\r
+  )\r
+{\r
+  UINTN   ErrTDPos;\r
+  UINTN   Delay;\r
+\r
+  ErrTDPos          = 0;\r
+  *TransferResult   = EFI_USB_NOERROR;\r
+  *ActualLen        = 0;\r
+\r
+  Delay = (TimeOut * STALL_1_MILLI_SECOND / 200) + 1;\r
+\r
+  do {\r
+\r
+    CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);\r
+\r
+    //\r
+    // TD is inactive, means the control transfer is end.\r
+    //\r
+    if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {\r
+      break;\r
+    }\r
+    MicroSecondDelay (200);\r
+    Delay--;\r
+\r
+  } while (Delay != 0);\r
+\r
+\r
+  if (*TransferResult != EFI_USB_NOERROR) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Execute Bulk Transfer.\r
+\r
+  @param  UhcDev            The UCHI device.\r
+  @param  PtrTD             A pointer to TD_STRUCT data.\r
+  @param  ActualLen         Actual transfer Length.\r
+  @param  DataToggle        DataToggle value.\r
+  @param  TimeOut           TimeOut value.\r
+  @param  TransferResult    Transfer Result.\r
+\r
+  @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @return EFI_TIMEOUT       The transfer failed due to time out.\r
+  @return EFI_SUCCESS       The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecBulkTransfer (\r
+  IN     USB_UHC_DEV *UhcDev,\r
+  IN     TD_STRUCT   *PtrTD,\r
+  IN OUT UINTN       *ActualLen,\r
+  IN     UINT8       *DataToggle,\r
+  IN     UINTN       TimeOut,\r
+  OUT    UINT32      *TransferResult\r
+  )\r
+{\r
+  UINTN   ErrTDPos;\r
+  UINTN   ScrollNum;\r
+  UINTN   Delay;\r
+\r
+  ErrTDPos          = 0;\r
+  *TransferResult   = EFI_USB_NOERROR;\r
+  *ActualLen        = 0;\r
+\r
+  Delay = (TimeOut * STALL_1_MILLI_SECOND / 200) + 1;\r
+\r
+  do {\r
+\r
+    CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);\r
+    //\r
+    // TD is inactive, thus meaning bulk transfer's end.\r
+    //\r
+    if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {\r
+      break;\r
+    }\r
+    MicroSecondDelay (200);\r
+    Delay--;\r
+\r
+  } while (Delay != 0);\r
+\r
+  //\r
+  // has error\r
+  //\r
+  if (*TransferResult != EFI_USB_NOERROR) {\r
+    //\r
+    // scroll the Data Toggle back to the last success TD\r
+    //\r
+    ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;\r
+    if ((ScrollNum % 2) != 0) {\r
+      *DataToggle ^= 1;\r
+    }\r
+\r
+  //\r
+  // If error, wait 100ms to retry by upper layer\r
+  //\r
+    MicroSecondDelay (100 * 1000);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Delete Queued TDs.\r
+\r
+  @param  UhcDev       The UCHI device.\r
+  @param  PtrFirstTD   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+DeleteQueuedTDs (\r
+  IN USB_UHC_DEV     *UhcDev,\r
+  IN TD_STRUCT       *PtrFirstTD\r
+  )\r
+{\r
+  TD_STRUCT *Tptr1;\r
+\r
+  TD_STRUCT *Tptr2;\r
+\r
+  Tptr1 = PtrFirstTD;\r
+  //\r
+  // Delete all the TDs in a queue.\r
+  //\r
+  while (Tptr1 != NULL) {\r
+\r
+    Tptr2 = Tptr1;\r
+\r
+    if (!GetTDLinkPtrValidorInvalid (Tptr2)) {\r
+      Tptr1 = NULL;\r
+    } else {\r
+      //\r
+      // has more than one TD in the queue.\r
+      //\r
+      Tptr1 = GetTDLinkPtr (Tptr2);\r
+    }\r
+\r
+    UhcFreePool (UhcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Check TDs Results.\r
+\r
+  @param  PtrTD               A pointer to TD_STRUCT data.\r
+  @param  Result              The result to return.\r
+  @param  ErrTDPos            The Error TD position.\r
+  @param  ActualTransferSize  Actual transfer size.\r
+\r
+  @retval The TD is executed successfully or not.\r
+\r
+**/\r
+BOOLEAN\r
+CheckTDsResults (\r
+  IN  TD_STRUCT               *PtrTD,\r
+  OUT UINT32                  *Result,\r
+  OUT UINTN                   *ErrTDPos,\r
+  OUT UINTN                   *ActualTransferSize\r
+  )\r
+{\r
+  UINTN Len;\r
+\r
+  *Result   = EFI_USB_NOERROR;\r
+  *ErrTDPos = 0;\r
+\r
+  //\r
+  // Init to zero.\r
+  //\r
+  *ActualTransferSize = 0;\r
+\r
+  while (PtrTD != NULL) {\r
+\r
+    if (IsTDStatusActive (PtrTD)) {\r
+      *Result |= EFI_USB_ERR_NOTEXECUTE;\r
+    }\r
+\r
+    if (IsTDStatusStalled (PtrTD)) {\r
+      *Result |= EFI_USB_ERR_STALL;\r
+    }\r
+\r
+    if (IsTDStatusBufferError (PtrTD)) {\r
+      *Result |= EFI_USB_ERR_BUFFER;\r
+    }\r
+\r
+    if (IsTDStatusBabbleError (PtrTD)) {\r
+      *Result |= EFI_USB_ERR_BABBLE;\r
+    }\r
+\r
+    if (IsTDStatusNAKReceived (PtrTD)) {\r
+      *Result |= EFI_USB_ERR_NAK;\r
+    }\r
+\r
+    if (IsTDStatusCRCTimeOutError (PtrTD)) {\r
+      *Result |= EFI_USB_ERR_TIMEOUT;\r
+    }\r
+\r
+    if (IsTDStatusBitStuffError (PtrTD)) {\r
+      *Result |= EFI_USB_ERR_BITSTUFF;\r
+    }\r
+    //\r
+    // Accumulate actual transferred data length in each TD.\r
+    //\r
+    Len = GetTDStatusActualLength (PtrTD) & 0x7FF;\r
+    *ActualTransferSize += Len;\r
+\r
+    //\r
+    // if any error encountered, stop processing the left TDs.\r
+    //\r
+    if ((*Result) != 0) {\r
+      return FALSE;\r
+    }\r
+\r
+    PtrTD = (TD_STRUCT *) (PtrTD->PtrNextTD);\r
+    //\r
+    // Record the first Error TD's position in the queue,\r
+    // this value is zero-based.\r
+    //\r
+    (*ErrTDPos)++;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Create Memory Block.\r
+\r
+  @param  UhcDev                   The UCHI device.\r
+  @param  MemoryHeader             The Pointer to allocated memory block.\r
+  @param  MemoryBlockSizeInPages   The page size of memory block to be allocated.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateMemoryBlock (\r
+  IN  USB_UHC_DEV           *UhcDev,\r
+  OUT MEMORY_MANAGE_HEADER  **MemoryHeader,\r
+  IN  UINTN                 MemoryBlockSizeInPages\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  TempPtr;\r
+  UINTN                 MemPages;\r
+  UINT8                 *Ptr;\r
+\r
+  //\r
+  // Memory Block uses MemoryBlockSizeInPages pages,\r
+  // memory management header and bit array use 1 page\r
+  //\r
+  MemPages = MemoryBlockSizeInPages + 1;\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesData,\r
+             MemPages,\r
+             &TempPtr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+\r
+  ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);\r
+\r
+  *MemoryHeader = (MEMORY_MANAGE_HEADER *) Ptr;\r
+  //\r
+  // adjust Ptr pointer to the next empty memory\r
+  //\r
+  Ptr += sizeof (MEMORY_MANAGE_HEADER);\r
+  //\r
+  // Set Bit Array initial address\r
+  //\r
+  (*MemoryHeader)->BitArrayPtr  = Ptr;\r
+\r
+  (*MemoryHeader)->Next         = NULL;\r
+\r
+  //\r
+  // Memory block initial address\r
+  //\r
+  Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+  Ptr += EFI_PAGE_SIZE;\r
+  (*MemoryHeader)->MemoryBlockPtr = Ptr;\r
+  //\r
+  // set Memory block size\r
+  //\r
+  (*MemoryHeader)->MemoryBlockSizeInBytes = MemoryBlockSizeInPages * EFI_PAGE_SIZE;\r
+  //\r
+  // each bit in Bit Array will manage 32byte memory in memory block\r
+  //\r
+  (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UHCI memory management.\r
+\r
+  @param  UhcDev                 The UCHI device.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeMemoryManagement (\r
+  IN USB_UHC_DEV           *UhcDev\r
+  )\r
+{\r
+  MEMORY_MANAGE_HEADER  *MemoryHeader;\r
+  EFI_STATUS            Status;\r
+  UINTN                 MemPages;\r
+\r
+  MemPages  = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
+  Status    = CreateMemoryBlock (UhcDev, &MemoryHeader, MemPages);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  UhcDev->Header1 = MemoryHeader;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize UHCI memory management.\r
+\r
+  @param  UhcDev           The UCHI device.\r
+  @param  Pool             Buffer pointer to store the buffer pointer.\r
+  @param  AllocSize        The size of the pool to be allocated.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+UhcAllocatePool (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  OUT UINT8           **Pool,\r
+  IN  UINTN           AllocSize\r
+  )\r
+{\r
+  MEMORY_MANAGE_HEADER  *MemoryHeader;\r
+  MEMORY_MANAGE_HEADER  *TempHeaderPtr;\r
+  MEMORY_MANAGE_HEADER  *NewMemoryHeader;\r
+  UINTN                 RealAllocSize;\r
+  UINTN                 MemoryBlockSizeInPages;\r
+  EFI_STATUS            Status;\r
+\r
+  *Pool = NULL;\r
+\r
+  MemoryHeader = UhcDev->Header1;\r
+\r
+  //\r
+  // allocate unit is 32 byte (align on 32 byte)\r
+  //\r
+  if ((AllocSize & 0x1F) != 0) {\r
+    RealAllocSize = (AllocSize / 32 + 1) * 32;\r
+  } else {\r
+    RealAllocSize = AllocSize;\r
+  }\r
+\r
+  Status = EFI_NOT_FOUND;\r
+  for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+    Status = AllocMemInMemoryBlock (\r
+              TempHeaderPtr,\r
+              (VOID **) Pool,\r
+              RealAllocSize / 32\r
+              );\r
+    if (!EFI_ERROR (Status)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  //\r
+  // There is no enough memory,\r
+  // Create a new Memory Block\r
+  //\r
+  //\r
+  // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,\r
+  // just allocate a large enough memory block.\r
+  //\r
+  if (RealAllocSize > (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES * EFI_PAGE_SIZE)) {\r
+    MemoryBlockSizeInPages = RealAllocSize / EFI_PAGE_SIZE + 1;\r
+  } else {\r
+    MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
+  }\r
+\r
+  Status = CreateMemoryBlock (UhcDev, &NewMemoryHeader, MemoryBlockSizeInPages);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Link the new Memory Block to the Memory Header list\r
+  //\r
+  InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);\r
+\r
+  Status = AllocMemInMemoryBlock (\r
+            NewMemoryHeader,\r
+            (VOID **) Pool,\r
+            RealAllocSize / 32\r
+            );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Alloc Memory In MemoryBlock.\r
+\r
+  @param  MemoryHeader           The pointer to memory manage header.\r
+  @param  Pool                   Buffer pointer to store the buffer pointer.\r
+  @param  NumberOfMemoryUnit     The size of the pool to be allocated.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocMemInMemoryBlock (\r
+  IN  MEMORY_MANAGE_HEADER  *MemoryHeader,\r
+  OUT VOID                  **Pool,\r
+  IN  UINTN                 NumberOfMemoryUnit\r
+  )\r
+{\r
+  UINTN TempBytePos;\r
+  UINTN FoundBytePos;\r
+  UINT8 Index;\r
+  UINT8 FoundBitPos;\r
+  UINT8 ByteValue;\r
+  UINT8 BitValue;\r
+  UINTN NumberOfZeros;\r
+  UINTN Count;\r
+\r
+  FoundBytePos  = 0;\r
+  FoundBitPos   = 0;\r
+\r
+  ByteValue     = MemoryHeader->BitArrayPtr[0];\r
+  NumberOfZeros = 0;\r
+  Index             = 0;\r
+  for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {\r
+    //\r
+    // Pop out BitValue from a byte in TempBytePos.\r
+    //\r
+    BitValue = (UINT8)(ByteValue & 0x1);\r
+\r
+    if (BitValue == 0) {\r
+      //\r
+      // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros\r
+      //\r
+      NumberOfZeros++;\r
+      //\r
+      // Found enough consecutive free space, break the loop\r
+      //\r
+      if (NumberOfZeros >= NumberOfMemoryUnit) {\r
+        break;\r
+      }\r
+    } else {\r
+      //\r
+      // Encountering a '1', meant the bit is ocupied.\r
+      //\r
+      if (NumberOfZeros >= NumberOfMemoryUnit) {\r
+        //\r
+        // Found enough consecutive free space,break the loop\r
+        //\r
+        break;\r
+      } else {\r
+        //\r
+        // the NumberOfZeros only record the number of those consecutive zeros,\r
+        // so reset the NumberOfZeros to 0 when encountering '1' before finding\r
+        // enough consecutive '0's\r
+        //\r
+        NumberOfZeros = 0;\r
+        //\r
+        // reset the (FoundBytePos,FoundBitPos) to the position of '1'\r
+        //\r
+        FoundBytePos  = TempBytePos;\r
+        FoundBitPos   = Index;\r
+      }\r
+    }\r
+    //\r
+    // right shift the byte\r
+    //\r
+    ByteValue /= 2;\r
+\r
+    //\r
+    // step forward a bit\r
+    //\r
+    Index++;\r
+    if (Index == 8) {\r
+      //\r
+      // step forward a byte, getting the byte value,\r
+      // and reset the bit pos.\r
+      //\r
+      TempBytePos += 1;\r
+      ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];\r
+      Index     = 0;\r
+    }\r
+  }\r
+\r
+  if (NumberOfZeros < NumberOfMemoryUnit) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Found enough free space.\r
+  //\r
+  //\r
+  // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:\r
+  //  1)(FoundBytePos,FoundBitPos) record the position\r
+  //    of the last '1' before the consecutive '0's, it must\r
+  //    be adjusted to the start position of the consecutive '0's.\r
+  //  2)the start address of the consecutive '0's is just the start of\r
+  //    the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).\r
+  //\r
+  if ((MemoryHeader->BitArrayPtr[0] & BIT0) != 0) {\r
+    FoundBitPos += 1;\r
+  }\r
+  //\r
+  // Have the (FoundBytePos,FoundBitPos) make sense.\r
+  //\r
+  if (FoundBitPos > 7) {\r
+    FoundBytePos += 1;\r
+    FoundBitPos -= 8;\r
+  }\r
+  //\r
+  // Set the memory as allocated\r
+  //\r
+  for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {\r
+\r
+    MemoryHeader->BitArrayPtr[TempBytePos] = (UINT8) (MemoryHeader->BitArrayPtr[TempBytePos] | (1 << Index));\r
+    Index++;\r
+    if (Index == 8) {\r
+      TempBytePos += 1;\r
+      Index = 0;\r
+    }\r
+  }\r
+\r
+  *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Uhci Free Pool.\r
+\r
+  @param  UhcDev                 The UHCI device.\r
+  @param  Pool                   A pointer to store the buffer address.\r
+  @param  AllocSize              The size of the pool to be freed.\r
+\r
+**/\r
+VOID\r
+UhcFreePool (\r
+  IN USB_UHC_DEV     *UhcDev,\r
+  IN UINT8           *Pool,\r
+  IN UINTN           AllocSize\r
+  )\r
+{\r
+  MEMORY_MANAGE_HEADER  *MemoryHeader;\r
+  MEMORY_MANAGE_HEADER  *TempHeaderPtr;\r
+  UINTN                 StartBytePos;\r
+  UINTN                 Index;\r
+  UINT8                 StartBitPos;\r
+  UINT8                 Index2;\r
+  UINTN                 Count;\r
+  UINTN                 RealAllocSize;\r
+\r
+  MemoryHeader = UhcDev->Header1;\r
+\r
+  //\r
+  // allocate unit is 32 byte (align on 32 byte)\r
+  //\r
+  if ((AllocSize & 0x1F) != 0) {\r
+    RealAllocSize = (AllocSize / 32 + 1) * 32;\r
+  } else {\r
+    RealAllocSize = AllocSize;\r
+  }\r
+\r
+  for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;\r
+       TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+    if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&\r
+        ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr +\r
+                                    TempHeaderPtr->MemoryBlockSizeInBytes))) {\r
+\r
+      //\r
+      // Pool is in the Memory Block area,\r
+      // find the start byte and bit in the bit array\r
+      //\r
+      StartBytePos  = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;\r
+      StartBitPos   = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);\r
+\r
+      //\r
+      // reset associated bits in bit arry\r
+      //\r
+      for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {\r
+\r
+        TempHeaderPtr->BitArrayPtr[Index] = (UINT8) (TempHeaderPtr->BitArrayPtr[Index] ^ (1 << Index2));\r
+        Index2++;\r
+        if (Index2 == 8) {\r
+          Index += 1;\r
+          Index2 = 0;\r
+        }\r
+      }\r
+      //\r
+      // break the loop\r
+      //\r
+      break;\r
+    }\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Insert a new memory header into list.\r
+\r
+  @param  MemoryHeader         A pointer to the memory header list.\r
+  @param  NewMemoryHeader      A new memory header to be inserted into the list.\r
+\r
+**/\r
+VOID\r
+InsertMemoryHeaderToList (\r
+  IN MEMORY_MANAGE_HEADER  *MemoryHeader,\r
+  IN MEMORY_MANAGE_HEADER  *NewMemoryHeader\r
+  )\r
+{\r
+  MEMORY_MANAGE_HEADER  *TempHeaderPtr;\r
+\r
+  for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+    if (TempHeaderPtr->Next == NULL) {\r
+      TempHeaderPtr->Next = NewMemoryHeader;\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Judge the memory block in the memory header is empty or not.\r
+\r
+  @param  MemoryHeaderPtr   A pointer to the memory header list.\r
+\r
+  @retval Whether the memory block in the memory header is empty or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsMemoryBlockEmptied (\r
+  IN MEMORY_MANAGE_HEADER  *MemoryHeaderPtr\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {\r
+    if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  remove a memory header from list.\r
+\r
+  @param  FirstMemoryHeader   A pointer to the memory header list.\r
+  @param  FreeMemoryHeader    A memory header to be removed into the list.\r
+\r
+**/\r
+VOID\r
+DelinkMemoryBlock (\r
+  IN MEMORY_MANAGE_HEADER    *FirstMemoryHeader,\r
+  IN MEMORY_MANAGE_HEADER    *FreeMemoryHeader\r
+  )\r
+{\r
+  MEMORY_MANAGE_HEADER  *TempHeaderPtr;\r
+\r
+  if ((FirstMemoryHeader == NULL) || (FreeMemoryHeader == NULL)) {\r
+    return ;\r
+  }\r
+\r
+  for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+    if (TempHeaderPtr->Next == FreeMemoryHeader) {\r
+      //\r
+      // Link the before and after\r
+      //\r
+      TempHeaderPtr->Next = FreeMemoryHeader->Next;\r
+      break;\r
+    }\r
+  }\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h b/MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.h
new file mode 100644 (file)
index 0000000..dc697ce
--- /dev/null
@@ -0,0 +1,1332 @@
+/** @file\r
+Private Header file for Usb Host Controller PEIM\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
+#ifndef _RECOVERY_UHC_H_\r
+#define _RECOVERY_UHC_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbController.h>\r
+#include <Ppi/UsbHostController.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#define USB_SLOW_SPEED_DEVICE 0x01\r
+#define USB_FULL_SPEED_DEVICE 0x02\r
+\r
+//\r
+// One memory block uses 16 page\r
+//\r
+#define NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES 16\r
+\r
+#define USBCMD                            0       /* Command Register Offset 00-01h */\r
+#define USBCMD_RS                         BIT0    /* Run/Stop */\r
+#define USBCMD_HCRESET                    BIT1    /* Host reset */\r
+#define USBCMD_GRESET                     BIT2    /* Global reset */\r
+#define USBCMD_EGSM                       BIT3    /* Global Suspend Mode */\r
+#define USBCMD_FGR                        BIT4    /* Force Global Resume */\r
+#define USBCMD_SWDBG                      BIT5    /* SW Debug mode */\r
+#define USBCMD_CF                         BIT6    /* Config Flag (sw only) */\r
+#define USBCMD_MAXP                       BIT7    /* Max Packet (0 = 32, 1 = 64) */\r
+\r
+/* Status register */\r
+#define USBSTS        2       /* Status Register Offset 02-03h */\r
+#define USBSTS_USBINT BIT0    /* Interrupt due to IOC */\r
+#define USBSTS_ERROR  BIT1    /* Interrupt due to error */\r
+#define USBSTS_RD     BIT2    /* Resume Detect */\r
+#define USBSTS_HSE    BIT3    /* Host System Error - basically PCI problems */\r
+#define USBSTS_HCPE   BIT4    /* Host Controller Process Error - the scripts were buggy */\r
+#define USBSTS_HCH    BIT5    /* HC Halted */\r
+\r
+/* Interrupt enable register */\r
+#define USBINTR         4       /* Interrupt Enable Register 04-05h */\r
+#define USBINTR_TIMEOUT BIT0    /* Timeout/CRC error enable */\r
+#define USBINTR_RESUME  BIT1    /* Resume interrupt enable */\r
+#define USBINTR_IOC     BIT2    /* Interrupt On Complete enable */\r
+#define USBINTR_SP      BIT3    /* Short packet interrupt enable */\r
+\r
+/* Frame Number Register Offset 06-08h */\r
+#define USBFRNUM  6\r
+\r
+/* Frame List Base Address Register Offset 08-0Bh */\r
+#define USBFLBASEADD  8\r
+\r
+/* Start of Frame Modify Register Offset 0Ch */\r
+#define USBSOF  0x0c\r
+\r
+/* USB port status and control registers */\r
+#define USBPORTSC1            0x10      /*Port 1 offset 10-11h */\r
+#define USBPORTSC2            0x12      /*Port 2 offset 12-13h */\r
+\r
+#define USBPORTSC_CCS         BIT0      /* Current Connect Status ("device present") */\r
+#define USBPORTSC_CSC         BIT1      /* Connect Status Change */\r
+#define USBPORTSC_PED         BIT2      /* Port Enable / Disable */\r
+#define USBPORTSC_PEDC        BIT3      /* Port Enable / Disable Change */\r
+#define USBPORTSC_LSL         BIT4      /* Line Status Low bit*/\r
+#define USBPORTSC_LSH         BIT5      /* Line Status High bit*/\r
+#define USBPORTSC_RD          BIT6      /* Resume Detect */\r
+#define USBPORTSC_LSDA        BIT8      /* Low Speed Device Attached */\r
+#define USBPORTSC_PR          BIT9      /* Port Reset */\r
+#define USBPORTSC_SUSP        BIT12     /* Suspend */\r
+\r
+#define SETUP_PACKET_ID       0x2D\r
+#define INPUT_PACKET_ID       0x69\r
+#define OUTPUT_PACKET_ID      0xE1\r
+#define ERROR_PACKET_ID       0x55\r
+\r
+#define STALL_1_MILLI_SECOND  1000\r
+\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  UINT32  FrameListPtrTerminate : 1;\r
+  UINT32  FrameListPtrQSelect : 1;\r
+  UINT32  FrameListRsvd : 2;\r
+  UINT32  FrameListPtr : 28;\r
+} FRAMELIST_ENTRY;\r
+\r
+typedef struct {\r
+  UINT32  QHHorizontalTerminate : 1;\r
+  UINT32  QHHorizontalQSelect : 1;\r
+  UINT32  QHHorizontalRsvd : 2;\r
+  UINT32  QHHorizontalPtr : 28;\r
+  UINT32  QHVerticalTerminate : 1;\r
+  UINT32  QHVerticalQSelect : 1;\r
+  UINT32  QHVerticalRsvd : 2;\r
+  UINT32  QHVerticalPtr : 28;\r
+} QUEUE_HEAD;\r
+\r
+typedef struct {\r
+  QUEUE_HEAD  QueueHead;\r
+  UINT32      Reserved1;\r
+  UINT32      Reserved2;\r
+  VOID        *PtrNext;\r
+  VOID        *PtrDown;\r
+  VOID        *Reserved3;\r
+  UINT32      Reserved4;\r
+} QH_STRUCT;\r
+\r
+typedef struct {\r
+  UINT32  TDLinkPtrTerminate : 1;\r
+  UINT32  TDLinkPtrQSelect : 1;\r
+  UINT32  TDLinkPtrDepthSelect : 1;\r
+  UINT32  TDLinkPtrRsvd : 1;\r
+  UINT32  TDLinkPtr : 28;\r
+  UINT32  TDStatusActualLength : 11;\r
+  UINT32  TDStatusRsvd : 5;\r
+  UINT32  TDStatus : 8;\r
+  UINT32  TDStatusIOC : 1;\r
+  UINT32  TDStatusIOS : 1;\r
+  UINT32  TDStatusLS : 1;\r
+  UINT32  TDStatusErr : 2;\r
+  UINT32  TDStatusSPD : 1;\r
+  UINT32  TDStatusRsvd2 : 2;\r
+  UINT32  TDTokenPID : 8;\r
+  UINT32  TDTokenDevAddr : 7;\r
+  UINT32  TDTokenEndPt : 4;\r
+  UINT32  TDTokenDataToggle : 1;\r
+  UINT32  TDTokenRsvd : 1;\r
+  UINT32  TDTokenMaxLen : 11;\r
+  UINT32  TDBufferPtr;\r
+} TD;\r
+\r
+typedef struct {\r
+  TD      TDData;\r
+  UINT8   *PtrTDBuffer;\r
+  VOID    *PtrNextTD;\r
+  VOID    *PtrNextQH;\r
+  UINT16  TDBufferLength;\r
+  UINT16  Reserved;\r
+} TD_STRUCT;\r
+\r
+#pragma pack()\r
+\r
+typedef struct _MEMORY_MANAGE_HEADER MEMORY_MANAGE_HEADER;\r
+\r
+struct _MEMORY_MANAGE_HEADER {\r
+  UINT8                         *BitArrayPtr;\r
+  UINTN                         BitArraySizeInBytes;\r
+  UINT8                         *MemoryBlockPtr;\r
+  UINTN                         MemoryBlockSizeInBytes;\r
+  MEMORY_MANAGE_HEADER          *Next;\r
+};\r
+\r
+#define USB_UHC_DEV_SIGNATURE SIGNATURE_32 ('p', 'u', 'h', 'c')\r
+typedef struct {\r
+  UINTN                       Signature;\r
+  PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR      PpiDescriptor;\r
+\r
+  UINT32                      UsbHostControllerBaseAddress;\r
+  FRAMELIST_ENTRY             *FrameListEntry;\r
+  QH_STRUCT                   *ConfigQH;\r
+  QH_STRUCT                   *BulkQH;\r
+  //\r
+  // Header1 used for QH,TD memory blocks management\r
+  //\r
+  MEMORY_MANAGE_HEADER        *Header1;\r
+\r
+} USB_UHC_DEV;\r
+\r
+#define PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS(a)  CR (a, USB_UHC_DEV, UsbHostControllerPpi, USB_UHC_DEV_SIGNATURE)\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param  DeviceAddress          The target device address.\r
+  @param  DeviceSpeed            Target device speed.\r
+  @param  MaximumPacketLength    Maximum packet size the default control transfer \r
+                                 endpoint is capable of sending or receiving.\r
+  @param  Request                USB device request to send.\r
+  @param  TransferDirection      Specifies the data direction for the data stage.\r
+  @param  Data                   Data buffer to be transmitted or received from USB device.\r
+  @param  DataLength             The size (in bytes) of the data buffer.\r
+  @param  TimeOut                Indicates the maximum timeout, in millisecond.\r
+  @param  TransferResult         Return the result of this control transfer.\r
+\r
+  @retval EFI_SUCCESS            Transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.\r
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcControlTransfer (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    * This,\r
+  IN     UINT8                      DeviceAddress,\r
+  IN     UINT8                      DeviceSpeed,\r
+  IN     UINT8                      MaximumPacketLength,\r
+  IN     EFI_USB_DEVICE_REQUEST     * Request,\r
+  IN     EFI_USB_DATA_DIRECTION     TransferDirection,\r
+  IN OUT VOID                       *Data OPTIONAL,\r
+  IN OUT UINTN                      *DataLength OPTIONAL,\r
+  IN     UINTN                      TimeOut,\r
+  OUT    UINT32                     *TransferResult\r
+  );\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param  DeviceAddress         Target device address.\r
+  @param  EndPointAddress       Endpoint number and its direction in bit 7.\r
+  @param  MaximumPacketLength   Maximum packet size the endpoint is capable of \r
+                                sending or receiving.\r
+  @param  Data                  Array of pointers to the buffers of data to transmit \r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  DataToggle            On input, the initial data toggle for the transfer;\r
+                                On output, it is updated to to next data toggle to use of \r
+                                the subsequent bulk transfer.\r
+  @param  TimeOut               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+  @param  TransferResult        A pointer to the detailed result information of the\r
+                                bulk transfer.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcBulkTransfer (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN  UINT8                         DeviceAddress,\r
+  IN  UINT8                         EndPointAddress,\r
+  IN  UINT8                         MaximumPacketLength,\r
+  IN OUT VOID                       *Data,\r
+  IN OUT UINTN                      *DataLength,\r
+  IN OUT UINT8                      *DataToggle,\r
+  IN  UINTN                         TimeOut,\r
+  OUT UINT32                        *TransferResult\r
+  );\r
+\r
+/**\r
+  Retrieves the number of root hub ports.\r
+\r
+  @param[in]  PeiServices   The pointer to the PEI Services Table.\r
+  @param[in]  This          The pointer to this instance of the \r
+                            PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param[out] PortNumber    The pointer to the number of the root hub ports.                                \r
+                                \r
+  @retval EFI_SUCCESS           The port number was retrieved successfully.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcGetRootHubPortNumber (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  OUT UINT8                         *PortNumber\r
+  );\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param  PortNumber             The root hub port to retrieve the state from.  \r
+  @param  PortStatus             Variable to receive the port state.\r
+\r
+  @retval EFI_SUCCESS            The status of the USB root hub port specified.\r
+                                 by PortNumber was returned in PortStatus.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcGetRootHubPortStatus (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN  UINT8                         PortNumber,\r
+  OUT EFI_USB_PORT_STATUS           *PortStatus\r
+  );\r
+\r
+/**\r
+  Sets a feature for the specified root hub port.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES\r
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI\r
+  @param  PortNumber            Root hub port to set.\r
+  @param  PortFeature           Feature to set.\r
+\r
+  @retval EFI_SUCCESS            The feature specified by PortFeature was set.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_TIMEOUT            The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcSetRootHubPortFeature (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN UINT8                          PortNumber,\r
+  IN EFI_USB_PORT_FEATURE           PortFeature\r
+  );\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param  PortNumber            Specifies the root hub port whose feature\r
+                                is requested to be cleared.\r
+  @param  PortFeature           Indicates the feature selector associated with the\r
+                                feature clear request.\r
+\r
+  @retval EFI_SUCCESS            The feature specified by PortFeature was cleared \r
+                                 for the USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcClearRootHubPortFeature (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI    *This,\r
+  IN UINT8                          PortNumber,\r
+  IN EFI_USB_PORT_FEATURE           PortFeature\r
+  );\r
+\r
+/**\r
+  Initialize UHCI.\r
+\r
+  @param  UhcDev                 UHCI Device.\r
+\r
+  @retval EFI_SUCCESS            UHCI successfully initialized.\r
+  @retval EFI_OUT_OF_RESOURCES   Resource can not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+  IN USB_UHC_DEV          *UhcDev\r
+  );\r
+\r
+/**\r
+  Create Frame List Structure.\r
+\r
+  @param  UhcDev                 UHCI device.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateFrameList (\r
+  USB_UHC_DEV             *UhcDev\r
+  );\r
+\r
+/**\r
+  Read a 16bit width data from Uhc HC IO space register.\r
+  \r
+  @param  UhcDev  The UHCI device.\r
+  @param  Port    The IO space address of the register.\r
+\r
+  @retval the register content read.\r
+\r
+**/\r
+UINT16\r
+USBReadPortW (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        Port\r
+  );\r
+\r
+/**\r
+  Write a 16bit width data into Uhc HC IO space register.\r
+  \r
+  @param  UhcDev  The UHCI device.\r
+  @param  Port    The IO space address of the register.\r
+  @param  Data    The data written into the register.\r
+\r
+**/\r
+VOID\r
+USBWritePortW (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        Port,\r
+  IN  UINT16        Data\r
+  );\r
+\r
+/**\r
+  Write a 32bit width data into Uhc HC IO space register.\r
+  \r
+  @param  UhcDev  The UHCI device.\r
+  @param  Port    The IO space address of the register.\r
+  @param  Data    The data written into the register.\r
+\r
+**/\r
+VOID\r
+USBWritePortDW (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        Port,\r
+  IN  UINT32        Data\r
+  );\r
+\r
+/**\r
+  Clear the content of UHCI's Status Register.\r
+  \r
+  @param  UhcDev       The UHCI device.\r
+  @param  StatusAddr   The IO space address of the register.\r
+\r
+**/\r
+VOID\r
+ClearStatusReg (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        StatusAddr\r
+  );\r
+\r
+/**\r
+  Check whether the host controller operates well.\r
+\r
+  @param  UhcDev        The UHCI device.\r
+  @param  StatusRegAddr The io address of status register.\r
+\r
+  @retval TRUE          Host controller is working.\r
+  @retval FALSE         Host controller is halted or system error.\r
+\r
+**/\r
+BOOLEAN\r
+IsStatusOK (\r
+  IN USB_UHC_DEV     *UhcDev,\r
+  IN UINT32          StatusRegAddr\r
+  );\r
+\r
+/**\r
+  Get Current Frame Number.\r
+\r
+  @param  UhcDev          The UHCI device.\r
+  @param  FrameNumberAddr The address of frame list register.\r
+\r
+  @retval The content of the frame list register.\r
+\r
+**/\r
+UINT16\r
+GetCurrentFrameNumber (\r
+  IN USB_UHC_DEV   *UhcDev,\r
+  IN UINT32        FrameNumberAddr\r
+  );\r
+\r
+/**\r
+  Set Frame List Base Address.\r
+\r
+  @param  UhcDev           The UHCI device.\r
+  @param  FrameListRegAddr The address of frame list register.\r
+  @param  Addr             The address of frame list table.\r
+\r
+**/\r
+VOID\r
+SetFrameListBaseAddress (\r
+  IN USB_UHC_DEV   *UhcDev,\r
+  IN UINT32        FrameListRegAddr,\r
+  IN UINT32        Addr\r
+  );\r
+\r
+/**\r
+  Create QH and initialize.\r
+\r
+  @param  UhcDev               The UHCI device.\r
+  @param  PtrQH                Place to store QH_STRUCT pointer.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+  @retval EFI_SUCCESS        Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateQH (\r
+  IN  USB_UHC_DEV  *UhcDev,\r
+  OUT QH_STRUCT    **PtrQH\r
+  );\r
+\r
+/**\r
+  Set the horizontal link pointer in QH.\r
+\r
+  @param  PtrQH               Place to store QH_STRUCT pointer.\r
+  @param  PtrNext             Place to the next QH_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalLinkPtr (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN VOID       *PtrNext\r
+  );\r
+\r
+/**\r
+  Get the horizontal link pointer in QH.\r
+\r
+  @param  PtrQH     Place to store QH_STRUCT pointer.\r
+\r
+  @retval The horizontal link pointer in QH.\r
+\r
+**/\r
+VOID  *\r
+GetQHHorizontalLinkPtr (\r
+  IN QH_STRUCT  *PtrQH\r
+  );\r
+\r
+/**\r
+  Set a QH or TD horizontally to be connected with a specific QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+  @param  IsQH       Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalQHorTDSelect (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN BOOLEAN    IsQH\r
+  );\r
+\r
+/**\r
+  Set the horizontal validor bit in QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+  @param  IsValid    Specify the horizontal linker is valid or not.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalValidorInvalid (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN BOOLEAN    IsValid\r
+  );\r
+\r
+/**\r
+  Set the vertical link pointer in QH.\r
+\r
+  @param  PtrQH       Place to store QH_STRUCT pointer.\r
+  @param  PtrNext     Place to the next QH_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalLinkPtr (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN VOID       *PtrNext\r
+  );\r
+\r
+/**\r
+  Set a QH or TD vertically to be connected with a specific QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+  @param  IsQH       Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalQHorTDSelect (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN BOOLEAN    IsQH\r
+  );\r
+\r
+/**\r
+  Set the vertical validor bit in QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+  @param  IsValid    Specify the vertical linker is valid or not.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalValidorInvalid (\r
+  IN QH_STRUCT  *PtrQH,\r
+  IN BOOLEAN    IsValid\r
+  );\r
+\r
+/**\r
+  Get the vertical validor bit in QH.\r
+\r
+  @param  PtrQH      Place to store QH_STRUCT pointer.\r
+\r
+  @retval The vertical linker is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+GetQHHorizontalValidorInvalid (\r
+  IN QH_STRUCT  *PtrQH\r
+  );\r
+\r
+/**\r
+  Allocate TD or QH Struct.\r
+\r
+  @param  UhcDev                 The UHCI device.\r
+  @param  Size                   The size of allocation.\r
+  @param  PtrStruct              Place to store TD_STRUCT pointer.\r
+\r
+  @return EFI_SUCCESS            Allocate successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocateTDorQHStruct (\r
+  IN  USB_UHC_DEV   *UhcDev,\r
+  IN  UINT32        Size,\r
+  OUT VOID          **PtrStruct\r
+  );\r
+\r
+/**\r
+  Create a TD Struct.\r
+\r
+  @param  UhcDev                 The UHCI device.\r
+  @param  PtrTD                  Place to store TD_STRUCT pointer.\r
+\r
+  @return EFI_SUCCESS            Allocate successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateTD (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  OUT TD_STRUCT       **PtrTD\r
+  );\r
+\r
+/**\r
+  Generate Setup Stage TD.\r
+\r
+  @param  UhcDev       The UHCI device.\r
+  @param  DevAddr      Device address.\r
+  @param  Endpoint     Endpoint number.\r
+  @param  DeviceSpeed  Device Speed.\r
+  @param  DevRequest   Device reuquest.\r
+  @param  RequestLen   Request length.\r
+  @param  PtrTD        TD_STRUCT generated.\r
+\r
+  @return EFI_SUCCESS            Generate setup stage TD successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GenSetupStageTD (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  IN  UINT8           DevAddr,\r
+  IN  UINT8           Endpoint,\r
+  IN  UINT8           DeviceSpeed,\r
+  IN  UINT8           *DevRequest,\r
+  IN  UINT8           RequestLen,\r
+  OUT TD_STRUCT       **PtrTD\r
+  );\r
+\r
+/**\r
+  Generate Data Stage TD.\r
+\r
+  @param  UhcDev       The UHCI device.\r
+  @param  DevAddr      Device address.\r
+  @param  Endpoint     Endpoint number.\r
+  @param  PtrData      Data buffer.\r
+  @param  Len          Data length.\r
+  @param  PktID        PacketID.\r
+  @param  Toggle       Data toggle value.\r
+  @param  DeviceSpeed  Device Speed.\r
+  @param  PtrTD        TD_STRUCT generated.\r
+\r
+  @return EFI_SUCCESS            Generate data stage TD successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GenDataTD (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  IN  UINT8           DevAddr,\r
+  IN  UINT8           Endpoint,\r
+  IN  UINT8           *PtrData,\r
+  IN  UINT8           Len,\r
+  IN  UINT8           PktID,\r
+  IN  UINT8           Toggle,\r
+  IN  UINT8           DeviceSpeed,\r
+  OUT TD_STRUCT       **PtrTD\r
+  );\r
+\r
+/**\r
+  Generate Status Stage TD.\r
+\r
+  @param  UhcDev       The UHCI device.\r
+  @param  DevAddr      Device address.\r
+  @param  Endpoint     Endpoint number.\r
+  @param  PktID        PacketID.\r
+  @param  DeviceSpeed  Device Speed.\r
+  @param  PtrTD        TD_STRUCT generated.\r
+\r
+  @return EFI_SUCCESS            Generate status stage TD successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateStatusTD (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  IN  UINT8           DevAddr,\r
+  IN  UINT8           Endpoint,\r
+  IN  UINT8           PktID,\r
+  IN  UINT8           DeviceSpeed,\r
+  OUT TD_STRUCT       **PtrTD\r
+  );\r
+\r
+/**\r
+  Set the link pointer validor bit in TD.\r
+\r
+  @param  PtrTDStruct  Place to store TD_STRUCT pointer.\r
+  @param  IsValid      Specify the linker pointer is valid or not.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrValidorInvalid (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsValid\r
+  );\r
+\r
+/**\r
+  Set the Link Pointer pointing to a QH or TD.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  IsQH          Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrQHorTDSelect (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsQH\r
+  );\r
+\r
+/**\r
+  Set the traverse is depth-first or breadth-first.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  IsDepth       Specify the traverse is depth-first or breadth-first.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrDepthorBreadth (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsDepth\r
+  );\r
+\r
+/**\r
+  Set TD Link Pointer in TD.\r
+\r
+  @param  PtrTDStruct  Place to store TD_STRUCT pointer.\r
+  @param  PtrNext      Place to the next TD_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtr (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  VOID      *PtrNext\r
+  );\r
+\r
+/**\r
+  Get TD Link Pointer.\r
+\r
+  @param  PtrTDStruct     Place to store TD_STRUCT pointer.\r
+\r
+  @retval Get TD Link Pointer in TD.\r
+\r
+**/\r
+VOID*\r
+GetTDLinkPtr (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Get the information about whether the Link Pointer field pointing to\r
+  a QH or a TD.\r
+\r
+  @param  PtrTDStruct     Place to store TD_STRUCT pointer.\r
+\r
+  @retval whether the Link Pointer field pointing to a QH or a TD.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDLinkPtrQHOrTD (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Enable/Disable short packet detection mechanism.\r
+\r
+  @param  PtrTDStruct  Place to store TD_STRUCT pointer.\r
+  @param  IsEnable     Enable or disable short packet detection mechanism.\r
+\r
+**/\r
+VOID\r
+EnableorDisableTDShortPacket (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsEnable\r
+  );\r
+\r
+/**\r
+  Set the max error counter in TD.\r
+\r
+  @param  PtrTDStruct  Place to store TD_STRUCT pointer.\r
+  @param  MaxErrors    The number of allowable error.\r
+\r
+**/\r
+VOID\r
+SetTDControlErrorCounter (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINT8     MaxErrors\r
+  );\r
+\r
+/**\r
+  Set the TD is targeting a low-speed device or not.\r
+\r
+  @param  PtrTDStruct       Place to store TD_STRUCT pointer.\r
+  @param  IsLowSpeedDevice  Whether The device is low-speed.\r
+\r
+**/\r
+VOID\r
+SetTDLoworFullSpeedDevice (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsLowSpeedDevice\r
+  );\r
+\r
+/**\r
+  Set the TD is isochronous transfer type or not.\r
+\r
+  @param  PtrTDStruct       Place to store TD_STRUCT pointer.\r
+  @param  IsIsochronous     Whether the transaction isochronous transfer type.\r
+\r
+**/\r
+VOID\r
+SetTDControlIsochronousorNot (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsIsochronous\r
+  );\r
+\r
+/**\r
+  Set if UCHI should issue an interrupt on completion of the frame\r
+  in which this TD is executed\r
+\r
+  @param  PtrTDStruct       Place to store TD_STRUCT pointer.\r
+  @param  IsSet             Whether HC should issue an interrupt on completion.\r
+\r
+**/\r
+VOID\r
+SetorClearTDControlIOC (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsSet\r
+  );\r
+\r
+/**\r
+  Set if the TD is active and can be executed.\r
+\r
+  @param  PtrTDStruct       Place to store TD_STRUCT pointer.\r
+  @param  IsActive          Whether the TD is active and can be executed.\r
+\r
+**/\r
+VOID\r
+SetTDStatusActiveorInactive (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  BOOLEAN   IsActive\r
+  );\r
+\r
+/**\r
+  Specifies the maximum number of data bytes allowed for the transfer.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  MaxLen        The maximum number of data bytes allowed.\r
+\r
+  @retval The allowed maximum number of data.\r
+**/\r
+UINT16\r
+SetTDTokenMaxLength (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINT16    MaxLen\r
+  );\r
+\r
+/**\r
+  Set the data toggle bit to DATA1.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDataToggle1 (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Set the data toggle bit to DATA0.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDataToggle0 (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Set EndPoint Number the TD is targeting at.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  EndPoint      The Endport number of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenEndPoint (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINTN     EndPoint\r
+  );\r
+\r
+/**\r
+  Set Device Address the TD is targeting at.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  DevAddr       The Device Address of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDeviceAddress (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINTN     DevAddr\r
+  );\r
+\r
+/**\r
+  Set Packet Identification the TD is targeting at.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+  @param  PacketID      The Packet Identification of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenPacketID (\r
+  IN  TD_STRUCT *PtrTDStruct,\r
+  IN  UINT8     PacketID\r
+  );\r
+\r
+/**\r
+  Set the beginning address of the data buffer that will be used\r
+  during the transaction.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDDataBuffer (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Detect whether the TD is active.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The TD is active or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusActive (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Detect whether the TD is stalled.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The TD is stalled or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusStalled (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Detect whether Data Buffer Error is happened.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The Data Buffer Error is happened or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBufferError (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Detect whether Babble Error is happened.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The Babble Error is happened or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBabbleError (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Detect whether NAK is received.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The NAK is received or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusNAKReceived (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Detect whether CRC/Time Out Error is encountered.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The CRC/Time Out Error is encountered or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusCRCTimeOutError (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Detect whether Bitstuff Error is received.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The Bitstuff Error is received or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBitStuffError (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Retrieve the actual number of bytes that were tansferred.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The actual number of bytes that were tansferred.\r
+\r
+**/\r
+UINT16\r
+GetTDStatusActualLength (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Retrieve the information of whether the Link Pointer field is valid or not.\r
+\r
+  @param  PtrTDStruct   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The linker pointer field is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+GetTDLinkPtrValidorInvalid (\r
+  IN  TD_STRUCT *PtrTDStruct\r
+  );\r
+\r
+/**\r
+  Count TD Number from PtrFirstTD.\r
+\r
+  @param  PtrFirstTD   Place to store TD_STRUCT pointer.\r
+\r
+  @retval The queued TDs number.\r
+\r
+**/\r
+UINTN\r
+CountTDsNumber (\r
+  IN  TD_STRUCT *PtrFirstTD\r
+  );\r
+\r
+/**\r
+  Link TD To QH.\r
+\r
+  @param  PtrQH   Place to store QH_STRUCT pointer.\r
+  @param  PtrTD   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+LinkTDToQH (\r
+  IN  QH_STRUCT *PtrQH,\r
+  IN  TD_STRUCT *PtrTD\r
+  );\r
+\r
+/**\r
+  Link TD To TD.\r
+\r
+  @param  PtrPreTD  Place to store TD_STRUCT pointer.\r
+  @param  PtrTD     Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+LinkTDToTD (\r
+  IN  TD_STRUCT *PtrPreTD,\r
+  IN  TD_STRUCT *PtrTD\r
+  );\r
+\r
+/**\r
+  Execute Control Transfer.\r
+\r
+  @param  UhcDev            The UCHI device.\r
+  @param  PtrTD             A pointer to TD_STRUCT data.\r
+  @param  ActualLen         Actual transfer Length.\r
+  @param  TimeOut           TimeOut value.\r
+  @param  TransferResult    Transfer Result.\r
+\r
+  @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @return EFI_TIMEOUT       The transfer failed due to time out.\r
+  @return EFI_SUCCESS       The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecuteControlTransfer (\r
+  IN  USB_UHC_DEV *UhcDev,\r
+  IN  TD_STRUCT   *PtrTD,\r
+  OUT UINTN       *ActualLen,\r
+  IN  UINTN       TimeOut,\r
+  OUT UINT32      *TransferResult\r
+  );\r
+\r
+/**\r
+  Execute Bulk Transfer.\r
+\r
+  @param  UhcDev            The UCHI device.\r
+  @param  PtrTD             A pointer to TD_STRUCT data.\r
+  @param  ActualLen         Actual transfer Length.\r
+  @param  DataToggle        DataToggle value.\r
+  @param  TimeOut           TimeOut value.\r
+  @param  TransferResult    Transfer Result.\r
+\r
+  @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @return EFI_TIMEOUT       The transfer failed due to time out.\r
+  @return EFI_SUCCESS       The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecBulkTransfer (\r
+  IN     USB_UHC_DEV *UhcDev,\r
+  IN     TD_STRUCT   *PtrTD,\r
+  IN OUT UINTN     *ActualLen,\r
+  IN     UINT8     *DataToggle,\r
+  IN     UINTN     TimeOut,\r
+  OUT    UINT32    *TransferResult\r
+  );\r
+\r
+/**\r
+  Delete Queued TDs.\r
+\r
+  @param  UhcDev       The UCHI device.\r
+  @param  PtrFirstTD   Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+DeleteQueuedTDs (\r
+  IN USB_UHC_DEV     *UhcDev,\r
+  IN TD_STRUCT       *PtrFirstTD\r
+  );\r
+\r
+/**\r
+  Check TDs Results.\r
+\r
+  @param  PtrTD               A pointer to TD_STRUCT data.\r
+  @param  Result              The result to return.\r
+  @param  ErrTDPos            The Error TD position.\r
+  @param  ActualTransferSize  Actual transfer size.\r
+\r
+  @retval The TD is executed successfully or not.\r
+\r
+**/\r
+BOOLEAN\r
+CheckTDsResults (\r
+  IN  TD_STRUCT               *PtrTD,\r
+  OUT UINT32                  *Result,\r
+  OUT UINTN                   *ErrTDPos,\r
+  OUT UINTN                   *ActualTransferSize\r
+  );\r
+\r
+/**\r
+  Create Memory Block.\r
+\r
+  @param  UhcDev                   The UCHI device.\r
+  @param  MemoryHeader             The Pointer to allocated memory block.\r
+  @param  MemoryBlockSizeInPages   The page size of memory block to be allocated.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateMemoryBlock (\r
+  IN  USB_UHC_DEV           *UhcDev,\r
+  OUT MEMORY_MANAGE_HEADER  **MemoryHeader,\r
+  IN  UINTN                 MemoryBlockSizeInPages\r
+  );\r
+\r
+/**\r
+  Initialize UHCI memory management.\r
+\r
+  @param  UhcDev                 The UCHI device.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeMemoryManagement (\r
+  IN USB_UHC_DEV           *UhcDev\r
+  );\r
+\r
+/**\r
+  Initialize UHCI memory management.\r
+\r
+  @param  UhcDev           The UCHI device.\r
+  @param  Pool             Buffer pointer to store the buffer pointer.\r
+  @param  AllocSize        The size of the pool to be allocated.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+UhcAllocatePool (\r
+  IN  USB_UHC_DEV     *UhcDev,\r
+  OUT UINT8           **Pool,\r
+  IN  UINTN           AllocSize\r
+  );\r
+\r
+/**\r
+  Alloc Memory In MemoryBlock.\r
+\r
+  @param  MemoryHeader           The pointer to memory manage header.\r
+  @param  Pool                   Buffer pointer to store the buffer pointer.\r
+  @param  NumberOfMemoryUnit     The size of the pool to be allocated.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.\r
+  @retval EFI_SUCCESS            Success.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocMemInMemoryBlock (\r
+  IN  MEMORY_MANAGE_HEADER  *MemoryHeader,\r
+  OUT VOID                  **Pool,\r
+  IN  UINTN                 NumberOfMemoryUnit\r
+  );\r
+\r
+/**\r
+  Uhci Free Pool.\r
+\r
+  @param  UhcDev                 The UHCI device.\r
+  @param  Pool                   A pointer to store the buffer address.\r
+  @param  AllocSize              The size of the pool to be freed.\r
+\r
+**/\r
+VOID\r
+UhcFreePool (\r
+  IN USB_UHC_DEV     *UhcDev,\r
+  IN UINT8           *Pool,\r
+  IN UINTN           AllocSize\r
+  );\r
+\r
+/**\r
+  Insert a new memory header into list.\r
+\r
+  @param  MemoryHeader         A pointer to the memory header list.\r
+  @param  NewMemoryHeader      A new memory header to be inserted into the list.\r
+\r
+**/\r
+VOID\r
+InsertMemoryHeaderToList (\r
+  IN MEMORY_MANAGE_HEADER  *MemoryHeader,\r
+  IN MEMORY_MANAGE_HEADER  *NewMemoryHeader\r
+  );\r
+\r
+/**\r
+  Judge the memory block in the memory header is empty or not.\r
+\r
+  @param  MemoryHeaderPtr   A pointer to the memory header list.\r
+\r
+  @retval Whether the memory block in the memory header is empty or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsMemoryBlockEmptied (\r
+  IN MEMORY_MANAGE_HEADER  *MemoryHeaderPtr\r
+  );\r
+\r
+/**\r
+  remove a memory header from list.\r
+\r
+  @param  FirstMemoryHeader   A pointer to the memory header list.\r
+  @param  FreeMemoryHeader    A memory header to be removed into the list.\r
+\r
+**/\r
+VOID\r
+DelinkMemoryBlock (\r
+  IN MEMORY_MANAGE_HEADER    *FirstMemoryHeader,\r
+  IN MEMORY_MANAGE_HEADER    *FreeMemoryHeader\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf b/MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf
new file mode 100644 (file)
index 0000000..cf91ebc
--- /dev/null
@@ -0,0 +1,62 @@
+## @file\r
+# Component description file for UhcPeim PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+# which is used to enable recovery function from USB Drivers.\r
+\r
+#\r
+# Usb Host Controller PEIM to support recovery from USB device.\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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UhciPei\r
+  FILE_GUID                      = C463CEAC-FC57-4f36-88B7-356C750C3BCA\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = UhcPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  UhcPeim.c\r
+  UhcPeim.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  IoLib\r
+  TimerLib\r
+  BaseMemoryLib\r
+  PeiServicesLib\r
+  PeimEntryPoint\r
+  DebugLib\r
+\r
+\r
+[Ppis]\r
+  gPeiUsbHostControllerPpiGuid                  # PPI ALWAYS_PRODUCED\r
+  gPeiUsbControllerPpiGuid                      # PPI ALWAYS_CONSUMED\r
+\r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c b/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c
new file mode 100644 (file)
index 0000000..55c4a53
--- /dev/null
@@ -0,0 +1,401 @@
+/** @file\r
+BOT Transportation implementation.\r
+\r
+Copyright (c) 2006, 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 "UsbBotPeim.h"\r
+#include "BotPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+/**\r
+  Reset the given usb device.\r
+\r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  PeiBotDev              The instance to PEI_BOT_DEVICE.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Can not get usb io ppi.\r
+  @retval EFI_SUCCESS            Failed to reset the given usb device.\r
+\r
+**/\r
+EFI_STATUS\r
+BotRecoveryReset (\r
+  IN  EFI_PEI_SERVICES          **PeiServices,\r
+  IN  PEI_BOT_DEVICE            *PeiBotDev\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+  UINT32                  Timeout;\r
+  PEI_USB_IO_PPI          *UsbIoPpi;\r
+  UINT8                   EndpointAddr;\r
+  EFI_STATUS              Status;\r
+\r
+  UsbIoPpi = PeiBotDev->UsbIoPpi;\r
+\r
+  if (UsbIoPpi == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  DevReq.RequestType  = 0x21;\r
+  DevReq.Request      = 0xFF;\r
+  DevReq.Value        = 0;\r
+  DevReq.Index        = 0;\r
+  DevReq.Length       = 0;\r
+\r
+  Timeout             = 3000;\r
+\r
+  Status = UsbIoPpi->UsbControlTransfer (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      &DevReq,\r
+                      EfiUsbNoData,\r
+                      Timeout,\r
+                      NULL,\r
+                      0\r
+                      );\r
+\r
+  //\r
+  // clear bulk in endpoint stall feature\r
+  //\r
+  EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;\r
+  PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);\r
+\r
+  //\r
+  // clear bulk out endpoint stall feature\r
+  //\r
+  EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;\r
+  PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send the command to the device using Bulk-Out endpoint.\r
+\r
+  This function sends the command to the device using Bulk-Out endpoint.\r
+  BOT transfer is composed of three phases: Command, Data, and Status.\r
+  This is the Command phase.\r
+\r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  PeiBotDev              The instance to PEI_BOT_DEVICE.\r
+  @param  Command                The command to transfer to device.\r
+  @param  CommandSize            The length of the command.\r
+  @param  DataTransferLength     The expected length of the data.\r
+  @param  Direction              The direction of the data.\r
+  @param  Timeout                Indicates the maximum time, in millisecond, which the\r
+                                 transfer is allowed to complete.\r
+\r
+  @retval EFI_DEVICE_ERROR       Successful to send the command to device.\r
+  @retval EFI_SUCCESS            Failed to send the command to device.\r
+\r
+**/\r
+EFI_STATUS\r
+BotCommandPhase (\r
+  IN  EFI_PEI_SERVICES          **PeiServices,\r
+  IN  PEI_BOT_DEVICE            *PeiBotDev,\r
+  IN  VOID                      *Command,\r
+  IN  UINT8                     CommandSize,\r
+  IN  UINT32                    DataTransferLength,\r
+  IN  EFI_USB_DATA_DIRECTION    Direction,\r
+  IN  UINT16                    Timeout\r
+  )\r
+{\r
+  CBW             Cbw;\r
+  EFI_STATUS      Status;\r
+  PEI_USB_IO_PPI  *UsbIoPpi;\r
+  UINTN           DataSize;\r
+\r
+  UsbIoPpi = PeiBotDev->UsbIoPpi;\r
+\r
+  ZeroMem (&Cbw, sizeof (CBW));\r
+\r
+  //\r
+  // Fill the command block, detailed see BOT spec\r
+  //\r
+  Cbw.Signature           = CBWSIG;\r
+  Cbw.Tag                 = 0x01;\r
+  Cbw.DataTransferLength  = DataTransferLength;\r
+  Cbw.Flags               = (UINT8) ((Direction == EfiUsbDataIn) ? 0x80 : 0);\r
+  Cbw.Lun                 = 0;\r
+  Cbw.CmdLen              = CommandSize;\r
+\r
+  CopyMem (Cbw.CmdBlock, Command, CommandSize);\r
+\r
+  DataSize = sizeof (CBW);\r
+\r
+  Status = UsbIoPpi->UsbBulkTransfer (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      (PeiBotDev->BulkOutEndpoint)->EndpointAddress,\r
+                      (UINT8 *) &Cbw,\r
+                      &DataSize,\r
+                      Timeout\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Command phase fail, we need to recovery reset this device\r
+    //\r
+    BotRecoveryReset (PeiServices, PeiBotDev);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Transfer the data between the device and host.\r
+\r
+  This function transfers the data between the device and host.\r
+  BOT transfer is composed of three phases: Command, Data, and Status.\r
+  This is the Data phase.\r
+\r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  PeiBotDev              The instance to PEI_BOT_DEVICE.\r
+  @param  DataSize               The length of the data.\r
+  @param  DataBuffer             The pointer to the data.\r
+  @param  Direction              The direction of the data.\r
+  @param  Timeout                Indicates the maximum time, in millisecond, which the\r
+                                 transfer is allowed to complete.\r
+\r
+  @retval EFI_DEVICE_ERROR       Successful to send the data to device.\r
+  @retval EFI_SUCCESS            Failed to send the data to device.\r
+\r
+**/\r
+EFI_STATUS\r
+BotDataPhase (\r
+  IN  EFI_PEI_SERVICES          **PeiServices,\r
+  IN  PEI_BOT_DEVICE            *PeiBotDev,\r
+  IN  UINT32                    *DataSize,\r
+  IN  OUT VOID                  *DataBuffer,\r
+  IN  EFI_USB_DATA_DIRECTION    Direction,\r
+  IN  UINT16                    Timeout\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  PEI_USB_IO_PPI  *UsbIoPpi;\r
+  UINT8           EndpointAddr;\r
+  UINTN           Remain;\r
+  UINTN           Increment;\r
+  UINT32          MaxPacketLen;\r
+  UINT8           *BufferPtr;\r
+  UINTN           TransferredSize;\r
+\r
+  UsbIoPpi        = PeiBotDev->UsbIoPpi;\r
+\r
+  Remain          = *DataSize;\r
+  BufferPtr       = (UINT8 *) DataBuffer;\r
+  TransferredSize = 0;\r
+\r
+  //\r
+  // retrieve the the max packet length of the given endpoint\r
+  //\r
+  if (Direction == EfiUsbDataIn) {\r
+    MaxPacketLen  = (PeiBotDev->BulkInEndpoint)->MaxPacketSize;\r
+    EndpointAddr  = (PeiBotDev->BulkInEndpoint)->EndpointAddress;\r
+  } else {\r
+    MaxPacketLen  = (PeiBotDev->BulkOutEndpoint)->MaxPacketSize;\r
+    EndpointAddr  = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;\r
+  }\r
+\r
+  while (Remain > 0) {\r
+    //\r
+    // Using 15 packets to avoid Bitstuff error\r
+    //\r
+    if (Remain > 16 * MaxPacketLen) {\r
+      Increment = 16 * MaxPacketLen;\r
+    } else {\r
+      Increment = Remain;\r
+    }\r
+\r
+    Status = UsbIoPpi->UsbBulkTransfer (\r
+                        PeiServices,\r
+                        UsbIoPpi,\r
+                        EndpointAddr,\r
+                        BufferPtr,\r
+                        &Increment,\r
+                        Timeout\r
+                        );\r
+\r
+    TransferredSize += Increment;\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);\r
+      return Status;\r
+    }\r
+\r
+    BufferPtr += Increment;\r
+    Remain -= Increment;\r
+  }\r
+\r
+  *DataSize = (UINT32) TransferredSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get the command execution status from device.\r
+\r
+  This function gets the command execution status from device.\r
+  BOT transfer is composed of three phases: Command, Data, and Status.\r
+  This is the Status phase.\r
+\r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  PeiBotDev              The instance to PEI_BOT_DEVICE.\r
+  @param  TransferStatus         The status of the transaction.\r
+  @param  Timeout                Indicates the maximum time, in millisecond, which the\r
+                                 transfer is allowed to complete.\r
+\r
+  @retval EFI_DEVICE_ERROR       Successful to get the status of device.\r
+  @retval EFI_SUCCESS            Failed to get the status of device.\r
+\r
+**/\r
+EFI_STATUS\r
+BotStatusPhase (\r
+  IN  EFI_PEI_SERVICES          **PeiServices,\r
+  IN  PEI_BOT_DEVICE            *PeiBotDev,\r
+  OUT UINT8                     *TransferStatus,\r
+  IN  UINT16                    Timeout\r
+  )\r
+{\r
+  CSW             Csw;\r
+  EFI_STATUS      Status;\r
+  PEI_USB_IO_PPI  *UsbIoPpi;\r
+  UINT8           EndpointAddr;\r
+  UINTN           DataSize;\r
+\r
+  UsbIoPpi = PeiBotDev->UsbIoPpi;\r
+\r
+  ZeroMem (&Csw, sizeof (CSW));\r
+\r
+  EndpointAddr  = (PeiBotDev->BulkInEndpoint)->EndpointAddress;\r
+\r
+  DataSize      = sizeof (CSW);\r
+\r
+  //\r
+  // Get the status field from bulk transfer\r
+  //\r
+  Status = UsbIoPpi->UsbBulkTransfer (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      EndpointAddr,\r
+                      &Csw,\r
+                      &DataSize,\r
+                      Timeout\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Csw.Signature == CSWSIG) {\r
+    *TransferStatus = Csw.Status;\r
+  } else {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send ATAPI command using BOT protocol.\r
+\r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  PeiBotDev              The instance to PEI_BOT_DEVICE.\r
+  @param  Command                The command to be sent to ATAPI device.\r
+  @param  CommandSize            The length of the data to be sent.\r
+  @param  DataBuffer             The pointer to the data.\r
+  @param  BufferLength           The length of the data.\r
+  @param  Direction              The direction of the data.\r
+  @param  TimeOutInMilliSeconds  Indicates the maximum time, in millisecond, which the\r
+                                 transfer is allowed to complete.\r
+\r
+  @retval EFI_DEVICE_ERROR       Successful to get the status of device.\r
+  @retval EFI_SUCCESS            Failed to get the status of device.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiAtapiCommand (\r
+  IN  EFI_PEI_SERVICES            **PeiServices,\r
+  IN  PEI_BOT_DEVICE              *PeiBotDev,\r
+  IN  VOID                        *Command,\r
+  IN  UINT8                       CommandSize,\r
+  IN  VOID                        *DataBuffer,\r
+  IN  UINT32                      BufferLength,\r
+  IN  EFI_USB_DATA_DIRECTION      Direction,\r
+  IN  UINT16                      TimeOutInMilliSeconds\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_STATUS  BotDataStatus;\r
+  UINT8       TransferStatus;\r
+  UINT32      BufferSize;\r
+\r
+  BotDataStatus = EFI_SUCCESS;\r
+  //\r
+  // First send ATAPI command through Bot\r
+  //\r
+  Status = BotCommandPhase (\r
+            PeiServices,\r
+            PeiBotDev,\r
+            Command,\r
+            CommandSize,\r
+            BufferLength,\r
+            Direction,\r
+            TimeOutInMilliSeconds\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Send/Get Data if there is a Data Stage\r
+  //\r
+  switch (Direction) {\r
+  case EfiUsbDataIn:\r
+  case EfiUsbDataOut:\r
+    BufferSize = BufferLength;\r
+\r
+    BotDataStatus = BotDataPhase (\r
+                      PeiServices,\r
+                      PeiBotDev,\r
+                      &BufferSize,\r
+                      DataBuffer,\r
+                      Direction,\r
+                      TimeOutInMilliSeconds\r
+                      );\r
+    break;\r
+\r
+  case EfiUsbNoData:\r
+    break;\r
+  }\r
+  //\r
+  // Status Phase\r
+  //\r
+  Status = BotStatusPhase (\r
+            PeiServices,\r
+            PeiBotDev,\r
+            &TransferStatus,\r
+            TimeOutInMilliSeconds\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    BotRecoveryReset (PeiServices, PeiBotDev);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (TransferStatus == 0x01) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return BotDataStatus;\r
+}\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h b/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h
new file mode 100644 (file)
index 0000000..07235c3
--- /dev/null
@@ -0,0 +1,224 @@
+/** @file\r
+BOT Transportation implementation.\r
+\r
+Copyright (c) 2006, 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
+#ifndef _PEI_BOT_PEIM_H_\r
+#define _PEI_BOT_PEIM_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbIo.h>\r
+#include <Ppi/UsbHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+\r
+//#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+#include <IndustryStandard/Atapi.h>\r
+\r
+#pragma pack(1)\r
+//\r
+// Bulk Only device protocol\r
+//\r
+typedef struct {\r
+  UINT32  Signature;\r
+  UINT32  Tag;\r
+  UINT32  DataTransferLength;\r
+  UINT8   Flags;\r
+  UINT8   Lun;\r
+  UINT8   CmdLen;\r
+  UINT8   CmdBlock[16];\r
+} CBW;\r
+\r
+typedef struct {\r
+  UINT32  Signature;\r
+  UINT32  Tag;\r
+  UINT32  DataResidue;\r
+  UINT8   Status;\r
+} CSW;\r
+\r
+#pragma pack()\r
+//\r
+// Status code, see Usb Bot device spec\r
+//\r
+#define CSWSIG  0x53425355\r
+#define CBWSIG  0x43425355\r
+\r
+/**\r
+  Sends out ATAPI Inquiry Packet Command to the specified device. This command will\r
+  return INQUIRY data of the device.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS       Inquiry command completes successfully.\r
+  @retval EFI_DEVICE_ERROR  Inquiry command failed.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbInquiry (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice\r
+  );\r
+\r
+/**\r
+  Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
+  to find out whether device is accessible.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS        TestUnit command executed successfully.\r
+  @retval EFI_DEVICE_ERROR   Device cannot be executed TestUnit command successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbTestUnitReady (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice\r
+  );\r
+\r
+/**\r
+  Sends out ATAPI Request Sense Packet Command to the specified device.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+  @param SenseCounts    Length of sense buffer.\r
+  @param SenseKeyBuffer Pointer to sense buffer.\r
+\r
+  @retval EFI_SUCCESS           Command executed successfully.\r
+  @retval EFI_DEVICE_ERROR      Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbRequestSense (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice,\r
+  OUT UINTN             *SenseCounts,\r
+  IN  UINT8             *SenseKeyBuffer\r
+  );\r
+\r
+/**\r
+  Sends out ATAPI Read Capacity Packet Command to the specified device.\r
+  This command will return the information regarding the capacity of the\r
+  media in the device.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS           Command executed successfully.\r
+  @retval EFI_DEVICE_ERROR      Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbReadCapacity (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice\r
+  );\r
+\r
+/**\r
+  Sends out ATAPI Read Format Capacity Data Command to the specified device.\r
+  This command will return the information regarding the capacity of the\r
+  media in the device.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS           Command executed successfully.\r
+  @retval EFI_DEVICE_ERROR      Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbReadFormattedCapacity (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice\r
+  );\r
+\r
+/**\r
+  Execute Read(10) ATAPI command on a specific SCSI target.\r
+\r
+  Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.\r
+\r
+  @param PeiServices       The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice      The pointer to PEI_BOT_DEVICE instance.\r
+  @param Buffer            The pointer to data buffer.\r
+  @param Lba               The start logic block address of reading.\r
+  @param NumberOfBlocks    The block number of reading.\r
+\r
+  @retval EFI_SUCCESS           Command executed successfully.\r
+  @retval EFI_DEVICE_ERROR      Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbRead10 (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice,\r
+  IN  VOID              *Buffer,\r
+  IN  EFI_PEI_LBA       Lba,\r
+  IN  UINTN             NumberOfBlocks\r
+  );\r
+\r
+/**  \r
+  Check if there is media according to sense data.\r
+\r
+  @param  SenseData   Pointer to sense data.\r
+  @param  SenseCounts Count of sense data.\r
+\r
+  @retval TRUE    No media\r
+  @retval FALSE   Media exists\r
+\r
+**/\r
+BOOLEAN\r
+IsNoMedia (\r
+  IN  ATAPI_REQUEST_SENSE_DATA    *SenseData,\r
+  IN  UINTN                 SenseCounts\r
+  );\r
+\r
+/**  \r
+  Check if there is media error according to sense data.\r
+\r
+  @param  SenseData   Pointer to sense data.\r
+  @param  SenseCounts Count of sense data.\r
+\r
+  @retval TRUE    Media error\r
+  @retval FALSE   No media error\r
+\r
+**/\r
+BOOLEAN\r
+IsMediaError (\r
+  IN  ATAPI_REQUEST_SENSE_DATA    *SenseData,\r
+  IN  UINTN                 SenseCounts\r
+  );\r
+\r
+/**  \r
+  Check if media is changed according to sense data.\r
+\r
+  @param  SenseData   Pointer to sense data.\r
+  @param  SenseCounts Count of sense data.\r
+\r
+  @retval TRUE    There is media change event.\r
+  @retval FALSE   media is NOT changed.\r
+\r
+**/\r
+BOOLEAN\r
+IsMediaChange (\r
+  IN  ATAPI_REQUEST_SENSE_DATA    *SenseData,\r
+  IN  UINTN                 SenseCounts\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
new file mode 100644 (file)
index 0000000..28574d0
--- /dev/null
@@ -0,0 +1,630 @@
+/** @file\r
+Pei USB ATATPI command implementations.\r
+\r
+Copyright (c) 1999 - 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 "UsbBotPeim.h"\r
+#include "BotPeim.h"\r
+\r
+#define MAXSENSEKEY 5\r
+\r
+/**\r
+  Sends out ATAPI Inquiry Packet Command to the specified device. This command will\r
+  return INQUIRY data of the device.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS       Inquiry command completes successfully.\r
+  @retval EFI_DEVICE_ERROR  Inquiry command failed.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbInquiry (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice\r
+  )\r
+{\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  EFI_STATUS            Status;\r
+  ATAPI_INQUIRY_DATA          Idata;\r
+\r
+  //\r
+  // fill command packet\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));\r
+\r
+  Packet.Inquiry.opcode             = ATA_CMD_INQUIRY;\r
+  Packet.Inquiry.page_code          = 0;\r
+  Packet.Inquiry.allocation_length  = 36;\r
+\r
+  //\r
+  // Send scsi INQUIRY command packet.\r
+  // According to SCSI Primary Commands-2 spec, host only needs to\r
+  // retrieve the first 36 bytes for standard INQUIRY data.\r
+  //\r
+  Status = PeiAtapiCommand (\r
+            PeiServices,\r
+            PeiBotDevice,\r
+            &Packet,\r
+            (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+            &Idata,\r
+            36,\r
+            EfiUsbDataIn,\r
+            2000\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((Idata.peripheral_type & 0x1f) == 0x05) {\r
+    PeiBotDevice->DeviceType      = USBCDROM;\r
+    PeiBotDevice->Media.BlockSize = 0x800;\r
+  } else {\r
+    PeiBotDevice->DeviceType      = USBFLOPPY;\r
+    PeiBotDevice->Media.BlockSize = 0x200;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
+  to find out whether device is accessible.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS        TestUnit command executed successfully.\r
+  @retval EFI_DEVICE_ERROR   Device cannot be executed TestUnit command successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbTestUnitReady (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice\r
+  )\r
+{\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  EFI_STATUS            Status;\r
+\r
+  //\r
+  // fill command packet\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;\r
+\r
+  //\r
+  // send command packet\r
+  //\r
+  Status = PeiAtapiCommand (\r
+            PeiServices,\r
+            PeiBotDevice,\r
+            &Packet,\r
+            (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+            NULL,\r
+            0,\r
+            EfiUsbNoData,\r
+            2000\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sends out ATAPI Request Sense Packet Command to the specified device.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+  @param SenseCounts    Length of sense buffer.\r
+  @param SenseKeyBuffer Pointer to sense buffer.\r
+\r
+  @retval EFI_SUCCESS           Command executed successfully.\r
+  @retval EFI_DEVICE_ERROR      Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbRequestSense (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice,\r
+  OUT UINTN             *SenseCounts,\r
+  IN  UINT8             *SenseKeyBuffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  UINT8                 *Ptr;\r
+  BOOLEAN               SenseReq;\r
+  ATAPI_REQUEST_SENSE_DATA    *Sense;\r
+\r
+  *SenseCounts = 0;\r
+\r
+  //\r
+  // fill command packet for Request Sense Packet Command\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  Packet.RequestSence.opcode            = ATA_CMD_REQUEST_SENSE;\r
+  Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);\r
+\r
+  Ptr = SenseKeyBuffer;\r
+\r
+  SenseReq = TRUE;\r
+\r
+  //\r
+  //  request sense data from device continuously\r
+  //  until no sense data exists in the device.\r
+  //\r
+  while (SenseReq) {\r
+    Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;\r
+\r
+    //\r
+    // send out Request Sense Packet Command and get one Sense\r
+    // data form device.\r
+    //\r
+    Status = PeiAtapiCommand (\r
+              PeiServices,\r
+              PeiBotDevice,\r
+              &Packet,\r
+              (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+              (VOID *) Ptr,\r
+              sizeof (ATAPI_REQUEST_SENSE_DATA),\r
+              EfiUsbDataIn,\r
+              2000\r
+              );\r
+\r
+    //\r
+    // failed to get Sense data\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      if (*SenseCounts == 0) {\r
+        return EFI_DEVICE_ERROR;\r
+      } else {\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    if (Sense->sense_key != ATA_SK_NO_SENSE) {\r
+\r
+      Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA);\r
+      //\r
+      // Ptr is byte based pointer\r
+      //\r
+      (*SenseCounts)++;\r
+\r
+      if (*SenseCounts == MAXSENSEKEY) {\r
+        break;\r
+      }\r
+\r
+    } else {\r
+      //\r
+      // when no sense key, skip out the loop\r
+      //\r
+      SenseReq = FALSE;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sends out ATAPI Read Capacity Packet Command to the specified device.\r
+  This command will return the information regarding the capacity of the\r
+  media in the device.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS           Command executed successfully.\r
+  @retval EFI_DEVICE_ERROR      Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbReadCapacity (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  ATAPI_READ_CAPACITY_DATA    Data;\r
+\r
+  ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA));\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+\r
+  Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;\r
+\r
+  //\r
+  // send command packet\r
+  //\r
+  Status = PeiAtapiCommand (\r
+            PeiServices,\r
+            PeiBotDevice,\r
+            &Packet,\r
+            (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+            (VOID *) &Data,\r
+            sizeof (ATAPI_READ_CAPACITY_DATA),\r
+            EfiUsbDataIn,\r
+            2000\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  PeiBotDevice->Media.LastBlock     = (Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;\r
+\r
+  PeiBotDevice->Media.MediaPresent  = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sends out ATAPI Read Format Capacity Data Command to the specified device.\r
+  This command will return the information regarding the capacity of the\r
+  media in the device.\r
+\r
+  @param PeiServices    The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS           Command executed successfully.\r
+  @retval EFI_DEVICE_ERROR      Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbReadFormattedCapacity (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  ATAPI_PACKET_COMMAND      Packet;\r
+  ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;\r
+\r
+  ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA));\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+\r
+  Packet.ReadFormatCapacity.opcode                = ATA_CMD_READ_FORMAT_CAPACITY;\r
+  Packet.ReadFormatCapacity.allocation_length_lo  = 12;\r
+\r
+  //\r
+  // send command packet\r
+  //\r
+  Status = PeiAtapiCommand (\r
+            PeiServices,\r
+            PeiBotDevice,\r
+            &Packet,\r
+            (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+            (VOID *) &FormatData,\r
+            sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),\r
+            EfiUsbDataIn,\r
+            2000\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (FormatData.DesCode == 3) {\r
+    //\r
+    // Media is not present\r
+    //\r
+    PeiBotDevice->Media.MediaPresent  = FALSE;\r
+    PeiBotDevice->Media.LastBlock     = 0;\r
+\r
+  } else {\r
+\r
+    PeiBotDevice->Media.LastBlock = (FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;\r
+\r
+    PeiBotDevice->Media.LastBlock--;\r
+\r
+    PeiBotDevice->Media.MediaPresent = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Execute Read(10) ATAPI command on a specific SCSI target.\r
+\r
+  Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.\r
+\r
+  @param PeiServices       The pointer of EFI_PEI_SERVICES.\r
+  @param PeiBotDevice      The pointer to PEI_BOT_DEVICE instance.\r
+  @param Buffer            The pointer to data buffer.\r
+  @param Lba               The start logic block address of reading.\r
+  @param NumberOfBlocks    The block number of reading.\r
+\r
+  @retval EFI_SUCCESS           Command executed successfully.\r
+  @retval EFI_DEVICE_ERROR      Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbRead10 (\r
+  IN  EFI_PEI_SERVICES  **PeiServices,\r
+  IN  PEI_BOT_DEVICE    *PeiBotDevice,\r
+  IN  VOID              *Buffer,\r
+  IN  EFI_PEI_LBA       Lba,\r
+  IN  UINTN             NumberOfBlocks\r
+  )\r
+{\r
+  ATAPI_PACKET_COMMAND  Packet;\r
+  ATAPI_READ10_CMD      *Read10Packet;\r
+  UINT16                MaxBlock;\r
+  UINT16                BlocksRemaining;\r
+  UINT16                SectorCount;\r
+  UINT32                Lba32;\r
+  UINT32                BlockSize;\r
+  UINT32                ByteCount;\r
+  VOID                  *PtrBuffer;\r
+  EFI_STATUS            Status;\r
+  UINT16                TimeOut;\r
+\r
+  //\r
+  // prepare command packet for the Inquiry Packet Command.\r
+  //\r
+  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+  Read10Packet    = &Packet.Read10;\r
+  Lba32           = (UINT32) Lba;\r
+  PtrBuffer       = Buffer;\r
+\r
+  BlockSize       = (UINT32) PeiBotDevice->Media.BlockSize;\r
+\r
+  MaxBlock        = (UINT16) (65535 / BlockSize);\r
+  BlocksRemaining = (UINT16) NumberOfBlocks;\r
+\r
+  Status          = EFI_SUCCESS;\r
+  while (BlocksRemaining > 0) {\r
+\r
+    if (BlocksRemaining <= MaxBlock) {\r
+\r
+      SectorCount = BlocksRemaining;\r
+\r
+    } else {\r
+\r
+      SectorCount = MaxBlock;\r
+    }\r
+    //\r
+    // fill the Packet data structure\r
+    //\r
+    Read10Packet->opcode = ATA_CMD_READ_10;\r
+\r
+    //\r
+    // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
+    // Lba0 is MSB, Lba3 is LSB\r
+    //\r
+    Read10Packet->Lba3  = (UINT8) (Lba32 & 0xff);\r
+    Read10Packet->Lba2  = (UINT8) (Lba32 >> 8);\r
+    Read10Packet->Lba1  = (UINT8) (Lba32 >> 16);\r
+    Read10Packet->Lba0  = (UINT8) (Lba32 >> 24);\r
+\r
+    //\r
+    // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
+    // TranLen0 is MSB, TranLen is LSB\r
+    //\r
+    Read10Packet->TranLen1  = (UINT8) (SectorCount & 0xff);\r
+    Read10Packet->TranLen0  = (UINT8) (SectorCount >> 8);\r
+\r
+    ByteCount               = SectorCount * BlockSize;\r
+\r
+    TimeOut                 = (UINT16) (SectorCount * 2000);\r
+\r
+    //\r
+    // send command packet\r
+    //\r
+    Status = PeiAtapiCommand (\r
+              PeiServices,\r
+              PeiBotDevice,\r
+              &Packet,\r
+              (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+              (VOID *) PtrBuffer,\r
+              ByteCount,\r
+              EfiUsbDataIn,\r
+              TimeOut\r
+              );\r
+\r
+    if (Status != EFI_SUCCESS) {\r
+      return Status;\r
+    }\r
+\r
+    Lba32 += SectorCount;\r
+    PtrBuffer       = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r
+    BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**  \r
+  Check if there is media according to sense data.\r
+\r
+  @param  SenseData   Pointer to sense data.\r
+  @param  SenseCounts Count of sense data.\r
+\r
+  @retval TRUE    No media\r
+  @retval FALSE   Media exists\r
+\r
+**/\r
+BOOLEAN\r
+IsNoMedia (\r
+  IN  ATAPI_REQUEST_SENSE_DATA *SenseData,\r
+  IN  UINTN                    SenseCounts\r
+  )\r
+{\r
+  ATAPI_REQUEST_SENSE_DATA  *SensePtr;\r
+  UINTN               Index;\r
+  BOOLEAN             NoMedia;\r
+\r
+  NoMedia   = FALSE;\r
+  SensePtr  = SenseData;\r
+\r
+  for (Index = 0; Index < SenseCounts; Index++) {\r
+\r
+    switch (SensePtr->sense_key) {\r
+\r
+    case ATA_SK_NOT_READY:\r
+      switch (SensePtr->addnl_sense_code) {\r
+      //\r
+      // if no media, fill IdeDev parameter with specific info.\r
+      //\r
+      case ATA_ASC_NO_MEDIA:\r
+        NoMedia = TRUE;\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+\r
+    SensePtr++;\r
+  }\r
+\r
+  return NoMedia;\r
+}\r
+\r
+/**  \r
+  Check if there is media error according to sense data.\r
+\r
+  @param  SenseData   Pointer to sense data.\r
+  @param  SenseCounts Count of sense data.\r
+\r
+  @retval TRUE    Media error\r
+  @retval FALSE   No media error\r
+\r
+**/\r
+BOOLEAN\r
+IsMediaError (\r
+  IN  ATAPI_REQUEST_SENSE_DATA    *SenseData,\r
+  IN  UINTN                 SenseCounts\r
+  )\r
+{\r
+  ATAPI_REQUEST_SENSE_DATA  *SensePtr;\r
+  UINTN               Index;\r
+  BOOLEAN             Error;\r
+\r
+  SensePtr  = SenseData;\r
+  Error     = FALSE;\r
+\r
+  for (Index = 0; Index < SenseCounts; Index++) {\r
+\r
+    switch (SensePtr->sense_key) {\r
+    //\r
+    // Medium error case\r
+    //\r
+    case ATA_SK_MEDIUM_ERROR:\r
+      switch (SensePtr->addnl_sense_code) {\r
+      case ATA_ASC_MEDIA_ERR1:\r
+        //\r
+        // fall through\r
+        //\r
+      case ATA_ASC_MEDIA_ERR2:\r
+        //\r
+        // fall through\r
+        //\r
+      case ATA_ASC_MEDIA_ERR3:\r
+        //\r
+        // fall through\r
+        //\r
+      case ATA_ASC_MEDIA_ERR4:\r
+        Error = TRUE;\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+\r
+      break;\r
+\r
+    //\r
+    // Medium upside-down case\r
+    //\r
+    case ATA_SK_NOT_READY:\r
+      switch (SensePtr->addnl_sense_code) {\r
+      case ATA_ASC_MEDIA_UPSIDE_DOWN:\r
+        Error = TRUE;\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+\r
+    SensePtr++;\r
+  }\r
+\r
+  return Error;\r
+}\r
+\r
+/**  \r
+  Check if media is changed according to sense data.\r
+\r
+  @param  SenseData   Pointer to sense data.\r
+  @param  SenseCounts Count of sense data.\r
+\r
+  @retval TRUE    There is media change event.\r
+  @retval FALSE   media is NOT changed.\r
+\r
+**/\r
+BOOLEAN\r
+IsMediaChange (\r
+  IN  ATAPI_REQUEST_SENSE_DATA *SenseData,\r
+  IN  UINTN                    SenseCounts\r
+  )\r
+{\r
+  ATAPI_REQUEST_SENSE_DATA  *SensePtr;\r
+  UINTN                     Index;\r
+  BOOLEAN                   MediaChange;\r
+\r
+  MediaChange = FALSE;\r
+\r
+  SensePtr    = SenseData;\r
+\r
+  for (Index = 0; Index < SenseCounts; Index++) {\r
+    //\r
+    // catch media change sense key and addition sense data\r
+    //\r
+    switch (SensePtr->sense_key) {\r
+    case ATA_SK_UNIT_ATTENTION:\r
+      switch (SensePtr->addnl_sense_code) {\r
+      case ATA_ASC_MEDIA_CHANGE:\r
+        MediaChange = TRUE;\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+\r
+    SensePtr++;\r
+  }\r
+\r
+  return MediaChange;\r
+}\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c
new file mode 100644 (file)
index 0000000..2a8fde0
--- /dev/null
@@ -0,0 +1,331 @@
+/** @file\r
+Common Libarary  for PEI USB.\r
+\r
+Copyright (c) 2006, 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 "PeiUsbLib.h"\r
+\r
+/**\r
+  Get a given usb descriptor.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Value              Request Value.\r
+  @param  Index              Request Index.\r
+  @param  DescriptorLength   Request descriptor Length.\r
+  @param  Descriptor         Request descriptor.\r
+\r
+\r
+  @retval EFI_SUCCESS        Usb descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the usb descriptor due to a hardware error.\r
+  @retval Others             Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetDescriptor (\r
+  IN  EFI_PEI_SERVICES         **PeiServices,\r
+  IN  PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN  UINT16                   Value,\r
+  IN  UINT16                   Index,\r
+  IN  UINT16                   DescriptorLength,\r
+  OUT VOID                     *Descriptor\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+\r
+  ASSERT (UsbIoPpi != NULL);\r
+\r
+  DevReq.RequestType  = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;\r
+  DevReq.Request      = USB_DEV_GET_DESCRIPTOR;\r
+  DevReq.Value        = Value;\r
+  DevReq.Index        = Index;\r
+  DevReq.Length       = DescriptorLength;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DevReq,\r
+                     EfiUsbDataIn,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     Descriptor,\r
+                     DescriptorLength\r
+                     );\r
+}\r
+\r
+/**\r
+  Set a usb device with a specified address.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+  @param  AddressValue       The address to assign.\r
+\r
+  @retval EFI_SUCCESS        Usb device address is set successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot set the usb address due to a hardware error.\r
+  @retval Others             Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetDeviceAddress (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINT16                   AddressValue\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+\r
+  ASSERT (UsbIoPpi != NULL);\r
+\r
+  DevReq.RequestType  = USB_DEV_SET_ADDRESS_REQ_TYPE;\r
+  DevReq.Request      = USB_DEV_SET_ADDRESS;\r
+  DevReq.Value        = AddressValue;\r
+  DevReq.Index        = 0;\r
+  DevReq.Length       = 0;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DevReq,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Clear a given usb feature.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Recipient         The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.\r
+  @param  Value             Request Value.\r
+  @param  Target            Request Index.\r
+\r
+  @retval EFI_SUCCESS       Usb feature is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the usb feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearDeviceFeature (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN EFI_USB_RECIPIENT        Recipient,\r
+  IN UINT16                   Value,\r
+  IN UINT16                   Target\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+\r
+  ASSERT (UsbIoPpi != NULL);\r
+\r
+  switch (Recipient) {\r
+  case EfiUsbDevice:\r
+    DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_D;\r
+    break;\r
+\r
+  case EfiUsbInterface:\r
+    DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_I;\r
+    break;\r
+\r
+  case EfiUsbEndpoint:\r
+    DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_E;\r
+    break;\r
+  }\r
+\r
+  DevReq.Request      = USB_DEV_CLEAR_FEATURE;\r
+  DevReq.Value        = Value;\r
+  DevReq.Index        = Target;\r
+  DevReq.Length       = 0;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DevReq,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Configure a usb device to Configuration 1.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS       Usb device is set to use Configuration 1 successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot set the usb device due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetConfiguration (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  DevReq.RequestType  = USB_DEV_SET_CONFIGURATION_REQ_TYPE;\r
+  DevReq.Request      = USB_DEV_SET_CONFIGURATION;\r
+  DevReq.Value        = 1;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DevReq,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Clear Endpoint Halt.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  EndpointAddress   The endpoint address.\r
+\r
+  @retval EFI_SUCCESS       Endpoint halt is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the endpoint halt status due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearEndpointHalt (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINT8                    EndpointAddress\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  PEI_USB_DEVICE              *PeiUsbDev;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;\r
+  UINT8                       EndpointIndex;\r
+\r
+  EndpointIndex = 0;\r
+  PeiUsbDev     = PEI_USB_DEVICE_FROM_THIS (UsbIoPpi);\r
+\r
+  while (EndpointIndex < MAX_ENDPOINT) {\r
+    Status = UsbIoPpi->UsbGetEndpointDescriptor (PeiServices, UsbIoPpi, EndpointIndex, &EndpointDescriptor);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (EndpointDescriptor->EndpointAddress == EndpointAddress) {\r
+      break;\r
+    }\r
+\r
+    EndpointIndex++;\r
+  }\r
+\r
+  if (EndpointIndex == MAX_ENDPOINT) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = PeiUsbClearDeviceFeature (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            EfiUsbEndpoint,\r
+            EfiUsbEndpointHalt,\r
+            EndpointAddress\r
+            );\r
+\r
+  //\r
+  // set data toggle to zero.\r
+  //\r
+  if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {\r
+    PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Judge if the port is connected with a usb device or not.\r
+\r
+  @param  PortStatus  The usb port status gotten.\r
+\r
+  @retval TRUE        A usb device is connected with the port.\r
+  @retval FALSE       No usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnect (\r
+  IN UINT16  PortStatus\r
+  )\r
+{\r
+  //\r
+  // return the bit 0 value of PortStatus\r
+  //\r
+  if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Judge if the port is connected with a low-speed usb device or not.\r
+\r
+  @param  PortStatus  The usb port status gotten.\r
+\r
+  @retval TRUE        A low-speed usb device is connected with the port.\r
+  @retval FALSE       No low-speed usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortLowSpeedDeviceAttached (\r
+  IN UINT16  PortStatus\r
+  )\r
+{\r
+  //\r
+  // return the bit 9 value of PortStatus\r
+  //\r
+  if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Judge if the port is in "connection change" status or not.\r
+\r
+  @param  PortChangeStatus  The usb port change status gotten.\r
+\r
+  @retval TRUE              The port is in "connection change" status.\r
+  @retval FALSE             The port is NOT in "connection change" status.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnectChange (\r
+  IN UINT16  PortChangeStatus\r
+  )\r
+{\r
+  //\r
+  // return the bit 0 value of PortChangeStatus\r
+  //\r
+  if ((PortChangeStatus & USB_PORT_STAT_C_CONNECTION) != 0) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h
new file mode 100644 (file)
index 0000000..eafccfd
--- /dev/null
@@ -0,0 +1,248 @@
+/** @file\r
+Common Libarary  for PEI USB.\r
+\r
+Copyright (c) 1999 - 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
+#ifndef _PEI_USB_LIB_H_\r
+#define _PEI_USB_LIB_H_\r
+//\r
+// Standard device request and request type\r
+// By [Spec-USB20/Chapter-9.4]\r
+//\r
+#define USB_DEV_GET_STATUS                  0x00\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_D       0x80 // Receiver : Device\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_I       0x81 // Receiver : Interface\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_E       0x82 // Receiver : Endpoint\r
+\r
+#define USB_DEV_CLEAR_FEATURE               0x01\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_D    0x00 // Receiver : Device\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_I    0x01 // Receiver : Interface\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_E    0x02 // Receiver : Endpoint\r
+\r
+#define USB_DEV_SET_FEATURE                 0x03\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_D      0x00 // Receiver : Device\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_I      0x01 // Receiver : Interface\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_E      0x02 // Receiver : Endpoint\r
\r
+#define USB_DEV_SET_ADDRESS                 0x05\r
+#define USB_DEV_SET_ADDRESS_REQ_TYPE        0x00\r
+\r
+#define USB_DEV_GET_DESCRIPTOR              0x06\r
+#define USB_DEV_GET_DESCRIPTOR_REQ_TYPE     0x80\r
+\r
+#define USB_DEV_SET_DESCRIPTOR              0x07\r
+#define USB_DEV_SET_DESCRIPTOR_REQ_TYPE     0x00\r
+\r
+#define USB_DEV_GET_CONFIGURATION           0x08\r
+#define USB_DEV_GET_CONFIGURATION_REQ_TYPE  0x80\r
+\r
+#define USB_DEV_SET_CONFIGURATION           0x09\r
+#define USB_DEV_SET_CONFIGURATION_REQ_TYPE  0x00\r
+\r
+#define USB_DEV_GET_INTERFACE               0x0A\r
+#define USB_DEV_GET_INTERFACE_REQ_TYPE      0x81\r
+\r
+#define USB_DEV_SET_INTERFACE               0x0B\r
+#define USB_DEV_SET_INTERFACE_REQ_TYPE      0x01\r
+\r
+#define USB_DEV_SYNCH_FRAME                 0x0C\r
+#define USB_DEV_SYNCH_FRAME_REQ_TYPE        0x82\r
+\r
+//\r
+// USB Descriptor types\r
+//\r
+#define USB_DT_DEVICE     0x01\r
+#define USB_DT_CONFIG     0x02\r
+#define USB_DT_STRING     0x03\r
+#define USB_DT_INTERFACE  0x04\r
+#define USB_DT_ENDPOINT   0x05\r
+#define USB_DT_HUB        0x29\r
+#define USB_DT_HID        0x21\r
+\r
+//\r
+// USB request type\r
+//\r
+#define USB_TYPE_STANDARD (0x00 << 5)\r
+#define USB_TYPE_CLASS    (0x01 << 5)\r
+#define USB_TYPE_VENDOR   (0x02 << 5)\r
+#define USB_TYPE_RESERVED (0x03 << 5)\r
+\r
+//\r
+// USB request targer device\r
+//\r
+#define USB_RECIP_DEVICE    0x00\r
+#define USB_RECIP_INTERFACE 0x01\r
+#define USB_RECIP_ENDPOINT  0x02\r
+#define USB_RECIP_OTHER     0x03\r
+\r
+typedef enum {\r
+  EfiUsbEndpointHalt,\r
+  EfiUsbDeviceRemoteWakeup\r
+} EFI_USB_STANDARD_FEATURE_SELECTOR;\r
+\r
+//\r
+// Usb Data recipient type\r
+//\r
+typedef enum {\r
+  EfiUsbDevice,\r
+  EfiUsbInterface,\r
+  EfiUsbEndpoint\r
+} EFI_USB_RECIPIENT;\r
+\r
+/**\r
+  Get a given usb descriptor.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Value              Request Value.\r
+  @param  Index              Request Index.\r
+  @param  DescriptorLength   Request descriptor Length.\r
+  @param  Descriptor         Request descriptor.\r
+\r
+\r
+  @retval EFI_SUCCESS       Usb descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the usb descriptor due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetDescriptor (\r
+  IN  EFI_PEI_SERVICES         **PeiServices,\r
+  IN  PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN  UINT16                   Value,\r
+  IN  UINT16                   Index,\r
+  IN  UINT16                   DescriptorLength,\r
+  OUT VOID                     *Descriptor\r
+  );\r
+\r
+/**\r
+  Set a usb device with a specified address.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+  @param  AddressValue       The address to assign.\r
+\r
+  @retval EFI_SUCCESS        Usb device address is set successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot set the usb address due to a hardware error.\r
+  @retval Others             Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetDeviceAddress (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINT16                   AddressValue\r
+  );\r
+\r
+/**\r
+  Clear a given usb feature.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Recipient         The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.\r
+  @param  Value             Request Value.\r
+  @param  Target            Request Index.\r
+\r
+  @retval EFI_SUCCESS       Usb feature is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the usb feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearDeviceFeature (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN EFI_USB_RECIPIENT        Recipient,\r
+  IN UINT16                   Value,\r
+  IN UINT16                   Target\r
+  );\r
+\r
+/**\r
+  Configure a usb device to Configuration 1.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS        Usb device is set to use Configuration 1 successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot set the usb device due to a hardware error.\r
+  @retval Others             Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetConfiguration (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi\r
+  );\r
+\r
+/**\r
+  Clear Endpoint Halt.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  EndpointAddress   The endpoint address.\r
+\r
+  @retval EFI_SUCCESS       Endpoint halt is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the endpoint halt status due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearEndpointHalt (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINT8                    EndpointAddress\r
+  );\r
+\r
+/**\r
+  Judge if the port is connected with a usb device or not.\r
+\r
+  @param  PortStatus  The usb port status gotten.\r
+\r
+  @retval TRUE        A usb device is connected with the port.\r
+  @retval FALSE       No usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnect (\r
+  IN UINT16  PortStatus\r
+  );\r
+\r
+/**\r
+  Judge if the port is connected with a low-speed usb device or not.\r
+\r
+  @param  PortStatus  The usb port status gotten.\r
+\r
+  @retval TRUE        A low-speed usb device is connected with the port.\r
+  @retval FALSE       No low-speed usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortLowSpeedDeviceAttached (\r
+  IN UINT16  PortStatus\r
+  );\r
+\r
+/**\r
+  Judge if the port is in "connection change" status or not.\r
+\r
+  @param  PortChangeStatus  The usb port change status gotten.\r
+\r
+  @retval TRUE              The port is in "connection change" status.\r
+  @retval FALSE             The port is NOT in "connection change" status.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnectChange (\r
+  IN UINT16  PortChangeStatus\r
+  );\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf
new file mode 100644 (file)
index 0000000..a2442c1
--- /dev/null
@@ -0,0 +1,65 @@
+## @file\r
+# Component description file for UsbBotPei module.\r
+#\r
+# Usb mass storage device Peim driver to support recovery from USB device.\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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UsbBotPei\r
+  FILE_GUID                      = 8401A046-6F70-4505-8471-7015B40355E3\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = PeimInitializeUsbBot\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  PeiUsbLib.c\r
+  PeiAtapi.c\r
+  BotPeim.c\r
+  UsbBotPeim.c\r
+  UsbPeim.h\r
+  UsbBotPeim.h\r
+  PeiUsbLib.h\r
+  BotPeim.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  BaseMemoryLib\r
+  PeiServicesLib\r
+  PeimEntryPoint\r
+  DebugLib\r
+  PcdLib\r
+\r
+[Pcd]\r
+  gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue\r
+\r
+[Ppis]\r
+  gEfiPeiVirtualBlockIoPpiGuid                  # PPI ALWAYS_PRODUCED\r
+  gPeiUsbIoPpiGuid                              # PPI ALWAYS_CONSUMED\r
+\r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbIoPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c
new file mode 100644 (file)
index 0000000..b04bd42
--- /dev/null
@@ -0,0 +1,720 @@
+/** @file\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 "UsbBotPeim.h"\r
+#include "BotPeim.h"\r
+\r
+//\r
+// Global function\r
+//\r
+EFI_PEI_NOTIFY_DESCRIPTOR        mNotifyList = {\r
+  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+  &gPeiUsbIoPpiGuid,\r
+  NotifyOnUsbIoPpi\r
+};\r
+\r
+EFI_PEI_RECOVERY_BLOCK_IO_PPI    mRecoveryBlkIoPpi = {\r
+  BotGetNumberOfBlockDevices,\r
+  BotGetMediaInfo,\r
+  BotReadBlocks\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR           mPpiList = {\r
+  EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+  &gEfiPeiVirtualBlockIoPpiGuid,\r
+  NULL\r
+};\r
+\r
+/**\r
+  Detect whether the removable media is present and whether it has changed.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM.\r
+  @param[in]  PeiBotDev     Indicates the PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS       The media status is successfully checked.\r
+  @retval Other             Failed to detect media.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiBotDetectMedia (\r
+  IN  EFI_PEI_SERVICES                          **PeiServices,\r
+  IN  PEI_BOT_DEVICE                            *PeiBotDev\r
+  );\r
+\r
+/**\r
+  Initializes the Usb Bot. \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 bot driver is successfully initialized.\r
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeUsbBot (\r
+  IN EFI_PEI_FILE_HANDLE       FileHandle,\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINTN                       UsbIoPpiInstance;\r
+  EFI_PEI_PPI_DESCRIPTOR      *TempPpiDescriptor;\r
+  PEI_USB_IO_PPI              *UsbIoPpi;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // locate all usb io PPIs\r
+  //\r
+  for (UsbIoPpiInstance = 0; UsbIoPpiInstance < PEI_FAT_MAX_USB_IO_PPI; UsbIoPpiInstance++) {\r
+\r
+    Status = PeiServicesLocatePpi (\r
+                              &gPeiUsbIoPpiGuid,\r
+                              UsbIoPpiInstance,\r
+                              &TempPpiDescriptor,\r
+                              (VOID **) &UsbIoPpi\r
+                              );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // Register a notify function\r
+  //\r
+  return PeiServicesNotifyPpi (&mNotifyList);\r
+}\r
+\r
+/**\r
+  UsbIo installation notification function. \r
+  \r
+  This function finds out all the current USB IO PPIs in the system and add them\r
+  into private data.\r
+\r
+  @param  PeiServices      Indirect reference to the PEI Services Table.\r
+  @param  NotifyDesc       Address of the notification descriptor data structure.\r
+  @param  InvokePpi        Address of the PPI that was invoked.\r
+\r
+  @retval EFI_SUCCESS      The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotifyOnUsbIoPpi (\r
+  IN  EFI_PEI_SERVICES                              **PeiServices,\r
+  IN  EFI_PEI_NOTIFY_DESCRIPTOR                     *NotifyDesc,\r
+  IN  VOID                                          *InvokePpi\r
+  )\r
+{\r
+  PEI_USB_IO_PPI  *UsbIoPpi;\r
+\r
+  UsbIoPpi = (PEI_USB_IO_PPI *) InvokePpi;\r
+\r
+  InitUsbBot (PeiServices, UsbIoPpi);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize the usb bot device.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM.\r
+  @param[in]  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS       The usb bot device is initialized successfully.\r
+  @retval Other             Failed to initialize media.\r
+\r
+**/\r
+EFI_STATUS\r
+InitUsbBot (\r
+  IN  EFI_PEI_SERVICES                          **PeiServices,\r
+  IN  PEI_USB_IO_PPI                            *UsbIoPpi\r
+  )\r
+{\r
+  PEI_BOT_DEVICE                *PeiBotDevice;\r
+  EFI_STATUS                    Status;\r
+  EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDesc;\r
+  UINTN                         MemPages;\r
+  EFI_PHYSICAL_ADDRESS          AllocateAddress;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR   *EndpointDesc;\r
+  UINT8                         Index;\r
+\r
+  //\r
+  // Check its interface\r
+  //\r
+  Status = UsbIoPpi->UsbGetInterfaceDescriptor (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      &InterfaceDesc\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check if it is the BOT device we support\r
+  //\r
+  if ((InterfaceDesc->InterfaceClass != 0x08) || (InterfaceDesc->InterfaceProtocol != 0x50)) {\r
+\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  MemPages = sizeof (PEI_BOT_DEVICE) / EFI_PAGE_SIZE + 1;\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             MemPages,\r
+             &AllocateAddress\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  PeiBotDevice                  = (PEI_BOT_DEVICE *) ((UINTN) AllocateAddress);\r
+\r
+  PeiBotDevice->Signature       = PEI_BOT_DEVICE_SIGNATURE;\r
+  PeiBotDevice->UsbIoPpi        = UsbIoPpi;\r
+  PeiBotDevice->AllocateAddress = (UINTN) AllocateAddress;\r
+  PeiBotDevice->BotInterface    = InterfaceDesc;\r
+\r
+  //\r
+  // Default value\r
+  //\r
+  PeiBotDevice->Media.DeviceType  = UsbMassStorage;\r
+  PeiBotDevice->Media.BlockSize   = 0x200;\r
+\r
+  //\r
+  // Check its Bulk-in/Bulk-out endpoint\r
+  //\r
+  for (Index = 0; Index < 2; Index++) {\r
+    Status = UsbIoPpi->UsbGetEndpointDescriptor (\r
+                        PeiServices,\r
+                        UsbIoPpi,\r
+                        Index,\r
+                        &EndpointDesc\r
+                        );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if ((EndpointDesc->EndpointAddress & 0x80) != 0) {\r
+      PeiBotDevice->BulkInEndpoint = EndpointDesc;\r
+    } else {\r
+      PeiBotDevice->BulkOutEndpoint = EndpointDesc;\r
+    }\r
+  }\r
+\r
+  CopyMem (\r
+    &(PeiBotDevice->BlkIoPpi),\r
+    &mRecoveryBlkIoPpi,\r
+    sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI)\r
+    );\r
+  CopyMem (\r
+    &(PeiBotDevice->BlkIoPpiList),\r
+    &mPpiList,\r
+    sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+    );\r
+  PeiBotDevice->BlkIoPpiList.Ppi  = &PeiBotDevice->BlkIoPpi;\r
+\r
+  Status                          = PeiUsbInquiry (PeiServices, PeiBotDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             1,\r
+             &AllocateAddress\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  PeiBotDevice->SensePtr = (ATAPI_REQUEST_SENSE_DATA *) ((UINTN) AllocateAddress);\r
+\r
+  Status = PeiServicesInstallPpi (&PeiBotDevice->BlkIoPpiList);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one \r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process. \r
+  To the PEI legacy floppy driver, it returns the number of all the legacy \r
+  devices it finds during its enumeration process. If no device is detected, \r
+  then the function will return zero.  \r
+  \r
+  @param[in]  PeiServices          General-purpose services that are available \r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI \r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          Operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotGetNumberOfBlockDevices (\r
+  IN  EFI_PEI_SERVICES                         **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI            *This,\r
+  OUT UINTN                                    *NumberBlockDevices\r
+  )\r
+{\r
+  //\r
+  // For Usb devices, this value should be always 1\r
+  //\r
+  *NumberBlockDevices = 1;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media \r
+  information. If the media changes, calling this function will update the media \r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants \r
+                            to talk. Because the driver that implements Block I/O \r
+                            PPIs will manage multiple block devices, the PPIs that \r
+                            want to talk to a single device must specify the \r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to \r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.  \r
+                            The caller is responsible for the ownership of this \r
+                            data structure.\r
+  \r
+  @retval EFI_SUCCESS        Media information about the specified block device \r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware \r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotGetMediaInfo (\r
+  IN  EFI_PEI_SERVICES                          **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI             *This,\r
+  IN  UINTN                                     DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO_MEDIA                    *MediaInfo\r
+  )\r
+{\r
+  PEI_BOT_DEVICE  *PeiBotDev;\r
+  EFI_STATUS      Status;\r
+\r
+  PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);\r
+\r
+  //\r
+  // First test unit ready\r
+  //\r
+  PeiUsbTestUnitReady (\r
+    PeiServices,\r
+    PeiBotDev\r
+    );\r
+\r
+  Status = PeiBotDetectMedia (\r
+            PeiServices,\r
+            PeiBotDev\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  CopyMem (\r
+    MediaInfo,\r
+    &(PeiBotDev->Media),\r
+    sizeof (EFI_PEI_BLOCK_IO_MEDIA)\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the \r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to \r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants \r
+                            to talk. Because the driver that implements Block I/O \r
+                            PPIs will manage multiple block devices, the PPIs that \r
+                            want to talk to a single device must specify the device \r
+                            index that was assigned during the enumeration process. \r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the \r
+                            buffer.\r
+                         \r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting \r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not \r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotReadBlocks (\r
+  IN  EFI_PEI_SERVICES                          **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI             *This,\r
+  IN  UINTN                                     DeviceIndex,\r
+  IN  EFI_PEI_LBA                               StartLBA,\r
+  IN  UINTN                                     BufferSize,\r
+  OUT VOID                                      *Buffer\r
+  )\r
+{\r
+  PEI_BOT_DEVICE  *PeiBotDev;\r
+  EFI_STATUS      Status;\r
+  UINTN           BlockSize;\r
+  UINTN           NumberOfBlocks;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);\r
+\r
+  //\r
+  // Check parameters\r
+  //\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (!PeiBotDev->Media.MediaPresent) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  BlockSize = PeiBotDev->Media.BlockSize;\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    Status = EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (StartLBA > PeiBotDev->Media.LastBlock) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NumberOfBlocks = BufferSize / (PeiBotDev->Media.BlockSize);\r
+\r
+  if (Status == EFI_SUCCESS) {\r
+\r
+    Status = PeiUsbTestUnitReady (\r
+              PeiServices,\r
+              PeiBotDev\r
+              );\r
+    if (Status == EFI_SUCCESS) {\r
+      Status = PeiUsbRead10 (\r
+                PeiServices,\r
+                PeiBotDev,\r
+                Buffer,\r
+                StartLBA,\r
+                1\r
+                );\r
+    }\r
+  } else {\r
+    //\r
+    // To generate sense data for DetectMedia use.\r
+    //\r
+    PeiUsbTestUnitReady (\r
+      PeiServices,\r
+      PeiBotDev\r
+      );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // if any error encountered, detect what happened to the media and\r
+    // update the media info accordingly.\r
+    //\r
+    Status = PeiBotDetectMedia (\r
+              PeiServices,\r
+              PeiBotDev\r
+              );\r
+    if (Status != EFI_SUCCESS) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    NumberOfBlocks = BufferSize / PeiBotDev->Media.BlockSize;\r
+\r
+    if (!(PeiBotDev->Media.MediaPresent)) {\r
+      return EFI_NO_MEDIA;\r
+    }\r
+\r
+    if (BufferSize % (PeiBotDev->Media.BlockSize) != 0) {\r
+      return EFI_BAD_BUFFER_SIZE;\r
+    }\r
+\r
+    if (StartLBA > PeiBotDev->Media.LastBlock) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if ((StartLBA + NumberOfBlocks - 1) > PeiBotDev->Media.LastBlock) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Status = PeiUsbRead10 (\r
+              PeiServices,\r
+              PeiBotDev,\r
+              Buffer,\r
+              StartLBA,\r
+              NumberOfBlocks\r
+              );\r
+\r
+    switch (Status) {\r
+\r
+    case EFI_SUCCESS:\r
+      return EFI_SUCCESS;\r
+\r
+    default:\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  } else {\r
+    StartLBA += 1;\r
+    NumberOfBlocks -= 1;\r
+    Buffer = (UINT8 *) Buffer + PeiBotDev->Media.BlockSize;\r
+\r
+    if (NumberOfBlocks == 0) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    Status = PeiUsbRead10 (\r
+              PeiServices,\r
+              PeiBotDev,\r
+              Buffer,\r
+              StartLBA,\r
+              NumberOfBlocks\r
+              );\r
+    switch (Status) {\r
+\r
+    case EFI_SUCCESS:\r
+      return EFI_SUCCESS;\r
+\r
+    default:\r
+      return EFI_DEVICE_ERROR;\r
+\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Detect whether the removable media is present and whether it has changed.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM.\r
+  @param[in]  PeiBotDev     Indicates the PEI_BOT_DEVICE instance.\r
+\r
+  @retval EFI_SUCCESS       The media status is successfully checked.\r
+  @retval Other             Failed to detect media.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiBotDetectMedia (\r
+  IN  EFI_PEI_SERVICES                          **PeiServices,\r
+  IN  PEI_BOT_DEVICE                            *PeiBotDev\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_STATUS            FloppyStatus;\r
+  UINTN                 SenseCounts;\r
+  BOOLEAN               NeedReadCapacity;\r
+  EFI_PHYSICAL_ADDRESS  AllocateAddress;\r
+  ATAPI_REQUEST_SENSE_DATA    *SensePtr;\r
+  UINTN                 Retry;\r
+\r
+  //\r
+  // if there is no media present,or media not changed,\r
+  // the request sense command will detect faster than read capacity command.\r
+  // read capacity command can be bypassed, thus improve performance.\r
+  //\r
+  SenseCounts       = 0;\r
+  NeedReadCapacity  = TRUE;\r
+\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             1,\r
+             &AllocateAddress\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SensePtr = PeiBotDev->SensePtr;\r
+  ZeroMem (SensePtr, EFI_PAGE_SIZE);\r
+\r
+  Status = PeiUsbRequestSense (\r
+            PeiServices,\r
+            PeiBotDev,\r
+            &SenseCounts,\r
+            (UINT8 *) SensePtr\r
+            );\r
+\r
+  if (Status == EFI_SUCCESS) {\r
+    //\r
+    // No Media\r
+    //\r
+    if (IsNoMedia (SensePtr, SenseCounts)) {\r
+      NeedReadCapacity              = FALSE;\r
+      PeiBotDev->Media.MediaPresent = FALSE;\r
+      PeiBotDev->Media.LastBlock    = 0;\r
+    } else {\r
+      //\r
+      // Media Changed\r
+      //\r
+      if (IsMediaChange (SensePtr, SenseCounts)) {\r
+        PeiBotDev->Media.MediaPresent = TRUE;\r
+      }\r
+      //\r
+      // Media Error\r
+      //\r
+      if (IsMediaError (SensePtr, SenseCounts)) {\r
+        //\r
+        // if media error encountered, make it look like no media present.\r
+        //\r
+        PeiBotDev->Media.MediaPresent = FALSE;\r
+        PeiBotDev->Media.LastBlock    = 0;\r
+      }\r
+\r
+    }\r
+\r
+  }\r
+\r
+  if (NeedReadCapacity) {\r
+    //\r
+    // Retry at most 4 times to detect media info\r
+    //\r
+    for (Retry = 0; Retry < 4; Retry++) {\r
+      switch (PeiBotDev->DeviceType) {\r
+      case USBCDROM:\r
+        Status = PeiUsbReadCapacity (\r
+                  PeiServices,\r
+                  PeiBotDev\r
+                  );\r
+        break;\r
+\r
+      case USBFLOPPY2:\r
+        Status = PeiUsbReadFormattedCapacity (\r
+                  PeiServices,\r
+                  PeiBotDev\r
+                  );\r
+          if (EFI_ERROR(Status)||\r
+              !PeiBotDev->Media.MediaPresent) {\r
+          //\r
+          // retry the ReadCapacity command\r
+          //\r
+          PeiBotDev->DeviceType = USBFLOPPY;\r
+            Status = EFI_DEVICE_ERROR;\r
+        }\r
+        break;\r
+\r
+      case USBFLOPPY:\r
+        Status = PeiUsbReadCapacity (\r
+                  PeiServices,\r
+                  PeiBotDev\r
+                  );\r
+        //\r
+        // retry the ReadFormatCapacity command\r
+        //\r
+        PeiBotDev->DeviceType = USBFLOPPY2;\r
+        break;\r
+\r
+      default:\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+\r
+      SenseCounts = 0;\r
+      ZeroMem (SensePtr, EFI_PAGE_SIZE);\r
+\r
+      if (Status == EFI_SUCCESS) {\r
+        break;\r
+      }\r
+\r
+      FloppyStatus = PeiUsbRequestSense (\r
+                      PeiServices,\r
+                      PeiBotDev,\r
+                      &SenseCounts,\r
+                      (UINT8 *) SensePtr\r
+                      );\r
+\r
+      //\r
+      // If Request Sense data failed,retry.\r
+      //\r
+      if (EFI_ERROR (FloppyStatus)) {\r
+        continue;\r
+      }\r
+      //\r
+      // No Media\r
+      //\r
+      if (IsNoMedia (SensePtr, SenseCounts)) {\r
+        PeiBotDev->Media.MediaPresent = FALSE;\r
+        PeiBotDev->Media.LastBlock    = 0;\r
+        break;\r
+      }\r
+\r
+      if (IsMediaError (SensePtr, SenseCounts)) {\r
+        //\r
+        // if media error encountered, make it look like no media present.\r
+        //\r
+        PeiBotDev->Media.MediaPresent = FALSE;\r
+        PeiBotDev->Media.LastBlock    = 0;\r
+        break;\r
+      }\r
+    }\r
+    //\r
+    // ENDFOR\r
+    //\r
+    // tell whether the readcapacity process is successful or not\r
+    // ("Status" variable record the latest status returned\r
+    // by ReadCapacity )\r
+    //\r
+    if (Status != EFI_SUCCESS) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h
new file mode 100644 (file)
index 0000000..26d08df
--- /dev/null
@@ -0,0 +1,233 @@
+/** @file\r
+Usb BOT Peim definition.\r
+\r
+Copyright (c) 2006, 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
+#ifndef _PEI_USB_BOT_PEIM_H_\r
+#define _PEI_USB_BOT_PEIM_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbIo.h>\r
+#include <Ppi/UsbHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+\r
+#include <IndustryStandard/Usb.h>\r
+#include <IndustryStandard/Atapi.h>\r
+\r
+#define PEI_FAT_MAX_USB_IO_PPI  127\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one \r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process. \r
+  To the PEI legacy floppy driver, it returns the number of all the legacy \r
+  devices it finds during its enumeration process. If no device is detected, \r
+  then the function will return zero.  \r
+  \r
+  @param[in]  PeiServices          General-purpose services that are available \r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI \r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          Operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotGetNumberOfBlockDevices (\r
+  IN  EFI_PEI_SERVICES                         **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI            *This,\r
+  OUT UINTN                                    *NumberBlockDevices\r
+  );\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media \r
+  information. If the media changes, calling this function will update the media \r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants \r
+                            to talk. Because the driver that implements Block I/O \r
+                            PPIs will manage multiple block devices, the PPIs that \r
+                            want to talk to a single device must specify the \r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to \r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.  \r
+                            The caller is responsible for the ownership of this \r
+                            data structure.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device \r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware \r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotGetMediaInfo (\r
+  IN  EFI_PEI_SERVICES                          **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI             *This,\r
+  IN  UINTN                                     DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO_MEDIA                    *MediaInfo\r
+  );\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the \r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to \r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants \r
+                            to talk. Because the driver that implements Block I/O \r
+                            PPIs will manage multiple block devices, the PPIs that \r
+                            want to talk to a single device must specify the device \r
+                            index that was assigned during the enumeration process. \r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the \r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting \r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not \r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotReadBlocks (\r
+  IN  EFI_PEI_SERVICES                          **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI             *This,\r
+  IN  UINTN                                     DeviceIndex,\r
+  IN  EFI_PEI_LBA                               StartLBA,\r
+  IN  UINTN                                     BufferSize,\r
+  OUT VOID                                      *Buffer\r
+  );\r
+\r
+/**\r
+  UsbIo installation notification function. \r
+  \r
+  This function finds out all the current USB IO PPIs in the system and add them\r
+  into private data.\r
+\r
+  @param  PeiServices      Indirect reference to the PEI Services Table.\r
+  @param  NotifyDesc       Address of the notification descriptor data structure.\r
+  @param  InvokePpi        Address of the PPI that was invoked.\r
+\r
+  @retval EFI_SUCCESS      The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotifyOnUsbIoPpi (\r
+  IN  EFI_PEI_SERVICES                              **PeiServices,\r
+  IN  EFI_PEI_NOTIFY_DESCRIPTOR                     *NotifyDesc,\r
+  IN  VOID                                          *InvokePpi\r
+  );\r
+\r
+/**\r
+  Initialize the usb bot device.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM.\r
+  @param[in]  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS       The usb bot device is initialized successfully.\r
+  @retval Other             Failed to initialize media.\r
+\r
+**/\r
+EFI_STATUS\r
+InitUsbBot (\r
+  IN  EFI_PEI_SERVICES                          **PeiServices,\r
+  IN  PEI_USB_IO_PPI                            *UsbIoPpi\r
+  );\r
+\r
+#define USBCDROM    1 // let the device type value equal to USBCDROM, which is defined by PI spec.\r
+                      // Therefore the CdExpressPei module can do recovery on UsbCdrom.\r
+#define USBFLOPPY   2 // for those that use ReadCapacity(0x25) command to retrieve media capacity\r
+#define USBFLOPPY2  3 // for those that use ReadFormatCapacity(0x23) command to retrieve media capacity\r
+\r
+//\r
+// Bot device structure\r
+//\r
+#define PEI_BOT_DEVICE_SIGNATURE  SIGNATURE_32 ('U', 'B', 'O', 'T')\r
+typedef struct {\r
+  UINTN                           Signature;\r
+  EFI_PEI_RECOVERY_BLOCK_IO_PPI   BlkIoPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR          BlkIoPpiList;\r
+  EFI_PEI_BLOCK_IO_MEDIA          Media;\r
+  PEI_USB_IO_PPI                  *UsbIoPpi;\r
+  EFI_USB_INTERFACE_DESCRIPTOR    *BotInterface;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR     *BulkInEndpoint;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR     *BulkOutEndpoint;\r
+  UINTN                           AllocateAddress;\r
+  UINTN                           DeviceType;\r
+  ATAPI_REQUEST_SENSE_DATA              *SensePtr;\r
+} PEI_BOT_DEVICE;\r
+\r
+#define PEI_BOT_DEVICE_FROM_THIS(a) CR (a, PEI_BOT_DEVICE, BlkIoPpi, PEI_BOT_DEVICE_SIGNATURE)\r
+\r
+/**\r
+  Send ATAPI command using BOT protocol.\r
+\r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  PeiBotDev              The instance to PEI_BOT_DEVICE.\r
+  @param  Command                The command to be sent to ATAPI device.\r
+  @param  CommandSize            The length of the data to be sent.\r
+  @param  DataBuffer             The pointer to the data.\r
+  @param  BufferLength           The length of the data.\r
+  @param  Direction              The direction of the data.\r
+  @param  TimeOutInMilliSeconds  Indicates the maximum time, in millisecond, which the\r
+                                 transfer is allowed to complete.\r
+\r
+  @retval EFI_DEVICE_ERROR       Successful to get the status of device.\r
+  @retval EFI_SUCCESS            Failed to get the status of device.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiAtapiCommand (\r
+  IN  EFI_PEI_SERVICES            **PeiServices,\r
+  IN  PEI_BOT_DEVICE              *PeiBotDev,\r
+  IN  VOID                        *Command,\r
+  IN  UINT8                       CommandSize,\r
+  IN  VOID                        *DataBuffer,\r
+  IN  UINT32                      BufferLength,\r
+  IN  EFI_USB_DATA_DIRECTION      Direction,\r
+  IN  UINT16                      TimeOutInMilliSeconds\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h
new file mode 100644 (file)
index 0000000..4f3f57f
--- /dev/null
@@ -0,0 +1,179 @@
+/** @file\r
+Usb Peim definition.\r
+\r
+Copyright (c) 2006, 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
+#ifndef _PEI_USB_PEIM_H_\r
+#define _PEI_USB_PEIM_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbIo.h>\r
+#include <Ppi/UsbHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <IndustryStandard/Usb.h>\r
+\r
+#define MAX_ROOT_PORT             2\r
+#define MAX_ENDPOINT              16\r
+\r
+#define USB_SLOW_SPEED_DEVICE     0x01\r
+#define USB_FULL_SPEED_DEVICE     0x02\r
+\r
+#define PEI_USB_DEVICE_SIGNATURE  SIGNATURE_32 ('U', 's', 'b', 'D')\r
+typedef struct {\r
+  UINTN                         Signature;\r
+  PEI_USB_IO_PPI                UsbIoPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR        UsbIoPpiList;\r
+  UINT8                         DeviceAddress;\r
+  UINT8                         MaxPacketSize0;\r
+  UINT8                         DeviceSpeed;\r
+  UINT8                         DataToggle;\r
+  UINT8                         IsHub;\r
+  UINT8                         DownStreamPortNo;\r
+  UINT8                         Reserved[2];  // Padding for IPF\r
+  UINTN                         AllocateAddress;\r
+  PEI_USB_HOST_CONTROLLER_PPI   *UsbHcPpi;\r
+  UINT8                         ConfigurationData[1024];\r
+  EFI_USB_CONFIG_DESCRIPTOR     *ConfigDesc;\r
+  EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDesc;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR   *EndpointDesc[MAX_ENDPOINT];\r
+} PEI_USB_DEVICE;\r
+\r
+#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE)\r
+\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB_IO_PPI.\r
+  @param  Request                USB device request to send.\r
+  @param  Direction              Specifies the data direction for the data stage.\r
+  @param  Timeout                Indicates the maximum timeout, in millisecond.\r
+  @param  Data                   Data buffer to be transmitted or received from USB device.\r
+  @param  DataLength             The size (in bytes) of the data buffer.\r
+\r
+  @retval EFI_SUCCESS            Transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.\r
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbControlTransfer (\r
+  IN     EFI_PEI_SERVICES          **PeiServices,\r
+  IN     PEI_USB_IO_PPI            *This,\r
+  IN     EFI_USB_DEVICE_REQUEST    *Request,\r
+  IN     EFI_USB_DATA_DIRECTION    Direction,\r
+  IN     UINT32                    Timeout,\r
+  IN OUT VOID                      *Data,      OPTIONAL\r
+  IN     UINTN                     DataLength  OPTIONAL\r
+  );\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB_IO_PPI.\r
+  @param  DeviceEndpoint        Endpoint number and its direction in bit 7.\r
+  @param  Data                  A pointer to the buffer of data to transmit \r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  Timeout               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbBulkTransfer (\r
+  IN     EFI_PEI_SERVICES    **PeiServices,\r
+  IN     PEI_USB_IO_PPI      *This,\r
+  IN     UINT8               DeviceEndpoint,\r
+  IN OUT VOID                *Data,\r
+  IN OUT UINTN               *DataLength,\r
+  IN     UINTN               Timeout\r
+  );\r
+\r
+/**\r
+  Get the usb interface descriptor.\r
+\r
+  @param  PeiServices          General-purpose services that are available to every PEIM.\r
+  @param  This                 Indicates the PEI_USB_IO_PPI instance.\r
+  @param  InterfaceDescriptor  Request interface descriptor.\r
+\r
+\r
+  @retval EFI_SUCCESS     Usb interface descriptor is obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetInterfaceDescriptor (\r
+  IN  EFI_PEI_SERVICES                **PeiServices,\r
+  IN  PEI_USB_IO_PPI                  *This,\r
+  OUT EFI_USB_INTERFACE_DESCRIPTOR    **InterfaceDescriptor\r
+  );\r
+\r
+/**\r
+  Get the usb endpoint descriptor.\r
+\r
+  @param  PeiServices          General-purpose services that are available to every PEIM.\r
+  @param  This                 Indicates the PEI_USB_IO_PPI instance.\r
+  @param  EndpointIndex        The valid index of the specified endpoint.\r
+  @param  EndpointDescriptor   Request endpoint descriptor.\r
+\r
+  @retval EFI_SUCCESS       Usb endpoint descriptor is obtained successfully.\r
+  @retval EFI_NOT_FOUND     Usb endpoint descriptor is NOT found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetEndpointDescriptor (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  PEI_USB_IO_PPI                 *This,\r
+  IN  UINT8                          EndpointIndex,\r
+  OUT EFI_USB_ENDPOINT_DESCRIPTOR    **EndpointDescriptor\r
+  );\r
+\r
+/**\r
+  Reset the port and re-configure the usb device.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  This           Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS    Usb device is reset and configured successfully.\r
+  @retval Others         Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbPortReset (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_IO_PPI      *This\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
new file mode 100644 (file)
index 0000000..5b7ebfa
--- /dev/null
@@ -0,0 +1,537 @@
+/** @file\r
+Usb Hub Request Support In PEI Phase\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
+  Get a given hub port status.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Port          Usb hub port number (starting from 1).\r
+  @param  PortStatus    Current Hub port status and change status.\r
+\r
+  @retval EFI_SUCCESS       Port status is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the port status due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetPortStatus (\r
+  IN  EFI_PEI_SERVICES    **PeiServices,\r
+  IN  PEI_USB_IO_PPI      *UsbIoPpi,\r
+  IN  UINT8               Port,\r
+  OUT UINT32              *PortStatus\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DeviceRequest;\r
+\r
+  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE;\r
+  DeviceRequest.Request     = USB_HUB_GET_PORT_STATUS;\r
+  DeviceRequest.Index       = Port;\r
+  DeviceRequest.Length      = (UINT16) sizeof (UINT32);\r
+\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DeviceRequest,\r
+                     EfiUsbDataIn,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     PortStatus,\r
+                     sizeof (UINT32)\r
+                     );\r
+\r
+}\r
+\r
+/**\r
+  Set specified feature to a given hub port.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Port          Usb hub port number (starting from 1).\r
+  @param  Value         New feature value.\r
+\r
+  @retval EFI_SUCCESS       Port feature is set successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot set the port feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetPortFeature (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_IO_PPI      *UsbIoPpi,\r
+  IN UINT8               Port,\r
+  IN UINT8               Value\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST      DeviceRequest;\r
+\r
+  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE;\r
+  DeviceRequest.Request     = USB_HUB_SET_PORT_FEATURE;\r
+  DeviceRequest.Value       = Value;\r
+  DeviceRequest.Index       = Port;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DeviceRequest,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Clear specified feature on a given hub port.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Port          Usb hub port number (starting from 1).\r
+  @param  Value         Feature value that will be cleared from the hub port.\r
+\r
+  @retval EFI_SUCCESS       Port feature is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the port feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearPortFeature (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_IO_PPI      *UsbIoPpi,\r
+  IN UINT8               Port,\r
+  IN UINT8               Value\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST      DeviceRequest;\r
+\r
+  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE;\r
+  DeviceRequest.Request     = USB_HUB_CLEAR_FEATURE_PORT;\r
+  DeviceRequest.Value       = Value;\r
+  DeviceRequest.Index       = Port;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DeviceRequest,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Get a given hub status.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  HubStatus     Current Hub status and change status.\r
+\r
+  @retval EFI_SUCCESS       Hub status is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the hub status due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetHubStatus (\r
+  IN  EFI_PEI_SERVICES    **PeiServices,\r
+  IN  PEI_USB_IO_PPI      *UsbIoPpi,\r
+  OUT UINT32              *HubStatus\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DeviceRequest;\r
+\r
+  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE;\r
+  DeviceRequest.Request     = USB_HUB_GET_HUB_STATUS;\r
+  DeviceRequest.Length      = (UINT16) sizeof (UINT32);\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DeviceRequest,\r
+                     EfiUsbDataIn,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     HubStatus,\r
+                     sizeof (UINT32)\r
+                     );\r
+}\r
+\r
+/**\r
+  Set specified feature to a given hub.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Value         New feature value.\r
+\r
+  @retval EFI_SUCCESS       Port feature is set successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot set the port feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetHubFeature (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_IO_PPI      *UsbIoPpi,\r
+  IN UINT8               Value\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST      DeviceRequest;\r
+\r
+  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DeviceRequest.RequestType = USB_HUB_SET_HUB_FEATURE_REQ_TYPE;\r
+  DeviceRequest.Request     = USB_HUB_SET_HUB_FEATURE;\r
+  DeviceRequest.Value       = Value;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DeviceRequest,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Clear specified feature on a given hub.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Value         Feature value that will be cleared from the hub port.\r
+\r
+  @retval EFI_SUCCESS       Hub feature is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the hub feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearHubFeature (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_IO_PPI      *UsbIoPpi,\r
+  IN UINT8               Value\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST      DeviceRequest;\r
+\r
+  ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;\r
+  DeviceRequest.Request     = USB_HUB_CLEAR_FEATURE;\r
+  DeviceRequest.Value       = Value;\r
+\r
+  return  UsbIoPpi->UsbControlTransfer (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      &DeviceRequest,\r
+                      EfiUsbNoData,\r
+                      PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                      NULL,\r
+                      0\r
+                      );\r
+}\r
+\r
+/**\r
+  Get a given hub descriptor.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.\r
+  @param  DescriptorSize The length of Hub Descriptor buffer.\r
+  @param  HubDescriptor  Caller allocated buffer to store the hub descriptor if\r
+                         successfully returned.\r
+\r
+  @retval EFI_SUCCESS       Hub descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiGetHubDescriptor (\r
+  IN  EFI_PEI_SERVICES          **PeiServices,\r
+  IN  PEI_USB_IO_PPI            *UsbIoPpi,\r
+  IN  UINTN                     DescriptorSize,\r
+  OUT EFI_USB_HUB_DESCRIPTOR    *HubDescriptor\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST      DevReq;\r
+  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  //\r
+  // Fill Device request packet\r
+  //\r
+  DevReq.RequestType = USB_RT_HUB | 0x80;\r
+  DevReq.Request     = USB_HUB_GET_DESCRIPTOR;\r
+  DevReq.Value       = USB_DT_HUB << 8;\r
+  DevReq.Length      = (UINT16)DescriptorSize;\r
+\r
+  return  UsbIoPpi->UsbControlTransfer (\r
+                      PeiServices,\r
+                      UsbIoPpi,\r
+                      &DevReq,\r
+                      EfiUsbDataIn,\r
+                      PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                      HubDescriptor,\r
+                      (UINT16)DescriptorSize\r
+                      );\r
+}\r
+\r
+/**\r
+  Configure a given hub.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  PeiUsbDevice   Indicating the hub controller device that will be configured\r
+\r
+  @retval EFI_SUCCESS       Hub configuration is done successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot configure the hub due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiDoHubConfig (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_DEVICE      *PeiUsbDevice\r
+  )\r
+{\r
+  EFI_USB_HUB_DESCRIPTOR  HubDescriptor;\r
+  EFI_STATUS              Status;\r
+  EFI_USB_HUB_STATUS      HubStatus;\r
+  UINTN                   Index;\r
+  UINT32                  PortStatus;\r
+  PEI_USB_IO_PPI          *UsbIoPpi;\r
+\r
+  ZeroMem (&HubDescriptor, sizeof (HubDescriptor));\r
+  UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+\r
+  //\r
+  // First get the hub descriptor length\r
+  //\r
+  Status = PeiGetHubDescriptor (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            2,\r
+            &HubDescriptor\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // First get the whole descriptor, then\r
+  // get the number of hub ports\r
+  //\r
+  Status = PeiGetHubDescriptor (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            HubDescriptor.Length,\r
+            &HubDescriptor\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;\r
+\r
+  Status = PeiHubGetHubStatus (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            (UINT32 *) &HubStatus\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  //  Get all hub ports status\r
+  //\r
+  for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+\r
+    Status = PeiHubGetPortStatus (\r
+              PeiServices,\r
+              UsbIoPpi,\r
+              (UINT8) (Index + 1),\r
+              &PortStatus\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+  }\r
+  //\r
+  //  Power all the hub ports\r
+  //\r
+  for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+    Status = PeiHubSetPortFeature (\r
+              PeiServices,\r
+              UsbIoPpi,\r
+              (UINT8) (Index + 1),\r
+              EfiUsbPortPower\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+  }\r
+  //\r
+  // Clear Hub Status Change\r
+  //\r
+  Status = PeiHubGetHubStatus (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            (UINT32 *) &HubStatus\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  } else {\r
+    //\r
+    // Hub power supply change happens\r
+    //\r
+    if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
+      PeiHubClearHubFeature (\r
+        PeiServices,\r
+        UsbIoPpi,\r
+        C_HUB_LOCAL_POWER\r
+        );\r
+    }\r
+    //\r
+    // Hub change overcurrent happens\r
+    //\r
+    if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
+      PeiHubClearHubFeature (\r
+        PeiServices,\r
+        UsbIoPpi,\r
+        C_HUB_OVER_CURRENT\r
+        );\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send reset signal over the given root hub port.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.\r
+  @param  PortNum        Usb hub port number (starting from 1).\r
+\r
+**/\r
+VOID\r
+PeiResetHubPort (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_IO_PPI      *UsbIoPpi,\r
+  IN UINT8               PortNum\r
+  )\r
+{\r
+  UINT8               Try;\r
+  EFI_USB_PORT_STATUS HubPortStatus;\r
+\r
+\r
+  MicroSecondDelay (100 * 1000);\r
+\r
+  //\r
+  // reset root port\r
+  //\r
+  PeiHubSetPortFeature (\r
+    PeiServices,\r
+    UsbIoPpi,\r
+    PortNum,\r
+    EfiUsbPortReset\r
+    );\r
+\r
+  Try = 10;\r
+  do {\r
+    PeiHubGetPortStatus (\r
+      PeiServices,\r
+      UsbIoPpi,\r
+      PortNum,\r
+      (UINT32 *) &HubPortStatus\r
+      );\r
+\r
+    MicroSecondDelay (2 * 1000);\r
+    Try -= 1;\r
+  } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);\r
+\r
+  //\r
+  // clear reset root port\r
+  //\r
+  PeiHubClearPortFeature (\r
+    PeiServices,\r
+    UsbIoPpi,\r
+    PortNum,\r
+    EfiUsbPortReset\r
+    );\r
+\r
+  MicroSecondDelay (1 * 1000);\r
+\r
+  PeiHubClearPortFeature (\r
+    PeiServices,\r
+    UsbIoPpi,\r
+    PortNum,\r
+    EfiUsbPortConnectChange\r
+    );\r
+\r
+  //\r
+  // Set port enable\r
+  //\r
+  PeiHubSetPortFeature (\r
+    PeiServices,\r
+    UsbIoPpi,\r
+    PortNum,\r
+    EfiUsbPortEnable\r
+    );\r
+\r
+  //\r
+  // Clear any change status\r
+  //\r
+\r
+  PeiHubClearPortFeature (\r
+    PeiServices,\r
+    UsbIoPpi,\r
+    PortNum,\r
+    EfiUsbPortEnableChange\r
+    );\r
+\r
+  MicroSecondDelay (10 * 1000);\r
+\r
+  return;\r
+}\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h
new file mode 100644 (file)
index 0000000..273a26c
--- /dev/null
@@ -0,0 +1,279 @@
+/** @file\r
+Constants definitions for Usb Hub Peim\r
+\r
+Copyright (c) 2006, 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
+#ifndef _PEI_HUB_PEIM_H_\r
+#define _PEI_HUB_PEIM_H_\r
+\r
+\r
+//\r
+// Hub feature numbers\r
+//\r
+#define C_HUB_LOCAL_POWER   0\r
+#define C_HUB_OVER_CURRENT  1\r
+\r
+//\r
+// Hub class code & sub class code\r
+//\r
+#define CLASS_CODE_HUB      0x09\r
+#define SUB_CLASS_CODE_HUB  0\r
+\r
+//\r
+// Hub Status & Hub Change bit masks\r
+//\r
+#define HUB_STATUS_LOCAL_POWER  0x0001\r
+#define HUB_STATUS_OVERCURRENT  0x0002\r
+\r
+#define HUB_CHANGE_LOCAL_POWER  0x0001\r
+#define HUB_CHANGE_OVERCURRENT  0x0002\r
+\r
+//\r
+// Hub Characteristics\r
+//\r
+#define HUB_CHAR_LPSM     0x0003\r
+#define HUB_CHAR_COMPOUND 0x0004\r
+#define HUB_CHAR_OCPM     0x0018\r
+\r
+//\r
+// Standard hub request and request type\r
+// By [Spec-USB20/Chapter-11.24]\r
+//\r
+#define USB_HUB_CLEAR_FEATURE               0x01\r
+#define USB_HUB_CLEAR_FEATURE_REQ_TYPE      0x20\r
+\r
+#define USB_HUB_CLEAR_FEATURE_PORT          0x01\r
+#define USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE 0x23\r
+\r
+#define USB_HUB_GET_BUS_STATE               0x02\r
+#define USB_HUB_GET_BUS_STATE_REQ_TYPE      0xA3\r
+\r
+#define USB_HUB_GET_DESCRIPTOR              0x06\r
+#define USB_HUB_GET_DESCRIPTOR_REQ_TYPE     0xA0\r
+\r
+#define USB_HUB_GET_HUB_STATUS              0x00\r
+#define USB_HUB_GET_HUB_STATUS_REQ_TYPE     0xA0\r
+\r
+#define USB_HUB_GET_PORT_STATUS             0x00\r
+#define USB_HUB_GET_PORT_STATUS_REQ_TYPE    0xA3\r
+\r
+#define USB_HUB_SET_DESCRIPTOR              0x07\r
+#define USB_HUB_SET_DESCRIPTOR_REQ_TYPE     0x20\r
+\r
+#define USB_HUB_SET_HUB_FEATURE             0x03\r
+#define USB_HUB_SET_HUB_FEATURE_REQ_TYPE    0x20\r
+\r
+#define USB_HUB_SET_PORT_FEATURE            0x03\r
+#define USB_HUB_SET_PORT_FEATURE_REQ_TYPE   0x23\r
+\r
+#define USB_RT_HUB        (USB_TYPE_CLASS | USB_RECIP_DEVICE)\r
+#define USB_RT_PORT       (USB_TYPE_CLASS | USB_RECIP_OTHER)\r
+\r
+#define MAXBYTES  8\r
+#pragma pack(1)\r
+//\r
+// Hub descriptor, the last two fields are of variable lenght.\r
+//\r
+typedef struct {\r
+  UINT8 Length;\r
+  UINT8 DescriptorType;\r
+  UINT8 NbrPorts;\r
+  UINT8 HubCharacteristics[2];\r
+  UINT8 PwrOn2PwrGood;\r
+  UINT8 HubContrCurrent;\r
+  UINT8 Filler[MAXBYTES];\r
+} EFI_USB_HUB_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UINT16  HubStatus;\r
+  UINT16  HubChangeStatus;\r
+} EFI_USB_HUB_STATUS;\r
+\r
+#pragma pack()\r
+/**\r
+  Get a given hub port status.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Port          Usb hub port number (starting from 1).\r
+  @param  PortStatus    Current Hub port status and change status.\r
+\r
+  @retval EFI_SUCCESS       Port status is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the port status due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetPortStatus (\r
+  IN EFI_PEI_SERVICES       **PeiServices,\r
+  IN PEI_USB_IO_PPI         *UsbIoPpi,\r
+  IN  UINT8                 Port,\r
+  OUT UINT32                *PortStatus\r
+  );\r
+\r
+/**\r
+  Set specified feature to a given hub port.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Port          Usb hub port number (starting from 1).\r
+  @param  Value         New feature value.\r
+\r
+  @retval EFI_SUCCESS       Port feature is set successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot set the port feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetPortFeature (\r
+  IN EFI_PEI_SERVICES       **PeiServices,\r
+  IN PEI_USB_IO_PPI         *UsbIoPpi,\r
+  IN  UINT8                 Port,\r
+  IN  UINT8                 Value\r
+  );\r
+\r
+/**\r
+  Set specified feature to a given hub.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Value         New feature value.\r
+\r
+  @retval EFI_SUCCESS       Port feature is set successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot set the port feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetHubFeature (\r
+  IN EFI_PEI_SERVICES       **PeiServices,\r
+  IN PEI_USB_IO_PPI         *UsbIoPpi,\r
+  IN  UINT8                 Value\r
+  );\r
+\r
+/**\r
+  Get a given hub status.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  HubStatus     Current Hub status and change status.\r
+\r
+  @retval EFI_SUCCESS       Hub status is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the hub status due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetHubStatus (\r
+  IN EFI_PEI_SERVICES       **PeiServices,\r
+  IN PEI_USB_IO_PPI         *UsbIoPpi,\r
+  OUT UINT32                *HubStatus\r
+  );\r
+\r
+/**\r
+  Clear specified feature on a given hub port.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Port          Usb hub port number (starting from 1).\r
+  @param  Value         Feature value that will be cleared from the hub port.\r
+\r
+  @retval EFI_SUCCESS       Port feature is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the port feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearPortFeature (\r
+  IN EFI_PEI_SERVICES       **PeiServices,\r
+  IN PEI_USB_IO_PPI         *UsbIoPpi,\r
+  IN  UINT8                 Port,\r
+  IN  UINT8                 Value\r
+  );\r
+\r
+/**\r
+  Clear specified feature on a given hub.\r
+\r
+  @param  PeiServices   General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Value         Feature value that will be cleared from the hub port.\r
+\r
+  @retval EFI_SUCCESS       Hub feature is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the hub feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearHubFeature (\r
+  IN EFI_PEI_SERVICES       **PeiServices,\r
+  IN PEI_USB_IO_PPI         *UsbIoPpi,\r
+  IN  UINT8                 Value\r
+  );\r
+\r
+/**\r
+  Get a given hub descriptor.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.\r
+  @param  DescriptorSize The length of Hub Descriptor buffer.\r
+  @param  HubDescriptor  Caller allocated buffer to store the hub descriptor if\r
+                         successfully returned.\r
+\r
+  @retval EFI_SUCCESS       Hub descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the hub descriptor due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiGetHubDescriptor (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINTN                    DescriptorSize,\r
+  OUT EFI_USB_HUB_DESCRIPTOR  *HubDescriptor\r
+  );\r
+\r
+/**\r
+  Configure a given hub.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  PeiUsbDevice   Indicating the hub controller device that will be configured\r
+\r
+  @retval EFI_SUCCESS       Hub configuration is done successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot configure the hub due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiDoHubConfig (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_DEVICE           *PeiUsbDevice\r
+  );\r
+\r
+/**\r
+  Send reset signal over the given root hub port.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi       Indicates the PEI_USB_IO_PPI instance.\r
+  @param  PortNum        Usb hub port number (starting from 1).\r
+\r
+**/\r
+VOID\r
+PeiResetHubPort (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_IO_PPI      *UsbIoPpi,\r
+  IN UINT8               PortNum\r
+  );\r
+\r
+#endif\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c
new file mode 100644 (file)
index 0000000..2ac8d7b
--- /dev/null
@@ -0,0 +1,333 @@
+/** @file\r
+Common Libarary for PEI USB\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 "PeiUsbLib.h"\r
+\r
+/**\r
+  Get a given usb descriptor.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Value              Request Value.\r
+  @param  Index              Request Index.\r
+  @param  DescriptorLength   Request descriptor Length.\r
+  @param  Descriptor         Request descriptor.\r
+\r
+\r
+  @retval EFI_SUCCESS       Usb descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the usb descriptor due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetDescriptor (\r
+  IN  EFI_PEI_SERVICES         **PeiServices,\r
+  IN  PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN  UINT16                   Value,\r
+  IN  UINT16                   Index,\r
+  IN  UINT16                   DescriptorLength,\r
+  OUT VOID                     *Descriptor\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+\r
+  ASSERT (UsbIoPpi != NULL);\r
+\r
+  DevReq.RequestType  = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;\r
+  DevReq.Request      = USB_DEV_GET_DESCRIPTOR;\r
+  DevReq.Value        = Value;\r
+  DevReq.Index        = Index;\r
+  DevReq.Length       = DescriptorLength;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DevReq,\r
+                     EfiUsbDataIn,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     Descriptor,\r
+                     DescriptorLength\r
+                     );\r
+}\r
+\r
+/**\r
+  Set a usb device with a specified address.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+  @param  AddressValue       The address to assign.\r
+\r
+  @retval EFI_SUCCESS       Usb device address is set successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot set the usb address due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetDeviceAddress (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINT16                   AddressValue\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+\r
+  ASSERT (UsbIoPpi != NULL);\r
+\r
+  DevReq.RequestType  = USB_DEV_SET_ADDRESS_REQ_TYPE;\r
+  DevReq.Request      = USB_DEV_SET_ADDRESS;\r
+  DevReq.Value        = AddressValue;\r
+  DevReq.Index        = 0;\r
+  DevReq.Length       = 0;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DevReq,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Clear a given usb feature.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Recipient         The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.\r
+  @param  Value             Request Value.\r
+  @param  Target            Request Index.\r
+\r
+  @retval EFI_SUCCESS       Usb feature is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the usb feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearDeviceFeature (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN EFI_USB_RECIPIENT        Recipient,\r
+  IN UINT16                   Value,\r
+  IN UINT16                   Target\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+\r
+  ASSERT (UsbIoPpi != NULL);\r
+\r
+  switch (Recipient) {\r
+  case EfiUsbDevice:\r
+    DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_D;\r
+    break;\r
+\r
+  case EfiUsbInterface:\r
+    DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_I;\r
+    break;\r
+\r
+  case EfiUsbEndpoint:\r
+    DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_E;\r
+    break;\r
+  }\r
+\r
+  DevReq.Request      = USB_DEV_CLEAR_FEATURE;\r
+  DevReq.Value        = Value;\r
+  DevReq.Index        = Target;\r
+  DevReq.Length       = 0;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DevReq,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Configure a usb device to Configuration 1.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS       Usb device is set to use Configuration 1 successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot set the usb device due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetConfiguration (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+  ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+  DevReq.RequestType  = USB_DEV_SET_CONFIGURATION_REQ_TYPE;\r
+  DevReq.Request      = USB_DEV_SET_CONFIGURATION;\r
+  DevReq.Value        = 1;\r
+\r
+  return UsbIoPpi->UsbControlTransfer (\r
+                     PeiServices,\r
+                     UsbIoPpi,\r
+                     &DevReq,\r
+                     EfiUsbNoData,\r
+                     PcdGet32 (PcdUsbTransferTimeoutValue),\r
+                     NULL,\r
+                     0\r
+                     );\r
+}\r
+\r
+/**\r
+  Clear Endpoint Halt.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  EndpointAddress   The endpoint address.\r
+\r
+  @retval EFI_SUCCESS       Endpoint halt is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the endpoint halt status due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearEndpointHalt (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINT8                    EndpointAddress\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  PEI_USB_DEVICE              *PeiUsbDev;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;\r
+  UINT8                       EndpointIndex;\r
+\r
+  EndpointIndex = 0;\r
+  PeiUsbDev     = PEI_USB_DEVICE_FROM_THIS (UsbIoPpi);\r
+\r
+  while (EndpointIndex < MAX_ENDPOINT) {\r
+    Status = UsbIoPpi->UsbGetEndpointDescriptor (PeiServices, UsbIoPpi, EndpointIndex, &EndpointDescriptor);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (EndpointDescriptor->EndpointAddress == EndpointAddress) {\r
+      break;\r
+    }\r
+\r
+    EndpointIndex++;\r
+  }\r
+\r
+  if (EndpointIndex == MAX_ENDPOINT) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = PeiUsbClearDeviceFeature (\r
+            PeiServices,\r
+            UsbIoPpi,\r
+            EfiUsbEndpoint,\r
+            EfiUsbEndpointHalt,\r
+            EndpointAddress\r
+            );\r
+\r
+  //\r
+  // set data toggle to zero.\r
+  //\r
+  if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {\r
+    PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Judge if the port is connected with a usb device or not.\r
+\r
+  @param  PortStatus  The usb port status gotten.\r
+\r
+  @retval TRUE        A usb device is connected with the port.\r
+  @retval FALSE       No usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnect (\r
+  IN UINT16  PortStatus\r
+  )\r
+{\r
+  //\r
+  // return the bit 0 value of PortStatus\r
+  //\r
+  if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Judge if the port is connected with a low-speed usb device or not.\r
+\r
+  @param  PortStatus  The usb port status gotten.\r
+\r
+  @retval TRUE        A low-speed usb device is connected with the port.\r
+  @retval FALSE       No low-speed usb device is connected with the port.\r
+\r
+**/\r
+UINTN\r
+IsPortLowSpeedDeviceAttached (\r
+  IN UINT16  PortStatus\r
+  )\r
+{\r
+  //\r
+  // return the bit 9 value of PortStatus\r
+  //\r
+  if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
+    return EFI_USB_SPEED_LOW;\r
+  } else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){\r
+    return EFI_USB_SPEED_HIGH;\r
+  } else {\r
+    return EFI_USB_SPEED_FULL;\r
+  }\r
+}\r
+\r
+/**\r
+  Judge if the port is in "connection change" status or not.\r
+\r
+  @param  PortChangeStatus  The usb port change status gotten.\r
+\r
+  @retval TRUE              The port is in "connection change" status.\r
+  @retval FALSE             The port is NOT in "connection change" status.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnectChange (\r
+  IN UINT16  PortChangeStatus\r
+  )\r
+{\r
+  //\r
+  // return the bit 0 value of PortChangeStatus\r
+  //\r
+  if ((PortChangeStatus & USB_PORT_STAT_C_CONNECTION) != 0) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h
new file mode 100644 (file)
index 0000000..dd4ce1b
--- /dev/null
@@ -0,0 +1,250 @@
+/** @file\r
+Common Libarary for PEI USB\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
+#ifndef _PEI_USB_LIB_H_\r
+#define _PEI_USB_LIB_H_\r
+\r
+\r
+//\r
+// Standard device request and request type\r
+// By [Spec-USB20/Chapter-9.4]\r
+//\r
+#define USB_DEV_GET_STATUS                  0x00\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_D       0x80 // Receiver : Device\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_I       0x81 // Receiver : Interface\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_E       0x82 // Receiver : Endpoint\r
+\r
+#define USB_DEV_CLEAR_FEATURE               0x01\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_D    0x00 // Receiver : Device\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_I    0x01 // Receiver : Interface\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_E    0x02 // Receiver : Endpoint\r
+\r
+#define USB_DEV_SET_FEATURE                 0x03\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_D      0x00 // Receiver : Device\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_I      0x01 // Receiver : Interface\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_E      0x02 // Receiver : Endpoint\r
+\r
+#define USB_DEV_SET_ADDRESS                 0x05\r
+#define USB_DEV_SET_ADDRESS_REQ_TYPE        0x00\r
+\r
+#define USB_DEV_GET_DESCRIPTOR              0x06\r
+#define USB_DEV_GET_DESCRIPTOR_REQ_TYPE     0x80\r
+\r
+#define USB_DEV_SET_DESCRIPTOR              0x07\r
+#define USB_DEV_SET_DESCRIPTOR_REQ_TYPE     0x00\r
+\r
+#define USB_DEV_GET_CONFIGURATION           0x08\r
+#define USB_DEV_GET_CONFIGURATION_REQ_TYPE  0x80\r
+\r
+#define USB_DEV_SET_CONFIGURATION           0x09\r
+#define USB_DEV_SET_CONFIGURATION_REQ_TYPE  0x00\r
+\r
+#define USB_DEV_GET_INTERFACE               0x0A\r
+#define USB_DEV_GET_INTERFACE_REQ_TYPE      0x81\r
+\r
+#define USB_DEV_SET_INTERFACE               0x0B\r
+#define USB_DEV_SET_INTERFACE_REQ_TYPE      0x01\r
+\r
+#define USB_DEV_SYNCH_FRAME                 0x0C\r
+#define USB_DEV_SYNCH_FRAME_REQ_TYPE        0x82\r
+\r
+//\r
+// USB Descriptor types\r
+//\r
+#define USB_DT_DEVICE     0x01\r
+#define USB_DT_CONFIG     0x02\r
+#define USB_DT_STRING     0x03\r
+#define USB_DT_INTERFACE  0x04\r
+#define USB_DT_ENDPOINT   0x05\r
+#define USB_DT_HUB        0x29\r
+#define USB_DT_HID        0x21\r
+\r
+//\r
+// USB request type\r
+//\r
+#define USB_TYPE_STANDARD (0x00 << 5)\r
+#define USB_TYPE_CLASS    (0x01 << 5)\r
+#define USB_TYPE_VENDOR   (0x02 << 5)\r
+#define USB_TYPE_RESERVED (0x03 << 5)\r
+\r
+//\r
+// USB request targer device\r
+//\r
+#define USB_RECIP_DEVICE    0x00\r
+#define USB_RECIP_INTERFACE 0x01\r
+#define USB_RECIP_ENDPOINT  0x02\r
+#define USB_RECIP_OTHER     0x03\r
+\r
+typedef enum {\r
+  EfiUsbEndpointHalt,\r
+  EfiUsbDeviceRemoteWakeup\r
+} EFI_USB_STANDARD_FEATURE_SELECTOR;\r
+\r
+//\r
+// Usb Data recipient type\r
+//\r
+typedef enum {\r
+  EfiUsbDevice,\r
+  EfiUsbInterface,\r
+  EfiUsbEndpoint\r
+} EFI_USB_RECIPIENT;\r
+\r
+/**\r
+  Get a given usb descriptor.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Value              Request Value.\r
+  @param  Index              Request Index.\r
+  @param  DescriptorLength   Request descriptor Length.\r
+  @param  Descriptor         Request descriptor.\r
+\r
+\r
+  @retval EFI_SUCCESS       Usb descriptor is obtained successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot get the usb descriptor due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetDescriptor (\r
+  IN  EFI_PEI_SERVICES         **PeiServices,\r
+  IN  PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN  UINT16                   Value,\r
+  IN  UINT16                   Index,\r
+  IN  UINT16                   DescriptorLength,\r
+  OUT VOID                     *Descriptor\r
+  );\r
+\r
+/**\r
+  Set a usb device with a specified address.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+  @param  AddressValue       The address to assign.\r
+\r
+  @retval EFI_SUCCESS        Usb device address is set successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot set the usb address due to a hardware error.\r
+  @retval Others             Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetDeviceAddress (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINT16                   AddressValue\r
+  );\r
+\r
+/**\r
+  Clear a given usb feature.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  Recipient         The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.\r
+  @param  Value             Request Value.\r
+  @param  Target            Request Index.\r
+\r
+  @retval EFI_SUCCESS       Usb feature is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the usb feature due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearDeviceFeature (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN EFI_USB_RECIPIENT        Recipient,\r
+  IN UINT16                   Value,\r
+  IN UINT16                   Target\r
+  );\r
+\r
+/**\r
+  Configure a usb device to Configuration 1.\r
+\r
+  @param  PeiServices        General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi           Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS        Usb device is set to use Configuration 1 successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot set the usb device due to a hardware error.\r
+  @retval Others             Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetConfiguration (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi\r
+  );\r
+\r
+/**\r
+  Clear Endpoint Halt.\r
+\r
+  @param  PeiServices       General-purpose services that are available to every PEIM.\r
+  @param  UsbIoPpi          Indicates the PEI_USB_IO_PPI instance.\r
+  @param  EndpointAddress   The endpoint address.\r
+\r
+  @retval EFI_SUCCESS       Endpoint halt is cleared successfully.\r
+  @retval EFI_DEVICE_ERROR  Cannot clear the endpoint halt status due to a hardware error.\r
+  @retval Others            Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearEndpointHalt (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN PEI_USB_IO_PPI           *UsbIoPpi,\r
+  IN UINT8                    EndpointAddress\r
+  );\r
+\r
+/**\r
+  Judge if the port is connected with a usb device or not.\r
+\r
+  @param  PortStatus  The usb port status gotten.\r
+\r
+  @retval TRUE        A usb device is connected with the port.\r
+  @retval FALSE       No usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnect (\r
+  IN UINT16  PortStatus\r
+  );\r
+\r
+/**\r
+  Judge if the port is connected with a low-speed usb device or not.\r
+\r
+  @param  PortStatus  The usb port status gotten.\r
+\r
+  @retval TRUE        A low-speed usb device is connected with the port.\r
+  @retval FALSE       No low-speed usb device is connected with the port.\r
+\r
+**/\r
+UINTN\r
+IsPortLowSpeedDeviceAttached (\r
+  IN UINT16  PortStatus\r
+  );\r
+\r
+/**\r
+  Judge if the port is in "connection change" status or not.\r
+\r
+  @param  PortChangeStatus  The usb port change status gotten.\r
+\r
+  @retval TRUE              The port is in "connection change" status.\r
+  @retval FALSE             The port is NOT in "connection change" status.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnectChange (\r
+  IN UINT16  PortChangeStatus\r
+  );\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf
new file mode 100644 (file)
index 0000000..e4a2cb4
--- /dev/null
@@ -0,0 +1,66 @@
+## @file\r
+# Component description file for UsbPeim module.\r
+#\r
+# Usb Bus Peim driver to support recovery from usb device.\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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UsbBusPei\r
+  FILE_GUID                      = 8401A045-6F70-4505-8471-7015B40355E3\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = PeimInitializeUsb\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  PeiUsbLib.c\r
+  HubPeim.c\r
+  UsbIoPeim.c\r
+  UsbPeim.c\r
+  UsbPeim.h\r
+  PeiUsbLib.h\r
+  HubPeim.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  TimerLib\r
+  BaseMemoryLib\r
+  PeiServicesLib\r
+  PeimEntryPoint\r
+  DebugLib\r
+  PcdLib\r
+\r
+[Pcd]\r
+  gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue\r
+  \r
+[Ppis]\r
+  gPeiUsbIoPpiGuid                              # PPI ALWAYS_PRODUCED\r
+  gPeiUsbHostControllerPpiGuid                  # PPI ALWAYS_CONSUMED\r
+  gPeiUsb2HostControllerPpiGuid                 # PPI ALWAYS_CONSUMED\r
+\r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid AND gPeiUsb2HostControllerPpiGuid OR gPeiUsbHostControllerPpiGuid\r
+\r
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c
new file mode 100644 (file)
index 0000000..897b228
--- /dev/null
@@ -0,0 +1,325 @@
+/** @file\r
+The module is used to implement Usb Io PPI interfaces.\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 "PeiUsbLib.h"\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB_IO_PPI.\r
+  @param  Request                USB device request to send.\r
+  @param  Direction              Specifies the data direction for the data stage.\r
+  @param  Timeout                Indicates the maximum timeout, in millisecond.\r
+  @param  Data                   Data buffer to be transmitted or received from USB device.\r
+  @param  DataLength             The size (in bytes) of the data buffer.\r
+\r
+  @retval EFI_SUCCESS            Transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.\r
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbControlTransfer (\r
+  IN     EFI_PEI_SERVICES          **PeiServices,\r
+  IN     PEI_USB_IO_PPI            *This,\r
+  IN     EFI_USB_DEVICE_REQUEST    *Request,\r
+  IN     EFI_USB_DATA_DIRECTION    Direction,\r
+  IN     UINT32                    Timeout,\r
+  IN OUT VOID                      *Data,      OPTIONAL\r
+  IN     UINTN                     DataLength  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  PEI_USB_DEVICE              *PeiUsbDev;\r
+  UINT32                      TransferResult;\r
+\r
+  PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);\r
+\r
+  if (PeiUsbDev->Usb2HcPpi != NULL) {\r
+    Status = PeiUsbDev->Usb2HcPpi->ControlTransfer (\r
+                        PeiServices,\r
+                        PeiUsbDev->Usb2HcPpi,\r
+                        PeiUsbDev->DeviceAddress,\r
+                        PeiUsbDev->DeviceSpeed,\r
+                        PeiUsbDev->MaxPacketSize0,\r
+                        Request,\r
+                        Direction,\r
+                        Data,\r
+                        &DataLength,\r
+                        Timeout,\r
+                        &(PeiUsbDev->Translator),\r
+                        &TransferResult\r
+                        );\r
+  } else {\r
+    Status = PeiUsbDev->UsbHcPpi->ControlTransfer (\r
+                        PeiServices,\r
+                        PeiUsbDev->UsbHcPpi,\r
+                        PeiUsbDev->DeviceAddress,\r
+                        PeiUsbDev->DeviceSpeed,\r
+                        PeiUsbDev->MaxPacketSize0,\r
+                        Request,\r
+                        Direction,\r
+                        Data,\r
+                        &DataLength,\r
+                        Timeout,\r
+                        &TransferResult\r
+                        );\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB_IO_PPI.\r
+  @param  DeviceEndpoint        Endpoint number and its direction in bit 7.\r
+  @param  Data                  A pointer to the buffer of data to transmit \r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  Timeout               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbBulkTransfer (\r
+  IN     EFI_PEI_SERVICES    **PeiServices,\r
+  IN     PEI_USB_IO_PPI      *This,\r
+  IN     UINT8               DeviceEndpoint,\r
+  IN OUT VOID                *Data,\r
+  IN OUT UINTN               *DataLength,\r
+  IN     UINTN               Timeout\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  PEI_USB_DEVICE              *PeiUsbDev;\r
+  UINT32                      TransferResult;\r
+  UINTN                       MaxPacketLength;\r
+  UINT8                       DataToggle;\r
+  UINT8                       OldToggle;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;\r
+  UINT8                       EndpointIndex;\r
+  VOID                        *Data2[EFI_USB_MAX_BULK_BUFFER_NUM];\r
+\r
+  PeiUsbDev     = PEI_USB_DEVICE_FROM_THIS (This);\r
+\r
+  EndpointDescriptor = NULL;\r
+  EndpointIndex = 0;\r
+  Data2[0] = Data;\r
+  Data2[1] = NULL;\r
+\r
+  while (EndpointIndex < MAX_ENDPOINT) {\r
+    Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (EndpointDescriptor->EndpointAddress == DeviceEndpoint) {\r
+      break;\r
+    }\r
+\r
+    EndpointIndex++;\r
+  }\r
+\r
+  if (EndpointIndex == MAX_ENDPOINT) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  MaxPacketLength = PeiUsbDev->EndpointDesc[EndpointIndex]->MaxPacketSize;\r
+  if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {\r
+    DataToggle = 1;\r
+  } else {\r
+    DataToggle = 0;\r
+  }\r
+\r
+  OldToggle = DataToggle;\r
+\r
+  if (PeiUsbDev->Usb2HcPpi != NULL) {\r
+    Status = PeiUsbDev->Usb2HcPpi->BulkTransfer (\r
+                        PeiServices,\r
+                        PeiUsbDev->Usb2HcPpi,\r
+                        PeiUsbDev->DeviceAddress,\r
+                        DeviceEndpoint,\r
+                        PeiUsbDev->DeviceSpeed,\r
+                        MaxPacketLength,\r
+                        Data2,\r
+                        DataLength,\r
+                        &DataToggle,\r
+                        Timeout,\r
+                        &(PeiUsbDev->Translator),\r
+                        &TransferResult\r
+                        );\r
+  } else {\r
+    Status = PeiUsbDev->UsbHcPpi->BulkTransfer (\r
+                        PeiServices,\r
+                        PeiUsbDev->UsbHcPpi,\r
+                        PeiUsbDev->DeviceAddress,\r
+                        DeviceEndpoint,\r
+                        (UINT8) MaxPacketLength,\r
+                        Data,\r
+                        DataLength,\r
+                        &DataToggle,\r
+                        Timeout,\r
+                        &TransferResult\r
+                        );\r
+  }\r
+\r
+  if (OldToggle != DataToggle) {\r
+    PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the usb interface descriptor.\r
+\r
+  @param  PeiServices          General-purpose services that are available to every PEIM.\r
+  @param  This                 Indicates the PEI_USB_IO_PPI instance.\r
+  @param  InterfaceDescriptor  Request interface descriptor.\r
+\r
+\r
+  @retval EFI_SUCCESS          Usb interface descriptor is obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetInterfaceDescriptor (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  PEI_USB_IO_PPI                 *This,\r
+  OUT EFI_USB_INTERFACE_DESCRIPTOR   **InterfaceDescriptor\r
+  )\r
+{\r
+  PEI_USB_DEVICE  *PeiUsbDev;\r
+  PeiUsbDev             = PEI_USB_DEVICE_FROM_THIS (This);\r
+  *InterfaceDescriptor  = PeiUsbDev->InterfaceDesc;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get the usb endpoint descriptor.\r
+\r
+  @param  PeiServices          General-purpose services that are available to every PEIM.\r
+  @param  This                 Indicates the PEI_USB_IO_PPI instance.\r
+  @param  EndpointIndex        The valid index of the specified endpoint.\r
+  @param  EndpointDescriptor   Request endpoint descriptor.\r
+\r
+  @retval EFI_SUCCESS       Usb endpoint descriptor is obtained successfully.\r
+  @retval EFI_NOT_FOUND     Usb endpoint descriptor is NOT found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetEndpointDescriptor (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  PEI_USB_IO_PPI                 *This,\r
+  IN  UINT8                          EndpointIndex,\r
+  OUT EFI_USB_ENDPOINT_DESCRIPTOR    **EndpointDescriptor\r
+  )\r
+{\r
+  PEI_USB_DEVICE  *PeiUsbDev;\r
+\r
+  PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);\r
+\r
+  ASSERT (EndpointDescriptor != NULL);\r
+\r
+  //\r
+  // The valid range of EndpointIndex is 0..15\r
+  // If EndpointIndex is lesser than 15 but larger than the number of interfaces,\r
+  // a EFI_NOT_FOUND should be returned\r
+  //\r
+  ASSERT (EndpointIndex <= 15);\r
+\r
+  if (EndpointIndex >= PeiUsbDev->InterfaceDesc->NumEndpoints) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *EndpointDescriptor = PeiUsbDev->EndpointDesc[EndpointIndex];\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reset the port and re-configure the usb device.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  This           Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS    Usb device is reset and configured successfully.\r
+  @retval Others         Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbPortReset (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_IO_PPI                 *This\r
+  )\r
+{\r
+  PEI_USB_DEVICE  *PeiUsbDev;\r
+  EFI_STATUS      Status;\r
+  UINT8           Address;\r
+\r
+  PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);\r
+\r
+  ResetRootPort (\r
+    PeiServices,\r
+    PeiUsbDev->UsbHcPpi,\r
+    PeiUsbDev->Usb2HcPpi,\r
+    PeiUsbDev->DeviceAddress,\r
+    0\r
+    );\r
+\r
+  //\r
+  // Set address\r
+  //\r
+  Address                   = PeiUsbDev->DeviceAddress;\r
+  PeiUsbDev->DeviceAddress  = 0;\r
+\r
+  Status = PeiUsbSetDeviceAddress (\r
+            PeiServices,\r
+            This,\r
+            Address\r
+            );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  PeiUsbDev->DeviceAddress = Address;\r
+\r
+  //\r
+  // Set default configuration\r
+  //\r
+  Status = PeiUsbSetConfiguration (\r
+            PeiServices,\r
+            This\r
+            );\r
+\r
+  return Status;\r
+}\r
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
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h
new file mode 100644 (file)
index 0000000..c9e75ba
--- /dev/null
@@ -0,0 +1,203 @@
+/** @file\r
+Usb Peim definition.\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
+#ifndef _PEI_USB_PEIM_H_\r
+#define _PEI_USB_PEIM_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbHostController.h>\r
+#include <Ppi/Usb2HostController.h>\r
+#include <Ppi/UsbIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <IndustryStandard/Usb.h>\r
+\r
+#define MAX_ROOT_PORT             2\r
+#define MAX_ENDPOINT              16\r
+\r
+#define USB_SLOW_SPEED_DEVICE     0x01\r
+#define USB_FULL_SPEED_DEVICE     0x02\r
+\r
+#define PEI_USB_DEVICE_SIGNATURE  SIGNATURE_32 ('U', 's', 'b', 'D')\r
+typedef struct {\r
+  UINTN                         Signature;\r
+  PEI_USB_IO_PPI                UsbIoPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR        UsbIoPpiList;\r
+  UINT8                         DeviceAddress;\r
+  UINT8                         MaxPacketSize0;\r
+  UINT8                         DeviceSpeed;\r
+  UINT8                         DataToggle;\r
+  UINT8                         IsHub;\r
+  UINT8                         DownStreamPortNo;\r
+  UINT8                         Reserved[2];  // Padding for IPF\r
+  UINTN                         AllocateAddress;\r
+  PEI_USB_HOST_CONTROLLER_PPI   *UsbHcPpi;\r
+  PEI_USB2_HOST_CONTROLLER_PPI  *Usb2HcPpi;\r
+  UINT8                         ConfigurationData[1024];\r
+  EFI_USB_CONFIG_DESCRIPTOR     *ConfigDesc;\r
+  EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDesc;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR   *EndpointDesc[MAX_ENDPOINT];\r
+  EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;  \r
+} PEI_USB_DEVICE;\r
+\r
+#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE)\r
+\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+  \r
+  @param  PeiServices            The pointer of EFI_PEI_SERVICES.\r
+  @param  This                   The pointer of PEI_USB_IO_PPI.\r
+  @param  Request                USB device request to send.\r
+  @param  Direction              Specifies the data direction for the data stage.\r
+  @param  Timeout                Indicates the maximum timeout, in millisecond.\r
+  @param  Data                   Data buffer to be transmitted or received from USB device.\r
+  @param  DataLength             The size (in bytes) of the data buffer.\r
+\r
+  @retval EFI_SUCCESS            Transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.\r
+  @retval EFI_TIMEOUT            Transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbControlTransfer (\r
+  IN     EFI_PEI_SERVICES          **PeiServices,\r
+  IN     PEI_USB_IO_PPI            *This,\r
+  IN     EFI_USB_DEVICE_REQUEST    *Request,\r
+  IN     EFI_USB_DATA_DIRECTION    Direction,\r
+  IN     UINT32                    Timeout,\r
+  IN OUT VOID                      *Data,      OPTIONAL\r
+  IN     UINTN                     DataLength  OPTIONAL\r
+  );\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+  \r
+  @param  PeiServices           The pointer of EFI_PEI_SERVICES.\r
+  @param  This                  The pointer of PEI_USB_IO_PPI.\r
+  @param  DeviceEndpoint        Endpoint number and its direction in bit 7.\r
+  @param  Data                  A pointer to the buffer of data to transmit \r
+                                from or receive into.\r
+  @param  DataLength            The lenght of the data buffer.\r
+  @param  Timeout               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbBulkTransfer (\r
+  IN     EFI_PEI_SERVICES    **PeiServices,\r
+  IN     PEI_USB_IO_PPI      *This,\r
+  IN     UINT8               DeviceEndpoint,\r
+  IN OUT VOID                *Data,\r
+  IN OUT UINTN               *DataLength,\r
+  IN     UINTN               Timeout\r
+  );\r
+\r
+/**\r
+  Get the usb interface descriptor.\r
+\r
+  @param  PeiServices          General-purpose services that are available to every PEIM.\r
+  @param  This                 Indicates the PEI_USB_IO_PPI instance.\r
+  @param  InterfaceDescriptor  Request interface descriptor.\r
+\r
+\r
+  @retval EFI_SUCCESS          Usb interface descriptor is obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetInterfaceDescriptor (\r
+  IN  EFI_PEI_SERVICES                **PeiServices,\r
+  IN  PEI_USB_IO_PPI                  *This,\r
+  OUT EFI_USB_INTERFACE_DESCRIPTOR    **InterfaceDescriptor\r
+  );\r
+\r
+/**\r
+  Get the usb endpoint descriptor.\r
+\r
+  @param  PeiServices          General-purpose services that are available to every PEIM.\r
+  @param  This                 Indicates the PEI_USB_IO_PPI instance.\r
+  @param  EndpointIndex        The valid index of the specified endpoint.\r
+  @param  EndpointDescriptor   Request endpoint descriptor.\r
+\r
+  @retval EFI_SUCCESS       Usb endpoint descriptor is obtained successfully.\r
+  @retval EFI_NOT_FOUND     Usb endpoint descriptor is NOT found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetEndpointDescriptor (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  PEI_USB_IO_PPI                 *This,\r
+  IN  UINT8                          EndpointIndex,\r
+  OUT EFI_USB_ENDPOINT_DESCRIPTOR    **EndpointDescriptor\r
+  );\r
+\r
+/**\r
+  Reset the port and re-configure the usb device.\r
+\r
+  @param  PeiServices    General-purpose services that are available to every PEIM.\r
+  @param  This           Indicates the PEI_USB_IO_PPI instance.\r
+\r
+  @retval EFI_SUCCESS    Usb device is reset and configured successfully.\r
+  @retval Others         Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbPortReset (\r
+  IN EFI_PEI_SERVICES    **PeiServices,\r
+  IN PEI_USB_IO_PPI      *This\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
+#endif\r
diff --git a/MdeModulePkg/Include/Ppi/Usb2HostController.h b/MdeModulePkg/Include/Ppi/Usb2HostController.h
new file mode 100644 (file)
index 0000000..e6d00ee
--- /dev/null
@@ -0,0 +1,263 @@
+/** @file\r
+  Defines the USB Host Controller PPI that provides I/O services for a USB Host \r
+  Controller that may be used to access recovery devices.  These interfaces are \r
+  modeled on the UEFI 2.3 specification EFI_USB2_HOST_CONTROLLER_PROTOCOL.\r
+  Refer to section 16.1 of the UEFI 2.3 Specification for more information on \r
+  these interfaces.\r
\r
+Copyright (c) 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
+#ifndef _PEI_USB2_HOST_CONTROLLER_PPI_H_\r
+#define _PEI_USB2_HOST_CONTROLLER_PPI_H_\r
+\r
+#include <Protocol/Usb2HostController.h>\r
+\r
+///\r
+/// Global ID for the PEI_USB2_HOST_CONTROLLER_PPI.\r
+///\r
+#define PEI_USB2_HOST_CONTROLLER_PPI_GUID \\r
+  { \\r
+    0xa7d09fe1, 0x74d4, 0x4ba5, { 0x84, 0x7c, 0x12, 0xed, 0x5b, 0x19, 0xad, 0xe4 } \\r
+  }\r
+\r
+///\r
+/// Forward declaration for the PEI_USB2_HOST_CONTROLLER_PPI.\r
+///\r
+typedef struct _PEI_USB2_HOST_CONTROLLER_PPI PEI_USB2_HOST_CONTROLLER_PPI;\r
+\r
+/**\r
+  Initiate a USB control transfer using a specific USB Host controller on the USB bus. \r
+\r
+  @param[in]     PeiServices           The pointer to the PEI Services Table.\r
+  @param[in]     This                  The pointer to this instance of the \r
+                                       PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param[in]     DeviceAddress         Represents the address of the target device \r
+                                       on the USB.\r
+  @param[in]     DeviceSpeed           Indicates device speed.\r
+  @param[in]     MaximumPacketLength   Indicates the maximum packet size that the \r
+                                       default control transfer\r
+                                       endpoint is capable of sending or receiving.\r
+  @param[in]     Request               A pointer to the USB device request that \r
+                                       will be sent to the USB device.\r
+  @param[in]     TransferDirection     Specifies the data direction for the transfer. \r
+                                       There are three values available: \r
+                                       EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.\r
+  @param[in,out] Data                  A pointer to the buffer of data that will \r
+                                       be transmitted to USB device or\r
+                                       received from USB device.\r
+  @param[in,out] DataLength            On input, indicates the size, in bytes, of \r
+                                       the data buffer specified by Data.\r
+                                       On output, indicates the amount of data \r
+                                       actually transferred.\r
+  @param[in]     TimeOut               Indicates the maximum time, in milliseconds, \r
+                                       that the transfer is allowed to complete.\r
+  @param[in]     Translator            A pointer to the transaction translator data.\r
+  @param[out]    TransferResult        A pointer to the detailed result information \r
+                                       generated by this control transfer.\r
+\r
+  @retval EFI_SUCCESS           The control transfer was completed successfully.\r
+  @retval EFI_DEVICE_ERROR      The control transfer failed due to host controller \r
+                                or device error.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The control transfer could not be completed due to a lack of resources.\r
+  @retval EFI_TIMEOUT           The control transfer failed due to timeout.\r
+  \r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_CONTROL_TRANSFER)(\r
+  IN EFI_PEI_SERVICES                         **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI             *This,\r
+  IN     UINT8                                DeviceAddress,\r
+  IN     UINT8                                DeviceSpeed,\r
+  IN     UINTN                                MaximumPacketLength,\r
+  IN     USB_DEVICE_REQUEST                   *Request,\r
+  IN     EFI_USB_DATA_DIRECTION               TransferDirection,\r
+  IN OUT VOID                                 *Data OPTIONAL,\r
+  IN OUT UINTN                                *DataLength OPTIONAL,\r
+  IN     UINTN                                TimeOut,\r
+  IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR   *Translator,\r
+  OUT    UINT32                               *TransferResult\r
+  );\r
+\r
+/**\r
+  Initiate a USB bulk transfer using a specific USB Host controller on the USB bus. \r
+\r
+  @param[in]     PeiServices           The pointer to the PEI Services Table.\r
+  @param[in]     This                  The pointer to this instance of the \r
+                                       PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param[in]     DeviceAddress         Represents the address of the target device \r
+                                       on the USB.\r
+  @param[in]     EndPointAddress       The combination of an endpoint number and \r
+                                       an endpoint direction of the target USB device.\r
+  @param[in]     DeviceSpeed           Indicates device speed.\r
+  @param[in]     MaximumPacketLength   Indicates the maximum packet size the target \r
+                                       endpoint is capable of sending or receiving.\r
+  @param[in,out] Data                  Array of pointers to the buffers of data \r
+                                       that will be transmitted to USB device or \r
+                                       received from USB device.\r
+  @param[in,out] DataLength            When input, indicates the size, in bytes, of  \r
+                                       the data buffers specified by Data. When output,\r
+                                       indicates the data size actually transferred.\r
+  @param[in,out] DataToggle            A pointer to the data toggle value.\r
+  @param[in]     TimeOut               Indicates the maximum time, in milliseconds,\r
+                                       in which the transfer is allowed to complete.\r
+  @param[in]     Translator            A pointer to the transaction translator data.\r
+  @param[out]    TransferResult        A pointer to the detailed result information \r
+                                       of the bulk transfer.\r
+\r
+  @retval EFI_SUCCESS           The bulk transfer was completed successfully.\r
+  @retval EFI_DEVICE_ERROR      The bulk transfer failed due to host controller or device error.\r
+                                Caller should check TransferResult for detailed error information.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The bulk transfer could not be submitted due to a lack of resources.\r
+  @retval EFI_TIMEOUT           The bulk transfer failed due to timeout.  \r
+  \r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_BULK_TRANSFER)(\r
+  IN     EFI_PEI_SERVICES                    **PeiServices,\r
+  IN     PEI_USB2_HOST_CONTROLLER_PPI        *This,\r
+  IN     UINT8                               DeviceAddress,\r
+  IN     UINT8                               EndPointAddress,\r
+  IN     UINT8                               DeviceSpeed,  \r
+  IN     UINTN                               MaximumPacketLength,\r
+  IN OUT VOID                                *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+  IN OUT UINTN                               *DataLength,\r
+  IN OUT UINT8                               *DataToggle,\r
+  IN     UINTN                               TimeOut,\r
+  IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT    UINT32                              *TransferResult\r
+  );\r
+\r
+/**\r
+  Retrieves the number of root hub ports.\r
+\r
+  @param[in]  PeiServices       The pointer to the PEI Services Table.\r
+  @param[in]  This              The pointer to this instance of the \r
+                                PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param[out] PortNumber        The pointer to the number of the root hub ports.                                \r
+                                \r
+  @retval EFI_SUCCESS           The port number was retrieved successfully.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER)(\r
+  IN  EFI_PEI_SERVICES              **PeiServices,\r
+  IN  PEI_USB2_HOST_CONTROLLER_PPI  *This,\r
+  OUT UINT8                         *PortNumber\r
+  );\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port.\r
+\r
+  @param[in]  PeiServices       The pointer to the PEI Services Table.\r
+  @param[in]  This              The pointer to this instance of the \r
+                                PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param[in]  PortNumber        Specifies the root hub port from which the status is \r
+                                to be retrieved.\r
+                                This value is zero based.\r
+  @param[out] PortStatus        A pointer to the current port status bits and port \r
+                                status change bits.\r
+  \r
+  @retval EFI_SUCCESS           The status of the USB root hub port specified by \r
+                                PortNumber was returned in PortStatus.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS)(\r
+  IN  EFI_PEI_SERVICES              **PeiServices,\r
+  IN  PEI_USB2_HOST_CONTROLLER_PPI  *This,\r
+  IN  UINT8                         PortNumber,\r
+  OUT EFI_USB_PORT_STATUS           *PortStatus\r
+  );\r
+\r
+/**\r
+  Sets a feature for the specified root hub port.\r
+\r
+  @param[in] PeiServices        The pointer to the PEI Services Table.\r
+  @param[in] This               The pointer to this instance of the \r
+                                PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param[in] PortNumber         Specifies the root hub port whose feature is requested \r
+                                to be set. This value is zero based.\r
+  @param[in] PortFeature        Indicates the feature selector associated with the feature \r
+                                set request.\r
+  \r
+  @retval EFI_SUCCESS           The feature specified by PortFeature was set for \r
+                                the USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid \r
+                                for this function.\r
+  @retval EFI_TIMEOUT           The time out occurred                                \r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE)(\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,\r
+  IN UINT8                          PortNumber,\r
+  IN EFI_USB_PORT_FEATURE           PortFeature\r
+  );\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+\r
+  @param[in] PeiServices          The pointer to the PEI Services Table.\r
+  @param[in] This                 The pointer to this instance of the \r
+                                  PEI_USB2_HOST_CONTROLLER_PPI.\r
+  @param[in] PortNumber           Specifies the root hub port whose feature is\r
+                                  requested to be cleared.\r
+  @param[in] PortFeature          Indicates the feature selector associated with the\r
+                                  feature clear request.\r
+\r
+  @return EFI_SUCCESS             The feature specified by PortFeature was cleared\r
+                                  for the USB root hub port specified by PortNumber.\r
+  @return EFI_INVALID_PARAMETER   PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE)(\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB2_HOST_CONTROLLER_PPI   *This,\r
+  IN UINT8                          PortNumber,\r
+  IN EFI_USB_PORT_FEATURE           PortFeature\r
+  );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the USB host controller.\r
+/// These interfaces are modeled on the UEFI 2.3 specification protocol\r
+/// EFI_USB2_HOST_CONTROLLER_PROTOCOL.  Refer to section 16.1 of the UEFI 2.3 \r
+/// Specification for more information on these interfaces.\r
+///\r
+struct _PEI_USB2_HOST_CONTROLLER_PPI {\r
+  PEI_USB2_HOST_CONTROLLER_CONTROL_TRANSFER            ControlTransfer;\r
+  PEI_USB2_HOST_CONTROLLER_BULK_TRANSFER               BulkTransfer;\r
+  PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER     GetRootHubPortNumber;\r
+  PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS     GetRootHubPortStatus;\r
+  PEI_USB2_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE    SetRootHubPortFeature;\r
+  PEI_USB2_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE  ClearRootHubPortFeature;\r
+};\r
+\r
+extern EFI_GUID gPeiUsb2HostControllerPpiGuid;\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Include/Ppi/UsbController.h b/MdeModulePkg/Include/Ppi/UsbController.h
new file mode 100644 (file)
index 0000000..10e025d
--- /dev/null
@@ -0,0 +1,88 @@
+/** @file\r
+  Define APIs to retrieve USB Host Controller Info such as controller type and \r
+  I/O Port Base Address.\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
+#ifndef _PEI_USB_CONTROLLER_PPI_H_\r
+#define _PEI_USB_CONTROLLER_PPI_H_\r
+\r
+///\r
+/// Global ID for the PEI_USB_CONTROLLER_PPI.\r
+///\r
+#define PEI_USB_CONTROLLER_PPI_GUID \\r
+  { \\r
+    0x3bc1f6de, 0x693e, 0x4547,{ 0xa3, 0x0, 0x21, 0x82, 0x3c, 0xa4, 0x20, 0xb2} \\r
+  }\r
+\r
+///\r
+/// Forward declaration for the PEI_USB_CONTROLLER_PPI.\r
+///\r
+typedef struct _PEI_USB_CONTROLLER_PPI PEI_USB_CONTROLLER_PPI;\r
+\r
+///\r
+/// This bit is used in the ControllerType return parameter of GetUsbController()\r
+/// to identify the USB Host Controller type as UHCI\r
+///\r
+#define PEI_UHCI_CONTROLLER 0x01\r
+\r
+///\r
+/// This bit is used in the ControllerType return parameter of GetUsbController()\r
+/// to identify the USB Host Controller type as OHCI\r
+///\r
+#define PEI_OHCI_CONTROLLER 0x02\r
+\r
+///\r
+/// This bit is used in the ControllerType return parameter of GetUsbController()\r
+/// to identify the USB Host Controller type as EHCI\r
+///\r
+#define PEI_EHCI_CONTROLLER 0x03\r
+\r
+/**\r
+  Retrieve USB Host Controller Info such as controller type and I/O Base Address.\r
+\r
+  @param[in]  PeiServices      The pointer to the PEI Services Table.\r
+  @param[in]  This             The pointer to this instance of the PEI_USB_CONTROLLER_PPI.\r
+  @param[in]  ControllerId     The ID of the USB controller.\r
+  @param[out] ControllerType   On output, returns the type of the USB controller.\r
+  @param[out] BaseAddress      On output, returns the base address of UHCI's I/O ports\r
+                               if UHCI is enabled or the base address of EHCI's MMIO \r
+                               if EHCI is enabled.\r
+\r
+  @retval EFI_SUCCESS             USB controller attributes were returned successfully.\r
+  @retval EFI_INVALID_PARAMETER   ControllerId is greater than the maximum number \r
+                                  of USB controller supported by this platform.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_GET_USB_CONTROLLER)(\r
+  IN  EFI_PEI_SERVICES        **PeiServices,\r
+  IN  PEI_USB_CONTROLLER_PPI  *This,\r
+  IN  UINT8                   UsbControllerId,\r
+  OUT UINTN                   *ControllerType,\r
+  OUT UINTN                   *BaseAddress\r
+  );\r
+\r
+///\r
+/// This PPI contains a single service to retrieve the USB Host Controller type\r
+/// and the base address of the I/O ports used to access the USB Host Controller.\r
+///\r
+struct _PEI_USB_CONTROLLER_PPI {\r
+  PEI_GET_USB_CONTROLLER  GetUsbController;\r
+};\r
+\r
+extern EFI_GUID gPeiUsbControllerPpiGuid;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Include/Ppi/UsbHostController.h b/MdeModulePkg/Include/Ppi/UsbHostController.h
new file mode 100644 (file)
index 0000000..107b799
--- /dev/null
@@ -0,0 +1,251 @@
+/** @file\r
+  Defines the USB Host Controller PPI that provides I/O services for a USB Host \r
+  Controller that may be used to access recovery devices.  These interfaces are \r
+  modeled on the UEFI 2.3 specification EFI_USB2_HOST_CONTROLLER_PROTOCOL.\r
+  Refer to section 16.1 of the UEFI 2.3 Specification for more information on \r
+  these interfaces.\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
+#ifndef _PEI_USB_HOST_CONTROLLER_PPI_H_\r
+#define _PEI_USB_HOST_CONTROLLER_PPI_H_\r
+\r
+#include <Protocol/Usb2HostController.h>\r
+\r
+///\r
+/// Global ID for the PEI_USB_HOST_CONTROLLER_PPI.\r
+///\r
+#define PEI_USB_HOST_CONTROLLER_PPI_GUID \\r
+  { \\r
+    0x652b38a9, 0x77f4, 0x453f, { 0x89, 0xd5, 0xe7, 0xbd, 0xc3, 0x52, 0xfc, 0x53} \\r
+  }\r
+\r
+///\r
+/// Forward declaration for the PEI_USB_HOST_CONTROLLER_PPI.\r
+///\r
+typedef struct _PEI_USB_HOST_CONTROLLER_PPI PEI_USB_HOST_CONTROLLER_PPI;\r
+\r
+/**\r
+  Initiate a USB control transfer using a specific USB Host controller on the USB bus. \r
+\r
+  @param[in]     PeiServices           The pointer to the PEI Services Table.\r
+  @param[in]     This                  The pointer to this instance of the \r
+                                       PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param[in]     DeviceAddress         Represents the address of the target device \r
+                                       on the USB.\r
+  @param[in]     DeviceSpeed           Indicates device speed.\r
+  @param[in]     MaximumPacketLength   Indicates the maximum packet size that the \r
+                                       default control transfer\r
+                                       endpoint is capable of sending or receiving.\r
+  @param[in]     Request               A pointer to the USB device request that \r
+                                       will be sent to the USB device.\r
+  @param[in]     TransferDirection     Specifies the data direction for the transfer. \r
+                                       There are three values available: \r
+                                       EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.\r
+  @param[in,out] Data                  A pointer to the buffer of data that will \r
+                                       be transmitted to USB device or\r
+                                       received from USB device.\r
+  @param[in,out] DataLength            On input, indicates the size, in bytes, of \r
+                                       the data buffer specified by Data.\r
+                                       On output, indicates the amount of data \r
+                                       actually transferred.\r
+  @param[in]     TimeOut               Indicates the maximum time, in milliseconds, \r
+                                       that the transfer is allowed to complete.\r
+  @param[out]    TransferResult        A pointer to the detailed result information \r
+                                       generated by this control transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR   The control transfer failed due to host controller \r
+                             or device error.\r
+  @retval EFI_SUCCESS        The control transfer was completed successfully.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_CONTROL_TRANSFER)(\r
+  IN EFI_PEI_SERVICES             **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,\r
+  IN     UINT8                    DeviceAddress,\r
+  IN     UINT8                    DeviceSpeed,\r
+  IN     UINT8                    MaximumPacketLength,\r
+  IN     USB_DEVICE_REQUEST       *Request,\r
+  IN     EFI_USB_DATA_DIRECTION   TransferDirection,\r
+  IN OUT VOID                     *Data OPTIONAL,\r
+  IN OUT UINTN                    *DataLength OPTIONAL,\r
+  IN     UINTN                    TimeOut,\r
+  OUT    UINT32                   *TransferResult\r
+  );\r
+\r
+/**\r
+  Initiate a USB bulk transfer using a specific USB Host controller on the USB bus. \r
+\r
+  @param[in]     PeiServices           The pointer to the PEI Services Table.\r
+  @param[in]     This                  The pointer to this instance of the \r
+                                       PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param[in]     DeviceAddress         Represents the address of the target device \r
+                                       on the USB.\r
+  @param[in]     EndPointAddress       The combination of an endpoint number and \r
+                                       an endpoint direction of the target USB device.\r
+  @param[in]     MaximumPacketLength   Indicates the maximum packet size the target \r
+                                       endpoint is capable of sending or receiving.\r
+  @param[in,out] Data                  Array of pointers to the buffers of data \r
+                                       that will be transmitted to USB device or \r
+                                       received from USB device.\r
+  @param[in,out] DataLength            When input, indicates the size, in bytes, of  \r
+                                       the data buffers specified by Data. When output,\r
+                                       indicates the data size actually transferred.\r
+  @param[in,out] DataToggle            A pointer to the data toggle value.\r
+  @param[in]     TimeOut               Indicates the maximum time, in milliseconds,\r
+                                       in which the transfer is allowed to complete.\r
+  @param[out]    TransferResult        A pointer to the detailed result information \r
+                                       of the bulk transfer.\r
+\r
+  @retval EFI_SUCCESS           The bulk transfer was completed successfully.\r
+  @retval EFI_DEVICE_ERROR      The bulk transfer failed due to host controller or device error.\r
+                                Caller should check TransferResult for detailed error information.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_BULK_TRANSFER)(\r
+  IN     EFI_PEI_SERVICES             **PeiServices,\r
+  IN     PEI_USB_HOST_CONTROLLER_PPI  *This,\r
+  IN     UINT8                        DeviceAddress,\r
+  IN     UINT8                        EndPointAddress,\r
+  IN     UINT8                        MaximumPacketLength,\r
+  IN OUT VOID                         *Data,\r
+  IN OUT UINTN                        *DataLength,\r
+  IN OUT UINT8                        *DataToggle,\r
+  IN     UINTN                        TimeOut,\r
+  OUT    UINT32                       *TransferResult\r
+  );\r
+\r
+/**\r
+  Retrieves the number of root hub ports.\r
+\r
+  @param[in]  PeiServices   The pointer to the PEI Services Table.\r
+  @param[in]  This          The pointer to this instance of the \r
+                            PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param[out] PortNumber    The pointer to the number of the root hub ports.                                \r
+                                \r
+  @retval EFI_SUCCESS           The port number was retrieved successfully.\r
+  @retval EFI_DEVICE_ERROR      An error was encountered while attempting to retrieve \r
+                                the port number.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER)(\r
+  IN  EFI_PEI_SERVICES             **PeiServices,\r
+  IN  PEI_USB_HOST_CONTROLLER_PPI  *This,\r
+  OUT UINT8                        *PortNumber\r
+  );\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port.\r
+\r
+  @param[in]  PeiServices   The pointer to the PEI Services Table.\r
+  @param[in]  This          The pointer to this instance of the \r
+                            PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param[in]  PortNumber    Specifies the root hub port from which the status is \r
+                            to be retrieved.\r
+                            This value is zero based.\r
+  @param[out] PortStatus    A pointer to the current port status bits and port \r
+                            status change bits.\r
+  \r
+  @retval EFI_SUCCESS           The status of the USB root hub port specified by \r
+                                PortNumber was returned in PortStatus.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS)(\r
+  IN  EFI_PEI_SERVICES             **PeiServices,\r
+  IN  PEI_USB_HOST_CONTROLLER_PPI  *This,\r
+  IN  UINT8                        PortNumber,\r
+  OUT EFI_USB_PORT_STATUS          *PortStatus\r
+  );\r
+\r
+/**\r
+  Sets a feature for the specified root hub port.\r
+\r
+  @param[in] PeiServices   The pointer to the PEI Services Table.\r
+  @param[in] This          The pointer to this instance of the \r
+                           PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param[in] PortNumber    Specifies the root hub port whose feature is requested \r
+                           to be set. This value is zero based.\r
+  @param[in] PortFeature   Indicates the feature selector associated with the feature \r
+                           set request.\r
+  \r
+  @retval EFI_SUCCESS           The feature specified by PortFeature was set for \r
+                                the USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid \r
+                                for this function.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE)(\r
+  IN EFI_PEI_SERVICES             **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,\r
+  IN UINT8                        PortNumber,\r
+  IN EFI_USB_PORT_FEATURE         PortFeature\r
+  );\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+\r
+  @param[in] PeiServices   The pointer to the PEI Services Table.\r
+  @param[in] This          The pointer to this instance of the \r
+                           PEI_USB_HOST_CONTROLLER_PPI.\r
+  @param[in] PortNumber    Specifies the root hub port whose feature is\r
+                           requested to be cleared.\r
+  @param[in] PortFeature   Indicates the feature selector associated with the\r
+                           feature clear request.\r
+\r
+  @return EFI_SUCCESS             The feature specified by PortFeature was cleared\r
+                                  for the USB root hub port specified by PortNumber.\r
+  @return EFI_INVALID_PARAMETER   PortNumber is invalid or PortFeature is invalid.\r
+  @return EFI_DEVICE_ERROR        Can't read the register.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE)(\r
+  IN EFI_PEI_SERVICES             **PeiServices,\r
+  IN PEI_USB_HOST_CONTROLLER_PPI  *This,\r
+  IN UINT8                        PortNumber,\r
+  IN EFI_USB_PORT_FEATURE         PortFeature\r
+  );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the USB host controller.\r
+/// These interfaces are modeled on the UEFI 2.3 specification protocol\r
+/// EFI_USB2_HOST_CONTROLLER_PROTOCOL.  Refer to section 16.1 of the UEFI 2.3 \r
+/// Specification for more information on these interfaces.\r
+///\r
+struct _PEI_USB_HOST_CONTROLLER_PPI {\r
+  PEI_USB_HOST_CONTROLLER_CONTROL_TRANSFER            ControlTransfer;\r
+  PEI_USB_HOST_CONTROLLER_BULK_TRANSFER               BulkTransfer;\r
+  PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER     GetRootHubPortNumber;\r
+  PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS     GetRootHubPortStatus;\r
+  PEI_USB_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE    SetRootHubPortFeature;\r
+  PEI_USB_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE  ClearRootHubPortFeature;\r
+};\r
+\r
+extern EFI_GUID gPeiUsbHostControllerPpiGuid;\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Include/Ppi/UsbIo.h b/MdeModulePkg/Include/Ppi/UsbIo.h
new file mode 100644 (file)
index 0000000..16660f8
--- /dev/null
@@ -0,0 +1,190 @@
+/** @file\r
+  Defines the PEI_USB_IO_PPI that the USB-related PEIM can use for I/O operations \r
+  on the USB BUS.  This interface enables recovery from a \r
+  USB-class storage device, such as USB CD/DVD, USB hard drive, or USB FLASH \r
+  drive.  These interfaces are modeled on the UEFI 2.3 specification EFI_USB_IO_PROTOCOL.\r
+  Refer to section 16.2.4 of the UEFI 2.3 Specification for more information on \r
+  these interfaces.\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
+#ifndef _PEI_USB_IO_PPI_H_\r
+#define _PEI_USB_IO_PPI_H_\r
+\r
+#include <Protocol/Usb2HostController.h>\r
+\r
+///\r
+/// Global ID for the PEI_USB_IO_PPI.\r
+///\r
+#define PEI_USB_IO_PPI_GUID \\r
+  { \\r
+    0x7c29785c, 0x66b9, 0x49fc, { 0xb7, 0x97, 0x1c, 0xa5, 0x55, 0xe, 0xf2, 0x83} \\r
+  }\r
+\r
+///\r
+/// Forward declaration for the PEI_USB_IO_PPI.\r
+///\r
+typedef struct _PEI_USB_IO_PPI  PEI_USB_IO_PPI;\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+\r
+  @param[in]     PeiServices   The pointer to the PEI Services Table.\r
+  @param[in]     This          The pointer to this instance of the PEI_USB_IO_PPI.\r
+  @param[in]     Request       A pointer to the USB device request that will be \r
+                               sent to the USB device.\r
+  @param[in]     Direction     Specifies the data direction for the transfer. There \r
+                               are three values available: \r
+                               EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.\r
+  @param[in]     TimeOut       Indicates the maximum time, in milliseconds, that \r
+                               the transfer is allowed to complete.\r
+  @param[in,out] Data          A pointer to the buffer of data that will be \r
+                               transmitted to or received from the USB device.\r
+  @param[in]     DataLength    On input, indicates the size, in bytes, of the data \r
+                               buffer specified by Data.\r
+                               \r
+  @retval EFI_SUCCESS             The control transfer was completed successfully.\r
+  @retval EFI_INVALID_PARAMETER   Some parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES    The control transfer could not be completed due \r
+                                  to a lack of resources.\r
+  @retval EFI_TIMEOUT             The control transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR        The control transfer failed due to host controller \r
+                                  or device error.\r
+                                  Caller should check TransferResult for detailed \r
+                                  error information.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_CONTROL_TRANSFER)(\r
+  IN     EFI_PEI_SERVICES        **PeiServices,\r
+  IN     PEI_USB_IO_PPI          *This,\r
+  IN     EFI_USB_DEVICE_REQUEST  *Request,\r
+  IN     EFI_USB_DATA_DIRECTION  Direction,\r
+  IN     UINT32                  Timeout,\r
+  IN OUT VOID                    *Data OPTIONAL,\r
+  IN     UINTN                   DataLength  OPTIONAL\r
+  );\r
+\r
+/**\r
+  Submits bulk transfer to a target USB device.\r
+\r
+  @param[in] PeiServices       The pointer to the PEI Services Table.\r
+  @param[in] This              The pointer to this instance of the PEI_USB_IO_PPI.\r
+  @param[in] EndPointAddress   The endpoint address.\r
+  @param[in] Data              The data buffer to be transfered.\r
+  @param[in] DataLength        The length of data buffer.\r
+  @param[in] TimeOut           The timeout for the transfer, in milliseconds.\r
+\r
+  @retval EFI_SUCCESS             The bulk transfer completed successfully.\r
+  @retval EFI_INVALID_PARAMETER   Some parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES    The bulk transfer could not be completed due to \r
+                                  a lack of resources.\r
+  @retval EFI_TIMEOUT             The bulk transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR        The bulk transfer failed due to host controller \r
+                                  or device error.\r
+                                  Caller should check TransferResult for detailed \r
+                                  error information.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_BULK_TRANSFER)(\r
+  IN EFI_PEI_SERVICES  **PeiServices,\r
+  IN PEI_USB_IO_PPI    *This,\r
+  IN UINT8             DeviceEndpoint,\r
+  IN OUT VOID          *Data,\r
+  IN OUT UINTN         *DataLength,\r
+  IN UINTN             Timeout\r
+  );\r
+\r
+/**\r
+  Get interface descriptor from a USB device.\r
+\r
+  @param[in] PeiServices           The pointer to the PEI Services Table.\r
+  @param[in] This                  The pointer to this instance of the PEI_USB_IO_PPI.\r
+  @param[in] InterfaceDescriptor   The interface descriptor.\r
+\r
+  @retval EFI_SUCCESS             The interface descriptor was returned.\r
+  @retval EFI_INVALID_PARAMETER   Some parameters are invalid.\r
+  @retval EFI_DEVICE_ERROR        A device error occurred, the function failed to \r
+                                  get the interface descriptor.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_GET_INTERFACE_DESCRIPTOR)(\r
+  IN EFI_PEI_SERVICES              **PeiServices,\r
+  IN PEI_USB_IO_PPI                *This,\r
+  IN EFI_USB_INTERFACE_DESCRIPTOR  **InterfaceDescriptor\r
+  );\r
+\r
+/**\r
+  Get endpoint descriptor from a USB device.\r
+\r
+  @param[in] PeiServices          The pointer to the PEI Services Table.\r
+  @param[in] This                 The pointer to this instance of the PEI_USB_IO_PPI.\r
+  @param[in] EndPointIndex        The index of the end point.\r
+  @param[in] EndpointDescriptor   The endpoint descriptor.\r
+\r
+  @retval EFI_SUCCESS             The endpoint descriptor was returned.\r
+  @retval EFI_INVALID_PARAMETER   Some parameters are invalid.\r
+  @retval EFI_DEVICE_ERROR        A device error occurred, the function failed to \r
+                                  get the endpoint descriptor.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_GET_ENDPOINT_DESCRIPTOR)(\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN PEI_USB_IO_PPI                 *This,\r
+  IN UINT8                          EndpointIndex,\r
+  IN EFI_USB_ENDPOINT_DESCRIPTOR    **EndpointDescriptor\r
+  );\r
+\r
+/**\r
+  Issue a port reset to the device.\r
+\r
+  @param[in] PeiServices   The pointer to the PEI Services Table.\r
+  @param[in] This          The pointer to this instance of the PEI_USB_IO_PPI.\r
+\r
+  @retval EFI_SUCCESS             The port reset was issued successfully.\r
+  @retval EFI_INVALID_PARAMETER   Some parameters are invalid.\r
+  @retval EFI_DEVICE_ERROR        Device error occurred.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_PORT_RESET)(\r
+  IN EFI_PEI_SERVICES  **PeiServices,\r
+  IN PEI_USB_IO_PPI    *This\r
+  );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the USB host controller.\r
+/// These interfaces are modeled on the UEFI 2.3 specification EFI_USB_IO_PROTOCOL.\r
+/// Refer to section 16.2.4 of the UEFI 2.3 Specification for more information on \r
+/// these interfaces.\r
+///\r
+struct _PEI_USB_IO_PPI {\r
+  PEI_USB_CONTROL_TRANSFER          UsbControlTransfer;\r
+  PEI_USB_BULK_TRANSFER             UsbBulkTransfer;\r
+  PEI_USB_GET_INTERFACE_DESCRIPTOR  UsbGetInterfaceDescriptor;\r
+  PEI_USB_GET_ENDPOINT_DESCRIPTOR   UsbGetEndpointDescriptor;\r
+  PEI_USB_PORT_RESET                UsbPortReset;\r
+};\r
+\r
+extern EFI_GUID gPeiUsbIoPpiGuid;\r
+\r
+#endif\r
index f2dbb7155621ac884b54e605f8a010199fafe63b..0987b7955d2db997dee646d80b735d129f44d043 100644 (file)
   #  Include/Guid/EventIdle.h\r
   gIdleLoopEventGuid  = { 0x3c8d294c, 0x5fc3, 0x4451, { 0xbb, 0x31, 0xc4, 0xc0, 0x32, 0x29, 0x5e, 0x6c } }\r
 \r
+[Ppis]\r
+  ## Include/Ppi/UsbHostController.h\r
+  gPeiUsbHostControllerPpiGuid   = { 0x652B38A9, 0x77F4, 0x453F, { 0x89, 0xD5, 0xE7, 0xBD, 0xC3, 0x52, 0xFC, 0x53 }}\r
+\r
+  ## Include/Ppi/Usb2HostController.h\r
+  gPeiUsb2HostControllerPpiGuid  = { 0xfedd6305, 0xe2d7, 0x4ed5, { 0x9f, 0xaa, 0xda, 0x8, 0xe, 0x33, 0x6c, 0x22   }}\r
+\r
+  ## Include/Ppi/UsbController.h\r
+  gPeiUsbControllerPpiGuid       = { 0x3BC1F6DE, 0x693E, 0x4547, { 0xA3, 0x00, 0x21, 0x82, 0x3C, 0xA4, 0x20, 0xB2 }}\r
+\r
+  ## Include/Ppi/UsbIo.h\r
+  gPeiUsbIoPpiGuid               = { 0x7C29785C, 0x66B9, 0x49FC, { 0xB7, 0x97, 0x1C, 0xA5, 0x55, 0x0E, 0xF2, 0x83 }}\r
+\r
 [Protocols]\r
   ## Load File protocol provides capability to load and unload EFI image into memory and execute it.\r
   #  Include/Protocol/LoadPe32Image.h\r
index 5fd84ee5fb4a93f534a423715f925842bee85e29..a81e4d8f7aa1a5855b5ca257fba77ed96f3b3574 100644 (file)
   MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
   MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf\r
   MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf\r
+  MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf\r
+  MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf\r
+  MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf\r
+  MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf\r
   MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf\r
   MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf\r
   MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf\r