]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Import EhciDxe and UhciDxe into MdeModulePkg.
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 11 Jul 2007 06:46:38 +0000 (06:46 +0000)
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 11 Jul 2007 06:46:38 +0000 (06:46 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3191 6f19259b-4bc3-4df7-8a09-765794883524

30 files changed:
MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/Ehci.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/Ehci.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/Ehci.msa [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/Uhci.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/Uhci.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/Uhci.msa [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.h [new file with mode: 0644]

diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/EhciDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..5595217
--- /dev/null
@@ -0,0 +1,200 @@
+/** @file\r
+\r
+Copyright 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Ehci.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+EhciComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EhciComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      ControllerHandle,\r
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL     gEhciComponentName = {\r
+  EhciComponentNameGetDriverName,\r
+  EhciComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mEhciDriverNameTable[] = {\r
+  { "eng", L"Usb Ehci Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EhciComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **DriverName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+  Arguments:\r
+    This       - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    Language   - A pointer to a three character ISO 639-2 language identifier.\r
+                 This is the language of the driver name that that the caller\r
+                 is requesting, and it must match one of the languages specified\r
+                 in SupportedLanguages.  The number of languages supported by a\r
+                 driver is up to the driver writer.\r
+    DriverName - A pointer to the Unicode string to return.  This Unicode string\r
+                 is the name of the driver specified by This in the language\r
+                 specified by Language.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the Driver specified by This\r
+                            and the language specified by Language was returned\r
+                            in DriverName.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - DriverName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gEhciComponentName.SupportedLanguages,\r
+          mEhciDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EhciComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      ControllerHandle,\r
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **ControllerName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the controller\r
+    that is being managed by an EFI Driver.\r
+\r
+  Arguments:\r
+    This             - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    ControllerHandle - The handle of a controller that the driver specified by\r
+                       This is managing.  This handle specifies the controller\r
+                       whose name is to be returned.\r
+    ChildHandle      - The handle of the child controller to retrieve the name\r
+                       of.  This is an optional parameter that may be NULL.  It\r
+                       will be NULL for device drivers.  It will also be NULL\r
+                       for a bus drivers that wish to retrieve the name of the\r
+                       bus controller.  It will not be NULL for a bus driver\r
+                       that wishes to retrieve the name of a child controller.\r
+    Language         - A pointer to a three character ISO 639-2 language\r
+                       identifier.  This is the language of the controller name\r
+                       that that the caller is requesting, and it must match one\r
+                       of the languages specified in SupportedLanguages.  The\r
+                       number of languages supported by a driver is up to the\r
+                       driver writer.\r
+    ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                       string is the name of the controller specified by\r
+                       ControllerHandle and ChildHandle in the language\r
+                       specified by Language from the point of view of the\r
+                       driver specified by This.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the user readable name in the\r
+                            language specified by Language for the driver\r
+                            specified by This was returned in DriverName.\r
+    EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid\r
+                            EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This is not currently\r
+                            managing the controller specified by\r
+                            ControllerHandle and ChildHandle.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS           Status;\r
+  USB2_HC_DEV          *EhciDev;\r
+  EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
+\r
+  //\r
+  // This is a device driver, so ChildHandle must be NULL.\r
+  //\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Make sure this driver is currently managing ControllerHandle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gEhciDriverBinding.DriverBindingHandle,\r
+             &gEfiPciIoProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get the device context\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  (VOID **) &Usb2Hc,\r
+                  gEhciDriverBinding.DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  EhciDev = EHC_FROM_THIS (Usb2Hc);\r
+\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gEhciComponentName.SupportedLanguages,\r
+          EhciDev->ControllerNameTable,\r
+          ControllerName\r
+          );\r
+\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
new file mode 100644 (file)
index 0000000..093388d
--- /dev/null
@@ -0,0 +1,1708 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    Ehci.c\r
+\r
+Abstract:\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+\r
+#include "Ehci.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
+/**\r
+  Retrieves the capablility of root hub ports.\r
+\r
+  @param  This                 This EFI_USB_HC_PROTOCOL instance.\r
+  @param  MaxSpeed             Max speed supported by the controller\r
+  @param  PortNumber           Number of the root hub ports.\r
+  @param  Is64BitCapable       Whether the controller supports 64-bit memory\r
+                               addressing.\r
+\r
+  @return EFI_SUCCESS           : host controller capability were retrieved successfully.\r
+  @return EFI_INVALID_PARAMETER : Either of the three capability pointer is NULL\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetCapability (\r
+  IN  EFI_USB2_HC_PROTOCOL  *This,\r
+  OUT UINT8                 *MaxSpeed,\r
+  OUT UINT8                 *PortNumber,\r
+  OUT UINT8                 *Is64BitCapable\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl          = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc             = EHC_FROM_THIS (This);\r
+\r
+  *MaxSpeed       = EFI_USB_SPEED_HIGH;\r
+  *PortNumber     = (UINT8) (Ehc->HcStructParams & HCSP_NPORTS);\r
+  *Is64BitCapable = (UINT8) (Ehc->HcCapParams & HCCP_64BIT);\r
+\r
+  EHC_DEBUG (("EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Provides software reset for the USB host controller.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  Attributes           A bit mask of the reset operation to perform.\r
+\r
+  @return EFI_SUCCESS           : The reset operation succeeded.\r
+  @return EFI_INVALID_PARAMETER : Attributes is not valid.\r
+  @return EFI_UNSUPPOURTED      : The type of reset specified by Attributes is\r
+  @return not currently supported by the host controller.\r
+  @return EFI_DEVICE_ERROR      : Host controller isn't halted to reset.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcReset (\r
+  IN EFI_USB2_HC_PROTOCOL *This,\r
+  IN UINT16               Attributes\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+\r
+  OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc     = EHC_FROM_THIS (This);\r
+\r
+  switch (Attributes) {\r
+  case EFI_USB_HC_RESET_GLOBAL:\r
+  //\r
+  // Flow through, same behavior as Host Controller Reset\r
+  //\r
+  case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
+    //\r
+    // Host Controller must be Halt when Reset it\r
+    //\r
+    if (!EhcIsHalt (Ehc)) {\r
+      Status = EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto ON_EXIT;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Clean up the asynchronous transfers, currently only\r
+    // interrupt supports asynchronous operation.\r
+    //\r
+    EhciDelAllAsyncIntTransfers (Ehc);\r
+    EhcAckAllInterrupt (Ehc);\r
+    EhcFreeSched (Ehc);\r
+\r
+    Status = EhcResetHC (Ehc, EHC_STALL_1_SECOND);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Status = EhcInitHC (Ehc);\r
+    break;\r
+\r
+  case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:\r
+  case EFI_USB_HC_RESET_HOST_WITH_DEBUG:\r
+    Status = EFI_UNSUPPORTED;\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+ON_EXIT:\r
+  EHC_DEBUG (("EhcReset: exit status %r\n", Status));\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Retrieve the current state of the USB host controller.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  State                Variable to return the current host controller\r
+                               state.\r
+\r
+  @return EFI_SUCCESS           : Host controller state was returned in State.\r
+  @return EFI_INVALID_PARAMETER : State is NULL.\r
+  @return EFI_DEVICE_ERROR      : An error was encountered while attempting to\r
+  @return retrieve the host controller's current state.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetState (\r
+  IN  CONST EFI_USB2_HC_PROTOCOL  *This,\r
+  OUT       EFI_USB_HC_STATE      *State\r
+  )\r
+{\r
+  EFI_TPL                 OldTpl;\r
+  USB2_HC_DEV             *Ehc;\r
+\r
+  if (State == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc     = EHC_FROM_THIS (This);\r
+\r
+  if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
+    *State = EfiUsbHcStateHalt;\r
+  } else {\r
+    *State = EfiUsbHcStateOperational;\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  EHC_DEBUG (("EhcGetState: current state %d\n", *State));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Sets the USB host controller to a specific state.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  State                The state of the host controller that will be set.\r
+\r
+  @return EFI_SUCCESS           : The USB host controller was successfully placed\r
+  @return in the state specified by State.\r
+  @return EFI_INVALID_PARAMETER : State is invalid.\r
+  @return EFI_DEVICE_ERROR      : Failed to set the state due to device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcSetState (\r
+  IN EFI_USB2_HC_PROTOCOL *This,\r
+  IN EFI_USB_HC_STATE     State\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+  EFI_USB_HC_STATE        CurState;\r
+\r
+  Status = EhcGetState (This, &CurState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (CurState == State) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc     = EHC_FROM_THIS (This);\r
+\r
+  switch (State) {\r
+  case EfiUsbHcStateHalt:\r
+    Status = EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+    break;\r
+\r
+  case EfiUsbHcStateOperational:\r
+    if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    Status = EhcRunHC (Ehc, EHC_GENERIC_TIME);\r
+    break;\r
+\r
+  case EfiUsbHcStateSuspend:\r
+    Status = EFI_UNSUPPORTED;\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  EHC_DEBUG (("EhcSetState: exit status %r\n", Status));\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  PortNumber           The root hub port to retrieve the state from.   This\r
+                               value is zero-based.\r
+  @param  PortStatus           Variable to receive the port state\r
+\r
+  @return EFI_SUCCESS           : The status of the USB root hub port specified\r
+  @return by PortNumber was returned in PortStatus.\r
+  @return EFI_INVALID_PARAMETER : PortNumber is invalid.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetRootHubPortStatus (\r
+  IN  CONST EFI_USB2_HC_PROTOCOL  *This,\r
+  IN  CONST UINT8                 PortNumber,\r
+  OUT       EFI_USB_PORT_STATUS   *PortStatus\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_TPL                 OldTpl;\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
+  OldTpl    = gBS->RaiseTPL (EHC_TPL);\r
+\r
+  Ehc       = EHC_FROM_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 |= 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 |= mUsbPortChangeMap[Index].UefiState;\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Sets a feature for the specified root hub port.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  PortNumber           Root hub port to set.\r
+  @param  PortFeature          Feature to set\r
+\r
+  @return EFI_SUCCESS           : The feature specified by PortFeature was set\r
+  @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcSetRootHubPortFeature (\r
+  IN  EFI_USB2_HC_PROTOCOL  *This,\r
+  IN  UINT8                 PortNumber,\r
+  IN  EFI_USB_PORT_FEATURE  PortFeature\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_TPL                 OldTpl;\r
+  UINT32                  Offset;\r
+  UINT32                  State;\r
+  UINT32                  TotalPort;\r
+  EFI_STATUS              Status;\r
+\r
+  OldTpl    = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc       = EHC_FROM_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_TIME);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        EHC_DEBUG (("EhcSetRootHubPortFeature :failed to start HC - %r\n", 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
+  EHC_DEBUG (("EhcSetRootHubPortFeature: exit status %r\n", Status));\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+\r
+  @param  This                 A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  @param  PortNumber           Specifies the root hub port whose feature is\r
+                               requested to be cleared.\r
+  @param  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
+  @return 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 register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcClearRootHubPortFeature (\r
+  IN  EFI_USB2_HC_PROTOCOL  *This,\r
+  IN  UINT8                 PortNumber,\r
+  IN  EFI_USB_PORT_FEATURE  PortFeature\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_TPL                 OldTpl;\r
+  UINT32                  Offset;\r
+  UINT32                  State;\r
+  UINT32                  TotalPort;\r
+  EFI_STATUS              Status;\r
+\r
+  OldTpl    = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc       = EHC_FROM_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
+  EHC_DEBUG (("EhcClearRootHubPortFeature: exit status %r\n", Status));\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\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\r
+                               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
+  @return EFI_SUCCESS           : Transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : The transfer failed due to lack of resources.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : Transfer failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : Transfer failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcControlTransfer (\r
+  IN  EFI_USB2_HC_PROTOCOL                *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
+  USB2_HC_DEV             *Ehc;\r
+  URB                     *Urb;\r
+  EFI_TPL                 OldTpl;\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
+  if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl          = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc             = EHC_FROM_THIS (This);\r
+\r
+  Status          = EFI_DEVICE_ERROR;\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+\r
+  if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+    EHC_ERROR (("EhcControlTransfer: HC halted at entrance\n"));\r
+\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 = 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
+    EHC_ERROR (("EhcControlTransfer: failed to create URB"));\r
+\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
+  Ehc->PciIo->Flush (Ehc->PciIo);\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\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  bulk\r
+                               transfer.\r
+  @param  MaximumPacketLength  Maximum packet size the endpoint is capable of\r
+                               sending or receiving.\r
+  @param  DataBuffersNumber    Number of data buffers prepared for the transfer.\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\r
+                               use                        of the subsequent bulk\r
+                               transfer.\r
+  @param  Translator           A pointr to the transaction translator data.\r
+  @param  TimeOut              Indicates the maximum time, in millisecond, which\r
+                               the transfer is allowed to complete.\r
+  @param  TransferResult       A pointer to the detailed result information of the\r
+                               bulk transfer.\r
+\r
+  @return EFI_SUCCESS           : The transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : The transfer failed due to lack of resource.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : The transfer failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : The transfer failed due to host controller error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcBulkTransfer (\r
+  IN  EFI_USB2_HC_PROTOCOL                *This,\r
+  IN  UINT8                               DeviceAddress,\r
+  IN  UINT8                               EndPointAddress,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINTN                               MaximumPacketLength,\r
+  IN  UINT8                               DataBuffersNumber,\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
+  USB2_HC_DEV             *Ehc;\r
+  URB                     *Urb;\r
+  EFI_TPL                 OldTpl;\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
+  OldTpl          = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc             = EHC_FROM_THIS (This);\r
+\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_DEVICE_ERROR;\r
+\r
+  if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+    EHC_ERROR (("EhcBulkTransfer: HC is halted\n"));\r
+\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
+    EHC_ERROR (("EhcBulkTransfer: failed to create URB\n"));\r
+\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
+  Ehc->PciIo->Flush (Ehc->PciIo);\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits an asynchronous interrupt transfer to an\r
+  interrupt endpoint of a USB device.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  DeviceAddress        Target device address\r
+  @param  EndPointAddress      Endpoint number and its direction encoded in bit 7\r
+  @param  DeviceSpeed          Indicates device speed.\r
+  @param  MaximumPacketLength  Maximum packet size the target endpoint is capable\r
+  @param  IsNewTransfer        If TRUE, to submit an new asynchronous interrupt\r
+                               transfer If FALSE, to remove the specified\r
+                               asynchronous interrupt\r
+  @param  DataToggle           On input, the initial data toggle to use; on output,\r
+                               it is updated to indicate the next data toggle\r
+  @param  PollingInterval      The he interval, in milliseconds, that the transfer\r
+                               is polled.\r
+  @param  DataLength           The length of data to receive at the rate specified\r
+                               by  PollingInterval.\r
+  @param  Translator           Transaction translator to use.\r
+  @param  CallBackFunction     Function to call at the rate specified by\r
+                               PollingInterval\r
+  @param  Context              Context to CallBackFunction.\r
+\r
+  @return EFI_SUCCESS           : The request has been successfully submitted or canceled.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_OUT_OF_RESOURCES  : The request failed due to a lack of resources.\r
+  @return EFI_DEVICE_ERROR      : The transfer failed due to host controller error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcAsyncInterruptTransfer (\r
+  IN  EFI_USB2_HC_PROTOCOL                  * This,\r
+  IN  UINT8                                 DeviceAddress,\r
+  IN  UINT8                                 EndPointAddress,\r
+  IN  UINT8                                 DeviceSpeed,\r
+  IN  UINTN                                 MaximumPacketLength,\r
+  IN  BOOLEAN                               IsNewTransfer,\r
+  IN  OUT UINT8                             *DataToggle,\r
+  IN  UINTN                                 PollingInterval,\r
+  IN  UINTN                                 DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    * Translator,\r
+  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK       CallBackFunction,\r
+  IN  VOID                                  *Context OPTIONAL\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  URB                     *Urb;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+  UINT8                   *Data;\r
+\r
+  //\r
+  // Validate parameters\r
+  //\r
+  if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (IsNewTransfer) {\r
+    if (DataLength == 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if ((PollingInterval > 255) || (PollingInterval < 1)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc     = EHC_FROM_THIS (This);\r
+\r
+  //\r
+  // Delete Async interrupt transfer request. DataToggle will return\r
+  // the next data toggle to use.\r
+  //\r
+  if (!IsNewTransfer) {\r
+    Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);\r
+\r
+    EHC_DEBUG (("EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+    EHC_ERROR (("EhcAsyncInterruptTransfer: HC is halt\n"));\r
+    EhcAckAllInterrupt (Ehc);\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EhcAckAllInterrupt (Ehc);\r
+\r
+  Data = AllocatePool (DataLength);\r
+\r
+  if (Data == NULL) {\r
+    EHC_ERROR (("EhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Urb = EhcCreateUrb (\r
+          Ehc,\r
+          DeviceAddress,\r
+          EndPointAddress,\r
+          DeviceSpeed,\r
+          *DataToggle,\r
+          MaximumPacketLength,\r
+          Translator,\r
+          EHC_INT_TRANSFER_ASYNC,\r
+          NULL,\r
+          Data,\r
+          DataLength,\r
+          CallBackFunction,\r
+          Context,\r
+          PollingInterval\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    EHC_ERROR (("EhcAsyncInterruptTransfer: failed to create URB\n"));\r
+\r
+    gBS->FreePool (Data);\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // New asynchronous transfer must inserted to the head.\r
+  // Check the comments in EhcMoniteAsyncRequests\r
+  //\r
+  EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
+  InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);\r
+\r
+ON_EXIT:\r
+  Ehc->PciIo->Flush (Ehc->PciIo);\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits synchronous interrupt transfer to an interrupt endpoint\r
+  of a USB device.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  DeviceAddress        Target device address\r
+  @param  EndPointAddress      Endpoint number and its direction encoded in bit 7\r
+  @param  DeviceSpeed          Indicates device speed.\r
+  @param  MaximumPacketLength  Maximum packet size the target endpoint is capable\r
+                               of sending or receiving.\r
+  @param  Data                 Buffer of data that will be transmitted to  USB\r
+                               device or received from USB device.\r
+  @param  DataLength           On input, the size, in bytes, of the data buffer; On\r
+                               output, the number of bytes transferred.\r
+  @param  DataToggle           On input, the initial data toggle to use; on output,\r
+                               it is updated to indicate the next data toggle\r
+  @param  TimeOut              Maximum time, in second, to complete\r
+  @param  Translator           Transaction translator to use.\r
+  @param  TransferResult       Variable to receive the transfer result\r
+\r
+  @return EFI_SUCCESS           : The transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : The transfer failed due to lack of resource.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : The transfer failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : The failed due to host controller or device error\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcSyncInterruptTransfer (\r
+  IN  EFI_USB2_HC_PROTOCOL                *This,\r
+  IN  UINT8                               DeviceAddress,\r
+  IN  UINT8                               EndPointAddress,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINTN                               MaximumPacketLength,\r
+  IN  OUT VOID                            *Data,\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
+  USB2_HC_DEV             *Ehc;\r
+  EFI_TPL                 OldTpl;\r
+  URB                     *Urb;\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Validates parameters\r
+  //\r
+  if ((DataLength == NULL) || (*DataLength == 0) ||\r
+      (Data == NULL) || (TransferResult == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8))  ||\r
+      ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+      ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl          = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc             = EHC_FROM_THIS (This);\r
+\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_DEVICE_ERROR;\r
+\r
+  if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+    EHC_ERROR (("EhcSyncInterruptTransfer: HC is halt\n"));\r
+\r
+    EhcAckAllInterrupt (Ehc);\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EhcAckAllInterrupt (Ehc);\r
+\r
+  Urb = EhcCreateUrb (\r
+          Ehc,\r
+          DeviceAddress,\r
+          EndPointAddress,\r
+          DeviceSpeed,\r
+          *DataToggle,\r
+          MaximumPacketLength,\r
+          Translator,\r
+          EHC_INT_TRANSFER_SYNC,\r
+          NULL,\r
+          Data,\r
+          *DataLength,\r
+          NULL,\r
+          NULL,\r
+          1\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    EHC_ERROR (("EhcSyncInterruptTransfer: failed to create URB\n"));\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
+  Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
+  EhcUnlinkQhFromPeriod (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
+ON_EXIT:\r
+  Ehc->PciIo->Flush (Ehc->PciIo);\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits isochronous transfer to a target USB device.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  DeviceAddress        Target device address\r
+  @param  EndPointAddress      End point address with its direction\r
+  @param  DeviceSpeed          Device speed, Low speed device doesn't support this\r
+                               type.\r
+  @param  MaximumPacketLength  Maximum packet size that the endpoint is capable of\r
+                               sending or receiving.\r
+  @param  DataBuffersNumber    Number of data buffers prepared for the transfer.\r
+  @param  Data                 Array of pointers to the buffers of data that will\r
+                               be transmitted to USB device or received from USB\r
+                               device.\r
+  @param  DataLength           The size, in bytes, of the data buffer\r
+  @param  Translator           Transaction translator to use.\r
+  @param  TransferResult       Variable to receive the transfer result\r
+\r
+  @return EFI_UNSUPPORTED : Isochronous transfer is unsupported.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcIsochronousTransfer (\r
+  IN  EFI_USB2_HC_PROTOCOL                *This,\r
+  IN  UINT8                               DeviceAddress,\r
+  IN  UINT8                               EndPointAddress,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINTN                               MaximumPacketLength,\r
+  IN  UINT8                               DataBuffersNumber,\r
+  IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+  IN  UINTN                               DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *TransferResult\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Submits Async isochronous transfer to a target USB device.\r
+\r
+  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  DeviceAddress        Target device address\r
+  @param  EndPointAddress      End point address with its direction\r
+  @param  DeviceSpeed          Device speed, Low speed device doesn't support this\r
+                               type.\r
+  @param  MaximumPacketLength  Maximum packet size that the endpoint is capable of\r
+                               sending or receiving.\r
+  @param  DataBuffersNumber    Number of data buffers prepared for the transfer.\r
+  @param  Data                 Array of pointers to the buffers of data that will\r
+                               be transmitted to USB device or received from USB\r
+                               device.\r
+  @param  DataLength           The size, in bytes, of the data buffer\r
+  @param  Translator           Transaction translator to use.\r
+  @param  IsochronousCallBack  Function to be called when the transfer complete\r
+  @param  Context              Context passed to the call back function as\r
+                               parameter\r
+\r
+  @return EFI_UNSUPPORTED : Isochronous transfer isn't supported\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcAsyncIsochronousTransfer (\r
+  IN  EFI_USB2_HC_PROTOCOL                *This,\r
+  IN  UINT8                               DeviceAddress,\r
+  IN  UINT8                               EndPointAddress,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINTN                               MaximumPacketLength,\r
+  IN  UINT8                               DataBuffersNumber,\r
+  IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+  IN  UINTN                               DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,\r
+  IN  VOID                                *Context\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (EhcDriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EhcDriverEntryPoint (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Entry point for EFI drivers.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - EFI_HANDLE\r
+  SystemTable - EFI_SYSTEM_TABLE\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS         Success\r
+  EFI_DEVICE_ERROR    Fail\r
+\r
+--*/\r
+{\r
+  return EfiLibInstallAllDriverProtocols (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gEhciDriverBinding,\r
+           ImageHandle,\r
+           &gEhciComponentName,\r
+           NULL,\r
+           NULL\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle. Any\r
+  ControllerHandle that has Usb2HcProtocol installed will\r
+  be supported.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controlle            Handle of device to test\r
+  @param  RemainingDevicePath  Not used\r
+\r
+  @return EFI_SUCCESS         : This driver supports this device.\r
+  @return EFI_UNSUPPORTED     : This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+  USB_CLASSC              UsbClassCReg;\r
+\r
+  //\r
+  // Test whether there is PCI IO Protocol attached on the controller handle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EHC_PCI_CLASSC,\r
+                        sizeof (USB_CLASSC) / sizeof (UINT8),\r
+                        &UsbClassCReg\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Test whether the controller belongs to Ehci type\r
+  //\r
+  if ((UsbClassCReg.BaseCode     != PCI_CLASS_SERIAL) ||\r
+      (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
+      (UsbClassCReg.PI           != EHC_PCI_CLASSC_PI)) {\r
+\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Create and initialize a USB2_HC_DEV\r
+\r
+  @param  PciIo                The PciIo on this device\r
+\r
+  @return The allocated and initialized USB2_HC_DEV structure\r
+  @return if created, otherwise NULL.\r
+\r
+**/\r
+STATIC\r
+USB2_HC_DEV *\r
+EhcCreateUsb2Hc (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_STATUS              Status;\r
+\r
+  Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));\r
+\r
+  if (Ehc == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Init EFI_USB2_HC_PROTOCOL interface and private data structure\r
+  //\r
+  Ehc->Signature                        = USB2_HC_DEV_SIGNATURE;\r
+\r
+  Ehc->Usb2Hc.GetCapability             = EhcGetCapability;\r
+  Ehc->Usb2Hc.Reset                     = EhcReset;\r
+  Ehc->Usb2Hc.GetState                  = EhcGetState;\r
+  Ehc->Usb2Hc.SetState                  = EhcSetState;\r
+  Ehc->Usb2Hc.ControlTransfer           = EhcControlTransfer;\r
+  Ehc->Usb2Hc.BulkTransfer              = EhcBulkTransfer;\r
+  Ehc->Usb2Hc.AsyncInterruptTransfer    = EhcAsyncInterruptTransfer;\r
+  Ehc->Usb2Hc.SyncInterruptTransfer     = EhcSyncInterruptTransfer;\r
+  Ehc->Usb2Hc.IsochronousTransfer       = EhcIsochronousTransfer;\r
+  Ehc->Usb2Hc.AsyncIsochronousTransfer  = EhcAsyncIsochronousTransfer;\r
+  Ehc->Usb2Hc.GetRootHubPortStatus      = EhcGetRootHubPortStatus;\r
+  Ehc->Usb2Hc.SetRootHubPortFeature     = EhcSetRootHubPortFeature;\r
+  Ehc->Usb2Hc.ClearRootHubPortFeature   = EhcClearRootHubPortFeature;\r
+  Ehc->Usb2Hc.MajorRevision             = 0x1;\r
+  Ehc->Usb2Hc.MinorRevision             = 0x1;\r
+\r
+  Ehc->PciIo = PciIo;\r
+\r
+  InitializeListHead (&Ehc->AsyncIntTransfers);\r
+\r
+  Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);\r
+  Ehc->HcCapParams    = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);\r
+  Ehc->CapLen         = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;\r
+\r
+  EHC_DEBUG (("EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));\r
+\r
+  //\r
+  // Create AsyncRequest Polling Timer\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  EhcMoniteAsyncRequests,\r
+                  Ehc,\r
+                  &Ehc->PollTimer\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (Ehc);\r
+    return NULL;\r
+  }\r
+\r
+  return Ehc;\r
+}\r
+\r
+\r
+/**\r
+  Starting the Usb EHCI Driver\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to test\r
+  @param  RemainingDevicePath  Not used\r
+\r
+  @return EFI_SUCCESS          : supports this device.\r
+  @return EFI_UNSUPPORTED      : do not support this device.\r
+  @return EFI_DEVICE_ERROR     : cannot be started due to device Error\r
+  @return EFI_OUT_OF_RESOURCES : cannot allocate resources\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+\r
+  //\r
+  // Open the PciIo Protocol, then enable the USB host controller\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcDriverBindingStart: failed to open PCI_IO\n"));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationEnable,\r
+                    EFI_PCI_DEVICE_ENABLE,\r
+                    NULL\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcDriverBindingStart: failed to enable controller\n"));\r
+    goto CLOSE_PCIIO;\r
+  }\r
+\r
+  //\r
+  // Create then install USB2_HC_PROTOCOL\r
+  //\r
+  Ehc = EhcCreateUsb2Hc (PciIo);\r
+\r
+  if (Ehc == NULL) {\r
+    EHC_ERROR (("EhcDriverBindingStart: failed to create USB2_HC\n"));\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto CLOSE_PCIIO;\r
+  }\r
+\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &Ehc->Usb2Hc\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
+    goto FREE_POOL;\r
+  }\r
+\r
+  //\r
+  // Robustnesss improvement such as for UoL\r
+  //\r
+  EhcClearLegacySupport (Ehc);\r
+  EhcResetHC (Ehc, EHC_STALL_1_SECOND);\r
+\r
+  Status = EhcInitHC (Ehc);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcDriverBindingStart: failed to init host controller\n"));\r
+    goto UNINSTALL_USBHC;\r
+  }\r
+\r
+  //\r
+  // Start the asynchronous interrupt monitor\r
+  //\r
+  Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_TIME);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
+\r
+    EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+    goto UNINSTALL_USBHC;\r
+  }\r
+\r
+  //\r
+  // Install the component name protocol, don't fail the start\r
+  // because of something for display.\r
+  //\r
+  AddUnicodeString (\r
+    "eng",\r
+    gEhciComponentName.SupportedLanguages,\r
+    &Ehc->ControllerNameTable,\r
+    L"Enhanced Host Controller (USB 2.0)"\r
+    );\r
+\r
+  EHC_DEBUG (("EhcDriverBindingStart: EHCI started for controller @ %x\n", Controller));\r
+  return EFI_SUCCESS;\r
+\r
+UNINSTALL_USBHC:\r
+  gBS->UninstallProtocolInterface (\r
+         Controller,\r
+         &gEfiUsb2HcProtocolGuid,\r
+         &Ehc->Usb2Hc\r
+         );\r
+\r
+FREE_POOL:\r
+  EhcFreeSched (Ehc);\r
+  gBS->CloseEvent (Ehc->PollTimer);\r
+  gBS->FreePool (Ehc);\r
+\r
+CLOSE_PCIIO:\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop this driver on ControllerHandle. Support stoping any child handles\r
+  created by this driver.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to stop driver on\r
+  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer\r
+  @param  ChildHandleBuffer    List of handles for the children we need to stop.\r
+\r
+  @return EFI_SUCCESS         Success\r
+  @return EFI_DEVICE_ERROR    Fail\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  Controller,\r
+  IN UINTN                       NumberOfChildren,\r
+  IN EFI_HANDLE                  *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_USB2_HC_PROTOCOL  *Usb2Hc;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  USB2_HC_DEV           *Ehc;\r
+\r
+  //\r
+  // Test whether the Controller handler passed in is a valid\r
+  // Usb controller handle that should be supported, if not,\r
+  // return the error status directly\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  &Usb2Hc,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Ehc   = EHC_FROM_THIS (Usb2Hc);\r
+  PciIo = Ehc->PciIo;\r
+\r
+  //\r
+  // Stop AsyncRequest Polling timer then stop the EHCI driver\r
+  // and uninstall the EHCI protocl.\r
+  //\r
+  gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_TIME);\r
+  EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  Usb2Hc\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Ehc->PollTimer != NULL) {\r
+    gBS->CloseEvent (Ehc->PollTimer);\r
+  }\r
+\r
+  EhcFreeSched (Ehc);\r
+\r
+  if (Ehc->ControllerNameTable) {\r
+    FreeUnicodeStringTable (Ehc->ControllerNameTable);\r
+  }\r
+\r
+  //\r
+  // Disable the USB Host Controller\r
+  //\r
+  PciIo->Attributes (\r
+           PciIo,\r
+           EfiPciIoAttributeOperationDisable,\r
+           EFI_PCI_DEVICE_ENABLE,\r
+           NULL\r
+           );\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  gBS->FreePool (Ehc);\r
+  return Status;\r
+}\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL\r
+gEhciDriverBinding = {\r
+  EhcDriverBindingSupported,\r
+  EhcDriverBindingStart,\r
+  EhcDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.h b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.h
new file mode 100644 (file)
index 0000000..57c0c00
--- /dev/null
@@ -0,0 +1,152 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    Ehci.h\r
+\r
+Abstract:\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_H_\r
+#define _EFI_EHCI_H_\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Protocol/Usb2HostController.h>\r
+#include <Protocol/PciIo.h>\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+typedef struct _USB2_HC_DEV  USB2_HC_DEV;\r
+\r
+#include "UsbHcMem.h"\r
+#include "EhciReg.h"\r
+#include "EhciUrb.h"\r
+#include "EhciSched.h"\r
+#include "EhciDebug.h"\r
+\r
+enum {\r
+  USB2_HC_DEV_SIGNATURE     = EFI_SIGNATURE_32 ('e', 'h', 'c', 'i'),\r
+  EHC_STALL_1_MICROSECOND   = 1,\r
+  EHC_STALL_1_MILLISECOND   = 1000 * EHC_STALL_1_MICROSECOND,\r
+  EHC_STALL_1_SECOND        = 1000 * EHC_STALL_1_MILLISECOND,\r
+\r
+  EHC_SET_PORT_RESET_TIME   = 50 * EHC_STALL_1_MILLISECOND,\r
+  EHC_CLEAR_PORT_RESET_TIME = EHC_STALL_1_MILLISECOND,\r
+  EHC_GENERIC_TIME          = 10 * EHC_STALL_1_MILLISECOND,\r
+  EHC_SYNC_POLL_TIME        = 20 * EHC_STALL_1_MICROSECOND,\r
+  EHC_ASYNC_POLL_TIME       = 50 * 10000UL,                 // The unit of time is 100us\r
+\r
+  EHC_TPL                   = TPL_NOTIFY,\r
+};\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) _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 EHC_FROM_THIS(a)   CR(a, USB2_HC_DEV, Usb2Hc, USB2_HC_DEV_SIGNATURE)\r
+\r
+typedef struct _USB2_HC_DEV {\r
+  UINTN                     Signature;\r
+  EFI_USB2_HC_PROTOCOL      Usb2Hc;\r
+\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\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
+  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
+  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
+  EHC_QH                    *PeriodOne;\r
+  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
+  // Misc\r
+  //\r
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;\r
+} USB2_HC_DEV;\r
+\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL     gEhciDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL     gEhciComponentName;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.inf b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.inf
new file mode 100644 (file)
index 0000000..2be0832
--- /dev/null
@@ -0,0 +1,100 @@
+#/** @file\r
+# Component name for module Ehci\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+#  All rights reserved. This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = Ehci\r
+  FILE_GUID                      = BDFE430E-8F2A-4db0-9991-6F856594777E\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = EhcDriverEntryPoint\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
+################################################################################\r
+#\r
+# Sources Section - list of files that are required for the build to succeed.\r
+#\r
+################################################################################\r
+\r
+[Sources.common]\r
+  UsbHcMem.h\r
+  EhciUrb.c\r
+  EhciReg.h\r
+  UsbHcMem.c\r
+  EhciSched.c\r
+  EhciDebug.c\r
+  EhciReg.c\r
+  EhciDebug.h\r
+  ComponentName.c\r
+  EhciUrb.h\r
+  Ehci.h\r
+  EhciSched.h\r
+  Ehci.c\r
+\r
+################################################################################\r
+#\r
+# Package Dependency Section - list of Package files that are required for\r
+#                              this module.\r
+#\r
+################################################################################\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+################################################################################\r
+#\r
+# Library Class Section - list of Library Classes that are required for\r
+#                         this module.\r
+#\r
+################################################################################\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  DebugLib\r
+\r
+\r
+################################################################################\r
+#\r
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names\r
+#                           that this module uses or produces.\r
+#\r
+################################################################################\r
+\r
+[Protocols]\r
+  gEfiPciIoProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUsb2HcProtocolGuid                        # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.msa b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.msa
new file mode 100644 (file)
index 0000000..dec9936
--- /dev/null
@@ -0,0 +1,81 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>Ehci</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>BDFE430E-8F2A-4db0-9991-6F856594777E</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module Ehci</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+    <License>All rights reserved. This program and the accompanying materials                          
+      are licensed and made available under the terms and conditions of the BSD License         
+      which accompanies this distribution.  The full text of the license may be found at        
+      http://opensource.org/licenses/bsd-license.php                                            
+      
+      THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+      WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>\r
+    <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION   0x00000052</Specification>\r
+  </MsaHeader>\r
+  <ModuleDefinitions>\r
+    <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+    <BinaryModule>false</BinaryModule>\r
+    <OutputFileBasename>Ehci</OutputFileBasename>\r
+  </ModuleDefinitions>\r
+  <LibraryClassDefinitions>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DebugLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseMemoryLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverEntryPoint</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiBootServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>MemoryAllocationLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>Ehci.c</Filename>\r
+    <Filename>EhciSched.h</Filename>\r
+    <Filename>Ehci.h</Filename>\r
+    <Filename>EhciUrb.h</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>EhciDebug.h</Filename>\r
+    <Filename>EhciReg.c</Filename>\r
+    <Filename>EhciDebug.c</Filename>\r
+    <Filename>EhciSched.c</Filename>\r
+    <Filename>UsbHcMem.c</Filename>\r
+    <Filename>EhciReg.h</Filename>\r
+    <Filename>EhciUrb.c</Filename>\r
+    <Filename>UsbHcMem.h</Filename>\r
+  </SourceFiles>\r
+  <PackageDependencies>\r
+    <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+    <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+  </PackageDependencies>\r
+  <Protocols>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUsb2HcProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+  </Protocols>\r
+  <Externs>\r
+    <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+    <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+    <Extern>\r
+      <ModuleEntryPoint>EhcDriverEntryPoint</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.c b/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.c
new file mode 100644 (file)
index 0000000..086cdbc
--- /dev/null
@@ -0,0 +1,345 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    EhciDebug.c\r
+\r
+Abstract:\r
+  This file provides the information dump support for EHCI when in debug mode.\r
+You can dynamically adjust the debug level by changing variable mEhcDebugLevel\r
+and mEhcErrorLevel.\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+\r
+#include "Ehci.h"\r
+\r
+#ifdef EFI_DEBUG\r
+UINTN mEhcDebugMask   = USB_DEBUG_FORCE_OUTPUT;\r
+\r
+\r
+/**\r
+  EHCI's debug output function. It determines whether\r
+  to output by the mask and level\r
+\r
+  @param  Level    The output level\r
+  @param  Format   The format parameters to the print\r
+  @param  ...      The variable length parameters after format\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhciDebugPrint (\r
+  IN  UINTN               Level,\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+{\r
+\r
+  VA_LIST                 Marker;\r
+\r
+  VA_START (Marker, Format);\r
+\r
+  if (Level & mEhcDebugMask) {\r
+    if (mEhcDebugMask & USB_DEBUG_FORCE_OUTPUT) {\r
+      DebugVPrint (DEBUG_ERROR, Format, Marker);\r
+    } else {\r
+      DebugVPrint (DEBUG_INFO, Format, Marker);\r
+    }\r
+  }\r
+\r
+  VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+  EHCI's debug output function. It determines whether\r
+  to output by the mask and level\r
+\r
+  @param  Format   The format parameters to the print\r
+  @param  ...      The variable length parameters after format\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcDebug (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST                 Marker;\r
+\r
+  VA_START (Marker, Format);\r
+  DebugVPrint (DEBUG_INFO, Format, Marker);\r
+  VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+  EHCI's error output function. It determines whether\r
+  to output by the mask and level\r
+\r
+  @param  Format   The format parameters to the print\r
+  @param  ...      The variable length parameters after format\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcError (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+{\r
+\r
+  VA_LIST                 Marker;\r
+\r
+  VA_START (Marker, Format);\r
+  DebugVPrint (DEBUG_ERROR, Format, Marker);\r
+  VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+  Dump the status byte in QTD/QH to a more friendly\r
+  format\r
+\r
+  @param  State    The state in the QTD/QH\r
+  @param  Level    The output level\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcDumpStatus (\r
+  IN UINT32               State,\r
+  IN UINTN                Level\r
+  )\r
+{\r
+  if (EHC_BIT_IS_SET (State, QTD_STAT_DO_PING)) {\r
+    EhciDebugPrint (Level, "  Do_Ping");\r
+  } else {\r
+    EhciDebugPrint (Level, "  Do_Out");\r
+  }\r
+\r
+  if (EHC_BIT_IS_SET (State, QTD_STAT_DO_CS)) {\r
+    EhciDebugPrint (Level, "  Do_CS");\r
+  } else {\r
+    EhciDebugPrint (Level, "  Do_SS");\r
+  }\r
+\r
+  if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR)) {\r
+    EhciDebugPrint (Level, "  Transfer_Error");\r
+  }\r
+\r
+  if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {\r
+    EhciDebugPrint (Level, "  Babble_Error");\r
+  }\r
+\r
+  if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {\r
+    EhciDebugPrint (Level, "  Buffer_Error");\r
+  }\r
+\r
+  if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {\r
+    EhciDebugPrint (Level, "  Halted");\r
+  }\r
+\r
+  if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {\r
+    EhciDebugPrint (Level, "  Active");\r
+  }\r
+\r
+  EhciDebugPrint (Level, "\n");\r
+}\r
+\r
+\r
+/**\r
+  Dump the fields of a QTD\r
+\r
+  @param  Qtd      The QTD to dump\r
+  @param  Msg      The message to print before the dump\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpQtd (\r
+  IN EHC_QTD              *Qtd,\r
+  IN UINT8                *Msg\r
+  )\r
+{\r
+  QTD_HW                  *QtdHw;\r
+  UINTN                   Index;\r
+  UINTN                   Level;\r
+\r
+  Level = EHC_DEBUG_QTD;\r
+\r
+  if (Msg != NULL) {\r
+    EhciDebugPrint (Level, Msg);\r
+  }\r
+\r
+  EhciDebugPrint (Level, "Queue TD @ 0x%x, data length %d\n", Qtd, Qtd->DataLen);\r
+\r
+  QtdHw = &Qtd->QtdHw;\r
+\r
+  EhciDebugPrint (Level, "Next QTD     : %x\n", QtdHw->NextQtd);\r
+  EhciDebugPrint (Level, "AltNext QTD  : %x\n", QtdHw->AltNext);\r
+  EhciDebugPrint (Level, "Status       : %x\n", QtdHw->Status);\r
+  EhcDumpStatus (QtdHw->Status, Level);\r
+\r
+  if (QtdHw->Pid == QTD_PID_SETUP) {\r
+    EhciDebugPrint (Level, "PID          : Setup\n");\r
+\r
+  } else if (QtdHw->Pid == QTD_PID_INPUT) {\r
+    EhciDebugPrint (Level, "PID          : IN\n");\r
+\r
+  } else if (QtdHw->Pid == QTD_PID_OUTPUT) {\r
+    EhciDebugPrint (Level, "PID          : OUT\n");\r
+\r
+  }\r
+\r
+  EhciDebugPrint (Level, "Error Count  : %d\n", QtdHw->ErrCnt);\r
+  EhciDebugPrint (Level, "Current Page : %d\n", QtdHw->CurPage);\r
+  EhciDebugPrint (Level, "IOC          : %d\n", QtdHw->IOC);\r
+  EhciDebugPrint (Level, "Total Bytes  : %d\n", QtdHw->TotalBytes);\r
+  EhciDebugPrint (Level, "Data Toggle  : %d\n", QtdHw->DataToggle);\r
+\r
+  for (Index = 0; Index < 5; Index++) {\r
+    EhciDebugPrint (Level, "Page[%d]      : 0x%x\n", Index, QtdHw->Page[Index]);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Dump the queue head\r
+\r
+  @param  Qh       The queue head to dump\r
+  @param  Msg      The message to print before the dump\r
+  @param  DumpBuf  Whether to dump the memory buffer of the associated QTD\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpQh (\r
+  IN EHC_QH               *Qh,\r
+  IN UINT8                *Msg,\r
+  IN BOOLEAN              DumpBuf\r
+  )\r
+{\r
+  EHC_QTD                 *Qtd;\r
+  QH_HW                   *QhHw;\r
+  LIST_ENTRY              *Entry;\r
+  UINTN                   Index;\r
+  UINTN                   Level;\r
+\r
+  Level = EHC_DEBUG_QH;\r
+\r
+  if (Msg != NULL) {\r
+    EhciDebugPrint (Level, Msg);\r
+  }\r
+\r
+  EhciDebugPrint (Level, "Queue head @ 0x%x, interval %d, next qh %x\n",\r
+                                Qh, Qh->Interval, Qh->NextQh);\r
+\r
+  QhHw = &Qh->QhHw;\r
+\r
+  EhciDebugPrint (Level, "Hoziontal link: %x\n", QhHw->HorizonLink);\r
+  EhciDebugPrint (Level, "Device address: %d\n", QhHw->DeviceAddr);\r
+  EhciDebugPrint (Level, "Inactive      : %d\n", QhHw->Inactive);\r
+  EhciDebugPrint (Level, "EP number     : %d\n", QhHw->EpNum);\r
+  EhciDebugPrint (Level, "EP speed      : %d\n", QhHw->EpSpeed);\r
+  EhciDebugPrint (Level, "DT control    : %d\n", QhHw->DtCtrl);\r
+  EhciDebugPrint (Level, "Reclaim head  : %d\n", QhHw->ReclaimHead);\r
+  EhciDebugPrint (Level, "Max packet len: %d\n", QhHw->MaxPacketLen);\r
+  EhciDebugPrint (Level, "Ctrl EP       : %d\n", QhHw->CtrlEp);\r
+  EhciDebugPrint (Level, "Nak reload    : %d\n", QhHw->NakReload);\r
+\r
+  EhciDebugPrint (Level, "SMask         : %x\n", QhHw->SMask);\r
+  EhciDebugPrint (Level, "CMask         : %x\n", QhHw->CMask);\r
+  EhciDebugPrint (Level, "Hub address   : %d\n", QhHw->HubAddr);\r
+  EhciDebugPrint (Level, "Hub port      : %d\n", QhHw->PortNum);\r
+  EhciDebugPrint (Level, "Multiplier    : %d\n", QhHw->Multiplier);\r
+\r
+  EhciDebugPrint (Level, "Cur QTD       : %x\n", QhHw->CurQtd);\r
+\r
+  EhciDebugPrint (Level, "Next QTD      : %x\n", QhHw->NextQtd);\r
+  EhciDebugPrint (Level, "AltNext QTD   : %x\n", QhHw->AltQtd);\r
+  EhciDebugPrint (Level, "Status        : %x\n", QhHw->Status);\r
+  EhcDumpStatus (QhHw->Status, Level);\r
+\r
+  if (QhHw->Pid == QTD_PID_SETUP) {\r
+    EhciDebugPrint (Level, "PID           : Setup\n");\r
+\r
+  } else if (QhHw->Pid == QTD_PID_INPUT) {\r
+    EhciDebugPrint (Level, "PID           : IN\n");\r
+\r
+  } else if (QhHw->Pid == QTD_PID_OUTPUT) {\r
+    EhciDebugPrint (Level, "PID           : OUT\n");\r
+  }\r
+\r
+  EhciDebugPrint (Level, "Error Count   : %d\n", QhHw->ErrCnt);\r
+  EhciDebugPrint (Level, "Current Page  : %d\n", QhHw->CurPage);\r
+  EhciDebugPrint (Level, "IOC           : %d\n", QhHw->IOC);\r
+  EhciDebugPrint (Level, "Total Bytes   : %d\n", QhHw->TotalBytes);\r
+  EhciDebugPrint (Level, "Data Toggle   : %d\n", QhHw->DataToggle);\r
+\r
+  for (Index = 0; Index < 5; Index++) {\r
+    EhciDebugPrint (Level, "Page[%d]       : 0x%x\n", Index, QhHw->Page[Index]);\r
+  }\r
+\r
+  EhciDebugPrint (Level, "\n");\r
+\r
+  EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r
+    Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
+    EhcDumpQtd (Qtd, NULL);\r
+\r
+    if (DumpBuf && (Qtd->DataLen != 0)) {\r
+      EhcDumpBuf (Qtd->Data, Qtd->DataLen);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Dump the buffer in the form of hex\r
+\r
+  @param  Buf      The buffer to dump\r
+  @param  Len      The length of buffer\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpBuf (\r
+  IN UINT8                *Buf,\r
+  IN UINTN                Len\r
+  )\r
+{\r
+  UINTN                   Index;\r
+\r
+  for (Index = 0; Index < Len; Index++) {\r
+    if (Index % 16 == 0) {\r
+      EhciDebugPrint (EHC_DEBUG_BUF, "\n");\r
+    }\r
+\r
+    EhciDebugPrint (EHC_DEBUG_BUF, "%02x ", Buf[Index]);\r
+  }\r
+\r
+  EhciDebugPrint (EHC_DEBUG_BUF, "\n");\r
+}\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.h b/MdeModulePkg/Bus/Pci/EhciDxe/EhciDebug.h
new file mode 100644 (file)
index 0000000..be4bcd6
--- /dev/null
@@ -0,0 +1,159 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  EhciDebug.h\r
+\r
+Abstract:\r
+\r
+  This file contains the definination for host controller debug support routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_DEBUG_H_\r
+#define _EFI_EHCI_DEBUG_H_\r
+\r
+\r
+enum {\r
+  USB_DEBUG_FORCE_OUTPUT  = (UINTN)(1 << 0),\r
+\r
+  EHC_DEBUG_QH            = (UINTN)(1 << 8),\r
+  EHC_DEBUG_QTD           = (UINTN)(1 << 9),\r
+  EHC_DEBUG_BUF           = (UINTN)(1 << 10),\r
+};\r
+\r
+\r
+/**\r
+  EHCI's debug output function. It determines whether\r
+  to output by the mask and level\r
+\r
+  @param  Level    The output level\r
+  @param  Format   The format parameters to the print\r
+  @param  ...      The variable length parameters after format\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhciDebugPrint (\r
+  IN  UINTN               Level,\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  EHCI's debug output function. It determines whether\r
+  to output by the mask and level\r
+\r
+  @param  Format   The format parameters to the print\r
+  @param  ...      The variable length parameters after format\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcDebug (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  EHCI's error output function. It determines whether\r
+  to output by the mask and level\r
+\r
+  @param  Format   The format parameters to the print\r
+  @param  ...      The variable length parameters after format\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcError (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Dump the fields of a QTD\r
+\r
+  @param  Qtd      The QTD to dump\r
+  @param  Msg      The message to print before the dump\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpQtd (\r
+  IN EHC_QTD              *Qtd,\r
+  IN UINT8                *Msg\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Dump the queue head\r
+\r
+  @param  Qh       The queue head to dump\r
+  @param  Msg      The message to print before the dump\r
+  @param  DumpBuf  Whether to dump the memory buffer of the associated QTD\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpQh (\r
+  IN EHC_QH               *Qh,\r
+  IN UINT8                *Msg,\r
+  IN BOOLEAN              DumpBuf\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Dump the buffer in the form of hex\r
+\r
+  @param  Buf      The buffer to dump\r
+  @param  Len      The length of buffer\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpBuf (\r
+  IN UINT8                *Buf,\r
+  IN UINTN                Len\r
+  )\r
+;\r
+\r
+#ifdef EFI_DEBUG\r
+  #define EHC_DEBUG(arg)                  EhcDebug    arg\r
+  #define EHC_ERROR(arg)                  EhcError    arg\r
+  #define EHC_DUMP_QH(arg)                EhcDumpQh   arg\r
+#else\r
+  #define EHC_DEBUG(arg)\r
+  #define EHC_ERROR(arg)\r
+  #define EHC_DUMP_QH(arg)\r
+#endif\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c b/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.c
new file mode 100644 (file)
index 0000000..aa16605
--- /dev/null
@@ -0,0 +1,634 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    EhciReg.c\r
+\r
+Abstract:\r
+\r
+    The EHCI register operation routines.\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+\r
+#include "Ehci.h"\r
+\r
+\r
+/**\r
+  Read  EHCI capability register\r
+\r
+  @param  Ehc          The Ehc device\r
+  @param  Offset       Capability register address\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+EhcReadCapRegister (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  EFI_STATUS              Status;\r
+\r
+  Status = Ehc->PciIo->Mem.Read (\r
+                             Ehc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             EHC_BAR_INDEX,\r
+                             (UINT64) Offset,\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcReadCapRegister: Pci Io read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFFFF;\r
+  }\r
+\r
+  return Data;\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
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+EhcReadOpReg (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Ehc->CapLen != 0);\r
+\r
+  Status = Ehc->PciIo->Mem.Read (\r
+                             Ehc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             EHC_BAR_INDEX,\r
+                             (UINT64) (Ehc->CapLen + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFFFF;\r
+  }\r
+\r
+  return Data;\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcWriteOpReg (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Ehc->CapLen != 0);\r
+\r
+  Status = Ehc->PciIo->Mem.Write (\r
+                             Ehc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             EHC_BAR_INDEX,\r
+                             (UINT64) (Ehc->CapLen + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));\r
+  }\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
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcSetOpRegBit (\r
+  IN 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
+/**\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
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcClearOpRegBit (\r
+  IN 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
+/**\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 operation register\r
+  @param  Bit          The bit 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
+STATIC\r
+EFI_STATUS\r
+EhcWaitOpRegBit (\r
+  IN 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_TIME + 1; Index++) {\r
+    if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    gBS->Stall (EHC_SYNC_POLL_TIME);\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+\r
+/**\r
+  Add support for UEFI Over Legacy (UoL) feature, stop\r
+  the legacy USB SMI support\r
+\r
+  @param  Ehc          The EHCI device.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcClearLegacySupport (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+{\r
+  UINT32                    ExtendCap;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  UINT32                    Value;\r
+  UINT32                    TimeOut;\r
+\r
+  EHC_DEBUG (("EhcClearLegacySupport: called to clear legacy support\n"));\r
+\r
+  PciIo     = Ehc->PciIo;\r
+  ExtendCap = (Ehc->HcCapParams >> 8) & 0xFF;\r
+\r
+  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);\r
+\r
+  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+  Value |= (0x1 << 24);\r
+  PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+\r
+  TimeOut = 40;\r
+  while (TimeOut--) {\r
+    gBS->Stall (500);\r
+\r
+    PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+\r
+    if ((Value & 0x01010000) == 0x01000000) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+  PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);\r
+}\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
+  @return EFI_SUCCESS : Synchronized with the hardware\r
+  @return EFI_TIMEOUT : Time out happened while waiting door bell to set\r
+\r
+**/\r
+EFI_STATUS\r
+EhcSetAndWaitDoorBell (\r
+  IN  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
+/**\r
+  Clear all the interrutp status bits, these bits\r
+  are Write-Clean\r
+\r
+  @param  Ehc          The EHCI device\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcAckAllInterrupt (\r
+  IN  USB2_HC_DEV         *Ehc\r
+  )\r
+{\r
+  EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);\r
+}\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
+  @return EFI_SUCCESS : The periodical schedule is enabled\r
+  @return EFI_TIMEOUT : Time out happened while enabling periodic schedule\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcEnablePeriodSchd (\r
+  IN 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
+\r
+/**\r
+  Disable periodic schedule\r
+\r
+  @param  Ehc          The EHCI device\r
+  @param  Timeout      Time to wait before abort (in millisecond, ms)\r
+\r
+  @return EFI_SUCCESS      : Periodic schedule is disabled.\r
+  @return EFI_DEVICE_ERROR : Fail to disable periodic schedule\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcDisablePeriodSchd (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);\r
+\r
+  Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, FALSE, Timeout);\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Enable asynchrounous schedule\r
+\r
+  @param  Ehc          The EHCI device\r
+  @param  Timeout      Time to wait before abort\r
+\r
+  @return EFI_SUCCESS : The EHCI asynchronous schedule is enabled\r
+  @return Others      : Failed to enable the asynchronous scheudle\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcEnableAsyncSchd (\r
+  IN 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
+\r
+/**\r
+  Disable asynchrounous schedule\r
+\r
+  @param  Ehc          The EHCI device\r
+  @param  Timeout      Time to wait before abort (in millisecond, ms)\r
+\r
+  @return EFI_SUCCESS : The asynchronous schedule is disabled\r
+  @return Others      : Failed to disable the asynchronous schedule\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcDisableAsyncSchd (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);\r
+\r
+  Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, FALSE, Timeout);\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Whether Ehc is halted\r
+\r
+  @param  Ehc          The EHCI device\r
+\r
+  @return TRUE  : The controller is halted\r
+  @return FALSE : It isn't halted\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsHalt (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+{\r
+  return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);\r
+}\r
+\r
+\r
+/**\r
+  Whether system error occurred\r
+\r
+  @param  Ehc          The EHCI device\r
+\r
+  @return TRUE  : System error happened\r
+  @return FALSE : No system error\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsSysError (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+{\r
+  return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);\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
+  @return EFI_SUCCESS : The host controller is reset\r
+  @return Others      : Failed to reset the host\r
+\r
+**/\r
+EFI_STATUS\r
+EhcResetHC (\r
+  IN 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
+/**\r
+  Halt the host controller\r
+\r
+  @param  Ehc          The EHCI device\r
+  @param  Timeout      Time to wait before abort\r
+\r
+  @return EFI_SUCCESS : The EHCI is halt\r
+  @return EFI_TIMEOUT : Failed to halt the controller before Timeout\r
+\r
+**/\r
+EFI_STATUS\r
+EhcHaltHC (\r
+  IN 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
+/**\r
+  Set the EHCI to run\r
+\r
+  @param  Ehc          The EHCI device\r
+  @param  Timeout      Time to wait before abort\r
+\r
+  @return EFI_SUCCESS : The EHCI is running\r
+  @return Others      : Failed to set the EHCI to run\r
+\r
+**/\r
+EFI_STATUS\r
+EhcRunHC (\r
+  IN 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
+/**\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
+  @return EFI_SUCCESS : The EHCI has come out of halt state\r
+  @return EFI_TIMEOUT : Time out happened\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitHC (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+{\r
+  EFI_STATUS              Status;\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
+\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
+  Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIME);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcInitHC: failed to enable period schedule\n"));\r
+    return Status;\r
+  }\r
+\r
+  Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIME);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcInitHC: failed to enable async schedule\n"));\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.h b/MdeModulePkg/Bus/Pci/EhciDxe/EhciReg.h
new file mode 100644 (file)
index 0000000..2ac27eb
--- /dev/null
@@ -0,0 +1,351 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  EhciReg.h\r
+\r
+Abstract:\r
+\r
+  This file contains the definination for host controller register operation routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_REG_H_\r
+#define _EFI_EHCI_REG_H_\r
+\r
+\r
+enum {\r
+  //\r
+  // Capability register offset\r
+  //\r
+  EHC_CAPLENGTH_OFFSET    = 0,    // Capability register length offset\r
+  EHC_HCSPARAMS_OFFSET    = 0x04, // Structural Parameters 04-07h\r
+  EHC_HCCPARAMS_OFFSET    = 0x08, // Capability parameters offset\r
+\r
+  //\r
+  // Capability register bit definition\r
+  //\r
+  HCSP_NPORTS             = 0x0F, // Number of root hub port\r
+  HCCP_64BIT              = 0x01, // 64-bit addressing capability\r
+\r
+  //\r
+  // Operational register offset\r
+  //\r
+  EHC_USBCMD_OFFSET       = 0x0,  // USB command register offset\r
+  EHC_USBSTS_OFFSET       = 0x04, // Statue register offset\r
+  EHC_USBINTR_OFFSET      = 0x08, // USB interrutp offset\r
+  EHC_FRINDEX_OFFSET      = 0x0C, // Frame index offset\r
+  EHC_CTRLDSSEG_OFFSET    = 0x10, // Control data structure segment offset\r
+  EHC_FRAME_BASE_OFFSET   = 0x14, // Frame list base address offset\r
+  EHC_ASYNC_HEAD_OFFSET   = 0x18, // Next asynchronous list address offset\r
+  EHC_CONFIG_FLAG_OFFSET  = 0x40, // Configure flag register offset\r
+  EHC_PORT_STAT_OFFSET    = 0x44, // Port status/control offset\r
+\r
+  EHC_FRAME_LEN           = 1024,\r
+\r
+  //\r
+  // Register bit definition\r
+  //\r
+  CONFIGFLAG_ROUTE_EHC    = 0x01, // Route port to EHC\r
+\r
+  USBCMD_RUN              = 0x01,   // Run/stop\r
+  USBCMD_RESET            = 0x02,   // Start the host controller reset\r
+  USBCMD_ENABLE_PERIOD    = 0x10,   // Enable periodic schedule\r
+  USBCMD_ENABLE_ASYNC     = 0x20,   // Enable asynchronous schedule\r
+  USBCMD_IAAD             = 0x40,   // Interrupt on async advance doorbell\r
+\r
+  USBSTS_IAA              = 0x20,   // Interrupt on async advance\r
+  USBSTS_PERIOD_ENABLED   = 0x4000, // Periodic schedule status\r
+  USBSTS_ASYNC_ENABLED    = 0x8000, // Asynchronous schedule status\r
+  USBSTS_HALT             = 0x1000, // Host controller halted\r
+  USBSTS_SYS_ERROR        = 0x10,   // Host system error\r
+  USBSTS_INTACK_MASK      = 0x003F, // Mask for the interrupt ACK, the WC\r
+                                    // (write clean) bits in USBSTS register\r
+\r
+  PORTSC_CONN             = 0x01,   // Current Connect Status\r
+  PORTSC_CONN_CHANGE      = 0x02,   // Connect Status Change\r
+  PORTSC_ENABLED          = 0x04,   // Port Enable / Disable\r
+  PORTSC_ENABLE_CHANGE    = 0x08,   // Port Enable / Disable Change\r
+  PORTSC_OVERCUR          = 0x10,   // Over current Active\r
+  PORTSC_OVERCUR_CHANGE   = 0x20,   // Over current Change\r
+  PORSTSC_RESUME          = 0x40,   // Force Port Resume\r
+  PORTSC_SUSPEND          = 0x80,   // Port Suspend State\r
+  PORTSC_RESET            = 0x100,  // Port Reset\r
+  PORTSC_LINESTATE_K      = 0x400,  // Line Status K-state\r
+  PORTSC_LINESTATE_J      = 0x800,  // Line Status J-state\r
+  PORTSC_POWER            = 0x1000, // Port Power\r
+  PORTSC_OWNER            = 0x2000, // Port Owner\r
+  PORTSC_CHANGE_MASK      = 0x2A,   // Mask of the port change bits,\r
+                                    // they are WC (write clean)\r
+  //\r
+  // PCI Configuration Registers\r
+  //\r
+  EHC_PCI_CLASSC          = 0x09,\r
+  EHC_PCI_CLASSC_PI       = 0x20,\r
+  EHC_BAR_INDEX           = 0, /* how many bytes away from USB_BASE to 0x10 */\r
+};\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
+UINT32\r
+EhcReadCapRegister (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  UINT32              Offset\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Read  EHCI capability register\r
+\r
+Arguments:\r
+\r
+  Ehc     - The Ehc device\r
+  Offset  - Capability register address\r
+\r
+Returns:\r
+\r
+  The register content read\r
+\r
+--*/\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
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+EhcReadOpReg (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  UINT32              Offset\r
+  )\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcWriteOpReg (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Add support for UEFI Over Legacy (UoL) feature, stop\r
+  the legacy USB SMI support\r
+\r
+  @param  Ehc      The EHCI device.\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcClearLegacySupport (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+;\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
+  @return EFI_SUCCESS : Synchronized with the hardware\r
+  @return EFI_TIMEOUT : Time out happened while waiting door bell to set\r
+\r
+**/\r
+EFI_STATUS\r
+EhcSetAndWaitDoorBell (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  UINT32               Timeout\r
+  )\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcAckAllInterrupt (\r
+  IN  USB2_HC_DEV         *Ehc\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Whether Ehc is halted\r
+\r
+  @param  Ehc      The EHCI device\r
+\r
+  @return TRUE  : The controller is halted\r
+  @return FALSE : It isn't halted\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsHalt (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Whether system error occurred\r
+\r
+  @param  Ehc      The EHCI device\r
+\r
+  @return TRUE  : System error happened\r
+  @return FALSE : No system error\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsSysError (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+;\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
+  @return EFI_SUCCESS : The host controller is reset\r
+  @return Others      : Failed to reset the host\r
+\r
+**/\r
+EFI_STATUS\r
+EhcResetHC (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+;\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
+  @return EFI_SUCCESS : The EHCI is halt\r
+  @return EFI_TIMEOUT : Failed to halt the controller before Timeout\r
+\r
+**/\r
+EFI_STATUS\r
+EhcHaltHC (\r
+  IN USB2_HC_DEV         *Ehc,\r
+  IN UINT32              Timeout\r
+  )\r
+;\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
+  @return EFI_SUCCESS : The EHCI is running\r
+  @return Others      : Failed to set the EHCI to run\r
+\r
+**/\r
+EFI_STATUS\r
+EhcRunHC (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN UINT32               Timeout\r
+  )\r
+;\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
+  @return EFI_SUCCESS : The EHCI has come out of halt state\r
+  @return EFI_TIMEOUT : Time out happened\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitHC (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c b/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c
new file mode 100644 (file)
index 0000000..b13e407
--- /dev/null
@@ -0,0 +1,941 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    EhciSched.c\r
+\r
+Abstract:\r
+\r
+    EHCI transfer scheduling routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#include "Ehci.h"\r
+\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
+STATIC\r
+EFI_STATUS\r
+EhcCreateHelpQ (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+{\r
+  USB_ENDPOINT            Ep;\r
+  EHC_QH                  *Qh;\r
+  QH_HW                   *QhHw;\r
+  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
+\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 USB2_HC_DEV          *Ehc\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  VOID                  *Buf;\r
+  EFI_PHYSICAL_ADDRESS  PhyAddr;\r
+  VOID                  *Map;\r
+  UINTN                 Pages;\r
+  UINTN                 Bytes;\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
+  PciIo = Ehc->PciIo;\r
+\r
+  Bytes = 4096;\r
+  Pages = EFI_SIZE_TO_PAGES (Bytes);\r
+\r
+  Status = PciIo->AllocateBuffer (\r
+                    PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    Pages,\r
+                    &Buf,\r
+                    0\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    EfiPciIoOperationBusMasterCommonBuffer,\r
+                    Buf,\r
+                    &Bytes,\r
+                    &PhyAddr,\r
+                    &Map\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != 4096)) {\r
+    PciIo->FreeBuffer (PciIo, Pages, Buf);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Ehc->PeriodFrameHost  = Buf;\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
+                   PciIo,\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
+\r
+/**\r
+  Free the schedule data. It may be partially initialized.\r
+\r
+  @param  Ehc                   The EHCI device\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcFreeSched (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\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 (EHC_QH));\r
+    Ehc->PeriodOne = NULL;\r
+  }\r
+\r
+  if (Ehc->ReclaimHead != NULL) {\r
+    UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));\r
+    Ehc->ReclaimHead = NULL;\r
+  }\r
+\r
+  if (Ehc->ShortReadStop != NULL) {\r
+    UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (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
+    PciIo = Ehc->PciIo;\r
+    ASSERT (PciIo != NULL);\r
+\r
+    PciIo->Unmap (PciIo, Ehc->PeriodFrameMap);\r
+\r
+    PciIo->FreeBuffer (\r
+             PciIo,\r
+             EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE),\r
+             Ehc->PeriodFrameHost\r
+             );\r
+\r
+    Ehc->PeriodFrame = NULL;\r
+  }\r
+}\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToAsync (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN EHC_QH               *Qh\r
+  )\r
+{\r
+  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
+/**\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromAsync (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN EHC_QH               *Qh\r
+  )\r
+{\r
+  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_TIME);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    EHC_ERROR (("EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n"));\r
+  }\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToPeriod (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN EHC_QH               *Qh\r
+  )\r
+{\r
+  UINT32                  *Frames;\r
+  UINTN                   Index;\r
+  EHC_QH                  *Prev;\r
+  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
+/**\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromPeriod (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN EHC_QH               *Qh\r
+  )\r
+{\r
+  UINT32                  *Frames;\r
+  UINTN                   Index;\r
+  EHC_QH                  *Prev;\r
+  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
+\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
+  @return Whether the result of URB transfer is finialized.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EhcCheckUrbResult (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  URB                 *Urb\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  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, 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
+          EHC_DEBUG (("EhcCheckUrbResult: Short packet read, break\n"));\r
+\r
+          Finished = TRUE;\r
+          goto ON_EXIT;\r
+        }\r
+\r
+        EHC_DEBUG (("EhcCheckUrbResult: Short packet read, continue\n"));\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
+/**\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
+  @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
+EhcExecTransfer (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  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_STALL_1_MILLISECOND / EHC_SYNC_POLL_TIME) + 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
+    gBS->Stall (EHC_SYNC_POLL_TIME);\r
+  }\r
+\r
+  if (!Finished) {\r
+    EHC_ERROR (("EhcExecTransfer: transfer not finished in %dms\n", TimeOut));\r
+    EHC_DUMP_QH ((Urb->Qh, NULL, FALSE));\r
+\r
+    Status = EFI_TIMEOUT;\r
+\r
+  } else if (Urb->Result != EFI_USB_NOERROR) {\r
+    EHC_ERROR (("EhcExecTransfer: transfer failed with %x\n", Urb->Result));\r
+    EHC_DUMP_QH ((Urb->Qh, NULL, FALSE));\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\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_SUCCESS           An asynchronous transfer is removed\r
+  @retval EFI_NOT_FOUND         No transfer for the device is found\r
+\r
+**/\r
+EFI_STATUS\r
+EhciDelAsyncIntTransfer (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               EpNum,\r
+  OUT UINT8               *DataToggle\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *Next;\r
+  URB                     *Urb;\r
+  EFI_USB_DATA_DIRECTION  Direction;\r
+\r
+  Direction = ((EpNum & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+  EpNum    &= 0x0F;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, 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
+      gBS->FreePool (Urb->Data);\r
+      EhcFreeUrb (Ehc, Urb);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Remove all the asynchronous interrutp transfers\r
+\r
+  @param  Ehc                   The EHCI device\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhciDelAllAsyncIntTransfers (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *Next;\r
+  URB                     *Urb;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+\r
+    EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
+    RemoveEntryList (&Urb->UrbList);\r
+\r
+    gBS->FreePool (Urb->Data);\r
+    EhcFreeUrb (Ehc, Urb);\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Update the queue head for next round of asynchronous transfer\r
+\r
+  @param  Urb                   The URB to update\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcUpdateAsyncRequest (\r
+  IN URB                  *Urb\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  EHC_QTD                 *FirstQtd;\r
+  QH_HW                   *QhHw;\r
+  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, 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
+/**\r
+  Interrupt transfer periodic check handler\r
+\r
+  @param  Event                 Interrupt event\r
+  @param  Context               Pointer to USB2_HC_DEV\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcMoniteAsyncRequests (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+{\r
+  USB2_HC_DEV             *Ehc;\r
+  EFI_TPL                 OldTpl;\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *Next;\r
+  BOOLEAN                 Finished;\r
+  UINT8                   *ProcBuf;\r
+  URB                     *Urb;\r
+\r
+  OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
+  Ehc     = (USB2_HC_DEV *) Context;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, 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
+    // 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
+\r
+      ProcBuf = AllocatePool (Urb->Completed);\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
+      //\r
+      // Restore the old TPL, USB bus maybe connect device in\r
+      // his callback. Some drivers may has a lower TPL restriction.\r
+      //\r
+      gBS->RestoreTPL (OldTpl);\r
+      (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
+      OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+    }\r
+\r
+    if (ProcBuf != NULL) {\r
+      gBS->FreePool (ProcBuf);\r
+    }\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.h b/MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.h
new file mode 100644 (file)
index 0000000..d8f2661
--- /dev/null
@@ -0,0 +1,220 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  EhciSched.h\r
+\r
+Abstract:\r
+\r
+  This file contains the definination for host controller schedule routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_SCHED_H_\r
+#define _EFI_EHCI_SCHED_H_\r
+\r
+EFI_STATUS\r
+EhcInitSched (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize the schedule data structure such as frame list\r
+\r
+Arguments:\r
+\r
+  Ehc - The EHCI device to init schedule data for\r
+\r
+Returns:\r
+\r
+  EFI_OUT_OF_RESOURCES  - Failed to allocate resource to init schedule data\r
+  EFI_SUCCESS           - The schedule data is initialized\r
+\r
+--*/\r
+;\r
+\r
+\r
+\r
+/**\r
+  Free the schedule data. It may be partially initialized.\r
+\r
+  @param  Ehc            The EHCI device\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcFreeSched (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+;\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToAsync (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN EHC_QH               *Qh\r
+  )\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromAsync (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN EHC_QH               *Qh\r
+  )\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToPeriod (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN EHC_QH               *Qh\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromPeriod (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN EHC_QH               *Qh\r
+  )\r
+;\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
+  @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
+EhcExecTransfer (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  URB                 *Urb,\r
+  IN  UINTN               TimeOut\r
+  )\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_SUCCESS    An asynchronous transfer is removed\r
+  @retval EFI_NOT_FOUND  No transfer for the device is found\r
+\r
+**/\r
+EFI_STATUS\r
+EhciDelAsyncIntTransfer (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               EpNum,\r
+  OUT UINT8               *DataToggle\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Remove all the asynchronous interrutp transfers\r
+\r
+  @param  Ehc            The EHCI device\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhciDelAllAsyncIntTransfers (\r
+  IN USB2_HC_DEV          *Ehc\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Interrupt transfer periodic check handler\r
+\r
+  @param  Event          Interrupt event\r
+  @param  Context        Pointer to USB2_HC_DEV\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcMoniteAsyncRequests (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c b/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
new file mode 100644 (file)
index 0000000..7b8b7b5
--- /dev/null
@@ -0,0 +1,669 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    EhciUrb.c\r
+\r
+Abstract:\r
+\r
+    This file contains URB request, each request is warpped in a\r
+    URB (Usb Request Block)\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#include "Ehci.h"\r
+\r
+\r
+/**\r
+  Create a single QTD to hold the data\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
+  @return Created QTD or NULL if failed to create one\r
+\r
+**/\r
+EHC_QTD *\r
+EhcCreateQtd (\r
+  IN 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
+  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->MemPool, sizeof (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
+\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
+  @return None\r
+\r
+**/\r
+STATIC\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
+\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
+  @return Created queue head or NULL if failed to create one\r
+\r
+**/\r
+EHC_QH *\r
+EhcCreateQh (\r
+  IN USB2_HC_DEV          *Ehci,\r
+  IN USB_ENDPOINT         *Ep\r
+  )\r
+{\r
+  EHC_QH                  *Qh;\r
+  QH_HW                   *QhHw;\r
+\r
+  Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (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
+\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
+  @return The converted interval\r
+\r
+**/\r
+STATIC\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 1 << (BitCount - 1);\r
+}\r
+\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
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcFreeQtds (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN LIST_ENTRY           *Qtds\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *Next;\r
+  EHC_QTD                 *Qtd;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {\r
+    Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
+\r
+    RemoveEntryList (&Qtd->QtdList);\r
+    UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));\r
+  }\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcFreeUrb (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN URB                  *Urb\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+\r
+  PciIo = Ehc->PciIo;\r
+\r
+  if (Urb->RequestPhy != NULL) {\r
+    PciIo->Unmap (PciIo, Urb->RequestMap);\r
+  }\r
+\r
+  if (Urb->DataMap != NULL) {\r
+    PciIo->Unmap (PciIo, Urb->DataMap);\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 (EHC_QH));\r
+  }\r
+\r
+  gBS->FreePool (Urb);\r
+}\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
+STATIC\r
+EFI_STATUS\r
+EhcCreateQtds (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN URB                  *Urb\r
+  )\r
+{\r
+  USB_ENDPOINT            *Ep;\r
+  EHC_QH                  *Qh;\r
+  EHC_QTD                 *Qtd;\r
+  EHC_QTD                 *StatusQtd;\r
+  EHC_QTD                 *NextQtd;\r
+  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 = 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, 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, 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, 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
+/**\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
+  @return Created URB or NULL\r
+\r
+**/\r
+URB *\r
+EhcCreateUrb (\r
+  IN 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_PCI_IO_PROTOCOL_OPERATION MapOp;\r
+  EFI_PCI_IO_PROTOCOL           *PciIo;\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Len;\r
+  URB                           *Urb;\r
+  VOID                          *Map;\r
+\r
+  Urb = AllocateZeroPool (sizeof (URB));\r
+\r
+  if (Urb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Urb->Signature  = EHC_URB_SIG;\r
+  InitializeListHead (&Urb->UrbList);\r
+\r
+  Ep              = &Urb->Ep;\r
+  Ep->DevAddr     = DevAddr;\r
+  Ep->EpAddr      = EpAddr & 0x0F;\r
+  Ep->Direction   = ((EpAddr & 0x80) ? 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
+\r
+  PciIo           = Ehc->PciIo;\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
+    MapOp   = EfiPciIoOperationBusMasterRead;\r
+    Status  = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);\r
+\r
+    if (EFI_ERROR (Status) || (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
+\r
+    if (Ep->Direction == EfiUsbDataIn) {\r
+      MapOp = EfiPciIoOperationBusMasterWrite;\r
+    } else {\r
+      MapOp = EfiPciIoOperationBusMasterRead;\r
+    }\r
+\r
+    Status  = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);\r
+\r
+    if (EFI_ERROR (Status) || (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/EhciDxe/EhciUrb.h b/MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.h
new file mode 100644 (file)
index 0000000..a2a5826
--- /dev/null
@@ -0,0 +1,350 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    EhciUrb.h\r
+\r
+Abstract:\r
+\r
+    This file contains URB request, each request is warpped in a\r
+    URB (Usb Request Block)\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_URB_H_\r
+#define _EFI_EHCI_URB_H_\r
+\r
+\r
+typedef struct _EHC_QTD  EHC_QTD;\r
+typedef struct _EHC_QH   EHC_QH;\r
+typedef struct _URB      URB;\r
+\r
+enum {\r
+  //\r
+  // Transfer types, used in URB to identify the transfer type\r
+  //\r
+  EHC_CTRL_TRANSFER       = 0x01,\r
+  EHC_BULK_TRANSFER       = 0x02,\r
+  EHC_INT_TRANSFER_SYNC   = 0x04,\r
+  EHC_INT_TRANSFER_ASYNC  = 0x08,\r
+\r
+  EHC_QTD_SIG             = EFI_SIGNATURE_32 ('U', 'S', 'B', 'T'),\r
+  EHC_QH_SIG              = EFI_SIGNATURE_32 ('U', 'S', 'B', 'H'),\r
+  EHC_URB_SIG             = EFI_SIGNATURE_32 ('U', 'S', 'B', 'R'),\r
+\r
+  //\r
+  // Hardware related bit definitions\r
+  //\r
+  EHC_TYPE_ITD            = 0x00,\r
+  EHC_TYPE_QH             = 0x02,\r
+  EHC_TYPE_SITD           = 0x04,\r
+  EHC_TYPE_FSTN           = 0x06,\r
+\r
+  QH_NAK_RELOAD           = 3,\r
+  QH_HSHBW_MULTI          = 1,\r
+\r
+  QTD_MAX_ERR             = 3,\r
+  QTD_PID_OUTPUT          = 0x00,\r
+  QTD_PID_INPUT           = 0x01,\r
+  QTD_PID_SETUP           = 0x02,\r
+\r
+  QTD_STAT_DO_OUT         = 0,\r
+  QTD_STAT_DO_SS          = 0,\r
+  QTD_STAT_DO_PING        = 0x01,\r
+  QTD_STAT_DO_CS          = 0x02,\r
+  QTD_STAT_TRANS_ERR      = 0x08,\r
+  QTD_STAT_BABBLE_ERR     = 0x10,\r
+  QTD_STAT_BUFF_ERR       = 0x20,\r
+  QTD_STAT_HALTED         = 0x40,\r
+  QTD_STAT_ACTIVE         = 0x80,\r
+  QTD_STAT_ERR_MASK       = QTD_STAT_TRANS_ERR | QTD_STAT_BABBLE_ERR | QTD_STAT_BUFF_ERR,\r
+\r
+  QTD_MAX_BUFFER          = 4,\r
+  QTD_BUF_LEN             = 4096,\r
+  QTD_BUF_MASK            = 0x0FFF,\r
+\r
+  QH_MICROFRAME_0         = 0x01,\r
+  QH_MICROFRAME_1         = 0x02,\r
+  QH_MICROFRAME_2         = 0x04,\r
+  QH_MICROFRAME_3         = 0x08,\r
+  QH_MICROFRAME_4         = 0x10,\r
+  QH_MICROFRAME_5         = 0x20,\r
+  QH_MICROFRAME_6         = 0x40,\r
+  QH_MICROFRAME_7         = 0x80,\r
+\r
+  USB_ERR_SHORT_PACKET    = 0x200,\r
+};\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
+typedef struct _EHC_QTD {\r
+  QTD_HW                  QtdHw;\r
+  UINT32                  Signature;\r
+  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
+} EHC_QTD;\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
+typedef struct _EHC_QH {\r
+  QH_HW                   QhHw;\r
+  UINT32                  Signature;\r
+  EHC_QH                  *NextQh;    // The queue head pointed to by horizontal link\r
+  LIST_ENTRY              Qtds;       // The list of QTDs to this queue head\r
+  UINTN                   Interval;\r
+} EHC_QH;\r
+\r
+//\r
+// URB (Usb Request Block) contains information for all kinds of\r
+// usb requests.\r
+//\r
+typedef struct _URB {\r
+  UINT32                          Signature;\r
+  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
+  EHC_QH                          *Qh;\r
+\r
+  //\r
+  // Transaction result\r
+  //\r
+  UINT32                          Result;\r
+  UINTN                           Completed;    // completed data length\r
+  UINT8                           DataToggle;\r
+} URB;\r
+\r
+\r
+\r
+/**\r
+  Create a single QTD to hold the data\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
+  @return Created QTD or NULL if failed to create one\r
+\r
+**/\r
+EHC_QTD *\r
+EhcCreateQtd (\r
+  IN 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
+\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
+  @return Created queue head or NULL if failed to create one\r
+\r
+**/\r
+EHC_QH *\r
+EhcCreateQh (\r
+  IN USB2_HC_DEV          *Ehci,\r
+  IN USB_ENDPOINT         *Ep\r
+  )\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
+  @return None\r
+\r
+**/\r
+VOID\r
+EhcFreeUrb (\r
+  IN USB2_HC_DEV          *Ehc,\r
+  IN URB                  *Urb\r
+  )\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
+  @return Created URB or NULL\r
+\r
+**/\r
+URB *\r
+EhcCreateUrb (\r
+  IN 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/EhciDxe/UsbHcMem.c b/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.c
new file mode 100644 (file)
index 0000000..b7e7d66
--- /dev/null
@@ -0,0 +1,549 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    EhciMem.c\r
+\r
+Abstract:\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+\r
+#include "Ehci.h"\r
+\r
+\r
+UINTN mUsbHcDebugLevel = DEBUG_INFO;\r
+\r
+\r
+/**\r
+  Allocate a block of memory to be used by the buffer pool\r
+\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
+STATIC\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+  IN  USBHC_MEM_POOL      *Pool,\r
+  IN  UINTN               Pages\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK         *Block;\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+  VOID                    *BufHost;\r
+  VOID                    *Mapping;\r
+  EFI_PHYSICAL_ADDRESS    MappedAddr;\r
+  UINTN                   Bytes;\r
+  EFI_STATUS              Status;\r
+\r
+  PciIo = Pool->PciIo;\r
+\r
+  Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
+  if (Block == NULL) {\r
+    return NULL;\r
+  }\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->BufLen   = EFI_PAGES_TO_SIZE (Pages);\r
+  Block->BitsLen  = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+  Block->Bits     = AllocateZeroPool (Block->BitsLen);\r
+\r
+  if (Block->Bits == NULL) {\r
+    gBS->FreePool (Block);\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Allocate the number of Pages of memory, then map it for\r
+  // bus master read and write.\r
+  //\r
+  Status = PciIo->AllocateBuffer (\r
+                    PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    Pages,\r
+                    &BufHost,\r
+                    0\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_BITARRAY;\r
+  }\r
+\r
+  Bytes = EFI_PAGES_TO_SIZE (Pages);\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    EfiPciIoOperationBusMasterCommonBuffer,\r
+                    BufHost,\r
+                    &Bytes,\r
+                    &MappedAddr,\r
+                    &Mapping\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
+    goto FREE_BUFFER;\r
+  }\r
+\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
+    PciIo->Unmap (PciIo, Mapping);\r
+    goto FREE_BUFFER;\r
+  }\r
+\r
+  Block->BufHost  = BufHost;\r
+  Block->Buf      = (UINT8 *) ((UINTN) MappedAddr);\r
+  Block->Mapping  = Mapping;\r
+\r
+  DEBUG ((mUsbHcDebugLevel, "UsbHcAllocMemBlock: block %x created with buffer %x\n",\r
+                          Block, Block->Buf));\r
+\r
+  return Block;\r
+\r
+FREE_BUFFER:\r
+  PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
+\r
+FREE_BITARRAY:\r
+  gBS->FreePool (Block->Bits);\r
+  gBS->FreePool (Block);\r
+  return NULL;\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
+  @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbHcFreeMemBlock (\r
+  IN USBHC_MEM_POOL       *Pool,\r
+  IN USBHC_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+\r
+  ASSERT ((Pool != NULL) && (Block != NULL));\r
+\r
+  PciIo = Pool->PciIo;\r
+\r
+  //\r
+  // Unmap the common buffer then free the structures\r
+  //\r
+  PciIo->Unmap (PciIo, Block->Mapping);\r
+  PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
+\r
+  gBS->FreePool (Block->Bits);\r
+  gBS->FreePool (Block);\r
+}\r
+\r
+\r
+/**\r
+  Alloc some memory from the block\r
+\r
+  @param  Block          The memory block to allocate memory from\r
+  @param  Mem            The variable to store the memory allocated\r
+  @param  Units          Number of memory units to allocate\r
+\r
+  @return EFI_SUCCESS   : The needed memory is allocated\r
+  @return EFI_NOT_FOUND : Can't find the free memory\r
+\r
+**/\r
+STATIC\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] |= 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
+/**\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
+  @return VOID\r
+\r
+**/\r
+STATIC\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
+/**\r
+  Is the memory block empty?\r
+\r
+  @param  Block          The memory block to check\r
+\r
+  @return TRUE  : The memory block is empty\r
+  @return FALSE : The memory block isn't empty\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+UsbHcIsMemBlockEmpty (\r
+  IN USBHC_MEM_BLOCK     *Block\r
+  )\r
+{\r
+  UINTN                   Index;\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
+/**\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
+  @return VOID\r
+\r
+**/\r
+STATIC\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
+/**\r
+  Initialize the memory management pool for the host controller\r
+\r
+  @param  Pool           The USB memory pool to initialize\r
+  @param  PciIo          The PciIo that can be used to access the host controller\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
+  @return EFI_SUCCESS         : The memory pool is initialized\r
+  @return EFI_OUT_OF_RESOURCE : Fail to init the memory pool\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN BOOLEAN              Check4G,\r
+  IN UINT32               Which4G\r
+  )\r
+{\r
+  USBHC_MEM_POOL          *Pool;\r
+\r
+  Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
+\r
+  if (Pool == NULL) {\r
+    return Pool;\r
+  }\r
+\r
+  Pool->PciIo   = PciIo;\r
+  Pool->Check4G = Check4G;\r
+  Pool->Which4G = Which4G;\r
+  Pool->Head    = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
+\r
+  if (Pool->Head == NULL) {\r
+    gBS->FreePool (Pool);\r
+    Pool = NULL;\r
+  }\r
+\r
+  return Pool;\r
+}\r
+\r
+\r
+/**\r
+  Release the memory management pool\r
+\r
+  @param  Pool           The USB memory pool to free\r
+\r
+  @return EFI_SUCCESS      : The memory pool is freed\r
+  @return EFI_DEVICE_ERROR : Failed to free the memory pool\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
+    UsbHcUnlinkMemBlock (Pool->Head, Block);\r
+    UsbHcFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  UsbHcFreeMemBlock (Pool, Pool->Head);\r
+  gBS->FreePool (Pool);\r
+  return EFI_SUCCESS;\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  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  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
+\r
+  NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
+\r
+  if (NewBlock == NULL) {\r
+    DEBUG ((mUsbHcDebugLevel, "UsbHcAllocateMem: failed to allocate block\n"));\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
+/**\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
+  @return VOID\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) 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
+    DEBUG ((mUsbHcDebugLevel, "UsbHcFreeMem: block %x is empty, recycle\n", Block));\r
+\r
+    UsbHcUnlinkMemBlock (Head, Block);\r
+    UsbHcFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  return ;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.h b/MdeModulePkg/Bus/Pci/EhciDxe/UsbHcMem.h
new file mode 100644 (file)
index 0000000..10d3545
--- /dev/null
@@ -0,0 +1,168 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  EhciMem.h\r
+\r
+Abstract:\r
+\r
+  This file contains the definination for host controller memory management routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_MEM_H_\r
+#define _EFI_EHCI_MEM_H_\r
+\r
+\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
+typedef 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
+} USBHC_MEM_BLOCK;\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
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+  BOOLEAN                 Check4G;\r
+  UINT32                  Which4G;\r
+  USBHC_MEM_BLOCK         *Head;\r
+} USBHC_MEM_POOL;\r
+\r
+enum {\r
+  USBHC_MEM_UNIT           = 64,     // Memory allocation unit, must be 2^n, n>4\r
+\r
+  USBHC_MEM_UNIT_MASK      = USBHC_MEM_UNIT - 1,\r
+  USBHC_MEM_DEFAULT_PAGES  = 16,\r
+};\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
+\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN BOOLEAN              Check4G,\r
+  IN UINT32               Which4G\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize the memory management pool for the host controller\r
+\r
+Arguments:\r
+\r
+  Pool    - The USB memory pool to initialize\r
+  PciIo   - The PciIo that can be used to access the host controller\r
+  Check4G - Whether the host controller requires allocated memory\r
+            from one 4G address space.\r
+  Which4G - The 4G memory area each memory allocated should be from\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS         : The memory pool is initialized\r
+  EFI_OUT_OF_RESOURCE : Fail to init the memory pool\r
+\r
+--*/\r
+;\r
+\r
+\r
+\r
+/**\r
+  Release the memory management pool\r
+\r
+  @param  Pool  The USB memory pool to free\r
+\r
+  @return EFI_SUCCESS      : The memory pool is freed\r
+  @return EFI_DEVICE_ERROR : Failed to free the memory pool\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+  IN USBHC_MEM_POOL       *Pool\r
+  )\r
+;\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  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  USBHC_MEM_POOL      *Pool,\r
+  IN  UINTN               Size\r
+  )\r
+;\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
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+  IN USBHC_MEM_POOL       *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  )\r
+;\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/UhciDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..d1cb1eb
--- /dev/null
@@ -0,0 +1,203 @@
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "uhci.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+UhciComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UhciComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      ControllerHandle,\r
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL     gUhciComponentName = {\r
+  UhciComponentNameGetDriverName,\r
+  UhciComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mUhciDriverNameTable[] = {\r
+  { "eng", L"Usb Uhci Driver" },\r
+  { NULL, NULL }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UhciComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **DriverName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+  Arguments:\r
+    This       - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    Language   - A pointer to a three character ISO 639-2 language identifier.\r
+                 This is the language of the driver name that that the caller\r
+                 is requesting, and it must match one of the languages specified\r
+                 in SupportedLanguages.  The number of languages supported by a\r
+                 driver is up to the driver writer.\r
+    DriverName - A pointer to the Unicode string to return.  This Unicode string\r
+                 is the name of the driver specified by This in the language\r
+                 specified by Language.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the Driver specified by This\r
+                            and the language specified by Language was returned\r
+                            in DriverName.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - DriverName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gUhciComponentName.SupportedLanguages,\r
+          mUhciDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UhciComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      ControllerHandle,\r
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **ControllerName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the controller\r
+    that is being managed by an EFI Driver.\r
+\r
+  Arguments:\r
+    This             - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    ControllerHandle - The handle of a controller that the driver specified by\r
+                       This is managing.  This handle specifies the controller\r
+                       whose name is to be returned.\r
+    ChildHandle      - The handle of the child controller to retrieve the name\r
+                       of.  This is an optional parameter that may be NULL.  It\r
+                       will be NULL for device drivers.  It will also be NULL\r
+                       for a bus drivers that wish to retrieve the name of the\r
+                       bus controller.  It will not be NULL for a bus driver\r
+                       that wishes to retrieve the name of a child controller.\r
+    Language         - A pointer to a three character ISO 639-2 language\r
+                       identifier.  This is the language of the controller name\r
+                       that that the caller is requesting, and it must match one\r
+                       of the languages specified in SupportedLanguages.  The\r
+                       number of languages supported by a driver is up to the\r
+                       driver writer.\r
+    ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                       string is the name of the controller specified by\r
+                       ControllerHandle and ChildHandle in the language\r
+                       specified by Language from the point of view of the\r
+                       driver specified by This.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the user readable name in the\r
+                            language specified by Language for the driver\r
+                            specified by This was returned in DriverName.\r
+    EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid\r
+                            EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This is not currently\r
+                            managing the controller specified by\r
+                            ControllerHandle and ChildHandle.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  USB_HC_DEV          *UhciDev;\r
+  EFI_USB_HC_PROTOCOL *UsbHc;\r
+\r
+  //\r
+  // This is a device driver, so ChildHandle must be NULL.\r
+  //\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Make sure this driver is currently managing ControllerHandle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gUhciDriverBinding.DriverBindingHandle,\r
+             &gEfiPciIoProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get the device context\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiUsbHcProtocolGuid,\r
+                  (VOID **) &UsbHc,\r
+                  gUhciDriverBinding.DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  UhciDev = UHC_FROM_USB_HC_PROTO (UsbHc);\r
+\r
+  return LookupUnicodeString (\r
+          Language,\r
+          gUhciComponentName.SupportedLanguages,\r
+          UhciDev->CtrlNameTable,\r
+          ControllerName\r
+          );\r
+\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c b/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c
new file mode 100644 (file)
index 0000000..1c3e37a
--- /dev/null
@@ -0,0 +1,2331 @@
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  Uhci.c\r
+\r
+Abstract:\r
+\r
+  The UHCI driver model and HC protocol routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#include "Uhci.h"\r
+\r
+\r
+/**\r
+  Provides software reset for the USB host controller.\r
+\r
+  This      : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  Attributes: A bit mask of the reset operation to perform.\r
+\r
+  @return EFI_SUCCESS           : The reset operation succeeded.\r
+  @return EFI_INVALID_PARAMETER : Attributes is not valid.\r
+  @return EFI_DEVICE_ERROR      : An error was encountered while attempting\r
+  @return to perform the reset operation.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciReset (\r
+  IN EFI_USB_HC_PROTOCOL     *This,\r
+  IN UINT16                  Attributes\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+  EFI_TPL             OldTpl;\r
+\r
+  OldTpl  = gBS->RaiseTPL (UHCI_TPL);\r
+  Uhc     = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+  switch (Attributes) {\r
+  case EFI_USB_HC_RESET_GLOBAL:\r
+    //\r
+    // Stop schedule and set the Global Reset bit in the command register\r
+    //\r
+    UhciStopHc (Uhc, STALL_1_SECOND);\r
+    UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);\r
+\r
+    //\r
+    // Wait 50ms for root port to let reset complete\r
+    // See UHCI spec page122 Reset signaling\r
+    //\r
+    gBS->Stall (ROOT_PORT_REST_TIME);\r
+\r
+    //\r
+    // Clear the Global Reset bit to zero.\r
+    //\r
+    UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);\r
+\r
+    //\r
+    // UHCI spec page120 reset recovery time\r
+    //\r
+    gBS->Stall (PORT_RESET_RECOVERY_TIME);\r
+    break;\r
+\r
+  case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
+    //\r
+    // Stop schedule and set Host Controller Reset bit to 1\r
+    //\r
+    UhciStopHc (Uhc, STALL_1_SECOND);\r
+    UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);\r
+\r
+    //\r
+    // this bit will be reset by Host Controller when reset is completed.\r
+    // wait 10ms to let reset complete\r
+    //\r
+    gBS->Stall (PORT_RESET_RECOVERY_TIME);\r
+    break;\r
+\r
+  default:\r
+    goto ON_INVAILD_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Delete all old transactions on the USB bus, then\r
+  // reinitialize the frame list\r
+  //\r
+  UhciFreeAllAsyncReq (Uhc);\r
+  UhciDestoryFrameList (Uhc);\r
+  UhciInitFrameList (Uhc);\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_INVAILD_PARAMETER:\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+\r
+/**\r
+  Retrieves current state of the USB host controller.\r
+\r
+  This    :  A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  State   :  A pointer to the EFI_USB_HC_STATE data structure that\r
+  indicates current state of the USB host controller.\r
+\r
+  @return EFI_SUCCESS           : State was returned\r
+  @return EFI_INVALID_PARAMETER : State is NULL.\r
+  @return EFI_DEVICE_ERROR      : An error was encountered\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciGetState (\r
+  IN  EFI_USB_HC_PROTOCOL     *This,\r
+  OUT EFI_USB_HC_STATE        *State\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+  UINT16              UsbSts;\r
+  UINT16              UsbCmd;\r
+\r
+  if (State == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Uhc     = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+  UsbCmd  = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
+  UsbSts  = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);\r
+\r
+  if (UsbCmd & USBCMD_EGSM) {\r
+    *State = EfiUsbHcStateSuspend;\r
+\r
+  } else if ((UsbSts & USBSTS_HCH) != 0) {\r
+    *State = EfiUsbHcStateHalt;\r
+\r
+  } else {\r
+    *State = EfiUsbHcStateOperational;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Sets the USB host controller to a specific state.\r
+\r
+  This     : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  State    : Indicates the state of the host controller that will be set.\r
+\r
+  @return EFI_SUCCESS           : The USB host controller was successfully set\r
+  @return EFI_INVALID_PARAMETER : State is invalid.\r
+  @return EFI_DEVICE_ERROR      : Failed to set the state specified\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciSetState (\r
+  IN EFI_USB_HC_PROTOCOL     *This,\r
+  IN EFI_USB_HC_STATE        State\r
+  )\r
+{\r
+  EFI_USB_HC_STATE    CurState;\r
+  USB_HC_DEV          *Uhc;\r
+  EFI_TPL             OldTpl;\r
+  EFI_STATUS          Status;\r
+  UINT16              UsbCmd;\r
+\r
+  Uhc     = UHC_FROM_USB_HC_PROTO (This);\r
+  Status  = UhciGetState (This, &CurState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (CurState == State) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status  = EFI_SUCCESS;\r
+  OldTpl  = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+  switch (State) {\r
+  case EfiUsbHcStateHalt:\r
+    Status = UhciStopHc (Uhc, STALL_1_SECOND);\r
+    break;\r
+\r
+  case EfiUsbHcStateOperational:\r
+    UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
+\r
+    if (CurState == EfiUsbHcStateHalt) {\r
+      //\r
+      // Set Run/Stop bit to 1, also set the bandwidht reclamation\r
+      // point to 64 bytes\r
+      //\r
+      UsbCmd |= USBCMD_RS | USBCMD_MAXP;\r
+      UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
+\r
+    } else if (CurState == EfiUsbHcStateSuspend) {\r
+      //\r
+      // If FGR(Force Global Resume) bit is 0, set it\r
+      //\r
+      if ((UsbCmd & USBCMD_FGR) == 0) {\r
+        UsbCmd |= USBCMD_FGR;\r
+        UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
+      }\r
+\r
+      //\r
+      // wait 20ms to let resume complete (20ms is specified by UHCI spec)\r
+      //\r
+      gBS->Stall (FORCE_GLOBAL_RESUME_TIME);\r
+\r
+      //\r
+      // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0\r
+      //\r
+      UsbCmd &= ~USBCMD_FGR;\r
+      UsbCmd &= ~USBCMD_EGSM;\r
+      UsbCmd |= USBCMD_RS;\r
+      UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
+    }\r
+\r
+    break;\r
+\r
+  case EfiUsbHcStateSuspend:\r
+    Status = UhciSetState (This, EfiUsbHcStateHalt);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    //\r
+    // Set Enter Global Suspend Mode bit to 1.\r
+    //\r
+    UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
+    UsbCmd |= USBCMD_EGSM;\r
+    UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+    break;\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Retrieves the number of root hub ports.\r
+\r
+  This       : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  PortNumber : A pointer to the number of the root hub ports.\r
+\r
+  @return EFI_SUCCESS           : The port number was retrieved successfully.\r
+  @return EFI_INVALID_PARAMETER : PortNumber is NULL.\r
+  @return EFI_DEVICE_ERROR      : An error was encountered\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciGetRootHubPortNumber (\r
+  IN  EFI_USB_HC_PROTOCOL     *This,\r
+  OUT UINT8                   *PortNumber\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+  UINT32              Offset;\r
+  UINT16              PortSC;\r
+  UINT32              Index;\r
+\r
+  Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+  if (PortNumber == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *PortNumber = 0;\r
+\r
+  for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {\r
+    Offset  = USBPORTSC_OFFSET + Index * 2;\r
+    PortSC  = UhciReadReg (Uhc->PciIo, Offset);\r
+\r
+    //\r
+    // Port status's bit 7 is reserved and always returns 1 if\r
+    // the port number is valid. Intel's UHCI (in EHCI controller)\r
+    // returns 0 in this bit if port number is invalid. Also, if\r
+    // PciIo IoRead returns error, 0xFFFF is returned to caller.\r
+    //\r
+    if (((PortSC & 0x80) != 0) && (PortSC != 0xFFFF)) {\r
+      (*PortNumber)++;\r
+    }\r
+  }\r
+\r
+  Uhc->RootPorts = *PortNumber;\r
+\r
+  UHCI_DEBUG (("UhciGetRootHubPortNumber: %d ports\n", Uhc->RootPorts));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port.\r
+\r
+  This        : A pointer to the EFI_USB_HC_PROTOCOL.\r
+  PortNumber  : Specifies the root hub port. This value is zero-based.\r
+  PortStatus  : A pointer to the current port status bits and port status change bits.\r
+\r
+  @return EFI_SUCCESS           : The port status was returned in PortStatus.\r
+  @return EFI_INVALID_PARAMETER : PortNumber is invalid.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhciGetRootHubPortStatus (\r
+  IN  EFI_USB_HC_PROTOCOL     *This,\r
+  IN  UINT8                   PortNumber,\r
+  OUT EFI_USB_PORT_STATUS     *PortStatus\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+  UINT32              Offset;\r
+  UINT16              PortSC;\r
+\r
+  Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+  if (PortStatus == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (PortNumber >= Uhc->RootPorts) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Offset                        = USBPORTSC_OFFSET + PortNumber * 2;\r
+  PortStatus->PortStatus        = 0;\r
+  PortStatus->PortChangeStatus  = 0;\r
+\r
+  PortSC                        = UhciReadReg (Uhc->PciIo, Offset);\r
+\r
+  if (PortSC & USBPORTSC_CCS) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
+  }\r
+\r
+  if (PortSC & USBPORTSC_PED) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
+  }\r
+\r
+  if (PortSC & USBPORTSC_SUSP) {\r
+    UHCI_DEBUG (("UhciGetRootHubPortStatus: port %d is suspended\n", PortNumber));\r
+    PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+  }\r
+\r
+  if (PortSC & USBPORTSC_PR) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
+  }\r
+\r
+  if (PortSC & USBPORTSC_LSDA) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+  }\r
+\r
+  //\r
+  // CHC will always return one in port owner bit\r
+  //\r
+  PortStatus->PortStatus |= USB_PORT_STAT_OWNER;\r
+\r
+  if (PortSC & USBPORTSC_CSC) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
+  }\r
+\r
+  if (PortSC & USBPORTSC_PEDC) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Sets a feature for the specified root hub port.\r
+\r
+  This        : A pointer to the EFI_USB_HC_PROTOCOL.\r
+  PortNumber  : Specifies the root hub port whose feature\r
+  is requested to be set.\r
+  PortFeature : Indicates the feature selector associated\r
+  with the feature set request.\r
+\r
+  @return EFI_SUCCESS           : The feature was set for the port.\r
+  @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciSetRootHubPortFeature (\r
+  IN  EFI_USB_HC_PROTOCOL     *This,\r
+  IN  UINT8                   PortNumber,\r
+  IN  EFI_USB_PORT_FEATURE    PortFeature\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+  EFI_TPL             OldTpl;\r
+  UINT32              Offset;\r
+  UINT16              PortSC;\r
+  UINT16              Command;\r
+\r
+  Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+  if (PortNumber >= Uhc->RootPorts) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Offset  = USBPORTSC_OFFSET + PortNumber * 2;\r
+\r
+  OldTpl  = gBS->RaiseTPL (UHCI_TPL);\r
+  PortSC  = UhciReadReg (Uhc->PciIo, Offset);\r
+\r
+  switch (PortFeature) {\r
+  case EfiUsbPortSuspend:\r
+    Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
+    if (!(Command & USBCMD_EGSM)) {\r
+      //\r
+      // if global suspend is not active, can set port suspend\r
+      //\r
+      PortSC &= 0xfff5;\r
+      PortSC |= USBPORTSC_SUSP;\r
+    }\r
+    break;\r
+\r
+  case EfiUsbPortReset:\r
+    PortSC &= 0xfff5;\r
+    PortSC |= USBPORTSC_PR;\r
+    break;\r
+\r
+  case EfiUsbPortPower:\r
+    //\r
+    // No action\r
+    //\r
+    break;\r
+\r
+  case EfiUsbPortEnable:\r
+    PortSC &= 0xfff5;\r
+    PortSC |= USBPORTSC_PED;\r
+    break;\r
+\r
+  default:\r
+    gBS->RestoreTPL (OldTpl);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UhciWriteReg (Uhc->PciIo, Offset, PortSC);\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+\r
+  This        : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  PortNumber  : Specifies the root hub port whose feature\r
+  is requested to be cleared.\r
+  PortFeature : Indicates the feature selector associated with the\r
+  feature clear request.\r
+\r
+  @return EFI_SUCCESS           : The feature was cleared for the port.\r
+  @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciClearRootHubPortFeature (\r
+  IN  EFI_USB_HC_PROTOCOL     *This,\r
+  IN  UINT8                   PortNumber,\r
+  IN  EFI_USB_PORT_FEATURE    PortFeature\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+  EFI_TPL             OldTpl;\r
+  UINT32              Offset;\r
+  UINT16              PortSC;\r
+\r
+  Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+  if (PortNumber >= Uhc->RootPorts) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Offset  = USBPORTSC_OFFSET + PortNumber * 2;\r
+\r
+  OldTpl  = gBS->RaiseTPL (UHCI_TPL);\r
+  PortSC  = UhciReadReg (Uhc->PciIo, Offset);\r
+\r
+  switch (PortFeature) {\r
+  case EfiUsbPortEnable:\r
+    PortSC &= 0xfff5;\r
+    PortSC &= ~USBPORTSC_PED;\r
+    break;\r
+\r
+  case EfiUsbPortSuspend:\r
+    //\r
+    // Cause a resume on the specified port if in suspend mode.\r
+    //\r
+    PortSC &= 0xfff5;\r
+    PortSC &= ~USBPORTSC_SUSP;\r
+    break;\r
+\r
+  case EfiUsbPortPower:\r
+    //\r
+    // No action\r
+    //\r
+    break;\r
+\r
+  case EfiUsbPortReset:\r
+    PortSC &= 0xfff5;\r
+    PortSC &= ~USBPORTSC_PR;\r
+    break;\r
+\r
+  case EfiUsbPortConnectChange:\r
+    PortSC &= 0xfff5;\r
+    PortSC |= USBPORTSC_CSC;\r
+    break;\r
+\r
+  case EfiUsbPortEnableChange:\r
+    PortSC &= 0xfff5;\r
+    PortSC |= USBPORTSC_PEDC;\r
+    break;\r
+\r
+  case EfiUsbPortSuspendChange:\r
+    //\r
+    // Root hub does not support this\r
+    //\r
+    break;\r
+\r
+  case EfiUsbPortOverCurrentChange:\r
+    //\r
+    // Root hub does not support this\r
+    //\r
+    break;\r
+\r
+  case EfiUsbPortResetChange:\r
+    //\r
+    // Root hub does not support this\r
+    //\r
+    break;\r
+\r
+  default:\r
+    gBS->RestoreTPL (OldTpl);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UhciWriteReg (Uhc->PciIo, Offset, PortSC);\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Submits control transfer to a target USB device.\r
+\r
+  This                : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  DeviceAddress       : Usb device address\r
+  IsSlowDevice        : Whether the device is of slow speed or full speed\r
+  MaximumPacketLength : maximum packet size of the default control endpoint\r
+  Request             : USB device request to send\r
+  TransferDirection   : Specifies the data direction for the transfer.\r
+  Data                : Data buffer to transmit from or receive into\r
+  DataLength          : Number of bytes of the data\r
+  TimeOut             : Maximum time, in microseconds\r
+  TransferResult      : Return result in this\r
+\r
+  @return EFI_SUCCESS           : Transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : Failed due to a lack of resources.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : Failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciControlTransfer (\r
+  IN       EFI_USB_HC_PROTOCOL        *This,\r
+  IN       UINT8                      DeviceAddress,\r
+  IN       BOOLEAN                    IsSlowDevice,\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_HC_DEV              *Uhc;\r
+  UHCI_TD_SW              *TDs;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+  UHCI_QH_RESULT          QhResult;\r
+  UINT8                   PktId;\r
+  UINT8                   *RequestPhy;\r
+  VOID                    *RequestMap;\r
+  UINT8                   *DataPhy;\r
+  VOID                    *DataMap;\r
+\r
+  Uhc         = UHC_FROM_USB_HC_PROTO (This);\r
+  TDs         = NULL;\r
+  DataPhy     = NULL;\r
+  DataMap     = NULL;\r
+  RequestPhy  = NULL;\r
+  RequestMap  = NULL;\r
+\r
+  //\r
+  // Parameters Checking\r
+  //\r
+  if (Request == NULL || TransferResult == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (IsSlowDevice && (MaximumPacketLength != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((MaximumPacketLength != 8) &&  (MaximumPacketLength != 16) &&\r
+      (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((TransferDirection != EfiUsbNoData) && (DataLength == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_DEVICE_ERROR;\r
+\r
+  //\r
+  // If errors exist that cause host controller halt,\r
+  // clear status then return EFI_DEVICE_ERROR.\r
+  //\r
+  UhciAckAllInterrupt (Uhc);\r
+\r
+  if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+  //\r
+  // Map the Request and data for bus master access,\r
+  // then create a list of TD for this transfer\r
+  //\r
+  Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  TDs = UhciCreateCtrlTds (\r
+          Uhc,\r
+          DeviceAddress,\r
+          PktId,\r
+          RequestPhy,\r
+          DataPhy,\r
+          *DataLength,\r
+          MaximumPacketLength,\r
+          IsSlowDevice\r
+          );\r
+\r
+  if (TDs == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto UNMAP_DATA;\r
+  }\r
+\r
+  //\r
+  // According to the speed of the end point, link\r
+  // the TD to corrosponding queue head, then check\r
+  // the execution result\r
+  //\r
+  UhciLinkTdToQh (Uhc->CtrlQh, TDs);\r
+  Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);\r
+  UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);\r
+\r
+  Uhc->PciIo->Flush (Uhc->PciIo);\r
+\r
+  *TransferResult = QhResult.Result;\r
+\r
+  if (DataLength != NULL) {\r
+    *DataLength = QhResult.Complete;\r
+  }\r
+\r
+  UhciDestoryTds (Uhc, TDs);\r
+\r
+UNMAP_DATA:\r
+  Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+  Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+  This                :A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  DeviceAddress       : Usb device address\r
+  EndPointAddress     : Endpoint number and endpoint direction\r
+  MaximumPacketLength : Maximum packet size of the target endpoint\r
+  Data                : Data buffer to transmit from or receive into\r
+  DataLength          : Length of the data buffer\r
+  DataToggle          : On input, data toggle to use, on output, the next toggle\r
+  TimeOut             : Indicates the maximum time\r
+  TransferResult      : Variable to receive the transfer result\r
+\r
+  @return EFI_SUCCESS           : The bulk transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : Failed due to lack of resource.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : Failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciBulkTransfer (\r
+  IN       EFI_USB_HC_PROTOCOL     *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
+  EFI_USB_DATA_DIRECTION  Direction;\r
+  EFI_TPL                 OldTpl;\r
+  USB_HC_DEV              *Uhc;\r
+  UHCI_TD_SW              *TDs;\r
+  UHCI_QH_SW              *BulkQh;\r
+  UHCI_QH_RESULT          QhResult;\r
+  EFI_STATUS              Status;\r
+  UINT8                   PktId;\r
+  UINT8                   *DataPhy;\r
+  VOID                    *DataMap;\r
+\r
+  Uhc     = UHC_FROM_USB_HC_PROTO (This);\r
+  DataPhy = NULL;\r
+  DataMap = NULL;\r
+\r
+  if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*DataLength == 0) {\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
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_OUT_OF_RESOURCES;\r
+\r
+  //\r
+  // If has errors that cause host controller halt,\r
+  // then return EFI_DEVICE_ERROR directly.\r
+  //\r
+  UhciAckAllInterrupt (Uhc);\r
+\r
+  if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+  //\r
+  // Map the source data buffer for bus master access,\r
+  // then create a list of TDs\r
+  //\r
+  if (EndPointAddress & 0x80) {\r
+    Direction = EfiUsbDataIn;\r
+  } else {\r
+    Direction = EfiUsbDataOut;\r
+  }\r
+\r
+  Status = UhciMapUserData (Uhc, Direction, Data, DataLength, &PktId, &DataPhy, &DataMap);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = EFI_OUT_OF_RESOURCES;\r
+  TDs    = UhciCreateBulkOrIntTds (\r
+             Uhc,\r
+             DeviceAddress,\r
+             EndPointAddress,\r
+             PktId,\r
+             DataPhy,\r
+             *DataLength,\r
+             DataToggle,\r
+             MaximumPacketLength,\r
+             FALSE\r
+             );\r
+\r
+  if (TDs == NULL) {\r
+    Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+    goto ON_EXIT;\r
+  }\r
+\r
+\r
+  //\r
+  // Link the TDs to bulk queue head. According to the platfore\r
+  // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured\r
+  // to do full speed bandwidth reclamation or not.\r
+  //\r
+  BulkQh = Uhc->BulkQh;\r
+\r
+  UhciLinkTdToQh (BulkQh, TDs);\r
+  Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);\r
+  UhciUnlinkTdFromQh (BulkQh, TDs);\r
+\r
+  Uhc->PciIo->Flush (Uhc->PciIo);\r
+\r
+  *TransferResult = QhResult.Result;\r
+  *DataToggle     = QhResult.NextToggle;\r
+  *DataLength     = QhResult.Complete;\r
+\r
+  UhciDestoryTds (Uhc, TDs);\r
+  Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+  This                : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  EndPointAddress     : Endpoint number with direction\r
+  IsSlowDevice        : Whether the target device is slow device or full-speed device.\r
+  MaximumPacketLength : Maximum packet size of the target endpoint\r
+  IsNewTransfer       : If TRUE, submit a new async interrupt transfer, otherwise\r
+  cancel an existed one\r
+  DataToggle          : On input, the data toggle to use; On output, next data toggle\r
+  PollingInterval     : Interrupt poll rate in milliseconds\r
+  DataLength          : Length of data to receive\r
+  CallBackFunction    : Function to call periodically\r
+  Context             : User context\r
+\r
+  @return EFI_SUCCESS           : Request is submitted or cancelled\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_OUT_OF_RESOURCES  : Failed due to a lack of resources.\r
+  @return EFI_DEVICE_ERROR      : Failed to due to device error\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciAsyncInterruptTransfer (\r
+  IN     EFI_USB_HC_PROTOCOL                * This,\r
+  IN     UINT8                              DeviceAddress,\r
+  IN     UINT8                              EndPointAddress,\r
+  IN     BOOLEAN                            IsSlowDevice,\r
+  IN     UINT8                              MaximumPacketLength,\r
+  IN     BOOLEAN                            IsNewTransfer,\r
+  IN OUT UINT8                              *DataToggle,\r
+  IN     UINTN                              PollingInterval,    OPTIONAL\r
+  IN     UINTN                              DataLength,         OPTIONAL\r
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK    CallBackFunction,   OPTIONAL\r
+  IN     VOID                               *Context OPTIONAL\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+  UHCI_QH_SW          *Qh;\r
+  UHCI_TD_SW          *IntTds;\r
+  EFI_TPL             OldTpl;\r
+  EFI_STATUS          Status;\r
+  UINT8               *DataPtr;\r
+  UINT8               *DataPhy;\r
+  VOID                *DataMap;\r
+  UINT8               PktId;\r
+\r
+  Uhc       = UHC_FROM_USB_HC_PROTO (This);\r
+  Qh        = NULL;\r
+  IntTds    = NULL;\r
+  DataPtr   = NULL;\r
+  DataPhy   = NULL;\r
+  DataMap   = NULL;\r
+\r
+  if ((EndPointAddress & 0x80) == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Delete Async interrupt transfer request\r
+  //\r
+  if (!IsNewTransfer) {\r
+    OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+    Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);\r
+\r
+    gBS->RestoreTPL (OldTpl);\r
+    return Status;\r
+  }\r
+\r
+  if (PollingInterval < 1 || PollingInterval > 255) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (DataLength == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // If has errors that cause host controller halt,\r
+  // then return EFI_DEVICE_ERROR directly.\r
+  //\r
+  UhciAckAllInterrupt (Uhc);\r
+\r
+  if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Allocate and map source data buffer for bus master access.\r
+  //\r
+  DataPtr = AllocatePool (DataLength);\r
+\r
+  if (DataPtr == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+  //\r
+  // Map the user data then create a queue head and\r
+  // list of TD for it.\r
+  //\r
+  Status = UhciMapUserData (\r
+             Uhc,\r
+             EfiUsbDataIn,\r
+             DataPtr,\r
+             &DataLength,\r
+             &PktId,\r
+             &DataPhy,\r
+             &DataMap\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_DATA;\r
+  }\r
+\r
+  Qh = UhciCreateQh (Uhc, PollingInterval);\r
+\r
+  if (Qh == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto UNMAP_DATA;\r
+  }\r
+\r
+  IntTds = UhciCreateBulkOrIntTds (\r
+             Uhc,\r
+             DeviceAddress,\r
+             EndPointAddress,\r
+             PktId,\r
+             DataPhy,\r
+             DataLength,\r
+             DataToggle,\r
+             MaximumPacketLength,\r
+             IsSlowDevice\r
+             );\r
+\r
+  if (IntTds == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto DESTORY_QH;\r
+  }\r
+\r
+  UhciLinkTdToQh (Qh, IntTds);\r
+\r
+  //\r
+  // Save QH-TD structures to async Interrupt transfer list,\r
+  // for monitor interrupt transfer execution routine use.\r
+  //\r
+  Status = UhciCreateAsyncReq (\r
+             Uhc,\r
+             Qh,\r
+             IntTds,\r
+             DeviceAddress,\r
+             EndPointAddress,\r
+             DataLength,\r
+             PollingInterval,\r
+             DataMap,\r
+             DataPtr,\r
+             CallBackFunction,\r
+             Context,\r
+             IsSlowDevice\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto DESTORY_QH;\r
+  }\r
+\r
+  UhciLinkQhToFrameList (Uhc->FrameBase, Qh);\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+\r
+DESTORY_QH:\r
+  UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));\r
+\r
+UNMAP_DATA:\r
+  Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+\r
+FREE_DATA:\r
+  gBS->FreePool (DataPtr);\r
+  Uhc->PciIo->Flush (Uhc->PciIo);\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits synchronous interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+  This                : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  DeviceAddress       : Device address of the target USB device\r
+  EndPointAddress     : Endpoint number and direction\r
+  IsSlowDevice        : Whether the target device is of slow speed or full speed\r
+  MaximumPacketLength : Maximum packet size of target endpoint\r
+  Data                : Data to transmit or receive\r
+  DataLength          : On input, data length to transmit or buffer size.\r
+  On output, the number of bytes transferred.\r
+  DataToggle          : On input, data toggle to use; On output, next data toggle\r
+  TimeOut             : Maximum time, in microseconds, transfer is allowed to complete.\r
+  TransferResult      : Variable to receive transfer result\r
+\r
+  @return EFI_SUCCESS           : Transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : Failed due to lack of resource.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : Failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : Failed due to host controller or device error\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciSyncInterruptTransfer (\r
+  IN       EFI_USB_HC_PROTOCOL     *This,\r
+  IN       UINT8                   DeviceAddress,\r
+  IN       UINT8                   EndPointAddress,\r
+  IN       BOOLEAN                 IsSlowDevice,\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
+  EFI_STATUS          Status;\r
+  USB_HC_DEV          *Uhc;\r
+  UHCI_TD_SW          *TDs;\r
+  UHCI_QH_RESULT      QhResult;\r
+  EFI_TPL             OldTpl;\r
+  UINT8               *DataPhy;\r
+  VOID                *DataMap;\r
+  UINT8               PktId;\r
+\r
+  Uhc     = UHC_FROM_USB_HC_PROTO (This);\r
+  DataPhy = NULL;\r
+  DataMap = NULL;\r
+  TDs     = NULL;\r
+\r
+  if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((EndPointAddress & 0x80) == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataLength == 0) || (MaximumPacketLength > 64)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (IsSlowDevice && (MaximumPacketLength > 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_DEVICE_ERROR;\r
+\r
+\r
+  UhciAckAllInterrupt (Uhc);\r
+\r
+  if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+    return Status;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+  //\r
+  // Map the source data buffer for bus master access.\r
+  // Create Tds list, then link it to the UHC's interrupt list\r
+  //\r
+  Status = UhciMapUserData (\r
+             Uhc,\r
+             EfiUsbDataIn,\r
+             Data,\r
+             DataLength,\r
+             &PktId,\r
+             &DataPhy,\r
+             &DataMap\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  TDs = UhciCreateBulkOrIntTds (\r
+          Uhc,\r
+          DeviceAddress,\r
+          EndPointAddress,\r
+          PktId,\r
+          DataPhy,\r
+          *DataLength,\r
+          DataToggle,\r
+          MaximumPacketLength,\r
+          IsSlowDevice\r
+          );\r
+\r
+  if (TDs == NULL) {\r
+    Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+\r
+  UhciLinkTdToQh (Uhc->SyncIntQh, TDs);\r
+\r
+  Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);\r
+\r
+  UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);\r
+  Uhc->PciIo->Flush (Uhc->PciIo);\r
+\r
+  *TransferResult = QhResult.Result;\r
+  *DataToggle     = QhResult.NextToggle;\r
+  *DataLength     = QhResult.Complete;\r
+\r
+  UhciDestoryTds (Uhc, TDs);\r
+  Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submits isochronous transfer to a target USB device.\r
+\r
+  This                : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  EndPointAddress     : End point address withdirection\r
+  MaximumPacketLength : Maximum packet size of the endpoint\r
+  Data                : Data to transmit or receive\r
+  DataLength          : Bytes of the data\r
+  TransferResult      : Variable to receive the result\r
+\r
+  @return EFI_UNSUPPORTED\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciIsochronousTransfer (\r
+  IN       EFI_USB_HC_PROTOCOL     *This,\r
+  IN       UINT8                   DeviceAddress,\r
+  IN       UINT8                   EndPointAddress,\r
+  IN       UINT8                   MaximumPacketLength,\r
+  IN OUT   VOID                    *Data,\r
+  IN       UINTN                   DataLength,\r
+  OUT      UINT32                  *TransferResult\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Submits Async isochronous transfer to a target USB device.\r
+\r
+  This                : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  EndPointAddress     : End point address withdirection\r
+  MaximumPacketLength : Maximum packet size of the endpoint\r
+  Data                : Data to transmit or receive\r
+  IsochronousCallBack : Function to call when the transfer completes\r
+  Context             : User context\r
+\r
+  @return EFI_UNSUPPORTED\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciAsyncIsochronousTransfer (\r
+  IN       EFI_USB_HC_PROTOCOL                 * This,\r
+  IN       UINT8                               DeviceAddress,\r
+  IN       UINT8                               EndPointAddress,\r
+  IN       UINT8                               MaximumPacketLength,\r
+  IN OUT   VOID                                *Data,\r
+  IN       UINTN                               DataLength,\r
+  IN       EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,\r
+  IN       VOID                                *Context OPTIONAL\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Provides software reset for the USB host controller according to UEFI 2.0 spec.\r
+\r
+  @param  This                 A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  @param  Attributes           A bit mask of the reset operation to perform.  See\r
+                               below for a list of the supported bit mask values.\r
+\r
+  @return EFI_SUCCESS           : The reset operation succeeded.\r
+  @return EFI_INVALID_PARAMETER : Attributes is not valid.\r
+  @return EFI_UNSUPPORTED       : This type of reset is not currently supported\r
+  @return EFI_DEVICE_ERROR      : Other errors\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2Reset (\r
+  IN EFI_USB2_HC_PROTOCOL   *This,\r
+  IN UINT16                 Attributes\r
+  )\r
+{\r
+  USB_HC_DEV          *UhciDev;\r
+\r
+  UhciDev = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+  if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||\r
+      (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return UhciReset (&UhciDev->UsbHc, Attributes);\r
+}\r
+\r
+\r
+/**\r
+  Retrieves current state of the USB host controller according to UEFI 2.0 spec.\r
+\r
+  @param  This                 A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  State                Variable to receive current device state\r
+\r
+  @return EFI_SUCCESS           : The state is returned\r
+  @return EFI_INVALID_PARAMETER : State is not valid.\r
+  @return EFI_DEVICE_ERROR      : Other errors2006\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2GetState (\r
+  IN CONST EFI_USB2_HC_PROTOCOL   *This,\r
+  OUT      EFI_USB_HC_STATE       *State\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+\r
+  Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+  return UhciGetState (&Uhc->UsbHc, State);\r
+}\r
+\r
+\r
+/**\r
+  Sets the USB host controller to a specific state according to UEFI 2.0 spec.\r
+\r
+  @param  This                 A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  State                Indicates the state of the host controller that will\r
+                               be set.\r
+\r
+  @return EFI_SUCCESS           : Host controller was successfully placed in the state\r
+  @return EFI_INVALID_PARAMETER : State is invalid.\r
+  @return EFI_DEVICE_ERROR      : Failed to set the state\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2SetState (\r
+  IN EFI_USB2_HC_PROTOCOL    *This,\r
+  IN EFI_USB_HC_STATE        State\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+\r
+  Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+  return UhciSetState (&Uhc->UsbHc, State);\r
+}\r
+\r
+\r
+/**\r
+  Retrieves capabilities of USB host controller according to UEFI 2.0 spec.\r
+\r
+  @param  This                 A pointer to the EFI_USB2_HC_PROTOCOL instance\r
+  @param  MaxSpeed             A pointer to the max speed USB host controller\r
+                               supports.\r
+  @param  PortNumber           A pointer to the number of root hub ports.\r
+  @param  Is64BitCapable       A pointer to an integer to show whether USB host\r
+                               controller supports 64-bit memory addressing.\r
+\r
+  @return EFI_SUCCESS           : capabilities were retrieved successfully.\r
+  @return EFI_INVALID_PARAMETER : MaxSpeed or PortNumber or Is64BitCapable is NULL.\r
+  @return EFI_DEVICE_ERROR      : An error was encountered\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2GetCapability (\r
+  IN  EFI_USB2_HC_PROTOCOL  *This,\r
+  OUT UINT8                 *MaxSpeed,\r
+  OUT UINT8                 *PortNumber,\r
+  OUT UINT8                 *Is64BitCapable\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+\r
+  Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+  if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *MaxSpeed       = EFI_USB_SPEED_FULL;\r
+  *Is64BitCapable = (UINT8) FALSE;\r
+\r
+  return UhciGetRootHubPortNumber (&Uhc->UsbHc, PortNumber);\r
+}\r
+\r
+\r
+/**\r
+  Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.\r
+\r
+  @param  This                 A pointer to the EFI_USB2_HC_PROTOCOL.\r
+  @param  PortNumber           The port to get status\r
+  @param  PortStatus           A pointer to the current port status bits and  port\r
+                               status change bits.\r
+\r
+  @return EFI_SUCCESS           : status of the USB root hub port was returned in PortStatus.\r
+  @return EFI_INVALID_PARAMETER : PortNumber is invalid.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2GetRootHubPortStatus (\r
+  IN  CONST EFI_USB2_HC_PROTOCOL   *This,\r
+  IN  CONST UINT8                  PortNumber,\r
+  OUT       EFI_USB_PORT_STATUS    *PortStatus\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+\r
+  Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+  return UhciGetRootHubPortStatus (&Uhc->UsbHc, PortNumber, PortStatus);\r
+}\r
+\r
+\r
+/**\r
+  Sets a feature for the specified root hub port according to UEFI 2.0 spec.\r
+\r
+  @param  This                 A pointer to the EFI_USB2_HC_PROTOCOL.\r
+  @param  PortNumber           Specifies the root hub port whose feature  is\r
+                               requested to be set.\r
+  @param  PortFeature          Indicates the feature selector associated  with the\r
+                               feature set request.\r
+\r
+  @return EFI_SUCCESS           : PortFeature was set for the root port\r
+  @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2SetRootHubPortFeature (\r
+  IN EFI_USB2_HC_PROTOCOL    *This,\r
+  IN UINT8                   PortNumber,\r
+  IN EFI_USB_PORT_FEATURE    PortFeature\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+\r
+  Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+  return UhciSetRootHubPortFeature (&Uhc->UsbHc, PortNumber, PortFeature);\r
+}\r
+\r
+\r
+/**\r
+  Clears a feature for the specified root hub port according to Uefi 2.0 spec.\r
+\r
+  @param  This                 A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  @param  PortNumber           Specifies the root hub port whose feature  is\r
+                               requested to be cleared.\r
+  @param  PortFeature          Indicates the feature selector associated with the\r
+                               feature clear request.\r
+\r
+  @return EFI_SUCCESS           : PortFeature was cleared for the USB root hub port\r
+  @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2ClearRootHubPortFeature (\r
+  IN EFI_USB2_HC_PROTOCOL    *This,\r
+  IN UINT8                   PortNumber,\r
+  IN EFI_USB_PORT_FEATURE    PortFeature\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+\r
+  Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+  return UhciClearRootHubPortFeature (&Uhc->UsbHc, PortNumber, PortFeature);\r
+}\r
+\r
+\r
+/**\r
+  Submits control transfer to a target USB device accroding to UEFI 2.0 spec..\r
+\r
+  This                : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  DeviceSpeed         : Device speed\r
+  MaximumPacketLength : Maximum packet size of the target endpoint\r
+  Request             : USB device request to send\r
+  TransferDirection   : Data direction of the Data stage in control transfer\r
+  Data                : Data to transmit/receive in data stage\r
+  DataLength          : Length of the data\r
+  TimeOut             : Maximum time, in microseconds, for transfer to complete.\r
+  TransferResult      : Variable to receive the transfer result\r
+\r
+  @return EFI_SUCCESS           : The control transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : Failed due to lack of resource.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : Failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2ControlTransfer (\r
+  IN     EFI_USB2_HC_PROTOCOL                 *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
+  USB_HC_DEV          *Uhc;\r
+  BOOLEAN             IsSlow;\r
+\r
+  Uhc     = UHC_FROM_USB2_HC_PROTO (This);\r
+  IsSlow  = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;\r
+\r
+  return UhciControlTransfer (\r
+           &Uhc->UsbHc,\r
+           DeviceAddress,\r
+           IsSlow,\r
+           (UINT8) MaximumPacketLength,\r
+           Request,\r
+           TransferDirection,\r
+           Data,\r
+           DataLength,\r
+           TimeOut,\r
+           TransferResult\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Submits bulk transfer to a bulk endpoint of a USB device\r
+\r
+  This                : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  EndPointAddress     : Endpoint number and direction\r
+  DeviceSpeed         : Device speed\r
+  MaximumPacketLength : Maximum packet size of the target endpoint\r
+  DataBuffersNumber   : Number of data buffers prepared for the transfer.\r
+  Data                : Array of pointers to the buffers of data\r
+  DataLength          : On input, size of the data buffer, On output,\r
+  actually transferred data size.\r
+  DataToggle          : On input, data toggle to use; On output, next data toggle\r
+  Translator          : A pointr to the transaction translator data.\r
+  TimeOut             : Maximum time out, in microseconds\r
+  TransferResult      : Variable to receive transfer result\r
+\r
+  @return EFI_SUCCESS           : The bulk transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : Failed due to lack of resource.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : Failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2BulkTransfer (\r
+  IN     EFI_USB2_HC_PROTOCOL               *This,\r
+  IN     UINT8                              DeviceAddress,\r
+  IN     UINT8                              EndPointAddress,\r
+  IN     UINT8                              DeviceSpeed,\r
+  IN     UINTN                              MaximumPacketLength,\r
+  IN     UINT8                              DataBuffersNumber,\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
+  USB_HC_DEV          *Uhc;\r
+\r
+  Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+  if (Data == NULL || DeviceSpeed == EFI_USB_SPEED_LOW) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // For full-speed bulk transfers only the data pointed by Data[0] shall be used\r
+  //\r
+  return UhciBulkTransfer (\r
+           &Uhc->UsbHc,\r
+           DeviceAddress,\r
+           EndPointAddress,\r
+           (UINT8) MaximumPacketLength,\r
+           *Data,\r
+           DataLength,\r
+           DataToggle,\r
+           TimeOut,\r
+           TransferResult\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Submits an asynchronous interrupt transfer to an\r
+  interrupt endpoint of a USB device according to UEFI 2.0 spec.\r
+\r
+  This                : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  EndPointAddress     : Endpoint number and direction\r
+  DeviceSpeed         : Device speed\r
+  MaximumPacketLength : Maximum packet size of the target endpoint\r
+  IsNewTransfer       : If TRUE, submit a new transfer, if FALSE cancel old transfer\r
+  DataToggle          : On input, data toggle to use; On output, next data toggle\r
+  PollingInterval     : Interrupt poll rate in milliseconds\r
+  DataLength          : On input, size of the data buffer, On output,\r
+  actually transferred data size.\r
+  Translator          : A pointr to the transaction translator data.\r
+  CallBackFunction    : Function to call periodically\r
+  Context             : User context\r
+\r
+  @return EFI_SUCCESS           : Transfer was submitted\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_OUT_OF_RESOURCES  : Failed due to a lack of resources.\r
+  @return EFI_DEVICE_ERROR      : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2AsyncInterruptTransfer (\r
+  IN     EFI_USB2_HC_PROTOCOL               *This,\r
+  IN     UINT8                              DeviceAddress,\r
+  IN     UINT8                              EndPointAddress,\r
+  IN     UINT8                              DeviceSpeed,\r
+  IN     UINTN                              MaximumPacketLength,\r
+  IN     BOOLEAN                            IsNewTransfer,\r
+  IN OUT UINT8                              *DataToggle,\r
+  IN     UINTN                              PollingInterval,\r
+  IN     UINTN                              DataLength,\r
+  IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK    CallBackFunction,\r
+  IN     VOID                               *Context\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+  BOOLEAN             IsSlow;\r
+\r
+  Uhc     = UHC_FROM_USB2_HC_PROTO (This);\r
+  IsSlow  = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;\r
+\r
+  return UhciAsyncInterruptTransfer (\r
+           &Uhc->UsbHc,\r
+           DeviceAddress,\r
+           EndPointAddress,\r
+           IsSlow,\r
+           (UINT8) MaximumPacketLength,\r
+           IsNewTransfer,\r
+           DataToggle,\r
+           PollingInterval,\r
+           DataLength,\r
+           CallBackFunction,\r
+           Context\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Submits synchronous interrupt transfer to an interrupt endpoint\r
+  of a USB device according to UEFI 2.0 spec.\r
+\r
+  This                : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  EndPointAddress     : Endpoint number and direction\r
+  DeviceSpeed         : Device speed\r
+  MaximumPacketLength : Maximum packet size of the target endpoint\r
+  DataBuffersNumber   : Number of data buffers prepared for the transfer.\r
+  Data                : Array of pointers to the buffers of data\r
+  DataLength          : On input, size of the data buffer, On output,\r
+  actually transferred data size.\r
+  DataToggle          : On input, data toggle to use; On output, next data toggle\r
+  TimeOut             : Maximum time out, in microseconds\r
+  Translator          : A pointr to the transaction translator data.\r
+  TransferResult      : Variable to receive transfer result\r
+\r
+  @return EFI_SUCCESS           : The transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  : Failed due to lack of resource.\r
+  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+  @return EFI_TIMEOUT           : Failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2SyncInterruptTransfer (\r
+  IN     EFI_USB2_HC_PROTOCOL                      *This,\r
+  IN     UINT8                                     DeviceAddress,\r
+  IN     UINT8                                     EndPointAddress,\r
+  IN     UINT8                                     DeviceSpeed,\r
+  IN     UINTN                                     MaximumPacketLength,\r
+  IN OUT VOID                                      *Data,\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
+  USB_HC_DEV          *Uhc;\r
+  BOOLEAN             IsSlow;\r
+\r
+  if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Uhc     = UHC_FROM_USB2_HC_PROTO (This);\r
+  IsSlow  = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;\r
+\r
+  return UhciSyncInterruptTransfer (\r
+           &Uhc->UsbHc,\r
+           DeviceAddress,\r
+           EndPointAddress,\r
+           IsSlow,\r
+           (UINT8) MaximumPacketLength,\r
+           Data,\r
+           DataLength,\r
+           DataToggle,\r
+           TimeOut,\r
+           TransferResult\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.\r
+\r
+  This                : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  EndPointAddress     : Endpoint number and direction\r
+  DeviceSpeed         : Device speed\r
+  MaximumPacketLength : Maximum packet size of the target endpoint\r
+  DataBuffersNumber   : Number of data buffers prepared for the transfer.\r
+  Data                : Array of pointers to the buffers of data\r
+  DataLength          : On input, size of the data buffer, On output,\r
+  actually transferred data size.\r
+  Translator          : A pointr to the transaction translator data.\r
+  TransferResult      : Variable to receive transfer result\r
+\r
+  @return EFI_UNSUPPORTED\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2IsochronousTransfer (\r
+  IN     EFI_USB2_HC_PROTOCOL               *This,\r
+  IN     UINT8                              DeviceAddress,\r
+  IN     UINT8                              EndPointAddress,\r
+  IN     UINT8                              DeviceSpeed,\r
+  IN     UINTN                              MaximumPacketLength,\r
+  IN     UINT8                              DataBuffersNumber,\r
+  IN OUT VOID                               *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+  IN     UINTN                              DataLength,\r
+  IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+  OUT    UINT32                             *TransferResult\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.\r
+\r
+  This                : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  DeviceAddress       : Target device address\r
+  EndPointAddress     : Endpoint number and direction\r
+  DeviceSpeed         : Device speed\r
+  MaximumPacketLength : Maximum packet size of the target endpoint\r
+  DataBuffersNumber   : Number of data buffers prepared for the transfer.\r
+  Data                : Array of pointers to the buffers of data\r
+  Translator          : A pointr to the transaction translator data.\r
+  IsochronousCallBack : Function to call when the transfer complete\r
+  Context             : Pass to the call back function as parameter\r
+\r
+  @return EFI_UNSUPPORTED\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2AsyncIsochronousTransfer (\r
+  IN     EFI_USB2_HC_PROTOCOL                *This,\r
+  IN     UINT8                               DeviceAddress,\r
+  IN     UINT8                               EndPointAddress,\r
+  IN     UINT8                               DeviceSpeed,\r
+  IN     UINTN                               MaximumPacketLength,\r
+  IN     UINT8                               DataBuffersNumber,\r
+  IN OUT VOID                                *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+  IN     UINTN                               DataLength,\r
+  IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,\r
+  IN     VOID                                *Context\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (UhciDriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UhciDriverEntryPoint (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+\r
+    Entry point for EFI drivers.\r
+\r
+  Arguments:\r
+\r
+    ImageHandle - EFI_HANDLE\r
+    SystemTable - EFI_SYSTEM_TABLE\r
+\r
+  Returns:\r
+\r
+    EFI_SUCCESS : Driver is successfully loaded\r
+    Others      : Failed\r
+\r
+--*/\r
+{\r
+  return EfiLibInstallAllDriverProtocols (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gUhciDriverBinding,\r
+           ImageHandle,\r
+           &gUhciComponentName,\r
+           NULL,\r
+           NULL\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle. Any\r
+  ControllerHandle that has UsbHcProtocol installed will be supported.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to test\r
+  @param  RemainingDevicePath  Not used\r
+\r
+  @return EFI_SUCCESS         : This driver supports this device.\r
+  @return EFI_UNSUPPORTED     : This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhciDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN EFI_HANDLE                      Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS            OpenStatus;\r
+  EFI_STATUS            Status;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  USB_CLASSC            UsbClassCReg;\r
+\r
+  //\r
+  // Test whether there is PCI IO Protocol attached on the controller handle.\r
+  //\r
+  OpenStatus = gBS->OpenProtocol (\r
+                      Controller,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      &PciIo,\r
+                      This->DriverBindingHandle,\r
+                      Controller,\r
+                      EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                      );\r
+\r
+  if (EFI_ERROR (OpenStatus)) {\r
+    return OpenStatus;\r
+  }\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        CLASSC_OFFSET,\r
+                        sizeof (USB_CLASSC) / sizeof (UINT8),\r
+                        &UsbClassCReg\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Test whether the controller belongs to UHCI type\r
+  //\r
+  if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
+      (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
+      (UsbClassCReg.PI != PCI_CLASSC_PI_UHCI)\r
+      ) {\r
+\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Allocate and initialize the empty UHCI device\r
+\r
+  @param  PciIo                The PCIIO to use\r
+\r
+  @return Allocated UHCI device\r
+\r
+**/\r
+STATIC\r
+USB_HC_DEV *\r
+UhciAllocateDev (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo\r
+  )\r
+{\r
+  USB_HC_DEV  *Uhc;\r
+  EFI_STATUS  Status;\r
+\r
+  Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));\r
+\r
+  if (Uhc == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.\r
+  // USB_HC_PROTOCOL is for EFI 1.1 backward compability.\r
+  //\r
+  Uhc->Signature                        = USB_HC_DEV_SIGNATURE;\r
+  Uhc->UsbHc.Reset                      = UhciReset;\r
+  Uhc->UsbHc.GetState                   = UhciGetState;\r
+  Uhc->UsbHc.SetState                   = UhciSetState;\r
+  Uhc->UsbHc.ControlTransfer            = UhciControlTransfer;\r
+  Uhc->UsbHc.BulkTransfer               = UhciBulkTransfer;\r
+  Uhc->UsbHc.AsyncInterruptTransfer     = UhciAsyncInterruptTransfer;\r
+  Uhc->UsbHc.SyncInterruptTransfer      = UhciSyncInterruptTransfer;\r
+  Uhc->UsbHc.IsochronousTransfer        = UhciIsochronousTransfer;\r
+  Uhc->UsbHc.AsyncIsochronousTransfer   = UhciAsyncIsochronousTransfer;\r
+  Uhc->UsbHc.GetRootHubPortNumber       = UhciGetRootHubPortNumber;\r
+  Uhc->UsbHc.GetRootHubPortStatus       = UhciGetRootHubPortStatus;\r
+  Uhc->UsbHc.SetRootHubPortFeature      = UhciSetRootHubPortFeature;\r
+  Uhc->UsbHc.ClearRootHubPortFeature    = UhciClearRootHubPortFeature;\r
+  Uhc->UsbHc.MajorRevision              = 0x1;\r
+  Uhc->UsbHc.MinorRevision              = 0x1;\r
+\r
+  Uhc->Usb2Hc.GetCapability             = Uhci2GetCapability;\r
+  Uhc->Usb2Hc.Reset                     = Uhci2Reset;\r
+  Uhc->Usb2Hc.GetState                  = Uhci2GetState;\r
+  Uhc->Usb2Hc.SetState                  = Uhci2SetState;\r
+  Uhc->Usb2Hc.ControlTransfer           = Uhci2ControlTransfer;\r
+  Uhc->Usb2Hc.BulkTransfer              = Uhci2BulkTransfer;\r
+  Uhc->Usb2Hc.AsyncInterruptTransfer    = Uhci2AsyncInterruptTransfer;\r
+  Uhc->Usb2Hc.SyncInterruptTransfer     = Uhci2SyncInterruptTransfer;\r
+  Uhc->Usb2Hc.IsochronousTransfer       = Uhci2IsochronousTransfer;\r
+  Uhc->Usb2Hc.AsyncIsochronousTransfer  = Uhci2AsyncIsochronousTransfer;\r
+  Uhc->Usb2Hc.GetRootHubPortStatus      = Uhci2GetRootHubPortStatus;\r
+  Uhc->Usb2Hc.SetRootHubPortFeature     = Uhci2SetRootHubPortFeature;\r
+  Uhc->Usb2Hc.ClearRootHubPortFeature   = Uhci2ClearRootHubPortFeature;\r
+  Uhc->Usb2Hc.MajorRevision             = 0x1;\r
+  Uhc->Usb2Hc.MinorRevision             = 0x1;\r
+\r
+  Uhc->PciIo   = PciIo;\r
+  Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);\r
+\r
+  if (Uhc->MemPool == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  InitializeListHead (&Uhc->AsyncIntList);\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  UhciMonitorAsyncReqList,\r
+                  Uhc,\r
+                  &Uhc->AsyncIntMonitor\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    UsbHcFreeMemPool (Uhc->MemPool);\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  return Uhc;\r
+\r
+ON_ERROR:\r
+  gBS->FreePool (Uhc);\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Free the UHCI device and release its associated resources\r
+\r
+  @param  Uhc                  The UHCI device to release\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciFreeDev (\r
+  IN USB_HC_DEV           *Uhc\r
+  )\r
+{\r
+  if (Uhc->AsyncIntMonitor != NULL) {\r
+    gBS->CloseEvent (Uhc->AsyncIntMonitor);\r
+  }\r
+\r
+  if (Uhc->MemPool != NULL) {\r
+    UsbHcFreeMemPool (Uhc->MemPool);\r
+  }\r
+\r
+  if (Uhc->CtrlNameTable) {\r
+    FreeUnicodeStringTable (Uhc->CtrlNameTable);\r
+  }\r
+\r
+  gBS->FreePool (Uhc);\r
+}\r
+\r
+\r
+/**\r
+  Uninstall all Uhci Interface\r
+\r
+  @param  Controller           Controller handle\r
+  @param  This                 Protocol instance pointer.\r
+\r
+  @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciCleanDevUp (\r
+  IN  EFI_HANDLE          Controller,\r
+  IN  EFI_USB_HC_PROTOCOL *This\r
+  )\r
+{\r
+  USB_HC_DEV          *Uhc;\r
+\r
+  //\r
+  // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller\r
+  //\r
+  Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+  UhciStopHc (Uhc, STALL_1_SECOND);\r
+\r
+  gBS->UninstallProtocolInterface (\r
+        Controller,\r
+        &gEfiUsbHcProtocolGuid,\r
+        &Uhc->UsbHc\r
+        );\r
+\r
+  gBS->UninstallProtocolInterface (\r
+        Controller,\r
+        &gEfiUsb2HcProtocolGuid,\r
+        &Uhc->Usb2Hc\r
+        );\r
+\r
+  UhciFreeAllAsyncReq (Uhc);\r
+  UhciDestoryFrameList (Uhc);\r
+\r
+  Uhc->PciIo->Attributes (\r
+                Uhc->PciIo,\r
+                EfiPciIoAttributeOperationDisable,\r
+                EFI_PCI_DEVICE_ENABLE,\r
+                NULL\r
+                );\r
+\r
+  UhciFreeDev (Uhc);\r
+}\r
+\r
+\r
+/**\r
+  Starting the Usb UHCI Driver\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to test\r
+  @param  RemainingDevicePath  Not used\r
+\r
+  @retval EFI_SUCCESS          This driver supports this device.\r
+  @retval EFI_UNSUPPORTED      This driver does not support this device.\r
+  @retval EFI_DEVICE_ERROR     This driver cannot be started due to device Error\r
+                               EFI_OUT_OF_RESOURCES- Failed due to resource\r
+                               shortage\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhciDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN EFI_HANDLE                      Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  USB_HC_DEV          *Uhc;\r
+\r
+  //\r
+  // Open PCIIO, then enable the EHC device and turn off emulation\r
+  //\r
+  Uhc = NULL;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  UhciTurnOffUsbEmulation (PciIo);\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationEnable,\r
+                    EFI_PCI_DEVICE_ENABLE,\r
+                    NULL\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto CLOSE_PCIIO;\r
+  }\r
+\r
+  Uhc = UhciAllocateDev (PciIo);\r
+\r
+  if (Uhc == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto CLOSE_PCIIO;\r
+  }\r
+\r
+  //\r
+  // Allocate and Init Host Controller's Frame List Entry\r
+  //\r
+  Status = UhciInitFrameList (Uhc);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FREE_UHC;\r
+  }\r
+\r
+  Status = gBS->SetTimer (\r
+                  Uhc->AsyncIntMonitor,\r
+                  TimerPeriodic,\r
+                  INTERRUPT_POLLING_TIME\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_UHC;\r
+  }\r
+\r
+  //\r
+  // Install both USB_HC_PROTOCOL and USB2_HC_PROTOCOL\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Controller,\r
+                  &gEfiUsbHcProtocolGuid,\r
+                  &Uhc->UsbHc,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  &Uhc->Usb2Hc,\r
+                  NULL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_UHC;\r
+  }\r
+\r
+  //\r
+  // Install the component name protocol\r
+  //\r
+  Uhc->CtrlNameTable = NULL;\r
+\r
+  AddUnicodeString (\r
+    "eng",\r
+    gUhciComponentName.SupportedLanguages,\r
+    &Uhc->CtrlNameTable,\r
+    L"Usb Universal Host Controller"\r
+    );\r
+\r
+  //\r
+  // Start the UHCI hardware, also set its reclamation point to 64 bytes\r
+  //\r
+  UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+FREE_UHC:\r
+  UhciFreeDev (Uhc);\r
+\r
+CLOSE_PCIIO:\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiPciIoProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop this driver on ControllerHandle. Support stoping any child handles\r
+  created by this driver.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to stop driver on\r
+  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer\r
+  @param  ChildHandleBuffer    List of handles for the children we need to stop.\r
+\r
+  @return EFI_SUCCESS\r
+  @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhciDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN EFI_HANDLE                      Controller,\r
+  IN UINTN                           NumberOfChildren,\r
+  IN EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_USB_HC_PROTOCOL   *UsbHc;\r
+  EFI_USB2_HC_PROTOCOL  *Usb2Hc;\r
+  EFI_STATUS            Status;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsbHcProtocolGuid,\r
+                  &UsbHc,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  //\r
+  // Test whether the Controller handler passed in is a valid\r
+  // Usb controller handle that should be supported, if not,\r
+  // return the error status directly\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  &Usb2Hc,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  //\r
+  // Test whether the Controller handler passed in is a valid\r
+  // Usb controller handle that should be supported, if not,\r
+  // return the error status directly\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  UhciCleanDevUp (Controller, UsbHc);\r
+\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiPciIoProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {\r
+  UhciDriverBindingSupported,\r
+  UhciDriverBindingStart,\r
+  UhciDriverBindingStop,\r
+  0x20,\r
+  NULL,\r
+  NULL\r
+};\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.h b/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.h
new file mode 100644 (file)
index 0000000..c37894d
--- /dev/null
@@ -0,0 +1,140 @@
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  Uhci.h\r
+\r
+Abstract:\r
+\r
+  The definition for UHCI driver model and HC protocol routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _UHCI_H\r
+#define _UHCI_H\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Protocol/Usb2HostController.h>\r
+#include <Protocol/UsbHostController.h>\r
+#include <Protocol/PciIo.h>\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+typedef struct _USB_HC_DEV  USB_HC_DEV;\r
+\r
+#include "UsbHcMem.h"\r
+#include "UhciQueue.h"\r
+#include "UhciReg.h"\r
+#include "UhciSched.h"\r
+#include "UhciDebug.h"\r
+\r
+enum {\r
+  //\r
+  // Stall times\r
+  //\r
+  STALL_1_MS               = 1000,\r
+  STALL_1_SECOND           = 1000 *STALL_1_MS,\r
+\r
+  UHC_SYN_POLL             = 50,\r
+  FORCE_GLOBAL_RESUME_TIME = 20 *STALL_1_MS,\r
+  ROOT_PORT_REST_TIME      = 50 *STALL_1_MS,\r
+  PORT_RESET_RECOVERY_TIME = 10 *STALL_1_MS,\r
+  INTERRUPT_POLLING_TIME   = 50 * 10000UL,\r
+\r
+  //\r
+  // UHC raises TPL to TPL_NOTIFY to serialize all its operations\r
+  // to protect shared data structures.\r
+  //\r
+  UHCI_TPL                 = TPL_NOTIFY,\r
+\r
+  USB_HC_DEV_SIGNATURE     = EFI_SIGNATURE_32 ('u', 'h', 'c', 'i'),\r
+};\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
+#define UHC_FROM_USB_HC_PROTO(This)   CR(This, USB_HC_DEV, UsbHc, USB_HC_DEV_SIGNATURE)\r
+#define UHC_FROM_USB2_HC_PROTO(This)  CR(This, USB_HC_DEV, Usb2Hc, USB_HC_DEV_SIGNATURE)\r
+\r
+//\r
+// USB_HC_DEV support the UHCI hardware controller. It schedules\r
+// the asynchronous interrupt transfer with the same method as\r
+// EHCI: a reversed tree structure. For synchronous interrupt,\r
+// control and bulk transfer, it uses three static queue head to\r
+// schedule them. SyncIntQh is for interrupt transfer. LsCtrlQh is\r
+// for LOW speed control transfer, and FsCtrlBulkQh is for FULL\r
+// speed control or bulk transfer. This is because FULL speed contrl\r
+// or bulk transfer can reclaim the unused bandwidth. Some USB\r
+// device requires this bandwidth reclamation capability.\r
+//\r
+typedef struct _USB_HC_DEV {\r
+  UINT32                    Signature;\r
+  EFI_USB_HC_PROTOCOL       UsbHc;\r
+  EFI_USB2_HC_PROTOCOL      Usb2Hc;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+\r
+  //\r
+  // Schedule data structures\r
+  //\r
+  UINT32                    *FrameBase;\r
+  UHCI_QH_SW                *SyncIntQh;\r
+  UHCI_QH_SW                *CtrlQh;\r
+  UHCI_QH_SW                *BulkQh;\r
+\r
+  //\r
+  // Structures to maintain asynchronus interrupt transfers.\r
+  // When asynchronous interrutp transfer is unlinked from\r
+  // the frame list, the hardware may still hold a pointer\r
+  // to it. To synchronize with hardware, its resoureces are\r
+  // released in two steps using Recycle and RecycleWait.\r
+  // Check the asynchronous interrupt management routines.\r
+  //\r
+  LIST_ENTRY                AsyncIntList;\r
+  EFI_EVENT                 AsyncIntMonitor;\r
+  UHCI_ASYNC_REQUEST        *Recycle;\r
+  UHCI_ASYNC_REQUEST        *RecycleWait;\r
+\r
+\r
+  UINTN                     RootPorts;\r
+  USBHC_MEM_POOL            *MemPool;\r
+  EFI_UNICODE_STRING_TABLE  *CtrlNameTable;\r
+  VOID                      *FrameMapping;\r
+} USB_HC_DEV;\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL  gUhciDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL  gUhciComponentName;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.inf b/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.inf
new file mode 100644 (file)
index 0000000..34d7b74
--- /dev/null
@@ -0,0 +1,101 @@
+#/** @file\r
+# Component name for module Uhci\r
+#\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+#  All rights reserved. This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = Uhci\r
+  FILE_GUID                      = 2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = UhciDriverEntryPoint\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
+################################################################################\r
+#\r
+# Sources Section - list of files that are required for the build to succeed.\r
+#\r
+################################################################################\r
+\r
+[Sources.common]\r
+  UhciSched.c\r
+  UhciDebug.c\r
+  UsbHcMem.h\r
+  UhciDebug.h\r
+  UhciQueue.c\r
+  UhciReg.c\r
+  UsbHcMem.c\r
+  UhciQueue.h\r
+  Uhci.c\r
+  Uhci.h\r
+  UhciReg.h\r
+  UhciSched.h\r
+  ComponentName.c\r
+\r
+\r
+################################################################################\r
+#\r
+# Package Dependency Section - list of Package files that are required for\r
+#                              this module.\r
+#\r
+################################################################################\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+################################################################################\r
+#\r
+# Library Class Section - list of Library Classes that are required for\r
+#                         this module.\r
+#\r
+################################################################################\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  DebugLib\r
+\r
+\r
+################################################################################\r
+#\r
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names\r
+#                           that this module uses or produces.\r
+#\r
+################################################################################\r
+\r
+[Protocols]\r
+  gEfiPciIoProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUsbHcProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUsb2HcProtocolGuid                        # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.msa b/MdeModulePkg/Bus/Pci/UhciDxe/Uhci.msa
new file mode 100644 (file)
index 0000000..75ebf35
--- /dev/null
@@ -0,0 +1,84 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>Uhci</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module Uhci</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+    <License>All rights reserved. This program and the accompanying materials                          
+      are licensed and made available under the terms and conditions of the BSD License         
+      which accompanies this distribution.  The full text of the license may be found at        
+      http://opensource.org/licenses/bsd-license.php                                            
+      
+      THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+      WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>\r
+    <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION   0x00000052</Specification>\r
+  </MsaHeader>\r
+  <ModuleDefinitions>\r
+    <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+    <BinaryModule>false</BinaryModule>\r
+    <OutputFileBasename>Uhci</OutputFileBasename>\r
+  </ModuleDefinitions>\r
+  <LibraryClassDefinitions>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DebugLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseMemoryLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverEntryPoint</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiBootServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>MemoryAllocationLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>uhci.h</Filename>\r
+    <Filename>UhciSched.h</Filename>\r
+    <Filename>UhciReg.h</Filename>\r
+    <Filename>uhci.c</Filename>\r
+    <Filename>UhciQueue.h</Filename>\r
+    <Filename>UsbHcMem.c</Filename>\r
+    <Filename>UhciReg.c</Filename>\r
+    <Filename>UhciQueue.c</Filename>\r
+    <Filename>UhciDebug.h</Filename>\r
+    <Filename>UsbHcMem.h</Filename>\r
+    <Filename>UhciDebug.c</Filename>\r
+    <Filename>UhciSched.c</Filename>\r
+  </SourceFiles>\r
+  <PackageDependencies>\r
+    <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+    <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+  </PackageDependencies>\r
+  <Protocols>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUsb2HcProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUsbHcProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+  </Protocols>\r
+  <Externs>\r
+    <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+    <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+    <Extern>\r
+      <ModuleEntryPoint>UhciDriverEntryPoint</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.c b/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.c
new file mode 100644 (file)
index 0000000..d47314f
--- /dev/null
@@ -0,0 +1,183 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UhciDebug.c\r
+\r
+Abstract:\r
+\r
+  This file provides the information dump support for Uhci when in debug mode.\r
+  You can dynamically adjust the debug level by changing variable gEHCDebugLevel\r
+  and gEHCErrorLevel.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#include "Uhci.h"\r
+#include "UhciDebug.h"\r
+\r
+#ifdef EFI_DEBUG\r
+\r
+UINTN mUhciDebugMask = USB_DEBUG_FORCE_OUTPUT;\r
+\r
+\r
+/**\r
+  Debug debug print interface for UHCI\r
+\r
+  @param  Format  String to use for the print, followed by print arguments\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciDebug (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST                 Marker;\r
+\r
+  VA_START (Marker, Format);\r
+  DebugVPrint (DEBUG_INFO, Format, Marker);\r
+  VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+  Debug error print interface for UHCI\r
+\r
+  @param  Format  String to use for the print, followed by print arguments\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciError (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST                 Marker;\r
+\r
+  VA_START (Marker, Format);\r
+  DebugVPrint (DEBUG_ERROR, Format, Marker);\r
+  VA_END (Marker);\r
+}\r
+\r
+\r
+\r
+/**\r
+  Debug print interface for UHCI\r
+\r
+  @param  Level   Level to control debug print\r
+  @param  Format  String to use for the print, followed by print arguments\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciDebugPrint (\r
+  IN  UINTN               Level,\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST                 Marker;\r
+\r
+  VA_START (Marker, Format);\r
+\r
+  if (Level & mUhciDebugMask) {\r
+    if (mUhciDebugMask & USB_DEBUG_FORCE_OUTPUT) {\r
+      DebugVPrint (DEBUG_ERROR, Format, Marker);\r
+    } else {\r
+      DebugVPrint (DEBUG_INFO, Format, Marker);\r
+    }\r
+  }\r
+\r
+  VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+  Dump the content of QH structure\r
+\r
+  @param  QhSw    Pointer to software QH structure\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciDumpQh (\r
+  IN UHCI_QH_SW    *QhSw\r
+  )\r
+{\r
+  UINTN                   Level;\r
+\r
+  Level = UHCI_DEBUG_QH;\r
+\r
+  UhciDebugPrint (Level, "&QhSw @ 0x%x\n", QhSw);\r
+  UhciDebugPrint (Level, "QhSw.NextQh    - 0x%x\n", QhSw->NextQh);\r
+  UhciDebugPrint (Level, "QhSw.TDs       - 0x%x\n", QhSw->TDs);\r
+  UhciDebugPrint (Level, "QhSw.QhHw:\n");\r
+  UhciDebugPrint (Level, " Horizon  Link - %x\n", QhSw->QhHw.HorizonLink);\r
+  UhciDebugPrint (Level, " Vertical Link - %x\n\n", QhSw->QhHw.VerticalLink);\r
+}\r
+\r
+\r
+/**\r
+  Dump the content of TD structure.\r
+\r
+  @param  TdSw    Pointer to software TD structure\r
+  @param  IsCur   Whether dump the whole list, or only dump the current TD\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciDumpTds (\r
+  IN UHCI_TD_SW           *TdSw\r
+  )\r
+{\r
+  UHCI_TD_SW              *CurTdSw;\r
+  UINTN                   Level;\r
+\r
+  Level   = UHCI_DEBUG_TD;\r
+  CurTdSw = TdSw;\r
+\r
+  while (CurTdSw != NULL) {\r
+    UhciDebugPrint (Level, "TdSw @ 0x%x\n",           CurTdSw);\r
+    UhciDebugPrint (Level, "TdSw.NextTd   - 0x%x\n",  CurTdSw->NextTd);\r
+    UhciDebugPrint (Level, "TdSw.DataLen  - %d\n",    CurTdSw->DataLen);\r
+    UhciDebugPrint (Level, "TdSw.Data     - 0x%x\n",  CurTdSw->Data);\r
+    UhciDebugPrint (Level, "TdHw:\n");\r
+    UhciDebugPrint (Level, " NextLink     - 0x%x\n",  CurTdSw->TdHw.NextLink);\r
+    UhciDebugPrint (Level, " ActualLen    - %d\n",    CurTdSw->TdHw.ActualLen);\r
+    UhciDebugPrint (Level, " Status       - 0x%x\n",  CurTdSw->TdHw.Status);\r
+    UhciDebugPrint (Level, " IOC          - %d\n",    CurTdSw->TdHw.IntOnCpl);\r
+    UhciDebugPrint (Level, " IsIsoCh      - %d\n",    CurTdSw->TdHw.IsIsoch);\r
+    UhciDebugPrint (Level, " LowSpeed     - %d\n",    CurTdSw->TdHw.LowSpeed);\r
+    UhciDebugPrint (Level, " ErrorCount   - %d\n",    CurTdSw->TdHw.ErrorCount);\r
+    UhciDebugPrint (Level, " ShortPacket  - %d\n",    CurTdSw->TdHw.ShortPacket);\r
+    UhciDebugPrint (Level, " PidCode      - 0x%x\n",  CurTdSw->TdHw.PidCode);\r
+    UhciDebugPrint (Level, " DevAddr      - %d\n",    CurTdSw->TdHw.DeviceAddr);\r
+    UhciDebugPrint (Level, " EndPoint     - %d\n",    CurTdSw->TdHw.EndPoint);\r
+    UhciDebugPrint (Level, " DataToggle   - %d\n",    CurTdSw->TdHw.DataToggle);\r
+    UhciDebugPrint (Level, " MaxPacketLen - %d\n",    CurTdSw->TdHw.MaxPacketLen);\r
+    UhciDebugPrint (Level, " DataBuffer   - 0x%x\n\n",CurTdSw->TdHw.DataBuffer);\r
+\r
+    CurTdSw = CurTdSw->NextTd;\r
+  }\r
+}\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.h b/MdeModulePkg/Bus/Pci/UhciDxe/UhciDebug.h
new file mode 100644 (file)
index 0000000..d71791a
--- /dev/null
@@ -0,0 +1,134 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UhciDebug.h\r
+\r
+Abstract:\r
+\r
+  This file contains the definination for host controller debug support routines\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _EFI_UHCI_DEBUG_H_\r
+#define _EFI_UHCI_DEBUG_H_\r
+\r
+//\r
+// DEBUG support\r
+//\r
+#define USB_DEBUG_FORCE_OUTPUT  (UINTN) (1 << 0)\r
+#define UHCI_DEBUG_QH           (UINTN) (1 << 2)\r
+#define UHCI_DEBUG_TD           (UINTN) (1 << 3)\r
+\r
+VOID\r
+UhciDebugPrint (\r
+  IN  UINTN               Level,\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Debug print interface for UHCI\r
+\r
+Arguments:\r
+\r
+  Level   - Level to control debug print\r
+  Format  - String to use for the print, followed by print arguments\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+;\r
+\r
+\r
+/**\r
+  Debug print interface for UHCI\r
+\r
+  @param  Format  String to use for the print, followed by print arguments\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciDebug (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Debug error print interface for UHCI\r
+\r
+  @param  Format  String to use for the print, followed by print arguments\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciError (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Dump the content of QH structure\r
+\r
+  @param  QhSw    Pointer to software QH structure\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciDumpQh (\r
+  IN UHCI_QH_SW         *QhSw\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Dump the content of TD structure.\r
+\r
+  @param  TdSw    Pointer to software TD structure\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciDumpTds (\r
+  IN UHCI_TD_SW           *TdSw\r
+  )\r
+;\r
+\r
+\r
+#ifdef EFI_DEBUG\r
+  #define UHCI_DEBUG(arg)             UhciDebug arg\r
+  #define UHCI_ERROR(arg)             UhciError arg\r
+  #define UHCI_DUMP_TDS(arg)          UhciDumpTds arg\r
+  #define UHCI_DUMP_QH(arg)           UhciDumpQh arg\r
+#else\r
+  #define UHCI_DEBUG(arg)\r
+  #define UHCI_ERROR(arg)\r
+  #define UHCI_DUMP_TDS(arg)\r
+  #define UHCI_DUMP_QH(arg)\r
+#endif\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c b/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c
new file mode 100644 (file)
index 0000000..843c9e3
--- /dev/null
@@ -0,0 +1,703 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UhciQueue.c\r
+\r
+Abstract:\r
+\r
+  The UHCI register operation routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#include "Uhci.h"\r
+\r
+\r
+/**\r
+  Map address of request structure buffer\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  Request     The user request buffer\r
+  @param  MappedAddr  Mapped address of request\r
+  @param  Map         Identificaion of this mapping to return\r
+\r
+  @return EFI_SUCCESS      : Success\r
+  @return EFI_DEVICE_ERROR : Fail to map the user request\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserRequest (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  OUT VOID            *Request,\r
+  OUT UINT8               **MappedAddr,\r
+  OUT VOID                **Map\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 Len;\r
+  EFI_PHYSICAL_ADDRESS  PhyAddr;\r
+\r
+  Len    = sizeof (EFI_USB_DEVICE_REQUEST);\r
+  Status = Uhc->PciIo->Map (\r
+                         Uhc->PciIo,\r
+                         EfiPciIoOperationBusMasterRead,\r
+                         Request,\r
+                         &Len,\r
+                         &PhyAddr,\r
+                         Map\r
+                         );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Map address of user data buffer\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  Direction   direction of the data transfer\r
+  @param  Data        The user data buffer\r
+  @param  Len         Length of the user data\r
+  @param  PktId       Packet identificaion\r
+  @param  MappedAddr  mapped address to return\r
+  @param  Map         identificaion of this mapping to return\r
+\r
+  @return EFI_SUCCESS      : Success\r
+  @return EFI_DEVICE_ERROR : Fail to map the user data\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserData (\r
+  IN  USB_HC_DEV              *Uhc,\r
+  IN  EFI_USB_DATA_DIRECTION  Direction,\r
+  IN  VOID                    *Data,\r
+  IN  OUT UINTN               *Len,\r
+  OUT UINT8                   *PktId,\r
+  OUT UINT8                   **MappedAddr,\r
+  OUT VOID                    **Map\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  PhyAddr;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (Direction) {\r
+  case EfiUsbDataIn:\r
+    //\r
+    // BusMasterWrite means cpu read\r
+    //\r
+    *PktId = INPUT_PACKET_ID;\r
+    Status = Uhc->PciIo->Map (\r
+                           Uhc->PciIo,\r
+                           EfiPciIoOperationBusMasterWrite,\r
+                           Data,\r
+                           Len,\r
+                           &PhyAddr,\r
+                           Map\r
+                           );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto EXIT;\r
+    }\r
+\r
+    *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+    break;\r
+\r
+  case EfiUsbDataOut:\r
+    *PktId = OUTPUT_PACKET_ID;\r
+    Status = Uhc->PciIo->Map (\r
+                           Uhc->PciIo,\r
+                           EfiPciIoOperationBusMasterRead,\r
+                           Data,\r
+                           Len,\r
+                           &PhyAddr,\r
+                           Map\r
+                           );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto EXIT;\r
+    }\r
+\r
+    *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+    break;\r
+\r
+  case EfiUsbNoData:\r
+    if ((Len != NULL) && (*Len != 0)) {\r
+      Status    = EFI_INVALID_PARAMETER;\r
+      goto EXIT;\r
+    }\r
+\r
+    *PktId      = OUTPUT_PACKET_ID;\r
+    *Len        = 0;\r
+    *MappedAddr = NULL;\r
+    *Map        = NULL;\r
+    break;\r
+\r
+  default:\r
+    Status      = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+EXIT:\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Link the TD To QH\r
+\r
+  @param  Qh          The queue head for the TD to link to\r
+  @param  Td          The TD to link\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciLinkTdToQh (\r
+  IN UHCI_QH_SW           *Qh,\r
+  IN UHCI_TD_SW           *Td\r
+  )\r
+{\r
+  ASSERT ((Qh != NULL) && (Td != NULL));\r
+\r
+  Qh->QhHw.VerticalLink = QH_VLINK (Td, FALSE);\r
+  Qh->TDs               = (VOID *) Td;\r
+}\r
+\r
+\r
+/**\r
+  Unlink TD from the QH\r
+\r
+  @param  Qh          The queue head to unlink from\r
+  @param  Td          The TD to unlink\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciUnlinkTdFromQh (\r
+  IN UHCI_QH_SW           *Qh,\r
+  IN UHCI_TD_SW           *Td\r
+  )\r
+{\r
+  ASSERT ((Qh != NULL) && (Td != NULL));\r
+\r
+  Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);\r
+  Qh->TDs               = NULL;\r
+}\r
+\r
+\r
+/**\r
+  Append a new TD To the previous TD\r
+\r
+  @param  PrevTd      Previous UHCI_TD_SW to be linked to\r
+  @param  ThisTd      TD to link\r
+\r
+  @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciAppendTd (\r
+  IN UHCI_TD_SW     *PrevTd,\r
+  IN UHCI_TD_SW     *ThisTd\r
+  )\r
+{\r
+  ASSERT ((PrevTd != NULL) && (ThisTd != NULL));\r
+\r
+  PrevTd->TdHw.NextLink = TD_LINK (ThisTd, TRUE, FALSE);\r
+  PrevTd->NextTd        = (VOID *) ThisTd;\r
+}\r
+\r
+\r
+/**\r
+  Delete a list of TDs\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  FirstTd     TD link list head\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciDestoryTds (\r
+  IN USB_HC_DEV           *Uhc,\r
+  IN UHCI_TD_SW           *FirstTd\r
+  )\r
+{\r
+  UHCI_TD_SW            *NextTd;\r
+  UHCI_TD_SW            *ThisTd;\r
+\r
+  NextTd = FirstTd;\r
+\r
+  while (NextTd != NULL) {\r
+    ThisTd  = NextTd;\r
+    NextTd  = ThisTd->NextTd;\r
+    UsbHcFreeMem (Uhc->MemPool, ThisTd, sizeof (UHCI_TD_SW));\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Create an initialize a new queue head\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  Interval    The polling interval for the queue\r
+\r
+  @return The newly created queue header\r
+\r
+**/\r
+UHCI_QH_SW *\r
+UhciCreateQh (\r
+  IN  USB_HC_DEV        *Uhc,\r
+  IN  UINTN             Interval\r
+  )\r
+{\r
+  UHCI_QH_SW            *Qh;\r
+\r
+  Qh = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_QH_SW));\r
+\r
+  if (Qh == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Qh->QhHw.HorizonLink  = QH_HLINK (NULL, TRUE);\r
+  Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);\r
+  Qh->Interval          = Interval;\r
+  Qh->TDs               = NULL;\r
+  Qh->NextQh            = NULL;\r
+\r
+  return Qh;\r
+}\r
+\r
+\r
+/**\r
+  Create and intialize a TD\r
+\r
+  @param  Uhc         The UHCI device\r
+\r
+  @return The newly allocated and initialized TD\r
+\r
+**/\r
+STATIC\r
+UHCI_TD_SW *\r
+UhciCreateTd (\r
+  IN  USB_HC_DEV          *Uhc\r
+  )\r
+{\r
+  UHCI_TD_SW              *Td;\r
+\r
+  Td     = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_TD_SW));\r
+  if (Td == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Td->TdHw.NextLink = TD_LINK (NULL, FALSE, TRUE);\r
+  Td->NextTd        = NULL;\r
+  Td->Data          = NULL;\r
+  Td->DataLen       = 0;\r
+\r
+  return Td;\r
+}\r
+\r
+\r
+/**\r
+  Create and initialize a TD for Setup Stage of a control transfer\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  DevAddr     Device address\r
+  @param  Request     Device request\r
+  @param  IsLow       Full speed or low speed\r
+\r
+  @return The created setup Td Pointer\r
+\r
+**/\r
+STATIC\r
+UHCI_TD_SW *\r
+UhciCreateSetupTd (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               *Request,\r
+  IN  BOOLEAN             IsLow\r
+  )\r
+{\r
+  UHCI_TD_SW              *Td;\r
+\r
+  Td = UhciCreateTd (Uhc);\r
+\r
+  if (Td == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Td->TdHw.NextLink     = TD_LINK (NULL, TRUE, TRUE);\r
+  Td->TdHw.ShortPacket  = FALSE;\r
+  Td->TdHw.IsIsoch      = FALSE;\r
+  Td->TdHw.IntOnCpl     = FALSE;\r
+  Td->TdHw.ErrorCount   = 0x03;\r
+  Td->TdHw.Status      |= USBTD_ACTIVE;\r
+  Td->TdHw.DataToggle   = 0;\r
+  Td->TdHw.EndPoint     = 0;\r
+  Td->TdHw.LowSpeed     = IsLow ? 1 : 0;\r
+  Td->TdHw.DeviceAddr   = DevAddr & 0x7F;\r
+  Td->TdHw.MaxPacketLen = (UINT32) (sizeof (EFI_USB_DEVICE_REQUEST) - 1);\r
+  Td->TdHw.PidCode      = SETUP_PACKET_ID;\r
+  Td->TdHw.DataBuffer   = (UINT32) (UINTN) Request;\r
+\r
+  Td->Data              = Request;\r
+  Td->DataLen           = sizeof (EFI_USB_DEVICE_REQUEST);\r
+\r
+  return Td;\r
+}\r
+\r
+\r
+/**\r
+  Create a TD for data\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  DevAddr     Device address\r
+  @param  Endpoint    Endpoint number\r
+  @param  DataPtr     Data buffer\r
+  @param  Len         Data length\r
+  @param  PktId       Packet ID\r
+  @param  Toggle      Data toggle value\r
+  @param  IsLow       Full speed or low speed\r
+\r
+  @return Data Td pointer if success, otherwise NUL\r
+\r
+**/\r
+STATIC\r
+UHCI_TD_SW *\r
+UhciCreateDataTd (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               Endpoint,\r
+  IN  UINT8               *DataPtr,\r
+  IN  UINTN               Len,\r
+  IN  UINT8               PktId,\r
+  IN  UINT8               Toggle,\r
+  IN  BOOLEAN             IsLow\r
+  )\r
+{\r
+  UHCI_TD_SW  *Td;\r
+\r
+  //\r
+  // Code as length - 1, and the max valid length is 0x500\r
+  //\r
+  ASSERT (Len <= 0x500);\r
+\r
+  Td  = UhciCreateTd (Uhc);\r
+\r
+  if (Td == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Td->TdHw.NextLink     = TD_LINK (NULL, TRUE, TRUE);\r
+  Td->TdHw.ShortPacket  = FALSE;\r
+  Td->TdHw.IsIsoch      = FALSE;\r
+  Td->TdHw.IntOnCpl     = FALSE;\r
+  Td->TdHw.ErrorCount   = 0X03;\r
+  Td->TdHw.Status       = USBTD_ACTIVE;\r
+  Td->TdHw.LowSpeed     = IsLow ? 1 : 0;\r
+  Td->TdHw.DataToggle   = Toggle & 0x01;\r
+  Td->TdHw.EndPoint     = Endpoint & 0x0F;\r
+  Td->TdHw.DeviceAddr   = DevAddr & 0x7F;\r
+  Td->TdHw.MaxPacketLen = (UINT32) (Len - 1);\r
+  Td->TdHw.PidCode      = (UINT8) PktId;\r
+  Td->TdHw.DataBuffer   = (UINT32) (UINTN) DataPtr;\r
+\r
+  Td->Data              = DataPtr;\r
+  Td->DataLen           = (UINT16) Len;\r
+\r
+  return Td;\r
+}\r
+\r
+\r
+/**\r
+  Create TD for the Status Stage of control transfer\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  DevAddr     Device address\r
+  @param  PktId       Packet ID\r
+  @param  IsLow       Full speed or low speed\r
+\r
+  @return Status Td Pointer\r
+\r
+**/\r
+STATIC\r
+UHCI_TD_SW *\r
+UhciCreateStatusTd (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               PktId,\r
+  IN  BOOLEAN             IsLow\r
+  )\r
+{\r
+  UHCI_TD_SW              *Td;\r
+\r
+  Td = UhciCreateTd (Uhc);\r
+\r
+  if (Td == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Td->TdHw.NextLink     = TD_LINK (NULL, TRUE, TRUE);\r
+  Td->TdHw.ShortPacket  = FALSE;\r
+  Td->TdHw.IsIsoch      = FALSE;\r
+  Td->TdHw.IntOnCpl     = FALSE;\r
+  Td->TdHw.ErrorCount   = 0x03;\r
+  Td->TdHw.Status      |= USBTD_ACTIVE;\r
+  Td->TdHw.MaxPacketLen = 0x7FF;      //0x7FF: there is no data (refer to UHCI spec)\r
+  Td->TdHw.DataToggle   = 1;\r
+  Td->TdHw.EndPoint     = 0;\r
+  Td->TdHw.LowSpeed     = IsLow ? 1 : 0;\r
+  Td->TdHw.DeviceAddr   = DevAddr & 0x7F;\r
+  Td->TdHw.PidCode      = (UINT8) PktId;\r
+  Td->TdHw.DataBuffer   = (UINT32) (UINTN) NULL;\r
+\r
+  Td->Data              = NULL;\r
+  Td->DataLen           = 0;\r
+\r
+  return Td;\r
+}\r
+\r
+\r
+/**\r
+  Create Tds list for Control Transfer\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  DeviceAddr  The device address\r
+  @param  DataPktId   Packet Identification of Data Tds\r
+  @param  Request     A pointer to request structure buffer to transfer\r
+  @param  Data        A pointer to user data buffer to transfer\r
+  @param  DataLen     Length of user data to transfer\r
+  @param  MaxPacket   Maximum packet size for control transfer\r
+  @param  IsLow       Full speed or low speed\r
+\r
+  @return The Td list head for the control transfer\r
+\r
+**/\r
+UHCI_TD_SW *\r
+UhciCreateCtrlTds (\r
+  IN USB_HC_DEV           *Uhc,\r
+  IN UINT8                DeviceAddr,\r
+  IN UINT8                DataPktId,\r
+  IN UINT8                *Request,\r
+  IN UINT8                *Data,\r
+  IN UINTN                DataLen,\r
+  IN UINT8                MaxPacket,\r
+  IN BOOLEAN              IsLow\r
+  )\r
+{\r
+  UHCI_TD_SW                *SetupTd;\r
+  UHCI_TD_SW                *FirstDataTd;\r
+  UHCI_TD_SW                *DataTd;\r
+  UHCI_TD_SW                *PrevDataTd;\r
+  UHCI_TD_SW                *StatusTd;\r
+  UINT8                     DataToggle;\r
+  UINT8                     StatusPktId;\r
+  UINTN                     ThisTdLen;\r
+\r
+\r
+  DataTd      = NULL;\r
+  SetupTd     = NULL;\r
+  FirstDataTd = NULL;\r
+  PrevDataTd  = NULL;\r
+  StatusTd    = NULL;\r
+\r
+  //\r
+  // Create setup packets for the transfer\r
+  //\r
+  SetupTd = UhciCreateSetupTd (Uhc, DeviceAddr, Request, IsLow);\r
+\r
+  if (SetupTd == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Create data packets for the transfer\r
+  //\r
+  DataToggle = 1;\r
+\r
+  while (DataLen > 0) {\r
+    //\r
+    // PktSize is the data load size in each Td.\r
+    //\r
+    ThisTdLen = (DataLen > MaxPacket ? MaxPacket : DataLen);\r
+\r
+    DataTd = UhciCreateDataTd (\r
+               Uhc,\r
+               DeviceAddr,\r
+               0,\r
+               Data,\r
+               ThisTdLen,\r
+               DataPktId,\r
+               DataToggle,\r
+               IsLow\r
+               );\r
+\r
+    if (DataTd == NULL) {\r
+      goto FREE_TD;\r
+    }\r
+\r
+    if (FirstDataTd == NULL) {\r
+      FirstDataTd         = DataTd;\r
+      FirstDataTd->NextTd = NULL;\r
+    } else {\r
+      UhciAppendTd (PrevDataTd, DataTd);\r
+    }\r
+\r
+    DataToggle ^= 1;\r
+    PrevDataTd = DataTd;\r
+    Data += ThisTdLen;\r
+    DataLen -= ThisTdLen;\r
+  }\r
+\r
+  //\r
+  // Status packet is on the opposite direction to data packets\r
+  //\r
+  if (OUTPUT_PACKET_ID == DataPktId) {\r
+    StatusPktId = INPUT_PACKET_ID;\r
+  } else {\r
+    StatusPktId = OUTPUT_PACKET_ID;\r
+  }\r
+\r
+  StatusTd = UhciCreateStatusTd (Uhc, DeviceAddr, StatusPktId, IsLow);\r
+\r
+  if (StatusTd == NULL) {\r
+    goto FREE_TD;\r
+  }\r
+\r
+  //\r
+  // Link setup Td -> data Tds -> status Td together\r
+  //\r
+  if (FirstDataTd != NULL) {\r
+    UhciAppendTd (SetupTd, FirstDataTd);\r
+    UhciAppendTd (PrevDataTd, StatusTd);\r
+  } else {\r
+    UhciAppendTd (SetupTd, StatusTd);\r
+  }\r
+\r
+  return SetupTd;\r
+\r
+FREE_TD:\r
+  if (SetupTd != NULL) {\r
+    UhciDestoryTds (Uhc, SetupTd);\r
+  }\r
+\r
+  if (FirstDataTd != NULL) {\r
+    UhciDestoryTds (Uhc, FirstDataTd);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Create Tds list for Bulk/Interrupt Transfer\r
+\r
+  @param  Uhc         USB_HC_DEV\r
+  @param  DevAddr     Address of Device\r
+  @param  EndPoint    Endpoint Number\r
+  @param  PktId       Packet Identification of Data Tds\r
+  @param  Data        A pointer to user data buffer to transfer\r
+  @param  DataLen     Length of user data to transfer\r
+  @param  DataToggle  Data Toggle Pointer\r
+  @param  MaxPacket   Maximum packet size for Bulk/Interrupt transfer\r
+  @param  IsLow       Is Low Speed Device\r
+\r
+  @return The Tds list head for the bulk transfer\r
+\r
+**/\r
+UHCI_TD_SW *\r
+UhciCreateBulkOrIntTds (\r
+  IN USB_HC_DEV           *Uhc,\r
+  IN UINT8                DevAddr,\r
+  IN UINT8                EndPoint,\r
+  IN UINT8                PktId,\r
+  IN UINT8                *Data,\r
+  IN UINTN                DataLen,\r
+  IN OUT UINT8            *DataToggle,\r
+  IN UINT8                MaxPacket,\r
+  IN BOOLEAN              IsLow\r
+  )\r
+{\r
+  UHCI_TD_SW              *DataTd;\r
+  UHCI_TD_SW              *FirstDataTd;\r
+  UHCI_TD_SW              *PrevDataTd;\r
+  UINTN                   ThisTdLen;\r
+\r
+  DataTd      = NULL;\r
+  FirstDataTd = NULL;\r
+  PrevDataTd  = NULL;\r
+\r
+  //\r
+  // Create data packets for the transfer\r
+  //\r
+  while (DataLen > 0) {\r
+    //\r
+    // PktSize is the data load size that each Td.\r
+    //\r
+    ThisTdLen = DataLen;\r
+\r
+    if (DataLen > MaxPacket) {\r
+      ThisTdLen = MaxPacket;\r
+    }\r
+\r
+    DataTd = UhciCreateDataTd (\r
+               Uhc,\r
+               DevAddr,\r
+               EndPoint,\r
+               Data,\r
+               ThisTdLen,\r
+               PktId,\r
+               *DataToggle,\r
+               IsLow\r
+               );\r
+\r
+    if (DataTd == NULL) {\r
+      goto FREE_TD;\r
+    }\r
+\r
+    if (PktId == INPUT_PACKET_ID) {\r
+      DataTd->TdHw.ShortPacket = TRUE;\r
+    }\r
+\r
+    if (FirstDataTd == NULL) {\r
+      FirstDataTd         = DataTd;\r
+      FirstDataTd->NextTd = NULL;\r
+    } else {\r
+      UhciAppendTd (PrevDataTd, DataTd);\r
+    }\r
+\r
+    *DataToggle ^= 1;\r
+    PrevDataTd   = DataTd;\r
+    Data        += ThisTdLen;\r
+    DataLen     -= ThisTdLen;\r
+  }\r
+\r
+  return FirstDataTd;\r
+\r
+FREE_TD:\r
+  if (FirstDataTd != NULL) {\r
+    UhciDestoryTds (Uhc, FirstDataTd);\r
+  }\r
+\r
+  return NULL;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.h b/MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.h
new file mode 100644 (file)
index 0000000..8b03ec6
--- /dev/null
@@ -0,0 +1,283 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UhciQueue.h\r
+\r
+Abstract:\r
+\r
+  The definition for UHCI register operation routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _EFI_UHCI_QUEUE_H_\r
+#define _EFI_UHCI_QUEUE_H_\r
+\r
+//\r
+// Macroes used to set various links in UHCI's driver.\r
+// In this UHCI driver, QH's horizontal link always pointers to other QH,\r
+// and its vertical link always pointers to TD. TD's next pointer always\r
+// pointers to other sibling TD. Frame link always pointers to QH because\r
+// ISO transfer isn't supported.\r
+//\r
+// We should use UINT32 to access these pointers to void race conditions\r
+// with hardware.\r
+//\r
+#define QH_HLINK(Pointer, Terminate)  \\r
+        (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | 0x02 | ((Terminate) ? 0x01 : 0))\r
+\r
+#define QH_VLINK(Pointer, Terminate)  \\r
+        (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | ((Terminate) ? 0x01 : 0))\r
+\r
+#define TD_LINK(Pointer, VertFirst, Terminate) \\r
+        (((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | \\r
+         ((VertFirst) ? 0x04 : 0) | ((Terminate) ? 0x01 : 0))\r
+\r
+#define LINK_TERMINATED(Link) (((Link) & 0x01) != 0)\r
+\r
+#define UHCI_ADDR(QhOrTd)     ((VOID *) (UINTN) ((QhOrTd) & 0xFFFFFFF0))\r
+\r
+#pragma pack(1)\r
+//\r
+// Both links in QH has this internal structure:\r
+//   Next pointer: 28, Reserved: 2, NextIsQh: 1, Terminate: 1\r
+// This is the same as frame list entry.\r
+//\r
+typedef struct {\r
+  UINT32              HorizonLink;\r
+  UINT32              VerticalLink;\r
+} UHCI_QH_HW;\r
+\r
+//\r
+// Next link in TD has this internal structure:\r
+//   Next pointer: 28, Reserved: 1, Vertical First: 1, NextIsQh: 1, Terminate: 1\r
+//\r
+typedef struct {\r
+  UINT32              NextLink;\r
+  UINT32              ActualLen   : 11;\r
+  UINT32              Reserved1   : 5;\r
+  UINT32              Status      : 8;\r
+  UINT32              IntOnCpl    : 1;\r
+  UINT32              IsIsoch     : 1;\r
+  UINT32              LowSpeed    : 1;\r
+  UINT32              ErrorCount  : 2;\r
+  UINT32              ShortPacket : 1;\r
+  UINT32              Reserved2   : 2;\r
+  UINT32              PidCode     : 8;\r
+  UINT32              DeviceAddr  : 7;\r
+  UINT32              EndPoint    : 4;\r
+  UINT32              DataToggle  : 1;\r
+  UINT32              Reserved3   : 1;\r
+  UINT32              MaxPacketLen: 11;\r
+  UINT32              DataBuffer;\r
+} UHCI_TD_HW;\r
+#pragma pack()\r
+\r
+typedef struct _UHCI_TD_SW  UHCI_TD_SW;\r
+typedef struct _UHCI_QH_SW  UHCI_QH_SW;\r
+\r
+typedef struct _UHCI_QH_SW {\r
+  UHCI_QH_HW        QhHw;\r
+  UHCI_QH_SW        *NextQh;\r
+  UHCI_TD_SW        *TDs;\r
+  UINTN             Interval;\r
+} UHCI_QH_SW;\r
+\r
+typedef struct _UHCI_TD_SW {\r
+  UHCI_TD_HW        TdHw;\r
+  UHCI_TD_SW        *NextTd;\r
+  UINT8             *Data;\r
+  UINT16            DataLen;\r
+} UHCI_TD_SW;\r
+\r
+\r
+/**\r
+  Link the TD To QH\r
+\r
+  @param  Qh          The queue head for the TD to link to\r
+  @param  Td          The TD to link\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciLinkTdToQh (\r
+  IN UHCI_QH_SW           *Qh,\r
+  IN UHCI_TD_SW           *Td\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Unlink TD from the QH\r
+\r
+  @param  Qh          The queue head to unlink from\r
+  @param  Td          The TD to unlink\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciUnlinkTdFromQh (\r
+  IN UHCI_QH_SW           *Qh,\r
+  IN UHCI_TD_SW           *Td\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Map address of request structure buffer\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  Request     The user request buffer\r
+  @param  MappedAddr  Mapped address of request\r
+  @param  Map         Identificaion of this mapping to return\r
+\r
+  @return EFI_SUCCESS      : Success\r
+  @return EFI_DEVICE_ERROR : Fail to map the user request\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserRequest (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  OUT VOID            *Request,\r
+  OUT UINT8               **MappedAddr,\r
+  OUT VOID                **Map\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Map address of user data buffer\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  Direction   direction of the data transfer\r
+  @param  Data        The user data buffer\r
+  @param  Len         Length of the user data\r
+  @param  PktId       Packet identificaion\r
+  @param  MappedAddr  mapped address to return\r
+  @param  Map         identificaion of this mapping to return\r
+\r
+  @return EFI_SUCCESS      : Success\r
+  @return EFI_DEVICE_ERROR : Fail to map the user data\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserData (\r
+  IN  USB_HC_DEV              *Uhc,\r
+  IN  EFI_USB_DATA_DIRECTION  Direction,\r
+  IN  VOID                    *Data,\r
+  IN  OUT UINTN               *Len,\r
+  OUT UINT8                   *PktId,\r
+  OUT UINT8                   **MappedAddr,\r
+  OUT VOID                    **Map\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Delete a list of TDs\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  FirstTd     TD link list head\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciDestoryTds (\r
+  IN USB_HC_DEV           *Uhc,\r
+  IN UHCI_TD_SW           *FirstTd\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Create an initialize a new queue head\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  Interval    The polling interval for the queue\r
+\r
+  @return The newly created queue header\r
+\r
+**/\r
+UHCI_QH_SW *\r
+UhciCreateQh (\r
+  IN  USB_HC_DEV        *Uhc,\r
+  IN  UINTN             Interval\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Create Tds list for Control Transfer\r
+\r
+  @param  Uhc         The UHCI device\r
+  @param  DeviceAddr  The device address\r
+  @param  DataPktId   Packet Identification of Data Tds\r
+  @param  Request     A pointer to request structure buffer to transfer\r
+  @param  Data        A pointer to user data buffer to transfer\r
+  @param  DataLen     Length of user data to transfer\r
+  @param  MaxPacket   Maximum packet size for control transfer\r
+  @param  IsLow       Full speed or low speed\r
+\r
+  @return The Td list head for the control transfer\r
+\r
+**/\r
+UHCI_TD_SW *\r
+UhciCreateCtrlTds (\r
+  IN USB_HC_DEV           *Uhc,\r
+  IN UINT8                DeviceAddr,\r
+  IN UINT8                DataPktId,\r
+  IN UINT8                *Request,\r
+  IN UINT8                *Data,\r
+  IN UINTN                DataLen,\r
+  IN UINT8                MaxPacket,\r
+  IN BOOLEAN              IsLow\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Create Tds list for Bulk/Interrupt Transfer\r
+\r
+  @param  Uhc         USB_HC_DEV\r
+  @param  DevAddr     Address of Device\r
+  @param  EndPoint    Endpoint Number\r
+  @param  PktId       Packet Identification of Data Tds\r
+  @param  Data        A pointer to user data buffer to transfer\r
+  @param  DataLen     Length of user data to transfer\r
+  @param  DataToggle  Data Toggle Pointer\r
+  @param  MaxPacket   Maximum packet size for Bulk/Interrupt transfer\r
+  @param  IsLow       Is Low Speed Device\r
+\r
+  @return The Tds list head for the bulk transfer\r
+\r
+**/\r
+UHCI_TD_SW *\r
+UhciCreateBulkOrIntTds (\r
+  IN USB_HC_DEV           *Uhc,\r
+  IN UINT8                DevAddr,\r
+  IN UINT8                EndPoint,\r
+  IN UINT8                PktId,\r
+  IN UINT8                *Data,\r
+  IN UINTN                DataLen,\r
+  IN OUT UINT8            *DataToggle,\r
+  IN UINT8                MaxPacket,\r
+  IN BOOLEAN              IsLow\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.c b/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.c
new file mode 100644 (file)
index 0000000..6332629
--- /dev/null
@@ -0,0 +1,303 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UhciReg.c\r
+\r
+Abstract:\r
+\r
+  The UHCI register operation routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#include "Uhci.h"\r
+\r
+\r
+/**\r
+  Read a UHCI register\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use\r
+  @param  Offset       Register offset to USB_BAR_INDEX\r
+\r
+  @return Content of register\r
+\r
+**/\r
+UINT16\r
+UhciReadReg (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN UINT32                  Offset\r
+  )\r
+{\r
+  UINT16      Data;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = PciIo->Io.Read (\r
+                      PciIo,\r
+                      EfiPciIoWidthUint16,\r
+                      USB_BAR_INDEX,\r
+                      Offset,\r
+                      1,\r
+                      &Data\r
+                      );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    UHCI_ERROR (("UhciReadReg: PciIo Io.Read error: %r at offset %d\n", Status, Offset));\r
+\r
+    Data = 0xFFFF;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+\r
+/**\r
+  Write data to UHCI register\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use\r
+  @param  Offset       Register offset to USB_BAR_INDEX\r
+  @param  Data         Data to write\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciWriteReg (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN UINT32                  Offset,\r
+  IN UINT16                  Data\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = PciIo->Io.Write (\r
+                      PciIo,\r
+                      EfiPciIoWidthUint16,\r
+                      USB_BAR_INDEX,\r
+                      Offset,\r
+                      1,\r
+                      &Data\r
+                      );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    UHCI_ERROR (("UhciWriteReg: PciIo Io.Write error: %r at offset %d\n", Status, Offset));\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Set a bit of the UHCI Register\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use\r
+  @param  Offset       Register offset to USB_BAR_INDEX\r
+  @param  Bit          The bit to set\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciSetRegBit (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN UINT32                  Offset,\r
+  IN UINT16                  Bit\r
+  )\r
+{\r
+  UINT16  Data;\r
+\r
+  Data = UhciReadReg (PciIo, Offset);\r
+  Data |= Bit;\r
+  UhciWriteReg (PciIo, Offset, Data);\r
+}\r
+\r
+\r
+/**\r
+  Clear a bit of the UHCI Register\r
+\r
+  @param  PciIo        The PCI_IO protocol to access the PCI\r
+  @param  Offset       Register offset to USB_BAR_INDEX\r
+  @param  Bit          The bit to clear\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciClearRegBit (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN UINT32                  Offset,\r
+  IN UINT16                  Bit\r
+  )\r
+{\r
+  UINT16  Data;\r
+\r
+  Data = UhciReadReg (PciIo, Offset);\r
+  Data &= ~Bit;\r
+  UhciWriteReg (PciIo, Offset, Data);\r
+}\r
+\r
+\r
+/**\r
+  Clear all the interrutp status bits, these bits\r
+  are Write-Clean\r
+\r
+  @param  Uhc          The UHCI device\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciAckAllInterrupt (\r
+  IN  USB_HC_DEV          *Uhc\r
+  )\r
+{\r
+  UhciWriteReg (Uhc->PciIo, USBSTS_OFFSET, 0x3F);\r
+\r
+  //\r
+  // If current HC is halted, re-enable it. Host Controller Process Error\r
+  // is a temporary error status.\r
+  //\r
+  if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+    UHCI_ERROR (("UhciAckAllInterrupt: re-enable the UHCI from system error\n"));\r
+    Uhc->UsbHc.SetState (&Uhc->UsbHc, EfiUsbHcStateOperational);\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Stop the host controller\r
+\r
+  @param  Uhc          The UHCI device\r
+  @param  Timeout      Max time allowed\r
+\r
+  @retval EFI_SUCCESS  The host controller is stopped\r
+  @retval EFI_TIMEOUT  Failed to stop the host controller\r
+\r
+**/\r
+EFI_STATUS\r
+UhciStopHc (\r
+  IN USB_HC_DEV         *Uhc,\r
+  IN UINTN              Timeout\r
+  )\r
+{\r
+  UINT16                UsbSts;\r
+  UINTN                 Index;\r
+\r
+  UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS);\r
+\r
+  //\r
+  // ensure the HC is in halt status after send the stop command\r
+  // Timeout is in us unit.\r
+  //\r
+  for (Index = 0; Index < (Timeout / 50) + 1; Index++) {\r
+    UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);\r
+\r
+    if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    gBS->Stall (50);\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the host controller operates well\r
+\r
+  @param  PciIo        The PCI_IO protocol to use\r
+\r
+  @retval TRUE         Host controller is working\r
+  @retval FALSE        Host controller is halted or system error\r
+\r
+**/\r
+BOOLEAN\r
+UhciIsHcWorking (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo\r
+  )\r
+{\r
+  UINT16                UsbSts;\r
+\r
+  UsbSts = UhciReadReg (PciIo, USBSTS_OFFSET);\r
+\r
+  if (UsbSts & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) {\r
+    UHCI_ERROR (("UhciIsHcWorking: current USB state is %x\n", UsbSts));\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Set the UHCI frame list base address. It can't use\r
+  UhciWriteReg which access memory in UINT16.\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use\r
+  @param  Addr         Address to set\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciSetFrameListBaseAddr (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN VOID                    *Addr\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT32                  Data;\r
+\r
+  Data = (UINT32) ((UINTN) Addr & 0xFFFFF000);\r
+\r
+  Status = PciIo->Io.Write (\r
+                       PciIo,\r
+                       EfiPciIoWidthUint32,\r
+                       USB_BAR_INDEX,\r
+                       (UINT64) USB_FRAME_BASE_OFFSET,\r
+                       1,\r
+                       &Data\r
+                       );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    UHCI_ERROR (("UhciSetFrameListBaseAddr: PciIo Io.Write error: %r\n", Status));\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Disable USB Emulation\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL protocol to use\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciTurnOffUsbEmulation (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo\r
+  )\r
+{\r
+  UINT16            Command;\r
+\r
+  Command = 0;\r
+\r
+  PciIo->Pci.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               USB_EMULATION_OFFSET,\r
+               1,\r
+               &Command\r
+               );\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.h b/MdeModulePkg/Bus/Pci/UhciDxe/UhciReg.h
new file mode 100644 (file)
index 0000000..95a98db
--- /dev/null
@@ -0,0 +1,264 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UhciReg.h\r
+\r
+Abstract:\r
+\r
+  The definition for UHCI register operation routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _EFI_UHCI_REG_H_\r
+#define _EFI_UHCI_REG_H_\r
+\r
+#define BIT(a)  (1 << (a))\r
+\r
+enum {\r
+  UHCI_FRAME_NUM        = 1024,\r
+\r
+  //\r
+  // Register offset and PCI related staff\r
+  //\r
+  CLASSC_OFFSET         = 0x09,\r
+  USBBASE_OFFSET        = 0x20,\r
+  USB_BAR_INDEX         = 4,\r
+  PCI_CLASSC_PI_UHCI    = 0x00,\r
+\r
+  USBCMD_OFFSET         = 0,\r
+  USBSTS_OFFSET         = 2,\r
+  USBINTR_OFFSET        = 4,\r
+  USBPORTSC_OFFSET      = 0x10,\r
+  USB_FRAME_NO_OFFSET   = 6,\r
+  USB_FRAME_BASE_OFFSET = 8,\r
+  USB_EMULATION_OFFSET  = 0xC0,\r
+\r
+  //\r
+  // Packet IDs\r
+  //\r
+  SETUP_PACKET_ID       = 0x2D,\r
+  INPUT_PACKET_ID       = 0x69,\r
+  OUTPUT_PACKET_ID      = 0xE1,\r
+  ERROR_PACKET_ID       = 0x55,\r
+\r
+  //\r
+  // USB port status and control bit definition.\r
+  //\r
+  USBPORTSC_CCS         = BIT(0),  // Current Connect Status\r
+  USBPORTSC_CSC         = BIT(1),  // Connect Status Change\r
+  USBPORTSC_PED         = BIT(2),  // Port Enable / Disable\r
+  USBPORTSC_PEDC        = BIT(3),  // Port Enable / Disable Change\r
+  USBPORTSC_LSL         = BIT(4),  // Line Status Low BIT\r
+  USBPORTSC_LSH         = BIT(5),  // Line Status High BIT\r
+  USBPORTSC_RD          = BIT(6),  // Resume Detect\r
+  USBPORTSC_LSDA        = BIT(8),  // Low Speed Device Attached\r
+  USBPORTSC_PR          = BIT(9),  // Port Reset\r
+  USBPORTSC_SUSP        = BIT(12), // Suspend\r
+\r
+  USB_MAX_ROOTHUB_PORT  = 0x0F,    // Max number of root hub port\r
+\r
+  //\r
+  // Command register bit definitions\r
+  //\r
+  USBCMD_RS             = BIT(0),  // Run/Stop\r
+  USBCMD_HCRESET        = BIT(1),  // Host reset\r
+  USBCMD_GRESET         = BIT(2),  // Global reset\r
+  USBCMD_EGSM           = BIT(3),  // Global Suspend Mode\r
+  USBCMD_FGR            = BIT(4),  // Force Global Resume\r
+  USBCMD_SWDBG          = BIT(5),  // SW Debug mode\r
+  USBCMD_CF             = BIT(6),  // Config Flag (sw only)\r
+  USBCMD_MAXP           = BIT(7),  // Max Packet (0 = 32, 1 = 64)\r
+\r
+  //\r
+  // USB Status register bit definitions\r
+  //\r
+  USBSTS_USBINT         = BIT(0),  // Interrupt due to IOC\r
+  USBSTS_ERROR          = BIT(1),  // Interrupt due to error\r
+  USBSTS_RD             = BIT(2),  // Resume Detect\r
+  USBSTS_HSE            = BIT(3),  // Host System Error\r
+  USBSTS_HCPE           = BIT(4),  // Host Controller Process Error\r
+  USBSTS_HCH            = BIT(5),  // HC Halted\r
+\r
+  USBTD_ACTIVE          = BIT(7),  // TD is still active\r
+  USBTD_STALLED         = BIT(6),  // TD is stalled\r
+  USBTD_BUFFERR         = BIT(5),  // Buffer underflow or overflow\r
+  USBTD_BABBLE          = BIT(4),  // Babble condition\r
+  USBTD_NAK             = BIT(3),  // NAK is received\r
+  USBTD_CRC             = BIT(2),  // CRC/Time out error\r
+  USBTD_BITSTUFF        = BIT(1),  // Bit stuff error\r
+};\r
+\r
+\r
+/**\r
+  Read a UHCI register\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use\r
+  @param  Offset       Register offset to USB_BAR_INDEX\r
+\r
+  @return Content of register\r
+\r
+**/\r
+UINT16\r
+UhciReadReg (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN UINT32                  Offset\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Write data to UHCI register\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use\r
+  @param  Offset       Register offset to USB_BAR_INDEX\r
+  @param  Data         Data to write\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciWriteReg (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN UINT32                  Offset,\r
+  IN UINT16                  Data\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Set a bit of the UHCI Register\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use\r
+  @param  Offset       Register offset to USB_BAR_INDEX\r
+  @param  Bit          The bit to set\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciSetRegBit (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN UINT32                  Offset,\r
+  IN UINT16                  Bit\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Clear a bit of the UHCI Register\r
+\r
+  @param  PciIo        The PCI_IO protocol to access the PCI\r
+  @param  Offset       Register offset to USB_BAR_INDEX\r
+  @param  Bit          The bit to clear\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciClearRegBit (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN UINT32                  Offset,\r
+  IN UINT16                  Bit\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Clear all the interrutp status bits, these bits\r
+  are Write-Clean\r
+\r
+  @param  Uhc          The UHCI device\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciAckAllInterrupt (\r
+  IN  USB_HC_DEV          *Uhc\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Stop the host controller\r
+\r
+  @param  Uhc          The UHCI device\r
+  @param  Timeout      Max time allowed\r
+\r
+  @retval EFI_SUCCESS  The host controller is stopped\r
+  @retval EFI_TIMEOUT  Failed to stop the host controller\r
+\r
+**/\r
+EFI_STATUS\r
+UhciStopHc (\r
+  IN USB_HC_DEV         *Uhc,\r
+  IN UINTN              Timeout\r
+  )\r
+;\r
+\r
+\r
+\r
+/**\r
+  Check whether the host controller operates well\r
+\r
+  @param  PciIo        The PCI_IO protocol to use\r
+\r
+  @retval TRUE         Host controller is working\r
+  @retval FALSE        Host controller is halted or system error\r
+\r
+**/\r
+BOOLEAN\r
+UhciIsHcWorking (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Set the UHCI frame list base address. It can't use\r
+  UhciWriteReg which access memory in UINT16.\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL to use\r
+  @param  Addr         Address to set\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciSetFrameListBaseAddr (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,\r
+  IN VOID                    *Addr\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Disable USB Emulation\r
+\r
+  @param  PciIo        The EFI_PCI_IO_PROTOCOL protocol to use\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciTurnOffUsbEmulation (\r
+  IN EFI_PCI_IO_PROTOCOL     *PciIo\r
+  )\r
+;\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c b/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c
new file mode 100644 (file)
index 0000000..222322a
--- /dev/null
@@ -0,0 +1,1051 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UhciSched.c\r
+\r
+Abstract:\r
+\r
+  The EHCI register operation routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#include "Uhci.h"\r
+\r
+\r
+/**\r
+  Create Frame List Structure\r
+\r
+  @param  Uhc                    UHCI device\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources\r
+  @retval EFI_UNSUPPORTED        Map memory fail\r
+  @retval EFI_SUCCESS            Success\r
+\r
+**/\r
+EFI_STATUS\r
+UhciInitFrameList (\r
+  IN USB_HC_DEV         *Uhc\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  MappedAddr;\r
+  EFI_STATUS            Status;\r
+  VOID                  *Buffer;\r
+  VOID                  *Mapping;\r
+  UINTN                 Pages;\r
+  UINTN                 Bytes;\r
+  UINTN                 Index;\r
+\r
+  //\r
+  // The Frame List is a common buffer that will be\r
+  // accessed by both the cpu and the usb bus master\r
+  // at the same time. The Frame List ocupies 4K bytes,\r
+  // and must be aligned on 4-Kbyte boundaries.\r
+  //\r
+  Bytes = 4096;\r
+  Pages = EFI_SIZE_TO_PAGES (Bytes);\r
+\r
+  Status = Uhc->PciIo->AllocateBuffer (\r
+                         Uhc->PciIo,\r
+                         AllocateAnyPages,\r
+                         EfiBootServicesData,\r
+                         Pages,\r
+                         &Buffer,\r
+                         0\r
+                         );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = Uhc->PciIo->Map (\r
+                         Uhc->PciIo,\r
+                         EfiPciIoOperationBusMasterCommonBuffer,\r
+                         Buffer,\r
+                         &Bytes,\r
+                         &MappedAddr,\r
+                         &Mapping\r
+                         );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != 4096)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Uhc->FrameBase    = (UINT32 *) (UINTN) MappedAddr;\r
+  Uhc->FrameMapping = Mapping;\r
+\r
+  //\r
+  // Allocate the QH used by sync interrupt/control/bulk transfer.\r
+  // FS ctrl/bulk queue head is set to loopback so additional BW\r
+  // can be reclaimed. Notice, LS don't support bulk transfer and\r
+  // also doesn't support BW reclamation.\r
+  //\r
+  Uhc->SyncIntQh  = UhciCreateQh (Uhc, 1);\r
+  Uhc->CtrlQh     = UhciCreateQh (Uhc, 1);\r
+  Uhc->BulkQh     = UhciCreateQh (Uhc, 1);\r
+\r
+  if ((Uhc->SyncIntQh == NULL) || (Uhc->CtrlQh == NULL) || (Uhc->BulkQh == NULL)) {\r
+    Uhc->PciIo->Unmap (Uhc->PciIo, Mapping);\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  //                                                +-------------+\r
+  //                                                |             |\r
+  // Link the three together: SyncIntQh->CtrlQh->BulkQh <---------+\r
+  // Each frame entry is linked to this sequence of QH. These QH\r
+  // will remain on the schedul, never got removed\r
+  //\r
+  Uhc->SyncIntQh->QhHw.HorizonLink  = QH_HLINK (Uhc->CtrlQh, FALSE);\r
+  Uhc->SyncIntQh->NextQh            = Uhc->CtrlQh;\r
+\r
+  Uhc->CtrlQh->QhHw.HorizonLink     = QH_HLINK (Uhc->BulkQh, FALSE);\r
+  Uhc->CtrlQh->NextQh               = Uhc->BulkQh;\r
+\r
+  //\r
+  // Some old platform such as Intel's Tiger 4 has a difficult time\r
+  // in supporting the full speed bandwidth reclamation in the previous\r
+  // mentioned form. Most new platforms don't suffer it.\r
+  //\r
+#ifdef UHCI_NO_BW_RECLAMATION\r
+  Uhc->BulkQh->QhHw.HorizonLink     = QH_HLINK (NULL, TRUE);\r
+#else\r
+  Uhc->BulkQh->QhHw.HorizonLink     = QH_HLINK (Uhc->BulkQh, FALSE);\r
+#endif\r
+\r
+  Uhc->BulkQh->NextQh               = NULL;\r
+\r
+  for (Index = 0; Index < UHCI_FRAME_NUM; Index++) {\r
+    Uhc->FrameBase[Index] = QH_HLINK (Uhc->SyncIntQh, FALSE);\r
+  }\r
+\r
+  //\r
+  // Tell the Host Controller where the Frame List lies,\r
+  // by set the Frame List Base Address Register.\r
+  //\r
+  UhciSetFrameListBaseAddr (Uhc->PciIo, (VOID *) (Uhc->FrameBase));\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  if (Uhc->SyncIntQh != NULL) {\r
+    UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW));\r
+  }\r
+\r
+  if (Uhc->CtrlQh != NULL) {\r
+    UsbHcFreeMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_SW));\r
+  }\r
+\r
+  if (Uhc->BulkQh != NULL) {\r
+    UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW));\r
+  }\r
+\r
+  Uhc->PciIo->FreeBuffer (Uhc->PciIo, Pages, Buffer);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Destory FrameList buffer\r
+\r
+  @param  Uhc                    The UHCI device\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciDestoryFrameList (\r
+  IN USB_HC_DEV           *Uhc\r
+  )\r
+{\r
+  //\r
+  // Unmap the common buffer for framelist entry,\r
+  // and free the common buffer.\r
+  // Uhci's frame list occupy 4k memory.\r
+  //\r
+  Uhc->PciIo->Unmap (Uhc->PciIo, Uhc->FrameMapping);\r
+\r
+  Uhc->PciIo->FreeBuffer (\r
+                Uhc->PciIo,\r
+                EFI_SIZE_TO_PAGES (4096),\r
+                (VOID *) Uhc->FrameBase\r
+                );\r
+\r
+  if (Uhc->SyncIntQh != NULL) {\r
+    UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW));\r
+  }\r
+\r
+  if (Uhc->CtrlQh != NULL) {\r
+    UsbHcFreeMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_SW));\r
+  }\r
+\r
+  if (Uhc->BulkQh != NULL) {\r
+    UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW));\r
+  }\r
+\r
+  Uhc->FrameBase    = NULL;\r
+  Uhc->SyncIntQh    = NULL;\r
+  Uhc->CtrlQh       = NULL;\r
+  Uhc->BulkQh       = NULL;\r
+}\r
+\r
+\r
+/**\r
+  Convert the poll rate to the maxium 2^n that is smaller\r
+  than Interval\r
+\r
+  @param  Interval               The poll rate to convert\r
+\r
+  @return The converted poll rate\r
+\r
+**/\r
+UINTN\r
+UhciConvertPollRate (\r
+  IN  UINTN               Interval\r
+  )\r
+{\r
+  UINTN                   BitCount;\r
+\r
+  ASSERT (Interval != 0);\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
+/**\r
+  Link a queue head (for asynchronous interrupt transfer) to\r
+  the frame list.\r
+\r
+  @param  FrameBase              The base of the frame list\r
+  @param  Qh                     The queue head to link into\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciLinkQhToFrameList (\r
+  UINT32                  *FrameBase,\r
+  UHCI_QH_SW              *Qh\r
+  )\r
+{\r
+  UINTN                   Index;\r
+  UHCI_QH_SW              *Prev;\r
+  UHCI_QH_SW              *Next;\r
+\r
+  ASSERT ((FrameBase != NULL) && (Qh != NULL));\r
+\r
+  for (Index = 0; Index < UHCI_FRAME_NUM; Index += Qh->Interval) {\r
+    //\r
+    // First QH can't be NULL because we always keep static queue\r
+    // heads on the frame list\r
+    //\r
+    ASSERT (!LINK_TERMINATED (FrameBase[Index]));\r
+    Next  = UHCI_ADDR (FrameBase[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
+    // This method is very much the same as that used by EHCI.\r
+    // Because each QH's interval is round down to 2^n, poll\r
+    // rate is correct.\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 FrameBase[0] and at FrameBase[0] it is\r
+    // impossible (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
+      // FrameBase[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_HLINK (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_HLINK (Next, FALSE);\r
+    }\r
+\r
+    if (Prev == NULL) {\r
+      FrameBase[Index]        = QH_HLINK (Qh, FALSE);\r
+    } else {\r
+      Prev->NextQh            = Qh;\r
+      Prev->QhHw.HorizonLink  = QH_HLINK (Qh, FALSE);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Unlink QH from the frame list is easier: find all\r
+  the precedence node, and pointer there next to QhSw's\r
+  next.\r
+\r
+  @param  FrameBase              The base address of the frame list\r
+  @param  Qh                     The queue head to unlink\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciUnlinkQhFromFrameList (\r
+  UINT32                *FrameBase,\r
+  UHCI_QH_SW            *Qh\r
+  )\r
+{\r
+  UINTN                   Index;\r
+  UHCI_QH_SW              *Prev;\r
+  UHCI_QH_SW              *This;\r
+\r
+  ASSERT ((FrameBase != NULL) && (Qh != NULL));\r
+\r
+  for (Index = 0; Index < UHCI_FRAME_NUM; Index += Qh->Interval) {\r
+    //\r
+    // Frame link can't be NULL because we always keep static\r
+    // queue heads on the frame list\r
+    //\r
+    ASSERT (!LINK_TERMINATED (FrameBase[Index]));\r
+    This  = UHCI_ADDR (FrameBase[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.\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
+      FrameBase[Index]        = Qh->QhHw.HorizonLink;\r
+    } else {\r
+      Prev->NextQh            = Qh->NextQh;\r
+      Prev->QhHw.HorizonLink  = Qh->QhHw.HorizonLink;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Check TDs Results\r
+\r
+  @param  Uhc                    This UHCI device\r
+  @param  Td                     UHCI_TD_SW to check\r
+  @param  IsLow                  Is Low Speed Device\r
+  @param  QhResult               Return the result of this TD list\r
+\r
+  @return Whether the TD's result is finialized.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+UhciCheckTdStatus (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  UHCI_TD_SW          *Td,\r
+  IN  BOOLEAN             IsLow,\r
+  OUT UHCI_QH_RESULT      *QhResult\r
+  )\r
+{\r
+  UINTN                   Len;\r
+  UINT8                   State;\r
+  UHCI_TD_HW              *TdHw;\r
+  BOOLEAN                 Finished;\r
+\r
+  Finished             = TRUE;\r
+\r
+  //\r
+  // Initialize the data toggle to that of the first\r
+  // TD. The next toggle to use is either:\r
+  // 1. first TD's toggle if no TD is executed OK\r
+  // 2. the next toggle of last executed-OK TD\r
+  //\r
+  QhResult->Result     = EFI_USB_NOERROR;\r
+  QhResult->NextToggle = (UINT8)Td->TdHw.DataToggle;\r
+  QhResult->Complete   = 0;\r
+\r
+  while (Td != NULL) {\r
+    TdHw  = &Td->TdHw;\r
+    State = (UINT8)TdHw->Status;\r
+\r
+    //\r
+    // UHCI will set STALLED bit when it abort the execution\r
+    // of TD list. There are several reasons:\r
+    //   1. BABBLE error happened\r
+    //   2. Received a STALL response\r
+    //   3. Error count decreased to zero.\r
+    //\r
+    // It also set CRC/Timeout/NAK/Buffer Error/BitStuff Error\r
+    // bits when corresponding conditions happen. But these\r
+    // conditions are not deadly, that is a TD can successfully\r
+    // completes even these bits are set. But it is likely that\r
+    // upper layer won't distinguish these condtions. So, only\r
+    // set these bits when TD is actually halted.\r
+    //\r
+    if (State & USBTD_STALLED) {\r
+      if (State & USBTD_BABBLE) {\r
+        QhResult->Result |= EFI_USB_ERR_BABBLE;\r
+\r
+      } else if (TdHw->ErrorCount != 0) {\r
+        QhResult->Result |= EFI_USB_ERR_STALL;\r
+      }\r
+\r
+      if (State & USBTD_CRC) {\r
+        QhResult->Result |= EFI_USB_ERR_CRC;\r
+      }\r
+\r
+      if (State & USBTD_BUFFERR) {\r
+        QhResult->Result |= EFI_USB_ERR_BUFFER;\r
+      }\r
+\r
+      if (Td->TdHw.Status & USBTD_BITSTUFF) {\r
+        QhResult->Result |= EFI_USB_ERR_BITSTUFF;\r
+      }\r
+\r
+      if (TdHw->ErrorCount == 0) {\r
+        QhResult->Result |= EFI_USB_ERR_TIMEOUT;\r
+      }\r
+\r
+      Finished = TRUE;\r
+      goto ON_EXIT;\r
+\r
+    } else if (State & USBTD_ACTIVE) {\r
+      //\r
+      // The TD is still active, no need to check further.\r
+      //\r
+      QhResult->Result |= EFI_USB_ERR_NOTEXECUTE;\r
+\r
+      Finished = FALSE;\r
+      goto ON_EXIT;\r
+\r
+    } else {\r
+      //\r
+      // Update the next data toggle, it is always the\r
+      // next to the last known-good TD's data toggle if\r
+      // any TD is executed OK\r
+      //\r
+      QhResult->NextToggle = 1 - (UINT8)TdHw->DataToggle;\r
+\r
+      //\r
+      // This TD is finished OK or met short packet read. Update the\r
+      // transfer length if it isn't a SETUP.\r
+      //\r
+      Len = (TdHw->ActualLen + 1) & 0x7FF;\r
+\r
+      if (TdHw->PidCode != SETUP_PACKET_ID) {\r
+        QhResult->Complete += Len;\r
+      }\r
+\r
+      //\r
+      // Short packet condition for full speed input TD, also\r
+      // terminate the transfer\r
+      //\r
+      if (!IsLow && (TdHw->ShortPacket == 1) && (Len < Td->DataLen)) {\r
+        UHCI_DEBUG (("UhciCheckTdStatus: short packet read occured\n"));\r
+\r
+        Finished = TRUE;\r
+        goto ON_EXIT;\r
+      }\r
+    }\r
+\r
+    Td = Td->NextTd;\r
+  }\r
+\r
+ON_EXIT:\r
+  //\r
+  // Check whether HC is halted. Don't move this up. It must be\r
+  // called after data toggle is successfully updated.\r
+  //\r
+  if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+    QhResult->Result |= EFI_USB_ERR_SYSTEM;\r
+    Finished  = TRUE;\r
+  }\r
+\r
+  if (Finished) {\r
+    Uhc->PciIo->Flush (Uhc->PciIo);\r
+  }\r
+\r
+  UhciAckAllInterrupt (Uhc);\r
+  return Finished;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Check the result of the transfer\r
+\r
+  @param  Uhc                    The UHCI device\r
+  @param  Td                     The first TDs of the transfer\r
+  @param  TimeOut                TimeOut value in milliseconds\r
+  @param  IsLow                  Is Low Speed Device\r
+  @param  QhResult               The variable to return result\r
+\r
+  @retval EFI_SUCCESS            The transfer finished with success\r
+  @retval EFI_DEVICE_ERROR       Transfer failed\r
+\r
+**/\r
+EFI_STATUS\r
+UhciExecuteTransfer (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  UHCI_QH_SW          *Qh,\r
+  IN  UHCI_TD_SW          *Td,\r
+  IN  UINTN               TimeOut,\r
+  IN  BOOLEAN             IsLow,\r
+  OUT UHCI_QH_RESULT      *QhResult\r
+  )\r
+{\r
+  UINTN                   Index;\r
+  UINTN                   Delay;\r
+  BOOLEAN                 Finished;\r
+  EFI_STATUS              Status;\r
+\r
+  Finished = FALSE;\r
+  Status   = EFI_SUCCESS;\r
+  Delay    = (TimeOut * STALL_1_MS / UHC_SYN_POLL) + 1;\r
+\r
+  for (Index = 0; Index < Delay; Index++) {\r
+    Finished = UhciCheckTdStatus (Uhc, Td, IsLow, QhResult);\r
+\r
+    //\r
+    // Transfer is OK or some error occured (TD inactive)\r
+    //\r
+    if (Finished) {\r
+      break;\r
+    }\r
+\r
+    gBS->Stall (UHC_SYN_POLL);\r
+  }\r
+\r
+  if (!Finished) {\r
+    UHCI_ERROR (("UhciExecuteTransfer: execution not finished for %dms\n", TimeOut));\r
+    UHCI_DUMP_QH  ((Qh));\r
+    UHCI_DUMP_TDS ((Td));\r
+\r
+    Status = EFI_TIMEOUT;\r
+\r
+  } else if (QhResult->Result != EFI_USB_NOERROR) {\r
+    UHCI_ERROR (("UhciExecuteTransfer: execution failed with result %x\n", QhResult->Result));\r
+    UHCI_DUMP_QH  ((Qh));\r
+    UHCI_DUMP_TDS ((Td));\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Update Async Request, QH and TDs\r
+\r
+  @param  AsyncReq               The UHCI asynchronous transfer to update\r
+  @param  Result                 Transfer reslut\r
+  @param  ErrTdPos               Error TD Position\r
+\r
+  @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciUpdateAsyncReq (\r
+  IN UHCI_ASYNC_REQUEST  *AsyncReq,\r
+  IN UINT32              Result,\r
+  IN UINT32              NextToggle\r
+  )\r
+{\r
+  UHCI_QH_SW              *Qh;\r
+  UHCI_TD_SW              *FirstTd;\r
+  UHCI_TD_SW              *Td;\r
+\r
+  Qh          = AsyncReq->QhSw;\r
+  FirstTd     = AsyncReq->FirstTd;\r
+\r
+  if (Result == EFI_USB_NOERROR) {\r
+    //\r
+    // The last transfer succeeds. Then we need to update\r
+    // the Qh and Td for next round of transfer.\r
+    // 1. Update the TD's data toggle\r
+    // 2. Activate all the TDs\r
+    // 3. Link the TD to the queue head again since during\r
+    //    execution, queue head's TD pointer is changed by\r
+    //    hardware.\r
+    //\r
+    for (Td = FirstTd; Td != NULL; Td = Td->NextTd) {\r
+      Td->TdHw.DataToggle = NextToggle;\r
+      NextToggle         ^= 1;\r
+      Td->TdHw.Status    |= USBTD_ACTIVE;\r
+    }\r
+\r
+    UhciLinkTdToQh (Qh, FirstTd);\r
+    return ;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Create Async Request node, and Link to List\r
+\r
+  @param  Uhc                    The UHCI device\r
+  @param  Qh                     The queue head of the transfer\r
+  @param  FirstTd                First TD of the transfer\r
+  @param  DevAddr                Device Address\r
+  @param  EndPoint               EndPoint Address\r
+  @param  DataLen                Data length\r
+  @param  Interval               Polling Interval when inserted to frame list\r
+  @param  Mapping                Mapping value\r
+  @param  Data                   Data buffer, unmapped\r
+  @param  Callback               Callback after interrupt transfeer\r
+  @param  Context                Callback Context passed as function parameter\r
+  @param  IsLow                  Is Low Speed\r
+\r
+  @retval EFI_SUCCESS            An asynchronous transfer is created\r
+  @retval EFI_INVALID_PARAMETER  Paremeter is error\r
+  @retval EFI_OUT_OF_RESOURCES   Failed because of resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciCreateAsyncReq (\r
+  IN USB_HC_DEV                       *Uhc,\r
+  IN UHCI_QH_SW                       *Qh,\r
+  IN UHCI_TD_SW                       *FirstTd,\r
+  IN UINT8                            DevAddr,\r
+  IN UINT8                            EndPoint,\r
+  IN UINTN                            DataLen,\r
+  IN UINTN                            Interval,\r
+  IN VOID                             *Mapping,\r
+  IN UINT8                            *Data,\r
+  IN EFI_ASYNC_USB_TRANSFER_CALLBACK  Callback,\r
+  IN VOID                             *Context,\r
+  IN BOOLEAN                          IsLow\r
+  )\r
+{\r
+  UHCI_ASYNC_REQUEST      *AsyncReq;\r
+\r
+  AsyncReq = AllocatePool (sizeof (UHCI_ASYNC_REQUEST));\r
+\r
+  if (AsyncReq == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Fill Request field. Data is allocated host memory, not mapped\r
+  //\r
+  AsyncReq->Signature   = UHCI_ASYNC_INT_SIGNATURE;\r
+  AsyncReq->DevAddr     = DevAddr;\r
+  AsyncReq->EndPoint    = EndPoint;\r
+  AsyncReq->DataLen     = DataLen;\r
+  AsyncReq->Interval    = Interval;\r
+  AsyncReq->Mapping     = Mapping;\r
+  AsyncReq->Data        = Data;\r
+  AsyncReq->Callback    = Callback;\r
+  AsyncReq->Context     = Context;\r
+  AsyncReq->QhSw        = Qh;\r
+  AsyncReq->FirstTd     = FirstTd;\r
+  AsyncReq->IsLow       = IsLow;\r
+\r
+  //\r
+  // Insert the new interrupt transfer to the head of the list.\r
+  // The interrupt transfer's monitor function scans the whole\r
+  // list from head to tail. The new interrupt transfer MUST be\r
+  // added to the head of the list.\r
+  //\r
+  InsertHeadList (&(Uhc->AsyncIntList), &(AsyncReq->Link));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Free an asynchronous request's resource such as memory\r
+\r
+  @param  Uhc                    The UHCI device\r
+  @param  AsyncReq               The asynchronous request to free\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciFreeAsyncReq (\r
+  IN USB_HC_DEV           *Uhc,\r
+  IN UHCI_ASYNC_REQUEST   *AsyncReq\r
+  )\r
+{\r
+  ASSERT ((Uhc != NULL) && (AsyncReq != NULL));\r
+\r
+  UhciDestoryTds (Uhc, AsyncReq->FirstTd);\r
+  UsbHcFreeMem (Uhc->MemPool, AsyncReq->QhSw, sizeof (UHCI_QH_SW));\r
+\r
+  if (AsyncReq->Mapping != NULL) {\r
+    Uhc->PciIo->Unmap (Uhc->PciIo, AsyncReq->Mapping);\r
+  }\r
+\r
+  if (AsyncReq->Data != NULL) {\r
+    gBS->FreePool (AsyncReq->Data);\r
+  }\r
+\r
+  gBS->FreePool (AsyncReq);\r
+}\r
+\r
+\r
+/**\r
+  Unlink an asynchronous request's from UHC's asynchronus list.\r
+  also remove the queue head from the frame list. If FreeNow,\r
+  release its resource also. Otherwise, add the request to the\r
+  UHC's recycle list to wait for a while before release the memory.\r
+  Until then, hardware won't hold point to the request.\r
+\r
+  @param  Uhc                    The UHCI device\r
+  @param  AsyncReq               The asynchronous request to free\r
+  @param  FreeNow                If TRUE, free the resource immediately, otherwise\r
+                                 add the request to recycle wait list.\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciUnlinkAsyncReq (\r
+  IN USB_HC_DEV           *Uhc,\r
+  IN UHCI_ASYNC_REQUEST   *AsyncReq,\r
+  IN BOOLEAN              FreeNow\r
+  )\r
+{\r
+  ASSERT ((Uhc != NULL) && (AsyncReq != NULL));\r
+\r
+  RemoveEntryList (&(AsyncReq->Link));\r
+  UhciUnlinkQhFromFrameList (Uhc->FrameBase, AsyncReq->QhSw);\r
+\r
+  if (FreeNow) {\r
+    UhciFreeAsyncReq (Uhc, AsyncReq);\r
+  } else {\r
+    //\r
+    // To sychronize with hardware, mark the queue head as inactive\r
+    // then add AsyncReq to UHC's recycle list\r
+    //\r
+    AsyncReq->QhSw->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);\r
+    AsyncReq->Recycle = Uhc->RecycleWait;\r
+    Uhc->RecycleWait  = AsyncReq;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Delete Async Interrupt QH and TDs\r
+\r
+  @param  Uhc                    The UHCI device\r
+  @param  DevAddr                Device Address\r
+  @param  EndPoint               EndPoint Address\r
+  @param  Toggle                 The next data toggle to use\r
+\r
+  @retval EFI_SUCCESS            The request is deleted\r
+  @retval EFI_INVALID_PARAMETER  Paremeter is error\r
+  @retval EFI_NOT_FOUND          The asynchronous isn't found\r
+\r
+**/\r
+EFI_STATUS\r
+UhciRemoveAsyncReq (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               EndPoint,\r
+  OUT UINT8               *Toggle\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UHCI_ASYNC_REQUEST  *AsyncReq;\r
+  UHCI_QH_RESULT      QhResult;\r
+  LIST_ENTRY          *Link;\r
+  BOOLEAN             Found;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // If no asynchronous interrupt transaction exists\r
+  //\r
+  if (IsListEmpty (&(Uhc->AsyncIntList))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Find the asynchronous transfer to this device/endpoint pair\r
+  //\r
+  Found = FALSE;\r
+  Link  = Uhc->AsyncIntList.ForwardLink;\r
+\r
+  do {\r
+    AsyncReq  = UHCI_ASYNC_INT_FROM_LINK (Link);\r
+    Link      = Link->ForwardLink;\r
+\r
+    if ((AsyncReq->DevAddr == DevAddr) && (AsyncReq->EndPoint == EndPoint)) {\r
+      Found = TRUE;\r
+      break;\r
+    }\r
+\r
+  } while (Link != &(Uhc->AsyncIntList));\r
+\r
+  if (!Found) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Check the result of the async transfer then update it\r
+  // to get the next data toggle to use.\r
+  //\r
+  UhciCheckTdStatus (Uhc, AsyncReq->FirstTd, AsyncReq->IsLow, &QhResult);\r
+  *Toggle = QhResult.NextToggle;\r
+\r
+  //\r
+  // Don't release the request now, keep it to synchronize with hardware.\r
+  //\r
+  UhciUnlinkAsyncReq (Uhc, AsyncReq, FALSE);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Recycle the asynchronouse request. When a queue head\r
+  is unlinked from frame list, host controller hardware\r
+  may still hold a cached pointer to it. To synchronize\r
+  with hardware, the request is released in two steps:\r
+  first it is linked to the UHC's RecycleWait list. At\r
+  the next time UhciMonitorAsyncReqList is fired, it is\r
+  moved to UHC's Recylelist. Then, at another timer\r
+  activation, all the requests on Recycle list is freed.\r
+  This guarrantes that each unlink queue head keeps\r
+  existing for at least 50ms, far enough for the hardware\r
+  to clear its cache.\r
+\r
+  @param  Uhc                    The UHCI device\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciRecycleAsyncReq (\r
+  IN USB_HC_DEV           *Uhc\r
+  )\r
+{\r
+  UHCI_ASYNC_REQUEST      *Req;\r
+  UHCI_ASYNC_REQUEST      *Next;\r
+\r
+  Req = Uhc->Recycle;\r
+\r
+  while (Req != NULL) {\r
+    Next = Req->Recycle;\r
+    UhciFreeAsyncReq (Uhc, Req);\r
+    Req  = Next;\r
+  }\r
+\r
+  Uhc->Recycle     = Uhc->RecycleWait;\r
+  Uhc->RecycleWait = NULL;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Release all the asynchronous transfers on the lsit.\r
+\r
+  @param  Uhc                    The UHCI device\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciFreeAllAsyncReq (\r
+  IN USB_HC_DEV           *Uhc\r
+  )\r
+{\r
+  LIST_ENTRY              *Head;\r
+  UHCI_ASYNC_REQUEST      *AsyncReq;\r
+\r
+  //\r
+  // Call UhciRecycleAsyncReq twice. The requests on Recycle\r
+  // will be released at the first call; The requests on\r
+  // RecycleWait will be released at the second call.\r
+  //\r
+  UhciRecycleAsyncReq (Uhc);\r
+  UhciRecycleAsyncReq (Uhc);\r
+\r
+  Head = &(Uhc->AsyncIntList);\r
+\r
+  if (IsListEmpty (Head)) {\r
+    return;\r
+  }\r
+\r
+  while (!IsListEmpty (Head)) {\r
+    AsyncReq  = UHCI_ASYNC_INT_FROM_LINK (Head->ForwardLink);\r
+    UhciUnlinkAsyncReq (Uhc, AsyncReq, TRUE);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Interrupt transfer periodic check handler\r
+\r
+  @param  Event                  The event of the time\r
+  @param  Context                Context of the event, pointer to USB_HC_DEV\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciMonitorAsyncReqList (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+{\r
+  UHCI_ASYNC_REQUEST      *AsyncReq;\r
+  LIST_ENTRY              *Link;\r
+  USB_HC_DEV              *Uhc;\r
+  VOID                    *Data;\r
+  BOOLEAN                 Finished;\r
+  UHCI_QH_RESULT          QhResult;\r
+\r
+  Uhc = (USB_HC_DEV *) Context;\r
+\r
+  //\r
+  // Recycle the asynchronous requests expired, and promote\r
+  // requests waiting to be recycled the next time when this\r
+  // timer expires\r
+  //\r
+  UhciRecycleAsyncReq (Uhc);\r
+\r
+  if (IsListEmpty (&(Uhc->AsyncIntList))) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // This loop must be delete safe\r
+  //\r
+  Link = Uhc->AsyncIntList.ForwardLink;\r
+\r
+  do {\r
+    AsyncReq  = UHCI_ASYNC_INT_FROM_LINK (Link);\r
+    Link      = Link->ForwardLink;\r
+\r
+    Finished = UhciCheckTdStatus (Uhc, AsyncReq->FirstTd, AsyncReq->IsLow, &QhResult);\r
+\r
+    if (!Finished) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Copy the data to temporary buffer if there are some\r
+    // data transferred. We may have zero-length packet\r
+    //\r
+    Data = NULL;\r
+\r
+    if (QhResult.Complete != 0) {\r
+      Data = AllocatePool (QhResult.Complete);\r
+\r
+      if (Data == NULL) {\r
+        return ;\r
+      }\r
+\r
+      CopyMem (Data, AsyncReq->FirstTd->Data, QhResult.Complete);\r
+    }\r
+\r
+    UhciUpdateAsyncReq (AsyncReq, QhResult.Result, QhResult.NextToggle);\r
+\r
+    //\r
+    // Now, either transfer is SUCCESS or met errors since\r
+    // we have skipped to next transfer earlier if current\r
+    // transfer is still active.\r
+    //\r
+    if (QhResult.Result == EFI_USB_NOERROR) {\r
+      AsyncReq->Callback (Data, QhResult.Complete, AsyncReq->Context, QhResult.Result);\r
+    } else {\r
+      //\r
+      // Leave error recovery to its related device driver.\r
+      // A common case of the error recovery is to re-submit\r
+      // the interrupt transfer. When an interrupt transfer\r
+      // is re-submitted, its position in the linked list is\r
+      // changed. It is inserted to the head of the linked\r
+      // list, while this function scans the whole list from\r
+      // head to tail. Thus, the re-submitted interrupt transfer's\r
+      // callback function will not be called again in this round.\r
+      //\r
+      AsyncReq->Callback (NULL, 0, AsyncReq->Context, QhResult.Result);\r
+    }\r
+\r
+    if (Data != NULL) {\r
+      gBS->FreePool (Data);\r
+    }\r
+  } while (Link != &(Uhc->AsyncIntList));\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.h b/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.h
new file mode 100644 (file)
index 0000000..cba65c6
--- /dev/null
@@ -0,0 +1,305 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UhciSched.h\r
+\r
+Abstract:\r
+\r
+  The definition for EHCI register operation routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _EFI_UHCI_SCHED_H_\r
+#define _EFI_UHCI_SCHED_H_\r
+\r
+\r
+enum {\r
+  UHCI_ASYNC_INT_SIGNATURE = EFI_SIGNATURE_32 ('u', 'h', 'c', 'a'),\r
+\r
+  //\r
+  // The failure mask for USB transfer return status. If any of\r
+  // these bit is set, the transfer failed. EFI_USB_ERR_NOEXECUTE\r
+  // and EFI_USB_ERR_NAK are not considered as error condition:\r
+  // the transfer is still going on.\r
+  //\r
+  USB_ERR_FAIL_MASK = EFI_USB_ERR_STALL   | EFI_USB_ERR_BUFFER |\r
+                      EFI_USB_ERR_BABBLE  | EFI_USB_ERR_CRC    |\r
+                      EFI_USB_ERR_TIMEOUT | EFI_USB_ERR_BITSTUFF |\r
+                      EFI_USB_ERR_SYSTEM,\r
+\r
+};\r
+\r
+//\r
+// Structure to return the result of UHCI QH execution.\r
+// Result is the final result of the QH's QTD. NextToggle\r
+// is the next data toggle to use. Complete is the actual\r
+// length of data transferred.\r
+//\r
+typedef struct {\r
+  UINT32                  Result;\r
+  UINT8                   NextToggle;\r
+  UINTN                   Complete;\r
+} UHCI_QH_RESULT;\r
+\r
+typedef struct _UHCI_ASYNC_REQUEST  UHCI_ASYNC_REQUEST;\r
+\r
+//\r
+// Structure used to manager the asynchronous interrupt transfers.\r
+//\r
+typedef struct _UHCI_ASYNC_REQUEST{\r
+  UINTN                           Signature;\r
+  LIST_ENTRY                      Link;\r
+  UHCI_ASYNC_REQUEST              *Recycle;\r
+\r
+  //\r
+  // Endpoint attributes\r
+  //\r
+  UINT8                           DevAddr;\r
+  UINT8                           EndPoint;\r
+  BOOLEAN                         IsLow;\r
+  UINTN                           Interval;\r
+\r
+  //\r
+  // Data and UHC structures\r
+  //\r
+  UHCI_QH_SW                      *QhSw;\r
+  UHCI_TD_SW                      *FirstTd;\r
+  UINT8                           *Data;      // Allocated host memory, not mapped memory\r
+  UINTN                           DataLen;\r
+  VOID                            *Mapping;\r
+\r
+  //\r
+  // User callback and its context\r
+  //\r
+  EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;\r
+  VOID                            *Context;\r
+} UHCI_ASYNC_REQUEST;\r
+\r
+#define UHCI_ASYNC_INT_FROM_LINK(a) \\r
+          CR (a, UHCI_ASYNC_REQUEST, Link, UHCI_ASYNC_INT_SIGNATURE)\r
+\r
+EFI_STATUS\r
+UhciInitFrameList (\r
+  IN USB_HC_DEV         *Uhc\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Frame List Structure\r
+\r
+Arguments:\r
+\r
+  Uhc         - UHCI device\r
+\r
+Returns:\r
+\r
+  EFI_OUT_OF_RESOURCES - Can't allocate memory resources\r
+  EFI_UNSUPPORTED      - Map memory fail\r
+  EFI_SUCCESS          - Success\r
+\r
+--*/\r
+;\r
+\r
+\r
+/**\r
+  Destory FrameList buffer\r
+\r
+  @param  Uhc                    The UHCI device\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciDestoryFrameList (\r
+  IN USB_HC_DEV           *Uhc\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Convert the poll rate to the maxium 2^n that is smaller\r
+  than Interval\r
+\r
+  @param  Interval               The poll rate to convert\r
+\r
+  @return The converted poll rate\r
+\r
+**/\r
+UINTN\r
+UhciConvertPollRate (\r
+  IN  UINTN               Interval\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Link a queue head (for asynchronous interrupt transfer) to\r
+  the frame list.\r
+\r
+  @param  FrameBase              The base of the frame list\r
+  @param  Qh                     The queue head to link into\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciLinkQhToFrameList (\r
+  UINT32                  *FrameBase,\r
+  UHCI_QH_SW              *Qh\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Unlink QH from the frame list is easier: find all\r
+  the precedence node, and pointer there next to QhSw's\r
+  next.\r
+\r
+  @param  FrameBase              The base address of the frame list\r
+  @param  Qh                     The queue head to unlink\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UhciUnlinkQhFromFrameList (\r
+  UINT32                *FrameBase,\r
+  UHCI_QH_SW            *Qh\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Check the result of the transfer\r
+\r
+  @param  Uhc                    The UHCI device\r
+  @param  Td                     The first TDs of the transfer\r
+  @param  TimeOut                TimeOut value in milliseconds\r
+  @param  IsLow                  Is Low Speed Device\r
+  @param  QhResult               The variable to return result\r
+\r
+  @retval EFI_SUCCESS            The transfer finished with success\r
+  @retval EFI_DEVICE_ERROR       Transfer failed\r
+\r
+**/\r
+EFI_STATUS\r
+UhciExecuteTransfer (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  UHCI_QH_SW          *Qh,\r
+  IN  UHCI_TD_SW          *Td,\r
+  IN  UINTN               TimeOut,\r
+  IN  BOOLEAN             IsLow,\r
+  OUT UHCI_QH_RESULT      *QhResult\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Create Async Request node, and Link to List\r
+\r
+  @param  Uhc                    The UHCI device\r
+  @param  Qh                     The queue head of the transfer\r
+  @param  FirstTd                First TD of the transfer\r
+  @param  DevAddr                Device Address\r
+  @param  EndPoint               EndPoint Address\r
+  @param  Toggle                 Data Toggle\r
+  @param  DataLen                Data length\r
+  @param  Interval               Polling Interval when inserted to frame list\r
+  @param  Mapping                Mapping value\r
+  @param  Data                   Data buffer, unmapped\r
+  @param  Callback               Callback after interrupt transfeer\r
+  @param  Context                Callback Context passed as function parameter\r
+  @param  IsLow                  Is Low Speed\r
+\r
+  @retval EFI_SUCCESS            An asynchronous transfer is created\r
+  @retval EFI_INVALID_PARAMETER  Paremeter is error\r
+  @retval EFI_OUT_OF_RESOURCES   Failed because of resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciCreateAsyncReq (\r
+  IN USB_HC_DEV                       *Uhc,\r
+  IN UHCI_QH_SW                       *Qh,\r
+  IN UHCI_TD_SW                       *FirstTd,\r
+  IN UINT8                            DevAddr,\r
+  IN UINT8                            EndPoint,\r
+  IN UINTN                            DataLen,\r
+  IN UINTN                            Interval,\r
+  IN VOID                             *Mapping,\r
+  IN UINT8                            *Data,\r
+  IN EFI_ASYNC_USB_TRANSFER_CALLBACK  Callback,\r
+  IN VOID                             *Context,\r
+  IN BOOLEAN                          IsLow\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Delete Async Interrupt QH and TDs\r
+\r
+  @param  Uhc                    The UHCI device\r
+  @param  DevAddr                Device Address\r
+  @param  EndPoint               EndPoint Address\r
+  @param  Toggle                 The next data toggle to use\r
+\r
+  @retval EFI_SUCCESS            The request is deleted\r
+  @retval EFI_INVALID_PARAMETER  Paremeter is error\r
+  @retval EFI_NOT_FOUND          The asynchronous isn't found\r
+\r
+**/\r
+EFI_STATUS\r
+UhciRemoveAsyncReq (\r
+  IN  USB_HC_DEV          *Uhc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               EndPoint,\r
+  OUT UINT8               *Toggle\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Release all the asynchronous transfers on the lsit.\r
+\r
+  @param  Uhc                    The UHCI device\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciFreeAllAsyncReq (\r
+  IN USB_HC_DEV           *Uhc\r
+  )\r
+;\r
+\r
+\r
+/**\r
+  Interrupt transfer periodic check handler\r
+\r
+  @param  Event                  The event of the time\r
+  @param  Context                Context of the event, pointer to USB_HC_DEV\r
+\r
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UhciMonitorAsyncReqList (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c b/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.c
new file mode 100644 (file)
index 0000000..32082b1
--- /dev/null
@@ -0,0 +1,548 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+    EhciMem.c\r
+\r
+Abstract:\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#include "Uhci.h"\r
+\r
+\r
+UINTN mUsbHcDebugLevel = DEBUG_INFO;\r
+\r
+\r
+/**\r
+  Allocate a block of memory to be used by the buffer pool\r
+\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
+STATIC\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+  IN  USBHC_MEM_POOL      *Pool,\r
+  IN  UINTN               Pages\r
+  )\r
+{\r
+  USBHC_MEM_BLOCK         *Block;\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+  VOID                    *BufHost;\r
+  VOID                    *Mapping;\r
+  EFI_PHYSICAL_ADDRESS    MappedAddr;\r
+  UINTN                   Bytes;\r
+  EFI_STATUS              Status;\r
+\r
+  PciIo = Pool->PciIo;\r
+\r
+  Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
+  if (Block == NULL) {\r
+    return NULL;\r
+  }\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->BufLen   = EFI_PAGES_TO_SIZE (Pages);\r
+  Block->BitsLen  = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+  Block->Bits     = AllocateZeroPool (Block->BitsLen);\r
+\r
+  if (Block->Bits == NULL) {\r
+    gBS->FreePool (Block);\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Allocate the number of Pages of memory, then map it for\r
+  // bus master read and write.\r
+  //\r
+  Status = PciIo->AllocateBuffer (\r
+                    PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    Pages,\r
+                    &BufHost,\r
+                    0\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_BITARRAY;\r
+  }\r
+\r
+  Bytes = EFI_PAGES_TO_SIZE (Pages);\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    EfiPciIoOperationBusMasterCommonBuffer,\r
+                    BufHost,\r
+                    &Bytes,\r
+                    &MappedAddr,\r
+                    &Mapping\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
+    goto FREE_BUFFER;\r
+  }\r
+\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
+    PciIo->Unmap (PciIo, Mapping);\r
+    goto FREE_BUFFER;\r
+  }\r
+\r
+  Block->BufHost  = BufHost;\r
+  Block->Buf      = (UINT8 *) ((UINTN) MappedAddr);\r
+  Block->Mapping  = Mapping;\r
+\r
+  DEBUG ((mUsbHcDebugLevel, "UsbHcAllocMemBlock: block %x created with buffer %x\n",\r
+                          Block, Block->Buf));\r
+\r
+  return Block;\r
+\r
+FREE_BUFFER:\r
+  PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
+\r
+FREE_BITARRAY:\r
+  gBS->FreePool (Block->Bits);\r
+  gBS->FreePool (Block);\r
+  return NULL;\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
+  @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbHcFreeMemBlock (\r
+  IN USBHC_MEM_POOL       *Pool,\r
+  IN USBHC_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+\r
+  ASSERT ((Pool != NULL) && (Block != NULL));\r
+\r
+  PciIo = Pool->PciIo;\r
+\r
+  //\r
+  // Unmap the common buffer then free the structures\r
+  //\r
+  PciIo->Unmap (PciIo, Block->Mapping);\r
+  PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
+\r
+  gBS->FreePool (Block->Bits);\r
+  gBS->FreePool (Block);\r
+}\r
+\r
+\r
+/**\r
+  Alloc some memory from the block\r
+\r
+  @param  Block          The memory block to allocate memory from\r
+  @param  Mem            The variable to store the memory allocated\r
+  @param  Units          Number of memory units to allocate\r
+\r
+  @return EFI_SUCCESS   : The needed memory is allocated\r
+  @return EFI_NOT_FOUND : Can't find the free memory\r
+\r
+**/\r
+STATIC\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] |= 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
+/**\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
+  @return VOID\r
+\r
+**/\r
+STATIC\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
+/**\r
+  Is the memory block empty?\r
+\r
+  @param  Block          The memory block to check\r
+\r
+  @return TRUE  : The memory block is empty\r
+  @return FALSE : The memory block isn't empty\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+UsbHcIsMemBlockEmpty (\r
+  IN USBHC_MEM_BLOCK     *Block\r
+  )\r
+{\r
+  UINTN                   Index;\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
+/**\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
+  @return VOID\r
+\r
+**/\r
+STATIC\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
+/**\r
+  Initialize the memory management pool for the host controller\r
+\r
+  @param  Pool           The USB memory pool to initialize\r
+  @param  PciIo          The PciIo that can be used to access the host controller\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
+  @return EFI_SUCCESS         : The memory pool is initialized\r
+  @return EFI_OUT_OF_RESOURCE : Fail to init the memory pool\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN BOOLEAN              Check4G,\r
+  IN UINT32               Which4G\r
+  )\r
+{\r
+  USBHC_MEM_POOL          *Pool;\r
+\r
+  Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
+\r
+  if (Pool == NULL) {\r
+    return Pool;\r
+  }\r
+\r
+  Pool->PciIo   = PciIo;\r
+  Pool->Check4G = Check4G;\r
+  Pool->Which4G = Which4G;\r
+  Pool->Head    = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
+\r
+  if (Pool->Head == NULL) {\r
+    gBS->FreePool (Pool);\r
+    Pool = NULL;\r
+  }\r
+\r
+  return Pool;\r
+}\r
+\r
+\r
+/**\r
+  Release the memory management pool\r
+\r
+  @param  Pool           The USB memory pool to free\r
+\r
+  @return EFI_SUCCESS      : The memory pool is freed\r
+  @return EFI_DEVICE_ERROR : Failed to free the memory pool\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
+    UsbHcUnlinkMemBlock (Pool->Head, Block);\r
+    UsbHcFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  UsbHcFreeMemBlock (Pool, Pool->Head);\r
+  gBS->FreePool (Pool);\r
+  return EFI_SUCCESS;\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  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  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
+\r
+  NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
+\r
+  if (NewBlock == NULL) {\r
+    DEBUG ((mUsbHcDebugLevel, "UsbHcAllocateMem: failed to allocate block\n"));\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
+/**\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
+  @return VOID\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) 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
+    DEBUG ((mUsbHcDebugLevel, "UsbHcFreeMem: block %x is empty, recycle\n", Block));\r
+\r
+    UsbHcUnlinkMemBlock (Head, Block);\r
+    UsbHcFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  return ;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.h b/MdeModulePkg/Bus/Pci/UhciDxe/UsbHcMem.h
new file mode 100644 (file)
index 0000000..df9ab0e
--- /dev/null
@@ -0,0 +1,167 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  EhciMem.h\r
+\r
+Abstract:\r
+\r
+  This file contains the definination for host controller memory management routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_MEM_H_\r
+#define _EFI_EHCI_MEM_H_\r
+\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
+typedef 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
+} USBHC_MEM_BLOCK;\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
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+  BOOLEAN                 Check4G;\r
+  UINT32                  Which4G;\r
+  USBHC_MEM_BLOCK         *Head;\r
+} USBHC_MEM_POOL;\r
+\r
+enum {\r
+  USBHC_MEM_UNIT           = 64,     // Memory allocation unit, must be 2^n, n>4\r
+\r
+  USBHC_MEM_UNIT_MASK      = USBHC_MEM_UNIT - 1,\r
+  USBHC_MEM_DEFAULT_PAGES  = 16,\r
+};\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
+\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN BOOLEAN              Check4G,\r
+  IN UINT32               Which4G\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize the memory management pool for the host controller\r
+\r
+Arguments:\r
+\r
+  Pool    - The USB memory pool to initialize\r
+  PciIo   - The PciIo that can be used to access the host controller\r
+  Check4G - Whether the host controller requires allocated memory\r
+            from one 4G address space.\r
+  Which4G - The 4G memory area each memory allocated should be from\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS         : The memory pool is initialized\r
+  EFI_OUT_OF_RESOURCE : Fail to init the memory pool\r
+\r
+--*/\r
+;\r
+\r
+\r
+\r
+/**\r
+  Release the memory management pool\r
+\r
+  @param  Pool  The USB memory pool to free\r
+\r
+  @return EFI_SUCCESS      : The memory pool is freed\r
+  @return EFI_DEVICE_ERROR : Failed to free the memory pool\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+  IN USBHC_MEM_POOL       *Pool\r
+  )\r
+;\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  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  USBHC_MEM_POOL      *Pool,\r
+  IN  UINTN               Size\r
+  )\r
+;\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
+  @return VOID\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+  IN USBHC_MEM_POOL       *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  )\r
+;\r
+#endif\r