]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Enabling usb3.0 XHCI support.
authorerictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 23 Aug 2011 14:36:33 +0000 (14:36 +0000)
committererictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 23 Aug 2011 14:36:33 +0000 (14:36 +0000)
Signed-off-by: erictian
Reviewed-by: jshi19
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12185 6f19259b-4bc3-4df7-8a09-765794883524

16 files changed:
MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h [new file with mode: 0644]
MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c
MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..2975e56
--- /dev/null
@@ -0,0 +1,224 @@
+/** @file\r
+  UEFI Component Name(2) protocol implementation for XHCI driver.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Xhci.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gXhciComponentName = {\r
+  XhciComponentNameGetDriverName,\r
+  XhciComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gXhciComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) XhciComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) XhciComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mXhciDriverNameTable[] = {\r
+  { "eng;en", L"Usb Xhci Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhciComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mXhciDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gXhciComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhciComponentNameGetControllerName (\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
+  EFI_STATUS           Status;\r
+  EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
+  USB_XHCI_DEV         *XhciDev;\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
+             gXhciDriverBinding.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
+                  &gEfiUsb2HcProtocolGuid,\r
+                  (VOID **) &Usb2Hc,\r
+                  gXhciDriverBinding.DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  XhciDev = XHC_FROM_THIS (Usb2Hc);\r
+\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           XhciDev->ControllerNameTable,\r
+           ControllerName,\r
+           (BOOLEAN)(This == &gXhciComponentName)\r
+           );\r
+\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.h b/MdeModulePkg/Bus/Pci/XhciDxe/ComponentName.h
new file mode 100644 (file)
index 0000000..c3c44cc
--- /dev/null
@@ -0,0 +1,146 @@
+/** @file\r
+\r
+  This file contains the delarations for componet name routines.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+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
+#ifndef _EFI_COMPONENT_NAME_H_\r
+#define _EFI_COMPONENT_NAME_H_\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhciComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhciComponentNameGetControllerName (\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
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
new file mode 100644 (file)
index 0000000..61c4b24
--- /dev/null
@@ -0,0 +1,2105 @@
+/** @file\r
+  The XHCI controller driver.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+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
+#include "Xhci.h"\r
+\r
+//\r
+// The device context array which supports up to 255 devices, entry 0 is reserved and should not be used.\r
+//\r
+USB_DEV_CONTEXT UsbDevContext[256];\r
+\r
+//\r
+// Two arrays used to translate the XHCI port state (change)\r
+// to the UEFI protocol's port state (change).\r
+//\r
+USB_PORT_STATE_MAP  mUsbPortStateMap[] = {\r
+  {XHC_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},\r
+  {XHC_PORTSC_PED,   USB_PORT_STAT_ENABLE},\r
+  {XHC_PORTSC_OCA,   USB_PORT_STAT_OVERCURRENT},\r
+  {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}\r
+};\r
+\r
+USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {\r
+  {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
+  {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
+  {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
+  {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
+};\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL  gXhciDriverBinding = {\r
+  XhcDriverBindingSupported,\r
+  XhcDriverBindingStart,\r
+  XhcDriverBindingStop,\r
+  0x30,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+/**\r
+  Retrieves the capability of root hub ports.\r
+\r
+  @param  This                  The EFI_USB2_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
+  @retval EFI_SUCCESS           Host controller capability were retrieved successfully.\r
+  @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcGetCapability (\r
+  IN  EFI_USB2_HC_PROTOCOL  *This,\r
+  OUT UINT8                 *MaxSpeed,\r
+  OUT UINT8                 *PortNumber,\r
+  OUT UINT8                 *Is64BitCapable\r
+  )\r
+{\r
+  USB_XHCI_DEV    *Xhc;\r
+  EFI_TPL         OldTpl;\r
+\r
+  if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl          = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc             = XHC_FROM_THIS (This);\r
+  *MaxSpeed       = EFI_USB_SPEED_SUPER;\r
+  *PortNumber     = (UINT8) (Xhc->HcSParams1.Data.MaxPorts);\r
+  *Is64BitCapable = (UINT8) (Xhc->HcCParams.Data.Ac64);\r
+  DEBUG ((EFI_D_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\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
+  @retval EFI_SUCCESS           The reset operation succeeded.\r
+  @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
+  @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is\r
+                                not currently supported by the host controller.\r
+  @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcReset (\r
+  IN EFI_USB2_HC_PROTOCOL  *This,\r
+  IN UINT16                Attributes\r
+  )\r
+{\r
+  USB_XHCI_DEV    *Xhc;\r
+  EFI_STATUS      Status;\r
+  EFI_TPL         OldTpl;\r
+\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc    = XHC_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 (!XhcIsHalt (Xhc)) {\r
+      Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto ON_EXIT;\r
+      }\r
+    }\r
+\r
+    Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
+    ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+    //\r
+    // Clean up the asynchronous transfers, currently only\r
+    // interrupt supports asynchronous operation.\r
+    //\r
+    XhciDelAllAsyncIntTransfers (Xhc);\r
+    XhcFreeSched (Xhc);\r
+\r
+    XhcInitSched (Xhc);\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
+  DEBUG ((EFI_D_INFO, "XhcReset: status %r\n", Status));\r
+  gBS->RestoreTPL (OldTpl);\r
+\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
+  @retval EFI_SUCCESS            Host controller state was returned in State.\r
+  @retval EFI_INVALID_PARAMETER  State is NULL.\r
+  @retval EFI_DEVICE_ERROR       An error was encountered while attempting to\r
+                                 retrieve the host controller's current state.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcGetState (\r
+  IN  EFI_USB2_HC_PROTOCOL  *This,\r
+  OUT EFI_USB_HC_STATE      *State\r
+  )\r
+{\r
+  USB_XHCI_DEV    *Xhc;\r
+  EFI_TPL         OldTpl;\r
+\r
+  if (State == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc    = XHC_FROM_THIS (This);\r
+\r
+  if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {\r
+    *State = EfiUsbHcStateHalt;\r
+  } else {\r
+    *State = EfiUsbHcStateOperational;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcGetState: current state %d\n", *State));\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\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
+  @retval EFI_SUCCESS           The USB host controller was successfully placed\r
+                                in the state specified by State.\r
+  @retval EFI_INVALID_PARAMETER State is invalid.\r
+  @retval EFI_DEVICE_ERROR      Failed to set the state due to device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSetState (\r
+  IN EFI_USB2_HC_PROTOCOL  *This,\r
+  IN EFI_USB_HC_STATE      State\r
+  )\r
+{\r
+  USB_XHCI_DEV        *Xhc;\r
+  EFI_STATUS          Status;\r
+  EFI_USB_HC_STATE    CurState;\r
+  EFI_TPL             OldTpl;\r
+\r
+  Status = XhcGetState (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 (XHC_TPL);\r
+\r
+  Xhc    = XHC_FROM_THIS (This);\r
+\r
+  switch (State) {\r
+  case EfiUsbHcStateHalt:\r
+    Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+    break;\r
+\r
+  case EfiUsbHcStateOperational:\r
+    if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Software must not write a one to this field unless the host controller\r
+    // is in the Halted state. Doing so will yield undefined results.\r
+    // refers to Spec[XHCI1.0-2.3.1]\r
+    //\r
+    if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+    break;\r
+\r
+  case EfiUsbHcStateSuspend:\r
+    Status = EFI_UNSUPPORTED;\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcSetState: status %r\n", Status));\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\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.\r
+                                This value is zero-based.\r
+  @param  PortStatus            Variable to receive the port state.\r
+\r
+  @retval EFI_SUCCESS           The status of the USB root hub port specified.\r
+                                by PortNumber was returned in PortStatus.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+  @retval EFI_DEVICE_ERROR      Can't read register.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcGetRootHubPortStatus (\r
+  IN  EFI_USB2_HC_PROTOCOL  *This,\r
+  IN  UINT8                 PortNumber,\r
+  OUT EFI_USB_PORT_STATUS   *PortStatus\r
+  )\r
+{\r
+  USB_XHCI_DEV            *Xhc;\r
+  UINT32                  Offset;\r
+  UINT32                  State;\r
+  UINT32                  TotalPort;\r
+  UINTN                   Index;\r
+  UINTN                   MapSize;\r
+  EFI_STATUS              Status;\r
+  USB_DEV_ROUTE           ParentRouteChart;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  if (PortStatus == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc       = XHC_FROM_THIS (This);\r
+  Status    = EFI_SUCCESS;\r
+\r
+  TotalPort = Xhc->HcSParams1.Data.MaxPorts;\r
+\r
+  if (PortNumber >= TotalPort) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Offset                       = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
+  PortStatus->PortStatus       = 0;\r
+  PortStatus->PortChangeStatus = 0;\r
+\r
+  State = XhcReadOpReg (Xhc, Offset);\r
+\r
+  //\r
+  // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.\r
+  //\r
+  switch ((State & XHC_PORTSC_PS) >> 10) {\r
+  case 2:\r
+    PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+    break;\r
+\r
+  case 3:\r
+    PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+    break;\r
+\r
+  case 4:\r
+    PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Convert the XHCI 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 (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
+      PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
+    }\r
+  }\r
+  //\r
+  // Bit5~8 reflects its current link state.\r
+  //\r
+  if ((State & XHC_PORTSC_PLS) >> 5 == 3) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+  }\r
+\r
+  MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+  for (Index = 0; Index < MapSize; Index++) {\r
+    if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
+      PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.\r
+  // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.\r
+  //\r
+  ParentRouteChart.Dword = 0;\r
+  XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);\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
+  @retval EFI_SUCCESS           The feature specified by PortFeature was set.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_DEVICE_ERROR      Can't read register.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSetRootHubPortFeature (\r
+  IN EFI_USB2_HC_PROTOCOL  *This,\r
+  IN UINT8                 PortNumber,\r
+  IN EFI_USB_PORT_FEATURE  PortFeature\r
+  )\r
+{\r
+  USB_XHCI_DEV            *Xhc;\r
+  UINT32                  Offset;\r
+  UINT32                  State;\r
+  UINT32                  TotalPort;\r
+  UINT8                   SlotId;\r
+  USB_DEV_ROUTE           RouteChart;\r
+  EFI_STATUS              Status;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc    = XHC_FROM_THIS (This);\r
+  Status = EFI_SUCCESS;\r
+\r
+  TotalPort = (Xhc->HcSParams1.Data.MaxPorts);\r
+\r
+  if (PortNumber >= TotalPort) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
+  State  = XhcReadOpReg (Xhc, Offset);\r
+\r
+  //\r
+  // Mask off the port status change bits, these bits are\r
+  // write clean bit\r
+  //\r
+  State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
+\r
+  switch (PortFeature) {\r
+  case EfiUsbPortEnable:\r
+    //\r
+    // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
+    // A port may be disabled by software writing a '1' to this flag.\r
+    //\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  case EfiUsbPortSuspend:\r
+    State |= XHC_PORTSC_LWS;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    State &= ~XHC_PORTSC_PLS;\r
+    State |= (3 << 5) ;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortReset:\r
+    DEBUG ((EFI_D_INFO, "XhcUsbPortReset!\n"));\r
+    //\r
+    // Make sure Host Controller not halt before reset it\r
+    //\r
+    if (XhcIsHalt (Xhc)) {\r
+      Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_INFO, "XhcSetRootHubPortFeature :failed to start HC - %r\n", Status));\r
+        break;\r
+      }\r
+    }\r
+\r
+    RouteChart.Field.RouteString = 0;\r
+    RouteChart.Field.RootPortNum = PortNumber + 1;\r
+    RouteChart.Field.TierNum     = 1;\r
+    //\r
+    // BUGBUG: If the port reset operation happens after the usb super speed device is enabled,\r
+    // The subsequent configuration, such as getting device descriptor, will fail.\r
+    // So here a workaround is introduced to skip the reset operation if the device is enabled.\r
+    //\r
+    SlotId = XhcRouteStringToSlotId (RouteChart);\r
+    if (SlotId == 0) {\r
+      //\r
+      // 4.3.1 Resetting a Root Hub Port\r
+      // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
+      //\r
+      State |= XHC_PORTSC_RESET;\r
+      XhcWriteOpReg (Xhc, Offset, State);\r
+      XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
+    }\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
+    //\r
+    // XHCI root hub port don't has the owner bit, ignore the operation\r
+    //\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+ON_EXIT:\r
+  DEBUG ((EFI_D_INFO, "XhcSetRootHubPortFeature: status %r\n", Status));\r
+  gBS->RestoreTPL (OldTpl);\r
+\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
+  @retval EFI_SUCCESS           The feature specified by PortFeature was cleared\r
+                                for the USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_DEVICE_ERROR      Can't read register.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcClearRootHubPortFeature (\r
+  IN EFI_USB2_HC_PROTOCOL  *This,\r
+  IN UINT8                 PortNumber,\r
+  IN EFI_USB_PORT_FEATURE  PortFeature\r
+  )\r
+{\r
+  USB_XHCI_DEV            *Xhc;\r
+  UINT32                  Offset;\r
+  UINT32                  State;\r
+  UINT32                  TotalPort;\r
+  EFI_STATUS              Status;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc       = XHC_FROM_THIS (This);\r
+  Status    = EFI_SUCCESS;\r
+\r
+  TotalPort = (Xhc->HcSParams1.Data.MaxPorts);\r
+\r
+  if (PortNumber >= TotalPort) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Offset = XHC_PORTSC_OFFSET + (0x10 * PortNumber);\r
+\r
+  //\r
+  // Mask off the port status change bits, these bits are\r
+  // write clean bit\r
+  //\r
+  State  = XhcReadOpReg (Xhc, Offset);\r
+  State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
+\r
+  switch (PortFeature) {\r
+  case EfiUsbPortEnable:\r
+    //\r
+    // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
+    // A port may be disabled by software writing a '1' to this flag.\r
+    //\r
+    State |= XHC_PORTSC_PED;\r
+    State &= ~XHC_PORTSC_RESET;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortSuspend:\r
+    State |= XHC_PORTSC_LWS;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    State &= ~XHC_PORTSC_PLS;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortReset:\r
+    //\r
+    // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:\r
+    // Register bits indicate status when read, a clear bit may be set by\r
+    // writing a '1'. Writing a '0' to RW1S bits has no effect.\r
+    //\r
+    break;\r
+\r
+  case EfiUsbPortOwner:\r
+    //\r
+    // XHCI root hub port don't has the owner bit, ignore the operation\r
+    //\r
+    break;\r
+\r
+  case EfiUsbPortConnectChange:\r
+    //\r
+    // Clear connect status change\r
+    //\r
+    State |= XHC_PORTSC_CSC;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortEnableChange:\r
+    //\r
+    // Clear enable status change\r
+    //\r
+    State |= XHC_PORTSC_PEC;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortOverCurrentChange:\r
+    //\r
+    // Clear PortOverCurrent change\r
+    //\r
+    State |= XHC_PORTSC_OCC;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortResetChange:\r
+    //\r
+    // Clear Port Reset change\r
+    //\r
+    State |= XHC_PORTSC_PRC;\r
+    XhcWriteOpReg (Xhc, Offset, State);\r
+    break;\r
+\r
+  case EfiUsbPortPower:\r
+  case EfiUsbPortSuspendChange:\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
+  DEBUG ((EFI_D_INFO, "XhcClearRootHubPortFeature: status %r\n", Status));\r
+  gBS->RestoreTPL (OldTpl);\r
+\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
+  @retval EFI_SUCCESS           Transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resources.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_TIMEOUT           Transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcControlTransfer (\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_XHCI_DEV            *Xhc;\r
+  URB                     *Urb;\r
+  UINT8                   Endpoint;\r
+  UINT8                   Index;\r
+  UINT8                   XhciDevAddr;\r
+  UINT8                   DescriptorType;\r
+  UINT8                   SlotId;\r
+  UINT8                   TTT;\r
+  UINT8                   MTT;\r
+  UINT32                  MaxPacket0;\r
+  EFI_USB_HUB_DESCRIPTOR  *HubDesc;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+  EFI_STATUS              RecoveryStatus;\r
+  UINTN                   MapSize;\r
+  EFI_USB_PORT_STATUS     PortStatus;\r
+  UINT32                  State;\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
+      (MaximumPacketLength != 512)\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc             = XHC_FROM_THIS (This);\r
+\r
+  Status          = EFI_DEVICE_ERROR;\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+\r
+  if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcControlTransfer: HC halted at entrance\n"));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check if the device is still enabled before every transaction.\r
+  //\r
+  SlotId = XhcBusDevAddrToSlotId (DeviceAddress);\r
+  if (SlotId == 0) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
+  //\r
+  XhciDevAddr = UsbDevContext[SlotId].XhciDevAddr;\r
+\r
+  //\r
+  // Hook the Set_Address request from UsbBus.\r
+  // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.\r
+  //\r
+  if (Request->Request == USB_REQ_SET_ADDRESS) {\r
+    //\r
+    // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.\r
+    // This way is used to clean the history to avoid using wrong device address by XhcAsyncInterruptTransfer().\r
+    //\r
+    for (Index = 0; Index < 255; Index++) {\r
+      if (!UsbDevContext[Index + 1].Enabled &&\r
+          (UsbDevContext[Index + 1].SlotId != 0) &&\r
+          (UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value)) {\r
+        UsbDevContext[Index + 1].BusDevAddr = 0;\r
+      }\r
+    }\r
+    //\r
+    // The actual device address has been assigned by XHCI during initializing the device slot.\r
+    // So we just need establish the mapping relationship between the device address requested from UsbBus\r
+    // and the actual device address assigned by XHCI. The the following invocations through EFI_USB2_HC_PROTOCOL interface\r
+    // can find out the actual device address by it.\r
+    //\r
+    UsbDevContext[SlotId].BusDevAddr = (UINT8)Request->Value;\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // BUGBUG: If the port reset operation happens after the usb super speed device is enabled,\r
+  // The subsequent configuration, such as getting device descriptor, will fail.\r
+  // So here a workaround is introduced to skip the reset operation if the device is enabled.\r
+  //\r
+  if ((Request->Request == USB_REQ_SET_FEATURE) &&\r
+      (Request->Value == EfiUsbPortReset)) {\r
+    if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+      Status = EFI_SUCCESS;\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Create a new URB, insert it into the asynchronous\r
+  // schedule list, then poll the execution status.\r
+  // Note that we encode the direction in address although default control\r
+  // endpoint is bidirectional. XhcCreateUrb expects this\r
+  // combination of Ep addr and its direction.\r
+  //\r
+  Endpoint = 0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0);\r
+  Urb = XhcCreateUrb (\r
+          Xhc,\r
+          XhciDevAddr,\r
+          Endpoint,\r
+          DeviceSpeed,\r
+          MaximumPacketLength,\r
+          XHC_CTRL_TRANSFER,\r
+          Request,\r
+          Data,\r
+          *DataLength,\r
+          NULL,\r
+          NULL\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcControlTransfer: failed to create URB"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+  ASSERT (Urb->EvtRing == &Xhc->CtrlTrEventRing);\r
+  Status = XhcExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
+\r
+  //\r
+  // Get the status from URB. The result is updated in XhcCheckUrbResult\r
+  // which is called by XhcExecTransfer\r
+  //\r
+  *TransferResult = Urb->Result;\r
+  *DataLength     = Urb->Completed;\r
+\r
+  if (*TransferResult == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  } else if ((*TransferResult == EFI_USB_ERR_STALL) ||\r
+             (*TransferResult == EFI_USB_ERR_TIMEOUT)) {\r
+    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+    ASSERT_EFI_ERROR (RecoveryStatus);\r
+    goto FREE_URB;\r
+  }\r
+\r
+  //\r
+  // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
+  // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.\r
+  // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
+  //\r
+  if (Request->Request == USB_REQ_GET_DESCRIPTOR) {\r
+    DescriptorType = (UINT8)(Request->Value >> 8);\r
+    if ((DescriptorType == USB_DESC_TYPE_DEVICE) && (*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR))) {\r
+        //\r
+        // Store a copy of device scriptor as hub device need this info to configure endpoint.\r
+        //\r
+        CopyMem (&UsbDevContext[SlotId].DevDesc, Data, *DataLength);\r
+        if (UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) {\r
+          //\r
+          // If it's a usb3.0 device, then its max packet size is a 2^n.\r
+          //\r
+          MaxPacket0 = 1 << UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
+        } else {\r
+          MaxPacket0 = UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
+        }\r
+        UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
+        Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);\r
+        ASSERT_EFI_ERROR (Status);\r
+    } else if ((DescriptorType == USB_DESC_TYPE_CONFIG) && (*DataLength == ((UINT16 *)Data)[1])) {\r
+      //\r
+      // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd.\r
+      //\r
+      Index = (UINT8)Request->Value;\r
+      ASSERT (Index < UsbDevContext[SlotId].DevDesc.NumConfigurations);\r
+      UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool(*DataLength);\r
+      CopyMem (UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
+    } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||\r
+               (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED))) {\r
+      HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;\r
+      //\r
+      // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.\r
+      //\r
+      TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);\r
+      if (UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {\r
+        //\r
+        // BUGBUG: Don't support multi-TT feature for super speed hub.\r
+        //\r
+        MTT = 1;\r
+        ASSERT (FALSE);\r
+      } else {\r
+        MTT = 0;\r
+      }\r
+\r
+      Status = XhcConfigHubContext (\r
+                 Xhc,\r
+                 SlotId,\r
+                 HubDesc->NumPorts,\r
+                 TTT,\r
+                 MTT\r
+                 );\r
+    }\r
+  } else if (Request->Request == USB_REQ_SET_CONFIG) {\r
+    //\r
+    // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
+    //\r
+    for (Index = 0; Index < UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
+      if (UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {\r
+        XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, UsbDevContext[SlotId].ConfDesc[Index]);\r
+        break;\r
+      }\r
+    }\r
+  } else if (Request->Request == USB_REQ_GET_STATUS) {\r
+    //\r
+    // Hook Get_Status request from UsbBus to keep track of the port status change.\r
+    //\r
+    State                       = *(UINT32 *)Data;\r
+    PortStatus.PortStatus       = 0;\r
+    PortStatus.PortChangeStatus = 0;\r
+\r
+    if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+      //\r
+      // For super speed hub, its bit10~12 presents the attached device speed.\r
+      //\r
+      if ((*(UINT32 *)Data & XHC_PORTSC_PS) >> 10 == 0) {\r
+        PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
+      }\r
+    } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+      //\r
+      // For high speed hub, its bit9~10 presents the attached device speed.\r
+      //\r
+      if (XHC_BIT_IS_SET (*(UINT32 *)Data, BIT9)) {\r
+        PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+      } else if (XHC_BIT_IS_SET (*(UINT32 *)Data, BIT10)) {\r
+        PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+      }\r
+    } else {\r
+      ASSERT (0);\r
+    }\r
+\r
+    //\r
+    // Convert the XHCI port/port change state to UEFI status\r
+    //\r
+    MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+    for (Index = 0; Index < MapSize; Index++) {\r
+      if (XHC_BIT_IS_SET (*(UINT32 *)Data, mUsbPortStateMap[Index].HwState)) {\r
+        PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbPortStateMap[Index].UefiState);\r
+      }\r
+    }\r
+    MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+    for (Index = 0; Index < MapSize; Index++) {\r
+      if (XHC_BIT_IS_SET (*(UINT32 *)Data, mUsbPortChangeMap[Index].HwState)) {\r
+      PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
+      }\r
+    }\r
+\r
+    XhcPollPortStatusChange (Xhc, UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);\r
+  }\r
+\r
+FREE_URB:\r
+  FreePool (Urb);\r
+\r
+ON_EXIT:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\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 transfer.\r
+  @param  TimeOut               Indicates the maximum time, in millisecond, which\r
+                                the transfer is allowed to complete.\r
+  @param  Translator            A pointr to the transaction translator data.\r
+  @param  TransferResult        A pointer to the detailed result information of the\r
+                                bulk transfer.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcBulkTransfer (\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_XHCI_DEV            *Xhc;\r
+  URB                     *Urb;\r
+  UINT8                   XhciDevAddr;\r
+  UINT8                   SlotId;\r
+  EFI_STATUS              Status;\r
+  EFI_STATUS              RecoveryStatus;\r
+  EFI_TPL                 OldTpl;\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
+      ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc             = XHC_FROM_THIS (This);\r
+\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_DEVICE_ERROR;\r
+\r
+  if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: HC is halted\n"));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check if the device is still enabled before every transaction.\r
+  //\r
+  SlotId = XhcBusDevAddrToSlotId (DeviceAddress);\r
+  if (SlotId == 0) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
+  //\r
+  XhciDevAddr = UsbDevContext[SlotId].XhciDevAddr;\r
+\r
+  //\r
+  // Create a new URB, insert it into the asynchronous\r
+  // schedule list, then poll the execution status.\r
+  //\r
+  Urb = XhcCreateUrb (\r
+          Xhc,\r
+          XhciDevAddr,\r
+          EndPointAddress,\r
+          DeviceSpeed,\r
+          MaximumPacketLength,\r
+          XHC_BULK_TRANSFER,\r
+          NULL,\r
+          Data[0],\r
+          *DataLength,\r
+          NULL,\r
+          NULL\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: failed to create URB\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  ASSERT (Urb->EvtRing == &Xhc->BulkTrEventRing);\r
+\r
+  Status = XhcExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
+\r
+  *TransferResult = Urb->Result;\r
+  *DataLength     = Urb->Completed;\r
+\r
+  if (*TransferResult == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  } else if ((*TransferResult == EFI_USB_ERR_STALL) ||\r
+             (*TransferResult == EFI_USB_ERR_TIMEOUT)) {\r
+    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+    ASSERT_EFI_ERROR (RecoveryStatus);\r
+  }\r
+\r
+  FreePool (Urb);\r
+\r
+ON_EXIT:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+  }\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\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
+  @retval EFI_SUCCESS           The request has been successfully submitted or canceled.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request failed due to a lack of resources.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcAsyncInterruptTransfer (\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
+  USB_XHCI_DEV            *Xhc;\r
+  URB                     *Urb;\r
+  EFI_STATUS              Status;\r
+  UINT8                   XhciDevAddr;\r
+  UINT8                   SlotId;\r
+  UINT8                   Index;\r
+  UINT8                   *Data;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  //\r
+  // Validate parameters\r
+  //\r
+  if (!XHCI_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 (XHC_TPL);\r
+\r
+  Xhc    = XHC_FROM_THIS (This);\r
+\r
+  //\r
+  // Delete Async interrupt transfer request.\r
+  //\r
+  if (!IsNewTransfer) {\r
+    //\r
+    // The delete request may happen after device is detached.\r
+    //\r
+    for (Index = 0; Index < 255; Index++) {\r
+      if ((UsbDevContext[Index + 1].SlotId != 0) &&\r
+          (UsbDevContext[Index + 1].BusDevAddr == DeviceAddress)) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (Index == 255) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    //\r
+    // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
+    //\r
+    XhciDevAddr = UsbDevContext[Index + 1].XhciDevAddr;\r
+\r
+    Status = XhciDelAsyncIntTransfer (Xhc, XhciDevAddr, EndPointAddress);\r
+    DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer, Status = %r\n", Status));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n"));\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check if the device is still enabled before every transaction.\r
+  //\r
+  SlotId = XhcBusDevAddrToSlotId (DeviceAddress);\r
+  if (SlotId == 0) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
+  //\r
+  XhciDevAddr = UsbDevContext[SlotId].XhciDevAddr;\r
+\r
+  Data = AllocatePool (DataLength);\r
+\r
+  if (Data == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Urb = XhcCreateUrb (\r
+          Xhc,\r
+          XhciDevAddr,\r
+          EndPointAddress,\r
+          DeviceSpeed,\r
+          MaximumPacketLength,\r
+          XHC_INT_TRANSFER_ASYNC,\r
+          NULL,\r
+          Data,\r
+          DataLength,\r
+          CallBackFunction,\r
+          Context\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to create URB\n"));\r
+    FreePool (Data);\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  ASSERT (Urb->EvtRing == &Xhc->AsynIntTrEventRing);\r
+\r
+  InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);\r
+  //\r
+  // Ring the doorbell\r
+  //\r
+  Status = RingIntTransferDoorBell (Xhc, Urb);\r
+\r
+ON_EXIT:\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
+EFI_STATUS\r
+EFIAPI\r
+XhcSyncInterruptTransfer (\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_XHCI_DEV            *Xhc;\r
+  URB                     *Urb;\r
+  UINT8                   XhciDevAddr;\r
+  UINT8                   SlotId;\r
+  EFI_STATUS              Status;\r
+  EFI_STATUS              RecoveryStatus;\r
+  EFI_TPL                 OldTpl;\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 (!XHCI_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 (XHC_TPL);\r
+\r
+  Xhc     = XHC_FROM_THIS (This);\r
+\r
+  *TransferResult = EFI_USB_ERR_SYSTEM;\r
+  Status          = EFI_DEVICE_ERROR;\r
+\r
+  if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
+    DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Check if the device is still enabled before every transaction.\r
+  //\r
+  SlotId = XhcBusDevAddrToSlotId (DeviceAddress);\r
+  if (SlotId == 0) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
+  //\r
+  XhciDevAddr = UsbDevContext[SlotId].XhciDevAddr;\r
+\r
+  Urb = XhcCreateUrb (\r
+          Xhc,\r
+          XhciDevAddr,\r
+          EndPointAddress,\r
+          DeviceSpeed,\r
+          MaximumPacketLength,\r
+          XHC_INT_TRANSFER_SYNC,\r
+          NULL,\r
+          Data,\r
+          *DataLength,\r
+          NULL,\r
+          NULL\r
+          );\r
+\r
+  if (Urb == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: failed to create URB\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = XhcExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
+\r
+  *TransferResult = Urb->Result;\r
+  *DataLength     = Urb->Completed;\r
+\r
+  if (*TransferResult == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  } else if ((*TransferResult == EFI_USB_ERR_STALL) ||\r
+             (*TransferResult == EFI_USB_ERR_TIMEOUT)) {\r
+    RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+    ASSERT_EFI_ERROR (RecoveryStatus);\r
+  }\r
+\r
+  FreePool (Urb);\r
+\r
+ON_EXIT:\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+  }\r
+  gBS->RestoreTPL (OldTpl);\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
+EFI_STATUS\r
+EFIAPI\r
+XhcIsochronousTransfer (\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
+EFI_STATUS\r
+EFIAPI\r
+XhcAsyncIsochronousTransfer (\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
+/**\r
+  Entry point for EFI drivers.\r
+\r
+  @param  ImageHandle       EFI_HANDLE.\r
+  @param  SystemTable       EFI_SYSTEM_TABLE.\r
+\r
+  @retval EFI_SUCCESS       Success.\r
+  @retval Others            Fail.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcDriverEntryPoint (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  return EfiLibInstallDriverBindingComponentName2 (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gXhciDriverBinding,\r
+           ImageHandle,\r
+           &gXhciComponentName,\r
+           &gXhciComponentName2\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  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
+XhcDriverBindingSupported (\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
+                  (VOID **) &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
+                        PCI_CLASSCODE_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 Xhci type\r
+  //\r
+  if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
+      (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
+      (UsbClassCReg.ProgInterface != PCI_IF_XHCI)) {\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
+  Create and initialize a USB_XHCI_DEV.\r
+\r
+  @param  PciIo                  The PciIo on this device.\r
+  @param  OriginalPciAttributes  Original PCI attributes.\r
+\r
+  @return The allocated and initialized USB_XHCI_DEV structure if created,\r
+          otherwise NULL.\r
+\r
+**/\r
+USB_XHCI_DEV*\r
+XhcCreateUsbHc (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN UINT64               OriginalPciAttributes\r
+  )\r
+{\r
+  USB_XHCI_DEV            *Xhc;\r
+  EFI_STATUS              Status;\r
+  UINT32                  PageSize;\r
+  UINT16                  ExtCapReg;\r
+\r
+  ZeroMem (UsbDevContext, sizeof (UsbDevContext));\r
+\r
+  Xhc = AllocateZeroPool (sizeof (USB_XHCI_DEV));\r
+\r
+  if (Xhc == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Init EFI_USB2_HC_PROTOCOL interface and private data structure\r
+  //\r
+  Xhc->Signature                        = USB_XHCI_DEV_SIGNATURE;\r
+\r
+  Xhc->Usb2Hc.GetCapability             = XhcGetCapability;\r
+  Xhc->Usb2Hc.Reset                     = XhcReset;\r
+  Xhc->Usb2Hc.GetState                  = XhcGetState;\r
+  Xhc->Usb2Hc.SetState                  = XhcSetState;\r
+  Xhc->Usb2Hc.ControlTransfer           = XhcControlTransfer;\r
+  Xhc->Usb2Hc.BulkTransfer              = XhcBulkTransfer;\r
+  Xhc->Usb2Hc.AsyncInterruptTransfer    = XhcAsyncInterruptTransfer;\r
+  Xhc->Usb2Hc.SyncInterruptTransfer     = XhcSyncInterruptTransfer;\r
+  Xhc->Usb2Hc.IsochronousTransfer       = XhcIsochronousTransfer;\r
+  Xhc->Usb2Hc.AsyncIsochronousTransfer  = XhcAsyncIsochronousTransfer;\r
+  Xhc->Usb2Hc.GetRootHubPortStatus      = XhcGetRootHubPortStatus;\r
+  Xhc->Usb2Hc.SetRootHubPortFeature     = XhcSetRootHubPortFeature;\r
+  Xhc->Usb2Hc.ClearRootHubPortFeature   = XhcClearRootHubPortFeature;\r
+  Xhc->Usb2Hc.MajorRevision             = 0x3;\r
+  Xhc->Usb2Hc.MinorRevision             = 0x0;\r
+\r
+  Xhc->PciIo                 = PciIo;\r
+  Xhc->OriginalPciAttributes = OriginalPciAttributes;\r
+\r
+  InitializeListHead (&Xhc->AsyncIntTransfers);\r
+\r
+  //\r
+  // Be caution that the Offset passed to XhcReadCapReg() should be Dword align\r
+  //\r
+  Xhc->CapLength        = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);\r
+  Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);\r
+  Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);\r
+  Xhc->HcCParams.Dword  = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);\r
+  Xhc->DBOff            = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);\r
+  Xhc->RTSOff           = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);\r
+\r
+  //\r
+  // This PageSize field defines the page size supported by the xHC implementation.\r
+  // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,\r
+  // if bit 0 is Set, the xHC supports 4k byte page sizes.\r
+  //\r
+  PageSize      = XhcReadOpReg(Xhc, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;\r
+  Xhc->PageSize = 1 << (HighBitSet32(PageSize) + 12);\r
+  ASSERT (Xhc->PageSize == 0x1000);\r
+\r
+  ExtCapReg                 = (UINT16) (Xhc->HcCParams.Data.ExtCapReg);\r
+  Xhc->ExtCapRegBase        = ExtCapReg << 2;\r
+  Xhc->UsbLegSupOffset = XhcGetLegSupCapAddr (Xhc);\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: capability length 0x%x\n", Xhc->CapLength));\r
+  DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));\r
+  DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));\r
+  DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));\r
+  DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));\r
+  DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));\r
+  DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: Xhc->UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));\r
+\r
+  //\r
+  // Create AsyncRequest Polling Timer\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  XhcMonitorAsyncRequests,\r
+                  Xhc,\r
+                  &Xhc->PollTimer\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  return Xhc;\r
+\r
+ON_ERROR:\r
+  FreePool (Xhc);\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
+\r
+  @param  Event                   Pointer to this event\r
+  @param  Context                 Event hanlder private data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+XhcExitBootService (\r
+  EFI_EVENT  Event,\r
+  VOID       *Context\r
+  )\r
+\r
+{\r
+  USB_XHCI_DEV         *Xhc;\r
+  EFI_PCI_IO_PROTOCOL  *PciIo;\r
+\r
+  Xhc = (USB_XHCI_DEV*) Context;\r
+  PciIo = Xhc->PciIo;\r
+\r
+  //\r
+  // Stop AsyncRequest Polling timer then stop the XHCI driver\r
+  // and uninstall the XHCI protocl.\r
+  //\r
+  gBS->SetTimer (Xhc->PollTimer, TimerCancel, XHC_ASYNC_POLL_INTERVAL);\r
+  XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+\r
+  if (Xhc->PollTimer != NULL) {\r
+    gBS->CloseEvent (Xhc->PollTimer);\r
+  }\r
+\r
+  //\r
+  // Restore original PCI attributes\r
+  //\r
+  PciIo->Attributes (\r
+                  PciIo,\r
+                  EfiPciIoAttributeOperationSet,\r
+                  Xhc->OriginalPciAttributes,\r
+                  NULL\r
+                  );\r
+\r
+  XhcClearBiosOwnership (Xhc);\r
+}\r
+\r
+/**\r
+  Starting the Usb XHCI 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
+XhcDriverBindingStart (\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
+  UINT64                  Supports;\r
+  UINT64                  OriginalPciAttributes;\r
+  BOOLEAN                 PciAttributesSaved;\r
+  USB_XHCI_DEV            *Xhc;\r
+\r
+  //\r
+  // Open the PciIo Protocol, then enable the USB host controller\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &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
+  PciAttributesSaved = FALSE;\r
+  //\r
+  // Save original PCI attributes\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationGet,\r
+                    0,\r
+                    &OriginalPciAttributes\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto CLOSE_PCIIO;\r
+  }\r
+  PciAttributesSaved = TRUE;\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= EFI_PCI_DEVICE_ENABLE;\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      Supports,\r
+                      NULL\r
+                      );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));\r
+    goto CLOSE_PCIIO;\r
+  }\r
+\r
+  //\r
+  // Create then install USB2_HC_PROTOCOL\r
+  //\r
+  Xhc = XhcCreateUsbHc (PciIo, OriginalPciAttributes);\r
+\r
+  if (Xhc == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  XhcSetBiosOwnership (Xhc);\r
+\r
+  XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
+  ASSERT (XhcIsHalt (Xhc));\r
+\r
+  //\r
+  // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag\r
+  // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.\r
+  //\r
+  ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));\r
+\r
+  //\r
+  // Initialize the schedule\r
+  //\r
+  XhcInitSched (Xhc);\r
+\r
+  //\r
+  // Start the Host Controller\r
+  //\r
+  XhcRunHC(Xhc, XHC_GENERIC_TIMEOUT);\r
+\r
+  //\r
+  // Start the asynchronous interrupt monitor\r
+  //\r
+  Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_POLL_INTERVAL);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
+    XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+    goto FREE_POOL;\r
+  }\r
+\r
+  //\r
+  // Create event to stop the HC when exit boot service.\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  XhcExitBootService,\r
+                  Xhc,\r
+                  &gEfiEventExitBootServicesGuid,\r
+                  &Xhc->ExitBootServiceEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_POOL;\r
+  }\r
+\r
+  //\r
+  // Install the component name protocol, don't fail the start\r
+  // because of something for display.\r
+  //\r
+  AddUnicodeString2 (\r
+    "eng",\r
+    gXhciComponentName.SupportedLanguages,\r
+    &Xhc->ControllerNameTable,\r
+    L"eXtensible Host Controller (USB 3.0)",\r
+    TRUE\r
+    );\r
+  AddUnicodeString2 (\r
+    "en",\r
+    gXhciComponentName2.SupportedLanguages,\r
+    &Xhc->ControllerNameTable,\r
+    L"eXtensible Host Controller (USB 3.0)",\r
+    FALSE\r
+    );\r
+\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &Xhc->Usb2Hc\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
+    goto FREE_POOL;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));\r
+  return EFI_SUCCESS;\r
+\r
+FREE_POOL:\r
+  gBS->CloseEvent (Xhc->PollTimer);\r
+  XhcFreeSched (Xhc);\r
+  FreePool (Xhc);\r
+\r
+CLOSE_PCIIO:\r
+  if (PciAttributesSaved) {\r
+    //\r
+    // Restore original PCI attributes\r
+    //\r
+    PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSet,\r
+                    OriginalPciAttributes,\r
+                    NULL\r
+                    );\r
+  }\r
+\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
+XhcDriverBindingStop (\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
+  USB_XHCI_DEV          *Xhc;\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
+                  (VOID **) &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
+  Xhc   = XHC_FROM_THIS (Usb2Hc);\r
+  PciIo = Xhc->PciIo;\r
+\r
+  //\r
+  // Stop AsyncRequest Polling timer then stop the XHCI driver\r
+  // and uninstall the XHCI protocl.\r
+  //\r
+  gBS->SetTimer (Xhc->PollTimer, TimerCancel, XHC_ASYNC_POLL_INTERVAL);\r
+  XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+  XhcClearBiosOwnership (Xhc);\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 (Xhc->PollTimer != NULL) {\r
+    gBS->CloseEvent (Xhc->PollTimer);\r
+  }\r
+\r
+  if (Xhc->ExitBootServiceEvent != NULL) {\r
+    gBS->CloseEvent (Xhc->ExitBootServiceEvent);\r
+  }\r
+\r
+  XhciDelAllAsyncIntTransfers (Xhc);\r
+  XhcFreeSched (Xhc);\r
+\r
+  if (Xhc->ControllerNameTable) {\r
+    FreeUnicodeStringTable (Xhc->ControllerNameTable);\r
+  }\r
+\r
+  //\r
+  // Restore original PCI attributes\r
+  //\r
+  PciIo->Attributes (\r
+                  PciIo,\r
+                  EfiPciIoAttributeOperationSet,\r
+                  Xhc->OriginalPciAttributes,\r
+                  NULL\r
+                  );\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  FreePool (Xhc);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h
new file mode 100644 (file)
index 0000000..953ba4c
--- /dev/null
@@ -0,0 +1,362 @@
+/** @file\r
+\r
+  Provides some data structure definitions used by the XHCI host controller driver.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+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
+#ifndef _EFI_XHCI_H_\r
+#define _EFI_XHCI_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/Usb2HostController.h>\r
+#include <Protocol/PciIo.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+typedef struct _USB_XHCI_DEV    USB_XHCI_DEV;\r
+typedef struct _USB_DEV_CONTEXT USB_DEV_CONTEXT;\r
+\r
+#include "XhciReg.h"\r
+#include "XhciSched.h"\r
+#include "ComponentName.h"\r
+\r
+//\r
+// XHC timeout experience values\r
+//\r
+#define XHC_1_MICROSECOND            1\r
+#define XHC_1_MILLISECOND            (1000 * XHC_1_MICROSECOND)\r
+#define XHC_1_SECOND                 (1000 * XHC_1_MILLISECOND)\r
+\r
+//\r
+// XHCI register operation timeout, set by experience\r
+//\r
+#define XHC_RESET_TIMEOUT            (1 * XHC_1_SECOND)\r
+#define XHC_GENERIC_TIMEOUT          (10 * XHC_1_MILLISECOND)\r
+\r
+//\r
+// Wait for roothub port power stable, refers to Spec[XHCI1.0-2.3.9]\r
+//\r
+#define XHC_ROOT_PORT_RECOVERY_STALL (20 * XHC_1_MILLISECOND)\r
+\r
+//\r
+// Sync and Async transfer polling interval, set by experience,\r
+// and the unit of Async is 100us, means 50ms as interval.\r
+//\r
+#define XHC_SYNC_POLL_INTERVAL       (20 * XHC_1_MILLISECOND)\r
+#define XHC_ASYNC_POLL_INTERVAL      (50 * 10000U)\r
+\r
+//\r
+// XHC raises TPL to TPL_NOTIFY to serialize all its operations\r
+// to protect shared data structures.\r
+//\r
+#define XHC_TPL                      TPL_NOTIFY\r
+\r
+#define CMD_RING_TRB_NUMBER          0x40\r
+#define TR_RING_TRB_NUMBER           0x40\r
+#define ERST_NUMBER                  0x01\r
+#define EVENT_RING_TRB_NUMBER        0x80\r
+\r
+#define CMD_INTER                    0\r
+#define CTRL_INTER                   1\r
+#define BULK_INTER                   2\r
+#define INT_INTER                    3\r
+#define INT_INTER_ASYNC              4\r
+\r
+//\r
+// Iterate through the doule linked list. This is delete-safe.\r
+// Don't touch NextEntry\r
+//\r
+#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \\r
+  for (Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\\r
+      Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink)\r
+\r
+#define EFI_LIST_CONTAINER(Entry, Type, Field) BASE_CR(Entry, Type, Field)\r
+\r
+#define XHC_LOW_32BIT(Addr64)        ((UINT32)(((UINTN)(Addr64)) & 0xFFFFFFFF))\r
+#define XHC_HIGH_32BIT(Addr64)       ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0xFFFFFFFF))\r
+#define XHC_BIT_IS_SET(Data, Bit)    ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+#define XHC_REG_BIT_IS_SET(Xhc, Offset, Bit) \\r
+          (XHC_BIT_IS_SET(XhcReadOpReg ((Xhc), (Offset)), (Bit)))\r
+\r
+#define XHCI_IS_DATAIN(EndpointAddr) XHC_BIT_IS_SET((EndpointAddr), 0x80)\r
+\r
+#define USB_XHCI_DEV_SIGNATURE       SIGNATURE_32 ('x', 'h', 'c', 'i')\r
+#define XHC_FROM_THIS(a)             CR(a, USB_XHCI_DEV, Usb2Hc, USB_XHCI_DEV_SIGNATURE)\r
+\r
+#define USB_DESC_TYPE_HUB              0x29\r
+#define USB_DESC_TYPE_HUB_SUPER_SPEED  0x2a\r
+\r
+//\r
+// Xhci Data and Ctrl Structures\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8                     ProgInterface;\r
+  UINT8                     SubClassCode;\r
+  UINT8                     BaseCode;\r
+} USB_CLASSC;\r
+\r
+typedef struct {\r
+  UINT8                     Length;\r
+  UINT8                     DescType;\r
+  UINT8                     NumPorts;\r
+  UINT16                    HubCharacter;\r
+  UINT8                     PwrOn2PwrGood;\r
+  UINT8                     HubContrCurrent;\r
+  UINT8                     Filler[16];\r
+} EFI_USB_HUB_DESCRIPTOR;\r
+#pragma pack()\r
+\r
+struct _USB_XHCI_DEV {\r
+  UINT32                    Signature;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  UINT64                    OriginalPciAttributes;\r
+\r
+  EFI_USB2_HC_PROTOCOL      Usb2Hc;\r
+\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+\r
+  //\r
+  // ExitBootServicesEvent is used to set OS semaphore and\r
+  // stop the XHC DMA operation after exit boot service.\r
+  //\r
+  EFI_EVENT                 ExitBootServiceEvent;\r
+  EFI_EVENT                 PollTimer;\r
+  LIST_ENTRY                AsyncIntTransfers;\r
+\r
+  UINT8                     CapLength;    ///< Capability Register Length\r
+  XHC_HCSPARAMS1            HcSParams1;   ///< Structural Parameters 1\r
+  XHC_HCSPARAMS2            HcSParams2;   ///< Structural Parameters 2\r
+  XHC_HCCPARAMS             HcCParams;    ///< Capability Parameters\r
+  UINT32                    DBOff;        ///< Doorbell Offset\r
+  UINT32                    RTSOff;       ///< Runtime Register Space Offset\r
+  UINT16                    MaxInterrupt;\r
+  UINT32                    PageSize;\r
+  UINT64                    *ScratchBuf;\r
+  UINT32                    MaxScratchpadBufs;\r
+  UINT32                    ExtCapRegBase;\r
+  UINT32                    UsbLegSupOffset;\r
+  UINT64                    *DCBAA;\r
+  UINT32                    MaxSlotsEn;\r
+  //\r
+  // Cmd Transfer Ring\r
+  //\r
+  TRANSFER_RING             CmdRing;\r
+  //\r
+  // CmdEventRing\r
+  //\r
+  EVENT_RING                CmdEventRing;\r
+  //\r
+  // ControlTREventRing\r
+  //\r
+  EVENT_RING                CtrlTrEventRing;\r
+  //\r
+  // BulkTREventRing\r
+  //\r
+  EVENT_RING                BulkTrEventRing;\r
+  //\r
+  // IntTREventRing\r
+  //\r
+  EVENT_RING                IntTrEventRing;\r
+  //\r
+  // AsyncIntTREventRing\r
+  //\r
+  EVENT_RING                AsynIntTrEventRing;\r
+  //\r
+  // Misc\r
+  //\r
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;\r
+\r
+};\r
+\r
+struct _USB_DEV_CONTEXT {\r
+  //\r
+  // Whether this entry in UsbDevContext array is used or not.\r
+  //\r
+  BOOLEAN                   Enabled;\r
+  //\r
+  // The slot id assigned to the new device through XHCI's Enable_Slot cmd.\r
+  //\r
+  UINT8                     SlotId;\r
+  //\r
+  // The route string presented an attached usb device.\r
+  //\r
+  USB_DEV_ROUTE             RouteString;\r
+  //\r
+  // The route string of parent device if it exists. Otherwise it's zero.\r
+  //\r
+  USB_DEV_ROUTE             ParentRouteString;\r
+  //\r
+  // The actual device address assigned by XHCI through Address_Device command.\r
+  //\r
+  UINT8                     XhciDevAddr;\r
+  //\r
+  // The requested device address from UsbBus driver through Set_Address standard usb request.\r
+  // As XHCI spec replaces this request with Address_Device command, we have to record the\r
+  // requested device address and establish a mapping relationship with the actual device address.\r
+  // Then UsbBus driver just need to be aware of the requested device address to access usb device\r
+  // through EFI_USB2_HC_PROTOCOL. Xhci driver would be responsible for translating it to actual\r
+  // device address and access the actual device.\r
+  //\r
+  UINT8                     BusDevAddr;\r
+  //\r
+  // The pointer to the input device context.\r
+  //\r
+  VOID                      *InputContext;\r
+  //\r
+  // The pointer to the output device context.\r
+  //\r
+  VOID                      *OutputDevContxt;\r
+  //\r
+  // The transfer queue for every endpoint.\r
+  //\r
+  VOID                      *EndpointTransferRing[31];\r
+  //\r
+  // The device descriptor which is stored to support XHCI's Evaluate_Context cmd.\r
+  //\r
+  EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
+  //\r
+  // As a usb device may include multiple configuration descriptors, we dynamically allocate an array\r
+  // to store them.\r
+  // Note that every configuration descriptor stored here includes those lower level descriptors,\r
+  // such as Interface descriptor, Endpoint descriptor, and so on.\r
+  // These information is used to support XHCI's Config_Endpoint cmd.\r
+  //\r
+  EFI_USB_CONFIG_DESCRIPTOR **ConfDesc;\r
+};\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL      gXhciDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL      gXhciComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL     gXhciComponentName2;\r
+extern USB_DEV_CONTEXT                  UsbDevContext[];\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  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
+XhcDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Starting the Usb XHCI 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
+XhcDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\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
+XhcDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  Controller,\r
+  IN UINTN                       NumberOfChildren,\r
+  IN EFI_HANDLE                  *ChildHandleBuffer\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
+  @retval EFI_SUCCESS           The feature specified by PortFeature was set.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_DEVICE_ERROR      Can't read register.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSetRootHubPortFeature (\r
+  IN EFI_USB2_HC_PROTOCOL  *This,\r
+  IN UINT8                 PortNumber,\r
+  IN EFI_USB_PORT_FEATURE  PortFeature\r
+  );\r
+\r
+/**\r
+  Clears a feature for the specified root hub port.\r
+\r
+  @param  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
+  @retval EFI_SUCCESS           The feature specified by PortFeature was cleared\r
+                                for the USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_DEVICE_ERROR      Can't read register.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcClearRootHubPortFeature (\r
+  IN EFI_USB2_HC_PROTOCOL  *This,\r
+  IN UINT8                 PortNumber,\r
+  IN EFI_USB_PORT_FEATURE  PortFeature\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf b/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
new file mode 100644 (file)
index 0000000..da701a6
--- /dev/null
@@ -0,0 +1,77 @@
+## @file\r
+#\r
+#  Component Description File For XhciDxe Module.\r
+#\r
+#  XhciDxe driver is responsible for managing the behavior of XHCI controller.\r
+#  It implements the interfaces of monitoring the status of all ports and transferring\r
+#  Control, Bulk, Interrupt and Isochronous requests to those attached usb LS/FS/HS/SS devices.\r
+#\r
+#  Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions 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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = XhciDxe\r
+  FILE_GUID                      = B7F50E91-A759-412c-ADE4-DCD03E7F7C28\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = XhcDriverEntryPoint\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
+#  DRIVER_BINDING                =  gXhciDriverBinding\r
+#  COMPONENT_NAME                =  gXhciComponentName\r
+#  COMPONENT_NAME2               =  gXhciComponentName2\r
+#\r
+\r
+[Sources]\r
+  Xhci.c\r
+  XhciReg.c\r
+  XhciSched.c\r
+  ComponentName.c\r
+  ComponentName.h\r
+  Xhci.h\r
+  XhciReg.h\r
+  XhciSched.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  DebugLib\r
+  PcdLib\r
+\r
+[Guids]\r
+  gEfiEventExitBootServicesGuid                 ## PRODUCES ## Event\r
+\r
+[Protocols]\r
+  gEfiPciIoProtocolGuid                         ## TO_START\r
+  gEfiUsb2HcProtocolGuid                        ## BY_START\r
+\r
+# [Event]\r
+#   ##\r
+#   # Periodic timer event for checking the result of interrupt transfer execution.\r
+#   #\r
+#   EVENT_TYPE_PERIODIC_TIMER                   ## PRODUCES\r
+#\r
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
new file mode 100644 (file)
index 0000000..f5e66e4
--- /dev/null
@@ -0,0 +1,827 @@
+/** @file\r
+\r
+  The XHCI register operation routines.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+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
+#include "Xhci.h"\r
+\r
+/**\r
+  Read 1-byte width XHCI capability register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 1-byte width capability register.\r
+\r
+  @return The register content read.\r
+  @retval If err, return 0xFF.\r
+\r
+**/\r
+UINT8\r
+XhcReadCapReg8 (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT8                   Data;\r
+  EFI_STATUS              Status;\r
+\r
+  Status = Xhc->PciIo->Mem.Read (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint8,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) Offset,\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFF;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Read 4-bytes width XHCI capability register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 4-bytes width capability register.\r
+\r
+  @return The register content read.\r
+  @retval If err, return 0xFFFFFFFF.\r
+\r
+**/\r
+UINT32\r
+XhcReadCapReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  EFI_STATUS              Status;\r
+\r
+  Status = Xhc->PciIo->Mem.Read (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) Offset,\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcReadCapReg: Pci Io read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFFFFFFFF;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Read 4-bytes width XHCI Operational register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 4-bytes width operational register.\r
+\r
+  @return The register content read.\r
+  @retval If err, return 0xFFFFFFFF.\r
+\r
+**/\r
+UINT32\r
+XhcReadOpReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->CapLength != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Read (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->CapLength + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFFFFFFFF;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write the data to the 4-bytes width XHCI operational register.\r
+\r
+  @param  Xhc      The XHCI device.\r
+  @param  Offset   The offset of the 4-bytes width operational register.\r
+  @param  Data     The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteOpReg (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->CapLength != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Write (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->CapLength + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));\r
+  }\r
+}\r
+\r
+/**\r
+  Write the data to the 2-bytes width XHCI operational register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 2-bytes width operational register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteOpReg16 (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT16               Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->CapLength != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Write (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint16,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->CapLength + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcWriteOpReg16: Pci Io Write error: %r at %d\n", Status, Offset));\r
+  }\r
+}\r
+\r
+/**\r
+  Write the data to the 8-bytes width XHCI operational register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 8-bytes width operational register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteOpReg64 (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT64               Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->CapLength != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Write (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint64,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->CapLength + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcWriteOpReg64: Pci Io Write error: %r at %d\n", Status, Offset));\r
+  }\r
+}\r
+\r
+/**\r
+  Read XHCI door bell register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the door bell register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadDoorBellReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->DBOff != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Read (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->DBOff + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcReadDoorBellReg: Pci Io Read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFFFFFFFF;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write the data to the XHCI door bell register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the door bell register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteDoorBellReg (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->DBOff != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Write (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->DBOff + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));\r
+  }\r
+}\r
+\r
+/**\r
+  Read XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadRuntimeReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->RTSOff != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Read (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->RTSOff + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcReadRuntimeReg: Pci Io Read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFFFFFFFF;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Read 8-bytes width XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 8-bytes width runtime register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT64\r
+XhcReadRuntimeReg64 (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT64                  Data;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->RTSOff != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Read (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint64,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->RTSOff + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcReadRuntimeReg64: Pci Io Read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFFFFFFFFFFFFFFFF;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write the data to the XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteRuntimeReg (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->RTSOff != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Write (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->RTSOff + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcWriteRuntimeReg: Pci Io Write error: %r at %d\n", Status, Offset));\r
+  }\r
+}\r
+\r
+/**\r
+  Write the data to the 8-bytes width XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 8-bytes width runtime register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteRuntimeReg64 (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT64               Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->RTSOff != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Write (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint64,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->RTSOff + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcWriteRuntimeReg64: Pci Io Write error: %r at %d\n", Status, Offset));\r
+  }\r
+}\r
+\r
+/**\r
+  Read XHCI extended capability register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the extended capability register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadExtCapReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->ExtCapRegBase != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Read (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->ExtCapRegBase + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcReadExtCapReg: Pci Io Read error - %r at %d\n", Status, Offset));\r
+    Data = 0xFFFFFFFF;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write the data to the XHCI extended capability register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the extended capability register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteExtCapReg (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT (Xhc->ExtCapRegBase != 0);\r
+\r
+  Status = Xhc->PciIo->Mem.Write (\r
+                             Xhc->PciIo,\r
+                             EfiPciIoWidthUint32,\r
+                             XHC_BAR_INDEX,\r
+                             (UINT64) (Xhc->ExtCapRegBase + Offset),\r
+                             1,\r
+                             &Data\r
+                             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcWriteExtCapReg: Pci Io Write error: %r at %d\n", Status, Offset));\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Set one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcSetRuntimeRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  Data  = XhcReadRuntimeReg (Xhc, Offset);\r
+  Data |= Bit;\r
+  XhcWriteRuntimeReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Clear one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcClearRuntimeRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  Data  = XhcReadRuntimeReg (Xhc, Offset);\r
+  Data &= ~Bit;\r
+  XhcWriteRuntimeReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Set one bit of the operational register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the operational register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcSetOpRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  Data  = XhcReadOpReg (Xhc, Offset);\r
+  Data |= Bit;\r
+  XhcWriteOpReg (Xhc, Offset, Data);\r
+}\r
+\r
+\r
+/**\r
+  Clear one bit of the operational register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the operational register.\r
+  @param  Bit          The bit mask of the register to clear.\r
+\r
+**/\r
+VOID\r
+XhcClearOpRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  Data  = XhcReadOpReg (Xhc, Offset);\r
+  Data &= ~Bit;\r
+  XhcWriteOpReg (Xhc, Offset, Data);\r
+}\r
+\r
+/**\r
+  Wait the operation register's bit as specified by Bit\r
+  to become set (or clear).\r
+\r
+  @param  Xhc          The XHCI 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, ms).\r
+\r
+  @retval EFI_SUCCESS  The bit successfully changed by host controller.\r
+  @retval EFI_TIMEOUT  The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcWaitOpRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\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 / XHC_SYNC_POLL_INTERVAL + 1; Index++) {\r
+    if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    gBS->Stall (XHC_SYNC_POLL_INTERVAL);\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Set Bios Ownership\r
+\r
+  @param  Xhc          The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcSetBiosOwnership (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  )\r
+{\r
+  UINT32                    Buffer;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcSetBiosOwnership: called to set BIOS ownership\n"));\r
+\r
+  Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);\r
+  Buffer = ((Buffer & (~USBLEGSP_OS_SEMAPHORE)) | USBLEGSP_BIOS_SEMAPHORE);\r
+  XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);\r
+}\r
+\r
+/**\r
+  Clear Bios Ownership\r
+\r
+  @param  Xhc       The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcClearBiosOwnership (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  )\r
+{\r
+  UINT32                    Buffer;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcClearBiosOwnership: called to clear BIOS ownership\n"));\r
+\r
+  Buffer = XhcReadExtCapReg (Xhc, Xhc->UsbLegSupOffset);\r
+  Buffer = ((Buffer & (~USBLEGSP_BIOS_SEMAPHORE)) | USBLEGSP_OS_SEMAPHORE);\r
+  XhcWriteExtCapReg (Xhc, Xhc->UsbLegSupOffset, Buffer);\r
+}\r
+\r
+/**\r
+  Calculate the XHCI legacy support capability register offset.\r
+\r
+  @param  Xhc     The XHCI device.\r
+\r
+  @return The offset of XHCI legacy support capability register.\r
+\r
+**/\r
+UINT32\r
+XhcGetLegSupCapAddr (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  )\r
+{\r
+  UINT32 ExtCapOffset;\r
+  UINT8  NextExtCapReg;\r
+  UINT32 Data;\r
+\r
+  ExtCapOffset = 0;\r
+\r
+  do {\r
+    //\r
+    // Check if the extended capability register's capability id is USB Legacy Support.\r
+    //\r
+    Data = XhcReadExtCapReg (Xhc, ExtCapOffset);\r
+    if ((Data & 0xFF) == 0x1) {\r
+      return ExtCapOffset;\r
+    }\r
+    //\r
+    // If not, then traverse all of the ext capability registers till finding out it.\r
+    //\r
+    NextExtCapReg = (Data >> 8) & 0xFF;\r
+    ExtCapOffset += (NextExtCapReg << 2);\r
+  } while (NextExtCapReg != 0);\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Whether the XHCI host controller is halted.\r
+\r
+  @param  Xhc     The XHCI device.\r
+\r
+  @retval TRUE    The controller is halted.\r
+  @retval FALSE   It isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+XhcIsHalt (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  )\r
+{\r
+  return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);\r
+}\r
+\r
+\r
+/**\r
+  Whether system error occurred.\r
+\r
+  @param  Xhc      The XHCI device.\r
+\r
+  @retval TRUE     System error happened.\r
+  @retval FALSE    No system error.\r
+\r
+**/\r
+BOOLEAN\r
+XhcIsSysError (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  )\r
+{\r
+  return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);\r
+}\r
+\r
+/**\r
+  Reset the XHCI host controller.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Timeout      Time to wait before abort (in millisecond, ms).\r
+\r
+  @retval EFI_SUCCESS  The XHCI host controller is reset.\r
+  @return Others       Failed to reset the XHCI before Timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcResetHC (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcResetHC!\n"));\r
+  //\r
+  // Host can only be reset when it is halt. If not so, halt it\r
+  //\r
+  if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {\r
+    Status = XhcHaltHC (Xhc, Timeout);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);\r
+  Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Halt the XHCI host controller.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Timeout      Time to wait before abort (in millisecond, ms).\r
+\r
+  @return EFI_SUCCESS  The XHCI host controller is halt.\r
+  @return EFI_TIMEOUT  Failed to halt the XHCI before Timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcHaltHC (\r
+  IN USB_XHCI_DEV        *Xhc,\r
+  IN UINT32              Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
+  Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Set the XHCI host controller to run.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Timeout      Time to wait before abort (in millisecond, ms).\r
+\r
+  @return EFI_SUCCESS  The XHCI host controller is running.\r
+  @return EFI_TIMEOUT  Failed to set the XHCI to run before Timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcRunHC (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Timeout\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  XhcSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
+  Status = XhcWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h
new file mode 100644 (file)
index 0000000..d004bf9
--- /dev/null
@@ -0,0 +1,569 @@
+/** @file\r
+\r
+  This file contains the register definition of XHCI host controller.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+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
+#ifndef _EFI_XHCI_REG_H_\r
+#define _EFI_XHCI_REG_H_\r
+\r
+#define PCI_IF_XHCI                 0x30\r
+\r
+//\r
+// PCI Configuration Registers\r
+//\r
+#define XHC_BAR_INDEX               0x00\r
+\r
+#define XHC_PCI_BAR_OFFSET          0x10       // Memory Bar Register Offset\r
+#define XHC_PCI_BAR_MASK            0xFFFF     // Memory Base Address Mask\r
+\r
+#define USB_HUB_CLASS_CODE          0x09\r
+#define USB_HUB_SUBCLASS_CODE       0x00\r
+\r
+//============================================//\r
+//           XHCI register offset             //\r
+//============================================//\r
+\r
+//\r
+// Capability registers offset\r
+//\r
+#define XHC_CAPLENGTH_OFFSET               0x00 // Capability register length offset\r
+#define XHC_HCIVERSION_OFFSET              0x02 // Interface Version Number 02-03h\r
+#define XHC_HCSPARAMS1_OFFSET              0x04 // Structural Parameters 1\r
+#define XHC_HCSPARAMS2_OFFSET              0x08 // Structural Parameters 2\r
+#define XHC_HCSPARAMS3_OFFSET              0x0c // Structural Parameters 3\r
+#define XHC_HCCPARAMS_OFFSET               0x10 // Capability Parameters\r
+#define XHC_DBOFF_OFFSET                   0x14 // Doorbell Offset\r
+#define XHC_RTSOFF_OFFSET                  0x18 // Runtime Register Space Offset\r
+\r
+//\r
+// Operational registers offset\r
+//\r
+#define XHC_USBCMD_OFFSET                  0x0000 // USB Command Register Offset\r
+#define XHC_USBSTS_OFFSET                  0x0004 // USB Status Register Offset\r
+#define XHC_PAGESIZE_OFFSET                0x0008 // USB Page Size Register Offset\r
+#define XHC_DNCTRL_OFFSET                  0x0014 // Device Notification Control Register Offset\r
+#define XHC_CRCR_OFFSET                    0x0018 // Command Ring Control Register Offset\r
+#define XHC_DCBAAP_OFFSET                  0x0030 // Device Context Base Address Array Pointer Register Offset\r
+#define XHC_CONFIG_OFFSET                  0x0038 // Configure Register Offset\r
+#define XHC_PORTSC_OFFSET                  0x0400 // Port Status and Control Register Offset\r
+\r
+//\r
+// Runtime registers offset\r
+//\r
+#define XHC_MFINDEX_OFFSET                 0x00 // Microframe Index Register Offset\r
+#define XHC_IMAN_OFFSET                    0x20 // Interrupter X Management Register Offset\r
+#define XHC_IMOD_OFFSET                    0x24 // Interrupter X Moderation Register Offset\r
+#define XHC_ERSTSZ_OFFSET                  0x28 // Event Ring Segment Table Size Register Offset\r
+#define XHC_ERSTBA_OFFSET                  0x30 // Event Ring Segment Table Base Address Register Offset\r
+#define XHC_ERDP_OFFSET                    0x38 // Event Ring Dequeue Pointer Register Offset\r
+\r
+#define USBLEGSP_BIOS_SEMAPHORE            BIT16 // HC BIOS Owned Semaphore\r
+#define USBLEGSP_OS_SEMAPHORE              BIT24 // HC OS Owned Semaphore\r
+\r
+#pragma pack (1)\r
+//\r
+// Structural Parameters 1 Register Bitmap Definition\r
+//\r
+typedef union _XHC_HCSPARAMS1 {\r
+  UINT32                    Dword;\r
+  struct {\r
+    UINT8                   MaxSlots;    // Number of Device Slots\r
+    UINT16                  MaxIntrs:11; // Number of Interrupters\r
+    UINT16                  Rsvd:5;\r
+    UINT8                   MaxPorts;    // Number of Ports\r
+  } Data;\r
+} XHC_HCSPARAMS1;\r
+\r
+//\r
+// Structural Parameters 2 Register Bitmap Definition\r
+//\r
+typedef union _XHC_HCSPARAMS2 {\r
+  UINT32                    Dword;\r
+  struct {\r
+    UINT32                  Ist:4;          // Isochronous Scheduling Threshold\r
+    UINT32                  Erst:4;         // Event Ring Segment Table Max\r
+    UINT32                  Rsvd:13;\r
+    UINT32                  ScratchBufHi:5; // Max Scratchpad Buffers Hi\r
+    UINT32                  Spr:1;          // Scratchpad Restore\r
+    UINT32                  ScratchBufLo:5; // Max Scratchpad Buffers Lo\r
+  } Data;\r
+} XHC_HCSPARAMS2;\r
+\r
+//\r
+// Capability Parameters Register Bitmap Definition\r
+//\r
+typedef union _XHC_HCCPARAMS {\r
+  UINT32                    Dword;\r
+  struct {\r
+    UINT16                  Ac64:1;        // 64-bit Addressing Capability\r
+    UINT16                  Bnc:1;         // BW Negotiation Capability\r
+    UINT16                  Csz:1;         // Context Size\r
+    UINT16                  Ppc:1;         // Port Power Control\r
+    UINT16                  Pind:1;        // Port Indicators\r
+    UINT16                  Lhrc:1;        // Light HC Reset Capability\r
+    UINT16                  Ltc:1;         // Latency Tolerance Messaging Capability\r
+    UINT16                  Nss:1;         // No Secondary SID Support\r
+    UINT16                  Pae:1;         // Parse All Event Data\r
+    UINT16                  Rsvd:3;\r
+    UINT16                  MaxPsaSize:4;  // Maximum Primary Stream Array Size\r
+    UINT16                  ExtCapReg;     // xHCI Extended Capabilities Pointer\r
+  } Data;\r
+} XHC_HCCPARAMS;\r
+\r
+#pragma pack ()\r
+\r
+//\r
+// Register Bit Definition\r
+//\r
+#define XHC_USBCMD_RUN                     BIT0  // Run/Stop\r
+#define XHC_USBCMD_RESET                   BIT1  // Host Controller Reset\r
+#define XHC_USBCMD_INTE                    BIT2  // Interrupter Enable\r
+#define XHC_USBCMD_HSEE                    BIT3  // Host System Error Enable\r
+\r
+#define XHC_USBSTS_HALT                    BIT0  // Host Controller Halted\r
+#define XHC_USBSTS_HSE                     BIT2  // Host System Error\r
+#define XHC_USBSTS_EINT                    BIT3  // Event Interrupt\r
+#define XHC_USBSTS_PCD                     BIT4  // Port Change Detect\r
+#define XHC_USBSTS_SSS                     BIT8  // Save State Status\r
+#define XHC_USBSTS_RSS                     BIT9  // Restore State Status\r
+#define XHC_USBSTS_SRE                     BIT10 // Save/Restore Error\r
+#define XHC_USBSTS_CNR                     BIT11 // Host Controller Not Ready\r
+#define XHC_USBSTS_HCE                     BIT12 // Host Controller Error\r
+\r
+#define XHC_PAGESIZE_MASK                  0xFFFF // Page Size\r
+\r
+#define XHC_CRCR_RCS                       BIT0  // Ring Cycle State\r
+#define XHC_CRCR_CS                        BIT1  // Command Stop\r
+#define XHC_CRCR_CA                        BIT2  // Command Abort\r
+#define XHC_CRCR_CRR                       BIT3  // Command Ring Running\r
+\r
+#define XHC_CONFIG_MASK                    0xFF  // Command Ring Running\r
+\r
+#define XHC_PORTSC_CCS                     BIT0  // Current Connect Status\r
+#define XHC_PORTSC_PED                     BIT1  // Port Enabled/Disabled\r
+#define XHC_PORTSC_OCA                     BIT3  // Over-current Active\r
+#define XHC_PORTSC_RESET                   BIT4  // Port Reset\r
+#define XHC_PORTSC_PLS                     (BIT5|BIT6|BIT7|BIT8)     // Port Link State\r
+#define XHC_PORTSC_PP                      BIT9  // Port Power\r
+#define XHC_PORTSC_PS                      (BIT10|BIT11|BIT12|BIT13) // Port Speed\r
+#define XHC_PORTSC_LWS                     BIT16 // Port Link State Write Strobe\r
+#define XHC_PORTSC_CSC                     BIT17 // Connect Status Change\r
+#define XHC_PORTSC_PEC                     BIT18 // Port Enabled/Disabled Change\r
+#define XHC_PORTSC_WRC                     BIT19 // Warm Port Reset Change\r
+#define XHC_PORTSC_OCC                     BIT20 // Over-Current Change\r
+#define XHC_PORTSC_PRC                     BIT21 // Port Reset Change\r
+#define XHC_PORTSC_PLC                     BIT22 // Port Link State Change\r
+#define XHC_PORTSC_CEC                     BIT23 // Port Config Error Change\r
+#define XHC_PORTSC_CAS                     BIT24 // Cold Attach Status\r
+\r
+#define XHC_IMAN_IP                        BIT0  // Interrupt Pending\r
+#define XHC_IMAN_IE                        BIT1  // Interrupt Enable\r
+\r
+#define XHC_IMODI_MASK                     0x0000FFFF  // Interrupt Moderation Interval\r
+#define XHC_IMODC_MASK                     0xFFFF0000  // Interrupt Moderation Counter\r
+\r
+//\r
+// Structure to map the hardware port states to the\r
+// UEFI's port states.\r
+//\r
+typedef struct {\r
+  UINT32                  HwState;\r
+  UINT16                  UefiState;\r
+} USB_PORT_STATE_MAP;\r
+\r
+/**\r
+  Read 1-byte width XHCI capability register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 1-byte width capability register.\r
+\r
+  @return The register content read.\r
+  @retval If err, return 0xFFFF.\r
+\r
+**/\r
+UINT8\r
+XhcReadCapReg8 (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  );\r
+\r
+/**\r
+  Read 4-bytes width XHCI capability register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 4-bytes width capability register.\r
+\r
+  @return The register content read.\r
+  @retval If err, return 0xFFFFFFFF.\r
+\r
+**/\r
+UINT32\r
+XhcReadCapReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  );\r
+\r
+/**\r
+  Read 4-bytes width XHCI Operational register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 4-bytes width operational register.\r
+\r
+  @return The register content read.\r
+  @retval If err, return 0xFFFFFFFF.\r
+\r
+**/\r
+UINT32\r
+XhcReadOpReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  );\r
+\r
+/**\r
+  Write the data to the 4-bytes width XHCI operational register.\r
+\r
+  @param  Xhc      The XHCI device.\r
+  @param  Offset   The offset of the 4-bytes width operational register.\r
+  @param  Data     The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteOpReg (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  );\r
+\r
+/**\r
+  Write the data to the 2-bytes width XHCI operational register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 2-bytes width operational register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteOpReg16 (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT16               Data\r
+  );\r
+\r
+/**\r
+  Write the data to the 8-bytes width XHCI operational register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 8-bytes width operational register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteOpReg64 (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT64               Data\r
+  );\r
+\r
+/**\r
+  Read XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadRuntimeReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  );\r
+\r
+/**\r
+  Read 8-bytes width XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 8-bytes width runtime register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT64\r
+XhcReadRuntimeReg64 (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  );\r
+\r
+/**\r
+  Write the data to the XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteRuntimeReg (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  );\r
+\r
+/**\r
+  Write the data to the 8-bytes width XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the 8-bytes width runtime register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteRuntimeReg64 (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT64               Data\r
+  );\r
+\r
+/**\r
+  Read XHCI door bell register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the door bell register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadDoorBellReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  );\r
+\r
+/**\r
+  Write the data to the XHCI door bell register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the door bell register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteDoorBellReg (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  );\r
+\r
+/**\r
+  Set one bit of the operational register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the operational register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcSetOpRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  );\r
+\r
+/**\r
+  Clear one bit of the operational register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the operational register.\r
+  @param  Bit          The bit mask of the register to clear.\r
+\r
+**/\r
+VOID\r
+XhcClearOpRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  );\r
+\r
+/**\r
+  Wait the operation register's bit as specified by Bit\r
+  to be set (or clear).\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the operational 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, ms).\r
+\r
+  @retval EFI_SUCCESS  The bit successfully changed by host controller.\r
+  @retval EFI_TIMEOUT  The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcWaitOpRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit,\r
+  IN BOOLEAN              WaitToSet,\r
+  IN UINT32               Timeout\r
+  );\r
+\r
+/**\r
+  Read XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+\r
+  @return The register content read\r
+\r
+**/\r
+UINT32\r
+XhcReadRuntimeReg (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT32              Offset\r
+  );\r
+\r
+/**\r
+  Write the data to the XHCI runtime register.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Data         The data to write.\r
+\r
+**/\r
+VOID\r
+XhcWriteRuntimeReg (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  );\r
+\r
+/**\r
+  Set one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcSetRuntimeRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  );\r
+\r
+/**\r
+  Clear one bit of the runtime register while keeping other bits.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Offset       The offset of the runtime register.\r
+  @param  Bit          The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+XhcClearRuntimeRegBit (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Bit\r
+  );\r
+\r
+/**\r
+  Whether the XHCI host controller is halted.\r
+\r
+  @param  Xhc     The XHCI device.\r
+\r
+  @retval TRUE    The controller is halted.\r
+  @retval FALSE   It isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+XhcIsHalt (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  );\r
+\r
+/**\r
+  Whether system error occurred.\r
+\r
+  @param  Xhc      The XHCI device.\r
+\r
+  @retval TRUE     System error happened.\r
+  @retval FALSE    No system error.\r
+\r
+**/\r
+BOOLEAN\r
+XhcIsSysError (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  );\r
+\r
+/**\r
+  Reset the XHCI host controller.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Timeout      Time to wait before abort (in millisecond, ms).\r
+\r
+  @retval EFI_SUCCESS  The XHCI host controller is reset.\r
+  @return Others       Failed to reset the XHCI before Timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcResetHC (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Timeout\r
+  );\r
+\r
+/**\r
+  Halt the XHCI host controller.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Timeout      Time to wait before abort (in millisecond, ms).\r
+\r
+  @return EFI_SUCCESS  The XHCI host controller is halt.\r
+  @return EFI_TIMEOUT  Failed to halt the XHCI before Timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcHaltHC (\r
+  IN USB_XHCI_DEV        *Xhc,\r
+  IN UINT32              Timeout\r
+  );\r
+\r
+/**\r
+  Set the XHCI host controller to run.\r
+\r
+  @param  Xhc          The XHCI device.\r
+  @param  Timeout      Time to wait before abort (in millisecond, ms).\r
+\r
+  @return EFI_SUCCESS  The XHCI host controller is running.\r
+  @return EFI_TIMEOUT  Failed to set the XHCI to run before Timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcRunHC (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT32               Timeout\r
+  );\r
+\r
+/**\r
+  Calculate the XHCI legacy support capability register offset.\r
+\r
+  @param  Xhc     The XHCI device.\r
+\r
+  @return The offset of XHCI legacy support capability register.\r
+\r
+**/\r
+UINT32\r
+XhcGetLegSupCapAddr (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
new file mode 100644 (file)
index 0000000..f160a1d
--- /dev/null
@@ -0,0 +1,2383 @@
+/** @file\r
+\r
+  XHCI transfer scheduling routines.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+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
+#include "Xhci.h"\r
+\r
+/**\r
+  Allocates a buffer of a certain pool type at a specified alignment.\r
+\r
+  Allocates the number bytes specified by AllocationSize of a certain pool type with an alignment\r
+  specified by Alignment.  The allocated buffer is returned.  If AllocationSize is 0, then a valid\r
+  buffer of 0 size is returned.  If there is not enough memory at the specified alignment remaining\r
+  to satisfy the request, then NULL is returned.\r
+  If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+\r
+  @param  PoolType              The type of pool to allocate.\r
+  @param  AllocationSize        The number of bytes to allocate.\r
+  @param  Alignment             The requested alignment of the allocation.  Must be a power of two.\r
+                                If Alignment is zero, then byte alignment is used.\r
+\r
+  @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+InternalAllocateAlignedPool (\r
+  IN EFI_MEMORY_TYPE  PoolType,\r
+  IN UINTN            AllocationSize,\r
+  IN UINTN            Alignment\r
+  )\r
+{\r
+  VOID        *RawAddress;\r
+  UINTN       AlignedAddress;\r
+  UINTN       AlignmentMask;\r
+  UINTN       OverAllocationSize;\r
+  UINTN       RealAllocationSize;\r
+  VOID        **FreePointer;\r
+\r
+  //\r
+  // Alignment must be a power of two or zero.\r
+  //\r
+  ASSERT ((Alignment & (Alignment - 1)) == 0);\r
+\r
+  if (Alignment == 0) {\r
+    AlignmentMask = Alignment;\r
+  } else {\r
+    AlignmentMask = Alignment - 1;\r
+  }\r
+  //\r
+  // Calculate the extra memory size, over-allocate memory pool and get the aligned memory address.\r
+  //\r
+  OverAllocationSize  = sizeof (RawAddress) + AlignmentMask;\r
+  RealAllocationSize  = AllocationSize + OverAllocationSize;\r
+  //\r
+  // Make sure that AllocationSize plus OverAllocationSize does not overflow.\r
+  //\r
+  ASSERT (RealAllocationSize > AllocationSize);\r
+\r
+  RawAddress = NULL;\r
+  gBS->AllocatePool (PoolType, RealAllocationSize, &RawAddress);\r
+  if (RawAddress == NULL) {\r
+    return NULL;\r
+  }\r
+  AlignedAddress      = ((UINTN) RawAddress + OverAllocationSize) & ~AlignmentMask;\r
+  //\r
+  // Save the original memory address just before the aligned address.\r
+  //\r
+  FreePointer         = (VOID **)(AlignedAddress - sizeof (RawAddress));\r
+  *FreePointer        = RawAddress;\r
+\r
+  return (VOID *) AlignedAddress;\r
+}\r
+\r
+/**\r
+  Allocates and zeros a buffer of a certain pool type at a specified alignment.\r
+\r
+  Allocates the number bytes specified by AllocationSize of a certain pool type with an alignment\r
+  specified by Alignment, clears the buffer with zeros, and returns a pointer to the allocated\r
+  buffer.  If AllocationSize is 0, then a valid buffer of 0 size is returned.  If there is not\r
+  enough memory at the specified alignment remaining to satisfy the request, then NULL is returned.\r
+  If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+\r
+  @param  PoolType              The type of pool to allocate.\r
+  @param  AllocationSize        The number of bytes to allocate.\r
+  @param  Alignment             The requested alignment of the allocation.  Must be a power of two.\r
+                                If Alignment is zero, then byte alignment is used.\r
+\r
+  @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+InternalAllocateAlignedZeroPool (\r
+  IN EFI_MEMORY_TYPE  PoolType,\r
+  IN UINTN            AllocationSize,\r
+  IN UINTN            Alignment\r
+  )\r
+{\r
+  VOID    *Memory;\r
+  Memory = InternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
+  if (Memory != NULL) {\r
+    ZeroMem (Memory, AllocationSize);\r
+  }\r
+  return Memory;\r
+}\r
+\r
+/**\r
+  Allocates and zeros a buffer of type EfiBootServicesData at a specified alignment.\r
+\r
+  Allocates the number bytes specified by AllocationSize of type EfiBootServicesData with an\r
+  alignment specified by Alignment, clears the buffer with zeros, and returns a pointer to the\r
+  allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size is returned.  If there\r
+  is not enough memory at the specified alignment remaining to satisfy the request, then NULL is\r
+  returned.\r
+  If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
+\r
+  @param  AllocationSize        The number of bytes to allocate.\r
+  @param  Alignment             The requested alignment of the allocation.  Must be a power of two.\r
+                                If Alignment is zero, then byte alignment is used.\r
+\r
+  @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateAlignedZeroPool (\r
+  IN UINTN  AllocationSize,\r
+  IN UINTN  Alignment\r
+  )\r
+{\r
+  return InternalAllocateAlignedZeroPool (EfiBootServicesData, AllocationSize, Alignment);\r
+}\r
+\r
+/**\r
+  Frees a buffer that was previously allocated with one of the aligned pool allocation functions\r
+  in the Memory Allocation Library.\r
+\r
+  Frees the buffer specified by Buffer.  Buffer must have been allocated on a previous call to the\r
+  aligned pool allocation services of the Memory Allocation Library.\r
+  If Buffer was not allocated with an aligned pool allocation function in the Memory Allocation\r
+  Library, then ASSERT().\r
+\r
+  @param  Buffer                Pointer to the buffer to free.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FreeAlignedPool (\r
+  IN VOID   *Buffer\r
+  )\r
+{\r
+  VOID        *RawAddress;\r
+  VOID        **FreePointer;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Get the pre-saved original address in the over-allocate pool.\r
+  //\r
+  FreePointer = (VOID **)((UINTN) Buffer - sizeof (RawAddress));\r
+  RawAddress  = *FreePointer;\r
+\r
+  Status = gBS->FreePool (RawAddress);\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Create a command transfer TRB to support XHCI command interfaces.\r
+\r
+  @param  Xhc       The XHCI device.\r
+  @param  CmdTrb    The cmd TRB to be executed.\r
+\r
+  @return Created URB or NULL.\r
+\r
+**/\r
+URB*\r
+XhcCreateCmdTrb (\r
+  IN USB_XHCI_DEV    *Xhc,\r
+  IN TRB             *CmdTrb\r
+  )\r
+{\r
+  URB    *Urb;\r
+\r
+  Urb = AllocateZeroPool (sizeof (URB));\r
+  if (Urb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Urb->Signature  = XHC_URB_SIG;\r
+\r
+  Urb->Ring       = &Xhc->CmdRing;\r
+  XhcSyncTrsRing (Xhc, Urb->Ring);\r
+  Urb->TrbNum     = 1;\r
+  Urb->TrbStart   = Urb->Ring->RingEnqueue;\r
+  CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB));\r
+  Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;\r
+  Urb->TrbEnd             = Urb->TrbStart;\r
+\r
+  Urb->EvtRing     = &Xhc->CmdEventRing;\r
+  XhcSyncEventRing (Xhc, Urb->EvtRing);\r
+  Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
+\r
+  return Urb;\r
+}\r
+\r
+/**\r
+  Execute a XHCI cmd TRB pointed by CmdTrb.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  CmdTrb                The cmd TRB to be executed.\r
+  @param  TimeOut               Indicates the maximum time, in millisecond, which the\r
+                                transfer is allowed to complete.\r
+  @param  EvtTrb                The event TRB corresponding to the cmd TRB.\r
+\r
+  @retval EFI_SUCCESS           The transfer was completed successfully.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcCmdTransfer (\r
+  IN  USB_XHCI_DEV          *Xhc,\r
+  IN  TRB                   *CmdTrb,\r
+  IN  UINTN                 TimeOut,\r
+  OUT TRB                   **EvtTrb\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  URB             *Urb;\r
+\r
+  //\r
+  // Validate the parameters\r
+  //\r
+  if ((Xhc == NULL) || (CmdTrb == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
+    DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: HC is halted\n"));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Create a new URB, then poll the execution status.\r
+  //\r
+  Urb = XhcCreateCmdTrb (Xhc, CmdTrb);\r
+\r
+  if (Urb == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: failed to create URB\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  ASSERT (Urb->EvtRing == &Xhc->CmdEventRing);\r
+\r
+  Status  = XhcExecTransfer (Xhc, TRUE, Urb, TimeOut);\r
+  *EvtTrb = Urb->EvtTrbStart;\r
+\r
+  if (Urb->Result == EFI_USB_NOERROR) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  FreePool (Urb);\r
+\r
+ON_EXIT:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Create a new URB for a new transaction.\r
+\r
+  @param  Xhc       The XHCI device\r
+  @param  DevAddr   The device address\r
+  @param  EpAddr    Endpoint addrress\r
+  @param  DevSpeed  The device speed\r
+  @param  MaxPacket The max packet length of the endpoint\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
+\r
+  @return Created URB or NULL\r
+\r
+**/\r
+URB*\r
+XhcCreateUrb (\r
+  IN USB_XHCI_DEV                       *Xhc,\r
+  IN UINT8                              DevAddr,\r
+  IN UINT8                              EpAddr,\r
+  IN UINT8                              DevSpeed,\r
+  IN UINTN                              MaxPacket,\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
+  )\r
+{\r
+  USB_ENDPOINT                  *Ep;\r
+  EFI_STATUS                    Status;\r
+  URB                           *Urb;\r
+\r
+  Urb = AllocateZeroPool (sizeof (URB));\r
+  if (Urb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Urb->Signature = XHC_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) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
+  Ep->DevSpeed  = DevSpeed;\r
+  Ep->MaxPacket = MaxPacket;\r
+  Ep->Type      = Type;\r
+\r
+  Urb->Request  = Request;\r
+  Urb->Data     = Data;\r
+  Urb->DataLen  = DataLen;\r
+  Urb->Callback = Callback;\r
+  Urb->Context  = Context;\r
+\r
+  Status = XhcCreateTransferTrb (Xhc, Urb);\r
+\r
+  return Urb;\r
+}\r
+\r
+/**\r
+  Create a transfer TRB.\r
+\r
+  @param  Xhc     The XHCI device\r
+  @param  Urb     The urb used to construct the transfer TRB.\r
+\r
+  @return Created TRB or NULL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcCreateTransferTrb (\r
+  IN USB_XHCI_DEV               *Xhc,\r
+  IN URB                        *Urb\r
+  )\r
+{\r
+  DEVICE_CONTEXT                *OutputDevContxt;\r
+  TRANSFER_RING                 *EPRing;\r
+  UINT8                         EPType;\r
+  UINT8                         SlotId;\r
+  UINT8                         Dci;\r
+  TRB                           *TrbStart;\r
+  UINTN                         TotalLen;\r
+  UINTN                         Len;\r
+  UINTN                         TrbNum;\r
+\r
+  SlotId    = XhcDevAddrToSlotId(Urb->Ep.DevAddr);\r
+  Dci       = XhcEndpointToDci (Urb->Ep.EpAddr, Urb->Ep.Direction);\r
+  EPRing    = (TRANSFER_RING *)(UINTN) UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
+  Urb->Ring = EPRing;\r
+  OutputDevContxt = (DEVICE_CONTEXT *)(UINTN) Xhc->DCBAA[SlotId];\r
+  EPType    = (UINT8) OutputDevContxt->EP[Dci-1].EPType;\r
+\r
+  //\r
+  // Construct the TRB\r
+  //\r
+  XhcSyncTrsRing (Xhc, EPRing);\r
+  Urb->TrbStart = EPRing->RingEnqueue;\r
+  switch (EPType) {\r
+    case ED_CONTROL_BIDIR:\r
+      Urb->EvtRing     = &Xhc->CtrlTrEventRing;\r
+      XhcSyncEventRing (Xhc, Urb->EvtRing);\r
+      Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
+      //\r
+      // For control transfer, create SETUP_STAGE_TRB first.\r
+      //\r
+      TrbStart = EPRing->RingEnqueue;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->bmRequestType = Urb->Request->RequestType;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->bRequest      = Urb->Request->Request;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->wValue        = Urb->Request->Value;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->wIndex        = Urb->Request->Index;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->wLength       = Urb->Request->Length;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->Lenth         = 8;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->IntTarget     = Urb->EvtRing->EventInterrupter;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->IOC           = 1;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->IDT           = 1;\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->Type          = TRB_TYPE_SETUP_STAGE;\r
+      if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+        ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->TRT = 3;\r
+      } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+        ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->TRT = 2;\r
+      } else {\r
+        ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->TRT = 0;\r
+      }\r
+      //\r
+      // Update the cycle bit\r
+      //\r
+      ((TRANSFER_TRB_CONTROL_SETUP *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0;\r
+      Urb->TrbNum++;\r
+\r
+      //\r
+      // For control transfer, create DATA_STAGE_TRB.\r
+      //\r
+      if (Urb->DataLen > 0) {\r
+        XhcSyncTrsRing (Xhc, EPRing);\r
+        TrbStart = EPRing->RingEnqueue;\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->TRBPtrLo  = XHC_LOW_32BIT(Urb->Data);\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->TRBPtrHi  = XHC_HIGH_32BIT(Urb->Data);\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->Lenth     = (UINT32) Urb->DataLen;\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->TDSize    = 0;\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter;\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->ISP       = 1;\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->IOC       = 1;\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->IDT       = 0;\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->CH        = 0;\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->Type      = TRB_TYPE_DATA_STAGE;\r
+        if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+          ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->DIR = 1;\r
+        } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+          ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->DIR = 0;\r
+        } else {\r
+          ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->DIR = 0;\r
+        }\r
+        //\r
+        // Update the cycle bit\r
+        //\r
+        ((TRANSFER_TRB_CONTROL_DATA *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0;\r
+        Urb->TrbNum++;\r
+      }\r
+      //\r
+      // For control transfer, create STATUS_STAGE_TRB.\r
+      // Get the pointer to next TRB for status stage use\r
+      //\r
+      XhcSyncTrsRing (Xhc, EPRing);\r
+      TrbStart = EPRing->RingEnqueue;\r
+      ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter;\r
+      ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->IOC       = 1;\r
+      ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->CH        = 0;\r
+      ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->Type      = TRB_TYPE_STATUS_STAGE;\r
+      if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+        ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->DIR = 0;\r
+      } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
+        ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->DIR = 1;\r
+      } else {\r
+        ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->DIR = 0;\r
+      }\r
+      //\r
+      // Update the cycle bit\r
+      //\r
+      ((TRANSFER_TRB_CONTROL_STATUS *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0;\r
+      //\r
+      // Update the enqueue pointer\r
+      //\r
+      XhcSyncTrsRing (Xhc, EPRing);\r
+      Urb->TrbNum++;\r
+      Urb->TrbEnd = TrbStart;\r
+\r
+      break;\r
+\r
+    case ED_BULK_OUT:\r
+    case ED_BULK_IN:\r
+      Urb->EvtRing     = &Xhc->BulkTrEventRing;\r
+      XhcSyncEventRing (Xhc, Urb->EvtRing);\r
+      Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
+\r
+      TotalLen = 0;\r
+      Len      = 0;\r
+      TrbNum   = 0;\r
+      TrbStart = EPRing->RingEnqueue;\r
+      while (TotalLen < Urb->DataLen) {\r
+        if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
+          Len = Urb->DataLen - TotalLen;\r
+        } else {\r
+          Len = 0x10000;\r
+        }\r
+        TrbStart = EPRing->RingEnqueue;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->Lenth     = (UINT32) Len;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->TDSize    = 0;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->ISP       = 1;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->IOC       = 1;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->Type      = TRB_TYPE_NORMAL;\r
+        //\r
+        // Update the cycle bit\r
+        //\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0;\r
+\r
+        XhcSyncTrsRing (Xhc, EPRing);\r
+        TrbNum++;\r
+        TotalLen += Len;\r
+      }\r
+\r
+      Urb->TrbNum = TrbNum;\r
+      Urb->TrbEnd = TrbStart;\r
+      break;\r
+\r
+    case ED_INTERRUPT_OUT:\r
+    case ED_INTERRUPT_IN:\r
+      if (Urb->Ep.Type == XHC_INT_TRANSFER_ASYNC) {\r
+        Urb->EvtRing = &Xhc->AsynIntTrEventRing;\r
+      } else if(Urb->Ep.Type == XHC_INT_TRANSFER_SYNC){\r
+        Urb->EvtRing = &Xhc->IntTrEventRing;\r
+      } else {\r
+        DEBUG ((EFI_D_ERROR, "EP Interrupt type error!\n"));\r
+        ASSERT(FALSE);\r
+      }\r
+      XhcSyncEventRing (Xhc, Urb->EvtRing);\r
+      Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
+\r
+      TotalLen = 0;\r
+      Len      = 0;\r
+      TrbNum   = 0;\r
+      TrbStart = EPRing->RingEnqueue;\r
+      while (TotalLen < Urb->DataLen) {\r
+        if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
+          Len = Urb->DataLen - TotalLen;\r
+        } else {\r
+          Len = 0x10000;\r
+        }\r
+        TrbStart = EPRing->RingEnqueue;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->TRBPtrLo  = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->TRBPtrHi  = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->Lenth     = (UINT32) Len;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->TDSize    = 0;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->IntTarget = Urb->EvtRing->EventInterrupter;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->ISP       = 1;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->IOC       = 1;\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->Type      = TRB_TYPE_NORMAL;\r
+        //\r
+        // Update the cycle bit\r
+        //\r
+        ((TRANSFER_TRB_NORMAL *) TrbStart)->CycleBit = EPRing->RingPCS & BIT0;\r
+\r
+        XhcSyncTrsRing (Xhc, EPRing);\r
+        TrbNum++;\r
+        TotalLen += Len;\r
+      }\r
+\r
+      Urb->TrbNum = TrbNum;\r
+      Urb->TrbEnd = TrbStart;\r
+      break;\r
+\r
+    default:\r
+      DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));\r
+      ASSERT (FALSE);\r
+      break;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Initialize the XHCI host controller for schedule.\r
+\r
+  @param  Xhc        The XHCI device to be initialized.\r
+\r
+**/\r
+VOID\r
+XhcInitSched (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  )\r
+{\r
+  VOID                  *Dcbaa;\r
+  UINT64                CmdRing;\r
+  UINTN                 Entries;\r
+  UINT32                MaxScratchpadBufs;\r
+  UINT64                *ScratchBuf;\r
+  UINT64                *ScratchEntryBuf;\r
+  UINT32                Index;\r
+\r
+  //\r
+  // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
+  // to enable the device slots that system software is going to use.\r
+  //\r
+  Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
+  ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
+  XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);\r
+\r
+  //\r
+  // The Device Context Base Address Array entry associated with each allocated Device Slot\r
+  // shall contain a 64-bit pointer to the base of the associated Device Context.\r
+  // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
+  // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
+  //\r
+  Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);\r
+  Dcbaa   = AllocateAlignedZeroPool(Entries, 64);\r
+  ASSERT (Dcbaa != NULL);\r
+\r
+  //\r
+  // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
+  // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
+  // mode (Run/Stop(R/S) ='1').\r
+  //\r
+  MaxScratchpadBufs      = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
+  Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
+  ASSERT (MaxScratchpadBufs >= 0 && MaxScratchpadBufs <= 1023);\r
+  if (MaxScratchpadBufs != 0) {\r
+    ScratchBuf      = AllocateAlignedZeroPool(MaxScratchpadBufs * sizeof (UINT64), Xhc->PageSize);\r
+    ASSERT (ScratchBuf != NULL);\r
+    Xhc->ScratchBuf = ScratchBuf;\r
+\r
+    for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
+      ScratchEntryBuf = AllocateAlignedZeroPool(Xhc->PageSize, Xhc->PageSize);\r
+      *ScratchBuf++   = (UINT64)(UINTN)ScratchEntryBuf;\r
+    }\r
+\r
+    //\r
+    // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
+    // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
+    //\r
+    *(UINT64 *)Dcbaa = (UINT64)(UINTN)Xhc->ScratchBuf;\r
+  }\r
+\r
+  //\r
+  // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
+  // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
+  //\r
+  Xhc->DCBAA     = (UINT64 *)(UINTN)Dcbaa;\r
+  XhcWriteOpReg64 (Xhc, XHC_DCBAAP_OFFSET, (UINT64)Xhc->DCBAA);\r
+  DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)Xhc->DCBAA));\r
+\r
+  //\r
+  // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
+  // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
+  // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
+  // always be '0'.\r
+  //\r
+  CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
+  //\r
+  // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
+  // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
+  // So we set RCS as inverted PCS init value to let Command Ring empty\r
+  //\r
+  CmdRing  = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;\r
+  ASSERT ((CmdRing & 0x3F) == 0);\r
+  CmdRing |= XHC_CRCR_RCS;\r
+  XhcWriteOpReg64 (Xhc, XHC_CRCR_OFFSET, CmdRing);\r
+\r
+  DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
+\r
+  //\r
+  // Disable the 'interrupter enable' bit in USB_CMD\r
+  // and clear IE & IP bit in all Interrupter X Management Registers.\r
+  //\r
+  XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
+  for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
+    XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
+    XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
+  }\r
+\r
+  //\r
+  // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
+  //\r
+  CreateEventRing (Xhc, CMD_INTER, &Xhc->CmdEventRing);\r
+  CreateEventRing (Xhc, CTRL_INTER, &Xhc->CtrlTrEventRing);\r
+  CreateEventRing (Xhc, BULK_INTER, &Xhc->BulkTrEventRing);\r
+  CreateEventRing (Xhc, INT_INTER,  &Xhc->IntTrEventRing);\r
+  CreateEventRing (Xhc, INT_INTER_ASYNC,  &Xhc->AsynIntTrEventRing);\r
+}\r
+\r
+/**\r
+  System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
+  condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
+  Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
+  reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
+  Stopped to the Running state.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  Urb                   The urb which makes the endpoint halted.\r
+\r
+  @retval EFI_SUCCESS           The recovery is successful.\r
+  @retval Others                Failed to recovery halted endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcRecoverHaltedEndpoint (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  URB                 *Urb\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EVT_TRB_COMMAND            *EvtTrb;\r
+  CMD_TRB_RESET_ED           CmdTrbResetED;\r
+  CMD_SET_TR_DEQ             CmdSetTRDeq;\r
+  UINT8                      Dci;\r
+  UINT8                      SlotId;\r
+\r
+  Status     = EFI_SUCCESS;\r
+  SlotId     = XhcDevAddrToSlotId(Urb->Ep.DevAddr);\r
+  Dci        = XhcEndpointToDci(Urb->Ep.EpAddr, Urb->Ep.Direction);\r
+\r
+  DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));\r
+\r
+  //\r
+  // 1) Send Reset endpoint command to transit from halt to stop state\r
+  //\r
+  ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
+  CmdTrbResetED.CycleBit = 1;\r
+  CmdTrbResetED.Type     = TRB_TYPE_RESET_ENDPOINT;\r
+  CmdTrbResetED.EDID     = Dci;\r
+  CmdTrbResetED.SlotId   = SlotId;\r
+  Status = XhcCmdTransfer (\r
+             Xhc,\r
+             (TRB *) (UINTN) &CmdTrbResetED,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB **) (UINTN) &EvtTrb\r
+             );\r
+  ASSERT (!EFI_ERROR(Status));\r
+\r
+  //\r
+  // 2)Set dequeue pointer\r
+  //\r
+  ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
+  CmdSetTRDeq.PtrLo    = XHC_LOW_32BIT (Urb->Ring->RingEnqueue) | Urb->Ring->RingPCS;\r
+  CmdSetTRDeq.PtrHi    = XHC_HIGH_32BIT (Urb->Ring->RingEnqueue);\r
+  CmdSetTRDeq.CycleBit = 1;\r
+  CmdSetTRDeq.Type     = TRB_TYPE_SET_TR_DEQUE;\r
+  CmdSetTRDeq.Endpoint = Dci;\r
+  CmdSetTRDeq.SlotId   = SlotId;\r
+  Status = XhcCmdTransfer (\r
+             Xhc,\r
+             (TRB *) (UINTN) &CmdSetTRDeq,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB **) (UINTN) &EvtTrb\r
+             );\r
+  ASSERT (!EFI_ERROR(Status));\r
+\r
+  //\r
+  // 3)Ring the doorbell to transit from stop to active\r
+  //\r
+  XhcRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Create XHCI event ring.\r
+\r
+  @param  Xhc                 The XHCI device.\r
+  @param  EventInterrupter    The interrupter of event.\r
+  @param  EventRing           The created event ring.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CreateEventRing (\r
+  IN  USB_XHCI_DEV          *Xhc,\r
+  IN  UINT8                 EventInterrupter,\r
+  OUT EVENT_RING            *EventRing\r
+  )\r
+{\r
+  VOID                        *Buf;\r
+  EVENT_RING_SEG_TABLE_ENTRY  *ERSTBase;\r
+\r
+  ASSERT (EventRing != NULL);\r
+\r
+  Buf = AllocateAlignedZeroPool(sizeof (TRB) * EVENT_RING_TRB_NUMBER, 64);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+\r
+  EventRing->EventRingSeg0    = Buf;\r
+  EventRing->EventInterrupter = EventInterrupter;\r
+  EventRing->TrbNumber        = EVENT_RING_TRB_NUMBER;\r
+  EventRing->EventRingDequeue = (TRB *) EventRing->EventRingSeg0;\r
+  EventRing->EventRingEnqueue = (TRB *) EventRing->EventRingSeg0;\r
+  //\r
+  // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
+  // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
+  //\r
+  EventRing->EventRingCCS = 1;\r
+\r
+  Buf = AllocateAlignedZeroPool(sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER, 64);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+\r
+  ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
+  EventRing->ERSTBase   = ERSTBase;\r
+  ERSTBase->PtrLo       = XHC_LOW_32BIT (EventRing->EventRingSeg0);\r
+  ERSTBase->PtrHi       = XHC_HIGH_32BIT (EventRing->EventRingSeg0);\r
+  ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
+\r
+  //\r
+  // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
+  //\r
+  XhcWriteRuntimeReg (\r
+    Xhc,\r
+    XHC_ERSTSZ_OFFSET + (32 * EventRing->EventInterrupter),\r
+    ERST_NUMBER\r
+    );\r
+  //\r
+  // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
+  //\r
+  XhcWriteRuntimeReg64 (\r
+    Xhc,\r
+    XHC_ERDP_OFFSET + (32 * EventRing->EventInterrupter),\r
+    (UINT64)EventRing->EventRingDequeue\r
+    );\r
+  //\r
+  // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)\r
+  //\r
+  XhcWriteRuntimeReg64 (\r
+    Xhc,\r
+    XHC_ERSTBA_OFFSET + (32 * EventRing->EventInterrupter),\r
+    (UINT64) ERSTBase\r
+    );\r
+  //\r
+  // Need set IMAN IE bit to enble the ring interrupt\r
+  //\r
+  XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (32 * EventRing->EventInterrupter), XHC_IMAN_IE);\r
+}\r
+\r
+/**\r
+  Create XHCI transfer ring.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  TrbNum            The number of TRB in the ring.\r
+  @param  TransferRing           The created transfer ring.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CreateTransferRing (\r
+  IN  USB_XHCI_DEV          *Xhc,\r
+  IN  UINTN                 TrbNum,\r
+  OUT TRANSFER_RING         *TransferRing\r
+  )\r
+{\r
+  VOID                  *Buf;\r
+  LNK_TRB               *EndTrb;\r
+\r
+  Buf = AllocateAlignedZeroPool(sizeof (TRB) * TrbNum, 64);\r
+  ASSERT (Buf != NULL);\r
+  ASSERT (((UINTN) Buf & 0x3F) == 0);\r
+\r
+  TransferRing->RingSeg0     = Buf;\r
+  TransferRing->TrbNumber    = TrbNum;\r
+  TransferRing->RingEnqueue  = (TRB *) TransferRing->RingSeg0;\r
+  TransferRing->RingDequeue  = (TRB *) TransferRing->RingSeg0;\r
+  TransferRing->RingPCS      = 1;\r
+  //\r
+  // 4.9.2 Transfer Ring Management\r
+  // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
+  // point to the first TRB in the ring.\r
+  //\r
+  EndTrb        = (LNK_TRB*) ((UINTN)Buf + sizeof (TRB) * (TrbNum - 1));\r
+  EndTrb->Type  = TRB_TYPE_LINK;\r
+  EndTrb->PtrLo = XHC_LOW_32BIT (Buf);\r
+  EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);\r
+  //\r
+  // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
+  //\r
+  EndTrb->TC    = 1;\r
+  //\r
+  // Set Cycle bit as other TRB PCS init value\r
+  //\r
+  EndTrb->CycleBit = 0;\r
+}\r
+\r
+/**\r
+  Free XHCI event ring.\r
+\r
+  @param  Xhc                 The XHCI device.\r
+  @param  EventRing           The event ring to be freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcFreeEventRing (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  EVENT_RING          *EventRing\r
+)\r
+{\r
+  UINT8                         Index;\r
+  EVENT_RING_SEG_TABLE_ENTRY    *TablePtr;\r
+  VOID                          *RingBuf;\r
+  EVENT_RING_SEG_TABLE_ENTRY    *EventRingPtr;\r
+  UINTN                         InterrupterTarget;\r
+\r
+  if(EventRing->EventRingSeg0 == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  InterrupterTarget = EventRing->EventInterrupter;\r
+  //\r
+  // Get the Event Ring Segment Table base address\r
+  //\r
+  TablePtr = (EVENT_RING_SEG_TABLE_ENTRY *)(EventRing->ERSTBase);\r
+\r
+  //\r
+  // Get all the TRBs Ring and release\r
+  //\r
+  for (Index = 0; Index < ERST_NUMBER; Index++) {\r
+    EventRingPtr = TablePtr + Index;\r
+    RingBuf      = (VOID *)(UINTN)(EventRingPtr->PtrLo | ((UINT64)EventRingPtr->PtrHi << 32));\r
+\r
+    if(RingBuf != NULL) {\r
+      FreeAlignedPool (RingBuf);\r
+      ZeroMem (EventRingPtr, sizeof (EVENT_RING_SEG_TABLE_ENTRY));\r
+    }\r
+  }\r
+\r
+  FreeAlignedPool (TablePtr);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free the resouce allocated at initializing schedule.\r
+\r
+  @param  Xhc        The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcFreeSched (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  )\r
+{\r
+  UINT32    Index;\r
+\r
+  if (Xhc->ScratchBuf != NULL) {\r
+    for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
+      FreeAlignedPool ((VOID*)(UINTN)*Xhc->ScratchBuf++);\r
+    }\r
+  }\r
+\r
+  if (Xhc->DCBAA != NULL) {\r
+    FreeAlignedPool (Xhc->DCBAA);\r
+    Xhc->DCBAA = NULL;\r
+  }\r
+\r
+  if (Xhc->CmdRing.RingSeg0 != NULL){\r
+    FreeAlignedPool (Xhc->CmdRing.RingSeg0);\r
+    Xhc->CmdRing.RingSeg0 = NULL;\r
+  }\r
+  XhcFreeEventRing (Xhc,&Xhc->CmdEventRing);\r
+  XhcFreeEventRing (Xhc,&Xhc->CtrlTrEventRing);\r
+  XhcFreeEventRing (Xhc,&Xhc->BulkTrEventRing);\r
+  XhcFreeEventRing (Xhc,&Xhc->AsynIntTrEventRing);\r
+  XhcFreeEventRing (Xhc,&Xhc->IntTrEventRing);\r
+}\r
+\r
+/**\r
+  Check if it is ring TRB.\r
+\r
+  @param Ring   The transfer ring\r
+  @param Trb    The TRB to check if it's in the transfer ring\r
+\r
+  @retval TRUE  It is in the ring\r
+  @retval FALSE It is not in the ring\r
+\r
+**/\r
+BOOLEAN\r
+IsTransferRingTrb (\r
+  IN  TRANSFER_RING       *Ring,\r
+  IN  TRB                 *Trb\r
+  )\r
+{\r
+  BOOLEAN       Flag;\r
+  TRB           *Trb1;\r
+  UINTN         Index;\r
+\r
+  Trb1 = Ring->RingSeg0;\r
+  Flag = FALSE;\r
+\r
+  ASSERT (Ring->TrbNumber == CMD_RING_TRB_NUMBER || Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
+\r
+  for (Index = 0; Index < Ring->TrbNumber; Index++) {\r
+    if (Trb == Trb1) {\r
+      Flag = TRUE;\r
+      break;\r
+    }\r
+    Trb1++;\r
+  }\r
+\r
+  return Flag;\r
+}\r
+\r
+/**\r
+  Check the URB's execution result and update the URB's\r
+  result accordingly.\r
+\r
+  @param  Xhc             The XHCI device.\r
+  @param  Urb             The URB to check result.\r
+\r
+  @return Whether the result of URB transfer is finialized.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcCheckUrbResult (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  URB                 *Urb\r
+  )\r
+{\r
+  BOOLEAN                 StartDone;\r
+  BOOLEAN                 EndDone;\r
+  EVT_TRB_TRANSFER        *EvtTrb;\r
+  TRB                     *TRBPtr;\r
+  UINTN                   Index;\r
+  UINT8                   TRBType;\r
+  EFI_STATUS              Status;\r
+\r
+  ASSERT ((Xhc != NULL) && (Urb != NULL));\r
+\r
+  Urb->Completed  = 0;\r
+  Urb->Result     = EFI_USB_NOERROR;\r
+  Status          = EFI_SUCCESS;\r
+  EvtTrb          = NULL;\r
+\r
+  if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
+    Urb->Result |= EFI_USB_ERR_SYSTEM;\r
+    Status       = EFI_DEVICE_ERROR;\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Restore the EventRingDequeue and poll the transfer event ring from beginning\r
+  //\r
+  StartDone = FALSE;\r
+  EndDone   = FALSE;\r
+  Urb->EvtRing->EventRingDequeue = Urb->EvtTrbStart;\r
+  for (Index = 0; Index < Urb->EvtRing->TrbNumber; Index++) {\r
+    XhcSyncEventRing (Xhc, Urb->EvtRing);\r
+    Status = XhcCheckNewEvent (Xhc, Urb->EvtRing, &(TRB *)EvtTrb);\r
+    if (Status == EFI_NOT_READY) {\r
+      Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
+      goto EXIT;\r
+    }\r
+\r
+    TRBPtr = (TRB *)(UINTN)(EvtTrb->TRBPtrLo | (UINT64) EvtTrb->TRBPtrHi << 32);\r
+\r
+    switch (EvtTrb->Completcode) {\r
+      case TRB_COMPLETION_STALL_ERROR:\r
+        Urb->Result |= EFI_USB_ERR_STALL;\r
+        Status       = EFI_DEVICE_ERROR;\r
+        DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completcode = %x\n",EvtTrb->Completcode));\r
+        goto EXIT;\r
+        break;\r
+\r
+      case TRB_COMPLETION_BABBLE_ERROR:\r
+        Urb->Result |= EFI_USB_ERR_BABBLE;\r
+        Status       = EFI_DEVICE_ERROR;\r
+        DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completcode = %x\n",EvtTrb->Completcode));\r
+        goto EXIT;\r
+        break;\r
+\r
+      case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
+        Urb->Result |= EFI_USB_ERR_BUFFER;\r
+        Status       = EFI_DEVICE_ERROR;\r
+        DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completcode = %x\n",EvtTrb->Completcode));\r
+        goto EXIT;\r
+        break;\r
+\r
+      case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
+        Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
+        Status       = EFI_DEVICE_ERROR;\r
+        DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completcode = %x\n",EvtTrb->Completcode));\r
+        goto EXIT;\r
+        break;\r
+\r
+      case TRB_COMPLETION_SHORT_PACKET:\r
+      case TRB_COMPLETION_SUCCESS:\r
+        if (IsTransferRingTrb (Urb->Ring, TRBPtr)) {\r
+          if (EvtTrb->Completcode == TRB_COMPLETION_SHORT_PACKET) {\r
+            DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));\r
+          }\r
+          TRBType = (UINT8) (TRBPtr->Type);\r
+          if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
+              (TRBType == TRB_TYPE_NORMAL) ||\r
+              (TRBType == TRB_TYPE_ISOCH)) {\r
+            Urb->Completed += (Urb->DataLen - EvtTrb->Lenth);\r
+          }\r
+        }\r
+        Status = EFI_SUCCESS;\r
+        break;\r
+\r
+      default:\r
+        DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completcode = 0x%x!\n",EvtTrb->Completcode));\r
+        Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto EXIT;\r
+        break;\r
+    }\r
+\r
+    //\r
+    // Only check first and end Trb event address\r
+    //\r
+    if (TRBPtr == Urb->TrbStart) {\r
+      StartDone = TRUE;\r
+    }\r
+\r
+    if (TRBPtr == Urb->TrbEnd) {\r
+      EndDone = TRUE;\r
+    }\r
+\r
+    if (StartDone && EndDone) {\r
+      break;\r
+    }\r
+  }\r
+\r
+EXIT:\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  CmdTransfer       The executed URB is for cmd transfer or not.\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
+XhcExecTransfer (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  BOOLEAN             CmdTransfer,\r
+  IN  URB                 *Urb,\r
+  IN  UINTN               TimeOut\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   Index;\r
+  UINTN                   Loop;\r
+  UINT8                   SlotId;\r
+  UINT8                   Dci;\r
+\r
+  if (CmdTransfer) {\r
+    SlotId = 0;\r
+    Dci    = 0;\r
+  } else {\r
+    SlotId = XhcDevAddrToSlotId(Urb->Ep.DevAddr);\r
+    Dci    = XhcEndpointToDci(Urb->Ep.EpAddr, Urb->Ep.Direction);\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  Loop   = (TimeOut * XHC_1_MILLISECOND / XHC_SYNC_POLL_INTERVAL) + 1;\r
+  if (TimeOut == 0) {\r
+    Loop = 0xFFFFFFFF;\r
+  }\r
+\r
+  XhcRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+  for (Index = 0; Index < Loop; Index++) {\r
+    Status = XhcCheckUrbResult (Xhc, Urb);\r
+    if ((Status != EFI_NOT_READY)) {\r
+      break;\r
+    }\r
+    gBS->Stall (XHC_SYNC_POLL_INTERVAL);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Delete a single asynchronous interrupt transfer for\r
+  the device and endpoint.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  DevAddr               The address of the target device.\r
+  @param  EpNum                 The endpoint of the target.\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
+XhciDelAsyncIntTransfer (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               EpNum\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *Next;\r
+  URB                     *Urb;\r
+  EFI_USB_DATA_DIRECTION  Direction;\r
+  BOOLEAN                 Found;\r
+\r
+  Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
+  EpNum    &= 0x0F;\r
+\r
+  Found = FALSE;\r
+  Urb   = NULL;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+    if ((Urb->Ep.DevAddr == DevAddr) &&\r
+        (Urb->Ep.EpAddr == EpNum) &&\r
+        (Urb->Ep.Direction == Direction)) {\r
+      RemoveEntryList (&Urb->UrbList);\r
+      FreePool (Urb->Data);\r
+      FreePool (Urb);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Remove all the asynchronous interrutp transfers.\r
+\r
+  @param  Xhc    The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhciDelAllAsyncIntTransfers (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *Next;\r
+  URB                     *Urb;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+    RemoveEntryList (&Urb->UrbList);\r
+    FreePool (Urb->Data);\r
+    FreePool (Urb);\r
+  }\r
+}\r
+\r
+/**\r
+  Update the queue head for next round of asynchronous transfer\r
+\r
+  @param  Xhc     The XHCI device.\r
+  @param  Urb     The URB to update\r
+\r
+**/\r
+VOID\r
+XhcUpdateAsyncRequest (\r
+  IN USB_XHCI_DEV*            Xhc,\r
+  IN URB                      *Urb\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  if (Urb->Result == EFI_USB_NOERROR) {\r
+    Status = XhcCreateTransferTrb (Xhc, Urb);\r
+    ASSERT_EFI_ERROR (Status);\r
+    Status = RingIntTransferDoorBell (Xhc, Urb);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Interrupt transfer periodic check handler.\r
+\r
+  @param  Event                 Interrupt event.\r
+  @param  Context               Pointer to USB_XHCI_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+XhcMonitorAsyncRequests (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+{\r
+  USB_XHCI_DEV            *Xhc;\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *Next;\r
+  UINT8                   *ProcBuf;\r
+  URB                     *Urb;\r
+  UINT8                   SlotId;\r
+  EFI_STATUS              Status;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+\r
+  Xhc    = (USB_XHCI_DEV*) Context;\r
+\r
+  EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
+    Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+\r
+    //\r
+    // Make sure that the device is available before every check.\r
+    //\r
+    SlotId = XhcDevAddrToSlotId(Urb->Ep.DevAddr);\r
+    if (SlotId == 0) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Check the result of URB execution. If it is still\r
+    // active, check the next one.\r
+    //\r
+    Status = XhcCheckUrbResult (Xhc, Urb);\r
+\r
+    if (Status == EFI_NOT_READY) {\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
+    if (Urb->Result == EFI_USB_NOERROR) {\r
+      ASSERT (Urb->Completed <= Urb->DataLen);\r
+\r
+      ProcBuf = AllocatePool (Urb->Completed);\r
+\r
+      if (ProcBuf == NULL) {\r
+        XhcUpdateAsyncRequest (Xhc, Urb);\r
+        continue;\r
+      }\r
+\r
+      CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
+    }\r
+\r
+    XhcUpdateAsyncRequest (Xhc, 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 (XHC_TPL);\r
+    }\r
+\r
+    if (ProcBuf != NULL) {\r
+      gBS->FreePool (ProcBuf);\r
+    }\r
+  }\r
+  gBS->RestoreTPL (OldTpl);\r
+}\r
+\r
+/**\r
+  Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  ParentRouteChart      The route string pointed to the parent device if it exists.\r
+  @param  Port                  The port to be polled.\r
+  @param  PortState             The port state.\r
+\r
+  @retval EFI_SUCCESS           Successfully enable/disable device slot according to port state.\r
+  @retval Others                Should not appear.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPollPortStatusChange (\r
+  IN  USB_XHCI_DEV*         Xhc,\r
+  IN  USB_DEV_ROUTE         ParentRouteChart,\r
+  IN  UINT8                 Port,\r
+  IN  EFI_USB_PORT_STATUS   *PortState\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  UINT8             Speed;\r
+  UINT8             SlotId;\r
+  USB_DEV_ROUTE     RouteChart;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (ParentRouteChart.Dword == 0) {\r
+    RouteChart.Field.RouteString = 0;\r
+    RouteChart.Field.RootPortNum = Port + 1;\r
+    RouteChart.Field.TierNum     = 1;\r
+  } else {\r
+    if(Port < 14) {\r
+      RouteChart.Field.RouteString = ParentRouteChart.Field.RouteString | (Port << (4 * (ParentRouteChart.Field.TierNum - 1)));\r
+    } else {\r
+      RouteChart.Field.RouteString = ParentRouteChart.Field.RouteString | (15 << (4 * (ParentRouteChart.Field.TierNum - 1)));\r
+    }\r
+    RouteChart.Field.RootPortNum   = ParentRouteChart.Field.RootPortNum;\r
+    RouteChart.Field.TierNum       = ParentRouteChart.Field.TierNum + 1;\r
+  }\r
+\r
+  if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
+      ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
+    //\r
+    // Has a device attached, Identify device speed after port is enabled.\r
+    //\r
+    Speed = EFI_USB_SPEED_FULL;\r
+    if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
+      Speed = EFI_USB_SPEED_LOW;\r
+    } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
+      Speed = EFI_USB_SPEED_HIGH;\r
+    } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
+      Speed = EFI_USB_SPEED_SUPER;\r
+    }\r
+    //\r
+    // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
+    //\r
+    SlotId = XhcRouteStringToSlotId (RouteChart);\r
+    if (SlotId == 0) {\r
+      Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+  } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {\r
+    //\r
+    // Device is detached. Disable the allocated device slot and release resource.\r
+    //\r
+    SlotId = XhcRouteStringToSlotId (RouteChart);\r
+    if (SlotId != 0) {\r
+      Status = XhcDisableSlotCmd (Xhc, SlotId);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Calculate the device context index by endpoint address and direction.\r
+\r
+  @param  EpAddr              The target endpoint number.\r
+  @param  Direction           The direction of the target endpoint.\r
+\r
+  @return The device context index of endpoint.\r
+\r
+**/\r
+UINT8\r
+XhcEndpointToDci (\r
+  IN  UINT8                   EpAddr,\r
+  IN  UINT8                   Direction\r
+  )\r
+{\r
+  UINT8 Index;\r
+\r
+  if (EpAddr == 0) {\r
+    return 1;\r
+  } else {\r
+    Index = 2 * EpAddr;\r
+    if (Direction == EfiUsbDataIn) {\r
+      Index += 1;\r
+    }\r
+    return Index;\r
+  }\r
+}\r
+\r
+/**\r
+  Find out the slot id according to device address assigned by XHCI's Address_Device cmd.\r
+\r
+  @param  DevAddr         The device address of the target device.\r
+\r
+  @return The slot id used by the device.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+XhcDevAddrToSlotId (\r
+  IN  UINT8       DevAddr\r
+  )\r
+{\r
+  UINT8  Index;\r
+\r
+  for (Index = 0; Index < 255; Index++) {\r
+    if (UsbDevContext[Index + 1].Enabled &&\r
+        (UsbDevContext[Index + 1].SlotId != 0) &&\r
+        (UsbDevContext[Index + 1].XhciDevAddr == DevAddr)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == 255) {\r
+    return 0;\r
+  }\r
+\r
+  return UsbDevContext[Index + 1].SlotId;\r
+}\r
+\r
+/**\r
+  Find out the actual device address according to the requested device address from UsbBus.\r
+\r
+  @param  BusDevAddr       The requested device address by UsbBus upper driver.\r
+\r
+  @return The actual device address assigned to the device.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+XhcBusDevAddrToSlotId (\r
+  IN  UINT8       BusDevAddr\r
+  )\r
+{\r
+  UINT8  Index;\r
+\r
+  for (Index = 0; Index < 255; Index++) {\r
+    if (UsbDevContext[Index + 1].Enabled &&\r
+        (UsbDevContext[Index + 1].SlotId != 0) &&\r
+        (UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == 255) {\r
+    return 0;\r
+  }\r
+\r
+  return UsbDevContext[Index + 1].SlotId;\r
+}\r
+\r
+/**\r
+  Find out the slot id according to the device's route string.\r
+\r
+  @param  RouteString      The route string described the device location.\r
+\r
+  @return The slot id used by the device.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+XhcRouteStringToSlotId (\r
+  IN  USB_DEV_ROUTE     RouteString\r
+  )\r
+{\r
+  UINT8  Index;\r
+\r
+  for (Index = 0; Index < 255; Index++) {\r
+    if (UsbDevContext[Index + 1].Enabled &&\r
+        (UsbDevContext[Index + 1].SlotId != 0) &&\r
+        (UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == 255) {\r
+    return 0;\r
+  }\r
+\r
+  return UsbDevContext[Index + 1].SlotId;\r
+}\r
+\r
+/**\r
+  Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Xhc         The XHCI device.\r
+  @param  EvtRing     The event ring to sync.\r
+\r
+  @retval EFI_SUCCESS The event ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSyncEventRing (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN EVENT_RING           *EvtRing\r
+  )\r
+{\r
+  UINTN               Index;\r
+  TRB                 *EvtTrb1;\r
+  TRB                 *EvtTrb2;\r
+  TRB                 *XhcDequeue;\r
+\r
+  ASSERT (EvtRing != NULL);\r
+\r
+  //\r
+  // Calculate the EventRingEnqueue and EventRingCCS.\r
+  // Note: only support single Segment\r
+  //\r
+  EvtTrb1 = EvtRing->EventRingSeg0;\r
+  EvtTrb2 = EvtRing->EventRingSeg0;\r
+\r
+  for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
+    if (EvtTrb1->CycleBit != EvtTrb2->CycleBit) {\r
+      break;\r
+    }\r
+    EvtTrb1++;\r
+  }\r
+\r
+  if (Index < EvtRing->TrbNumber) {\r
+    EvtRing->EventRingEnqueue = EvtTrb1;\r
+    EvtRing->EventRingCCS     = (EvtTrb2->CycleBit) ? 1 : 0;\r
+  } else {\r
+    EvtRing->EventRingEnqueue = EvtTrb2;\r
+    EvtRing->EventRingCCS     = (EvtTrb2->CycleBit) ? 0 : 1;\r
+  }\r
+\r
+  //\r
+  // Apply the EventRingDequeue to Xhc\r
+  //\r
+  XhcDequeue = (TRB *)(UINTN) XhcReadRuntimeReg64 (\r
+                                Xhc,\r
+                                XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter)\r
+                                );\r
+\r
+  if (((UINT64) XhcDequeue & (~0x0F)) != ((UINT64) EvtRing->EventRingDequeue & (~0x0F))) {\r
+    XhcWriteRuntimeReg64 (\r
+      Xhc,\r
+      XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter),\r
+      (UINT64)EvtRing->EventRingDequeue | BIT3\r
+      );\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Xhc         The XHCI device.\r
+  @param  TrsRing     The transfer ring to sync.\r
+\r
+  @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSyncTrsRing (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN TRANSFER_RING        *TrsRing\r
+  )\r
+{\r
+  UINTN               Index;\r
+  TRB                 *TrsTrb;\r
+\r
+  ASSERT (TrsRing != NULL);\r
+  //\r
+  // Calculate the latest RingEnqueue and RingPCS\r
+  //\r
+  TrsTrb = TrsRing->RingEnqueue;\r
+  ASSERT (TrsTrb != NULL);\r
+\r
+  for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
+    if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
+      break;\r
+    }\r
+    TrsTrb++;\r
+    if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
+      ASSERT (((LNK_TRB*)TrsTrb)->TC != 0);\r
+      //\r
+      // set cycle bit in Link TRB as normal\r
+      //\r
+      ((LNK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
+      //\r
+      // Toggle PCS maintained by software\r
+      //\r
+      TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
+      TrsTrb           = (TRB*)(UINTN)((TrsTrb->Dword1 | ((UINT64)TrsTrb->Dword2 << 32)) & ~0x0F);\r
+    }\r
+  }\r
+\r
+  ASSERT (Index != TrsRing->TrbNumber);\r
+\r
+  if (TrsTrb != TrsRing->RingEnqueue) {\r
+    TrsRing->RingEnqueue = TrsTrb;\r
+  }\r
+\r
+  //\r
+  // Clear the Trb context for enqueue, but reserve the PCS bit\r
+  //\r
+  TrsTrb->Dword1  = 0;\r
+  TrsTrb->Dword2  = 0;\r
+  TrsTrb->Dword3  = 0;\r
+  TrsTrb->RsvdZ1  = 0;\r
+  TrsTrb->Type    = 0;\r
+  TrsTrb->RsvdZ2  = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check if there is a new generated event.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  EvtRing       The event ring to check.\r
+  @param  NewEvtTrb     The new event TRB found.\r
+\r
+  @retval EFI_SUCCESS   Found a new event TRB at the event ring.\r
+  @retval EFI_NOT_READY The event ring has no new event.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcCheckNewEvent (\r
+  IN  USB_XHCI_DEV            *Xhc,\r
+  IN  EVENT_RING              *EvtRing,\r
+  OUT TRB                     **NewEvtTrb\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  TRB         *EvtTrb;\r
+\r
+  ASSERT (EvtRing != NULL);\r
+\r
+  EvtTrb     = EvtRing->EventRingDequeue;\r
+  *NewEvtTrb = EvtRing->EventRingDequeue;\r
+\r
+  if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (((EvtTrb->Dword3 >> 24) & 0xFF) != TRB_COMPLETION_SUCCESS) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  EvtRing->EventRingDequeue++;\r
+  //\r
+  // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
+  //\r
+  if ((UINTN)EvtRing->EventRingDequeue >=  ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB) * EvtRing->TrbNumber)) {\r
+    EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Ring the door bell to notify XHCI there is a transaction to be executed.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+\r
+  @retval EFI_SUCCESS   Successfully ring the door bell.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcRingDoorBell (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT8                SlotId,\r
+  IN UINT8                Dci\r
+  )\r
+{\r
+  if (SlotId == 0) {\r
+    XhcWriteDoorBellReg (Xhc, 0, 0);\r
+  } else {\r
+    XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Urb           The URB to be rung.\r
+\r
+  @retval EFI_SUCCESS   Successfully ring the door bell.\r
+\r
+**/\r
+EFI_STATUS\r
+RingIntTransferDoorBell (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  URB                 *Urb\r
+  )\r
+{\r
+  UINT8                SlotId;\r
+  UINT8                Dci;\r
+\r
+  SlotId = XhcDevAddrToSlotId(Urb->Ep.DevAddr);\r
+  Dci    = XhcEndpointToDci(Urb->Ep.EpAddr, Urb->Ep.Direction);\r
+  XhcRingDoorBell (Xhc, SlotId, Dci);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Assign and initialize the device slot for a new device.\r
+\r
+  @param  Xhc                 The XHCI device.\r
+  @param  ParentRouteChart    The route string pointed to the parent device.\r
+  @param  ParentPort          The port at which the device is located.\r
+  @param  RouteChart          The route string pointed to the device.\r
+  @param  DeviceSpeed         The device speed.\r
+\r
+  @retval EFI_SUCCESS   Successfully assign a slot to the device and assign an address to it.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcInitializeDeviceSlot (\r
+  IN  USB_XHCI_DEV              *Xhc,\r
+  IN  USB_DEV_ROUTE             ParentRouteChart,\r
+  IN  UINT16                    ParentPort,\r
+  IN  USB_DEV_ROUTE             RouteChart,\r
+  IN  UINT8                     DeviceSpeed\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EVT_TRB_COMMAND       *EvtTrb;\r
+  INPUT_CONTEXT         *InputContext;\r
+  DEVICE_CONTEXT        *OutputDevContxt;\r
+  TRANSFER_RING         *EndpointTransferRing;\r
+  CMD_TRB_ADDR_DEV      CmdTrbAddr;\r
+  UINT8                 DeviceAddress;\r
+  CMD_TRB_EN_SLOT       CmdTrb;\r
+  UINT8                 SlotId;\r
+  UINT8                 ParentSlotId;\r
+  DEVICE_CONTEXT        *ParentDeviceContext;\r
+\r
+  ZeroMem (&CmdTrb, sizeof (CMD_TRB_EN_SLOT));\r
+  CmdTrb.CycleBit = 1;\r
+  CmdTrb.Type     = TRB_TYPE_EN_SLOT;\r
+\r
+  Status = XhcCmdTransfer (\r
+              Xhc,\r
+              (TRB *) (UINTN) &CmdTrb,\r
+              XHC_GENERIC_TIMEOUT,\r
+              (TRB **) (UINTN) &EvtTrb\r
+              );\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
+  DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
+  SlotId = (UINT8)EvtTrb->SlotId;\r
+  ASSERT (SlotId != 0);\r
+\r
+  ZeroMem (&UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
+  UsbDevContext[SlotId].Enabled                 = TRUE;\r
+  UsbDevContext[SlotId].SlotId                  = SlotId;\r
+  UsbDevContext[SlotId].RouteString.Dword       = RouteChart.Dword;\r
+  UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
+\r
+  //\r
+  // 4.3.3 Device Slot Initialization\r
+  // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
+  //\r
+  InputContext = AllocateAlignedZeroPool(sizeof (INPUT_CONTEXT), 64);\r
+  ASSERT (InputContext != NULL);\r
+  ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
+\r
+  UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
+\r
+  //\r
+  // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
+  //    flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
+  //    Context are affected by the command.\r
+  //\r
+  InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
+\r
+  //\r
+  // 3) Initialize the Input Slot Context data structure\r
+  //\r
+  InputContext->Slot.RouteStr       = RouteChart.Field.RouteString;\r
+  InputContext->Slot.Speed          = DeviceSpeed + 1;\r
+  InputContext->Slot.ContextEntries = 1;\r
+  InputContext->Slot.RootHubPortNum = RouteChart.Field.RootPortNum;\r
+\r
+  if (RouteChart.Field.RouteString) {\r
+    //\r
+    // The device is behind of hub device.\r
+    //\r
+    ParentSlotId = XhcRouteStringToSlotId(ParentRouteChart);\r
+    ASSERT (ParentSlotId != 0);\r
+    //\r
+    //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
+    //\r
+    ParentDeviceContext = (DEVICE_CONTEXT *)UsbDevContext[ParentSlotId].OutputDevContxt;\r
+    if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
+        (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
+      if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
+        //\r
+        // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
+        // environment from Full/Low speed signaling environment for a device\r
+        //\r
+        InputContext->Slot.TTPortNum   = ParentPort;\r
+        InputContext->Slot.TTHubSlotId = ParentSlotId;\r
+      }\r
+    } else {\r
+      //\r
+      // Inherit the TT parameters from parent device.\r
+      //\r
+      InputContext->Slot.TTPortNum   = ParentDeviceContext->Slot.TTPortNum;\r
+      InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
+      //\r
+      // If the device is a High speed device then down the speed to be the same as its parent Hub\r
+      //\r
+      if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+        InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
+  //\r
+  EndpointTransferRing = AllocateAlignedZeroPool(sizeof (TRANSFER_RING), 64);\r
+  UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
+  CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)UsbDevContext[SlotId].EndpointTransferRing[0]);\r
+  //\r
+  // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
+  //\r
+  InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
+\r
+  if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+    InputContext->EP[0].MaxPacketSize = 512;\r
+  } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+    InputContext->EP[0].MaxPacketSize = 64;\r
+  } else {\r
+    InputContext->EP[0].MaxPacketSize = 8;\r
+  }\r
+  //\r
+  // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
+  // 1KB, and Bulk and Isoch endpoints 3KB.\r
+  //\r
+  InputContext->EP[0].AverageTRBLength = 8;\r
+  InputContext->EP[0].MaxBurstSize     = 0;\r
+  InputContext->EP[0].Interval         = 0;\r
+  InputContext->EP[0].MaxPStreams      = 0;\r
+  InputContext->EP[0].Mult             = 0;\r
+  InputContext->EP[0].CErr             = 3;\r
+\r
+  //\r
+  // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
+  //\r
+  InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0;\r
+  InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0);\r
+\r
+  //\r
+  // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
+  //\r
+  OutputDevContxt = AllocateAlignedZeroPool(sizeof (DEVICE_CONTEXT), 64);\r
+  ASSERT (OutputDevContxt != NULL);\r
+  ASSERT (((UINTN) OutputDevContxt & 0x3F) == 0);\r
+\r
+  UsbDevContext[SlotId].OutputDevContxt = OutputDevContxt;\r
+  //\r
+  // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
+  //    a pointer to the Output Device Context data structure (6.2.1).\r
+  //\r
+  Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputDevContxt;\r
+\r
+  //\r
+  // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
+  //    Context data structure described above.\r
+  //\r
+  ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
+  CmdTrbAddr.PtrLo    = XHC_LOW_32BIT (UsbDevContext[SlotId].InputContext);\r
+  CmdTrbAddr.PtrHi    = XHC_HIGH_32BIT (UsbDevContext[SlotId].InputContext);\r
+  CmdTrbAddr.CycleBit = 1;\r
+  CmdTrbAddr.Type     = TRB_TYPE_ADDRESS_DEV;\r
+  CmdTrbAddr.SlotId   = UsbDevContext[SlotId].SlotId;\r
+  Status = XhcCmdTransfer (\r
+             Xhc,\r
+             (TRB *) (UINTN) &CmdTrbAddr,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB **) (UINTN) &EvtTrb\r
+             );\r
+  ASSERT (!EFI_ERROR(Status));\r
+\r
+  DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputDevContxt)->Slot.DeviceAddress;\r
+  DEBUG ((EFI_D_INFO, "    Address %d assigned succeefully\n", DeviceAddress));\r
+\r
+  UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Disable the specified device slot.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be disabled.\r
+\r
+  @retval EFI_SUCCESS   Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcDisableSlotCmd (\r
+  IN USB_XHCI_DEV              *Xhc,\r
+  IN UINT8                     SlotId\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  TRB                   *EvtTrb;\r
+  CMD_TRB_DIS_SLOT      CmdTrbDisSlot;\r
+  UINT8                 Index;\r
+  VOID                  *RingSeg;\r
+\r
+  //\r
+  // Disable the device slots occupied by these devices on its downstream ports.\r
+  // Entry 0 is reserved.\r
+  //\r
+  for (Index = 0; Index < 255; Index++) {\r
+    if (!UsbDevContext[Index + 1].Enabled ||\r
+        (UsbDevContext[Index + 1].SlotId == 0) ||\r
+        (UsbDevContext[Index + 1].ParentRouteString.Dword != UsbDevContext[SlotId].RouteString.Dword)) {\r
+      continue;\r
+    }\r
+\r
+    Status = XhcDisableSlotCmd (Xhc, UsbDevContext[Index + 1].SlotId);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
+      UsbDevContext[Index + 1].SlotId = 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Construct the disable slot command\r
+  //\r
+  DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
+\r
+  ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
+  CmdTrbDisSlot.CycleBit = 1;\r
+  CmdTrbDisSlot.Type     = TRB_TYPE_DIS_SLOT;\r
+  CmdTrbDisSlot.SlotId   = SlotId;\r
+  Status = XhcCmdTransfer (\r
+             Xhc,\r
+             (TRB *) (UINTN) &CmdTrbDisSlot,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB **) (UINTN) &EvtTrb\r
+             );\r
+  ASSERT_EFI_ERROR(Status);\r
+  //\r
+  // Free the slot's device context entry\r
+  //\r
+  Xhc->DCBAA[SlotId] = 0;\r
+\r
+  //\r
+  // Free the slot related data structure\r
+  //\r
+  for (Index = 0; Index < 31; Index++) {\r
+    if (UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
+      RingSeg = ((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
+      if (RingSeg != NULL) {\r
+        FreeAlignedPool(RingSeg);\r
+      }\r
+      FreeAlignedPool(UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
+    }\r
+  }\r
+\r
+  for (Index = 0; Index < UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
+    if (UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
+      FreePool (UsbDevContext[SlotId].ConfDesc[Index]);\r
+    }\r
+  }\r
+\r
+  if (UsbDevContext[SlotId].InputContext != NULL) {\r
+    FreeAlignedPool (UsbDevContext[SlotId].InputContext);\r
+  }\r
+\r
+  if (UsbDevContext[SlotId].OutputDevContxt != NULL) {\r
+    FreeAlignedPool (UsbDevContext[SlotId].OutputDevContxt);\r
+  }\r
+  //\r
+  // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
+  // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
+  // remove urb from XHCI's asynchronous transfer list.\r
+  //\r
+  UsbDevContext[SlotId].Enabled = FALSE;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  DeviceSpeed   The device's speed.\r
+  @param  ConfigDesc    The pointer to the usb device configuration descriptor.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSetConfigCmd (\r
+  IN USB_XHCI_DEV             *Xhc,\r
+  IN UINT8                    SlotId,\r
+  IN  UINT8                   DeviceSpeed,\r
+  IN USB_CONFIG_DESCRIPTOR    *ConfigDesc\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+\r
+  USB_INTERFACE_DESCRIPTOR   *IfDesc;\r
+  USB_ENDPOINT_DESCRIPTOR    *EpDesc;\r
+  UINT8                      Index;\r
+  UINTN                      NumEp;\r
+  UINTN                      EpIndex;\r
+  UINT8                      EpAddr;\r
+  UINT8                      Direction;\r
+  UINT8                      Dci;\r
+  UINT8                      MaxDci;\r
+  UINT32                     PhyAddr;\r
+  UINT8                      Interval;\r
+\r
+  TRANSFER_RING              *EndpointTransferRing;\r
+  CMD_CFG_ED                 CmdTrbCfgEP;\r
+  INPUT_CONTEXT              *InputContext;\r
+  DEVICE_CONTEXT             *OutputDevContxt;\r
+  EVT_TRB_COMMAND            *EvtTrb;\r
+  //\r
+  // 4.6.6 Configure Endpoint\r
+  //\r
+  InputContext    = UsbDevContext[SlotId].InputContext;\r
+  OutputDevContxt = UsbDevContext[SlotId].OutputDevContxt;\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+  CopyMem (&InputContext->Slot, &OutputDevContxt->Slot, sizeof (SLOT_CONTEXT));\r
+\r
+  ASSERT (ConfigDesc != NULL);\r
+\r
+  MaxDci = 0;\r
+\r
+  IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
+  for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
+    while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {\r
+      IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
+    }\r
+\r
+    NumEp = IfDesc->NumEndpoints;\r
+\r
+    EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
+    for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
+      while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
+        EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+      }\r
+\r
+      EpAddr    = EpDesc->EndpointAddress & 0x0F;\r
+      Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+\r
+      Dci = XhcEndpointToDci (EpAddr, Direction);\r
+      if (Dci > MaxDci) {\r
+        MaxDci = Dci;\r
+      }\r
+\r
+      InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
+      InputContext->EP[Dci-1].MaxPacketSize     = EpDesc->MaxPacketSize;\r
+\r
+      if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+        //\r
+        // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
+        //\r
+        InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+      } else {\r
+        InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
+      }\r
+\r
+      switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
+        case USB_ENDPOINT_BULK:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
+          }\r
+\r
+          InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+          if (UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+            EndpointTransferRing = AllocateAlignedZeroPool(sizeof (TRANSFER_RING), 64);\r
+            UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+            CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+          }\r
+\r
+          break;\r
+        case USB_ENDPOINT_ISO:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 0;\r
+            InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 0;\r
+            InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
+          }\r
+          break;\r
+        case USB_ENDPOINT_INTERRUPT:\r
+          if (Direction == EfiUsbDataIn) {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
+          } else {\r
+            InputContext->EP[Dci-1].CErr   = 3;\r
+            InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
+          }\r
+          InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+          InputContext->EP[Dci-1].MaxESITPayload   = EpDesc->MaxPacketSize;\r
+          //\r
+          // Get the bInterval from descriptor and init the the interval field of endpoint context\r
+          //\r
+          if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
+            Interval = EpDesc->Interval;\r
+            //\r
+            // BUGBUG: Hard code the interval to MAX\r
+            //\r
+            InputContext->EP[Dci-1].Interval = 6;\r
+          } else if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
+            Interval = EpDesc->Interval;\r
+            InputContext->EP[Dci-1].Interval         = 0x0F;\r
+            InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
+            InputContext->EP[Dci-1].MaxESITPayload   = 0x0002;\r
+            InputContext->EP[Dci-1].MaxBurstSize     = 0x0;\r
+            InputContext->EP[Dci-1].CErr             = 3;\r
+          }\r
+\r
+          if (UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
+            EndpointTransferRing = AllocateAlignedZeroPool(sizeof (TRANSFER_RING), 64);\r
+            UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
+            CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+          }\r
+          break;\r
+\r
+        case USB_ENDPOINT_CONTROL:\r
+        default:\r
+          ASSERT (0);\r
+          break;\r
+      }\r
+\r
+      PhyAddr  = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);\r
+      PhyAddr &= ~(0x0F);\r
+      PhyAddr |= ((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
+      InputContext->EP[Dci-1].PtrLo = PhyAddr;\r
+      InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);\r
+\r
+      EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+    }\r
+    IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
+  }\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT0;\r
+  InputContext->Slot.ContextEntries         = MaxDci;\r
+  //\r
+  // configure endpoint\r
+  //\r
+  ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+  CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (InputContext);\r
+  CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (InputContext);\r
+  CmdTrbCfgEP.CycleBit = 1;\r
+  CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;\r
+  CmdTrbCfgEP.SlotId   = UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
+  Status = XhcCmdTransfer (\r
+             Xhc,\r
+             (TRB *) (UINTN) &CmdTrbCfgEP,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB **) (UINTN) &EvtTrb\r
+             );\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be evaluated.\r
+  @param  MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+  @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcEvaluateContext (\r
+  IN USB_XHCI_DEV             *Xhc,\r
+  IN UINT8                    SlotId,\r
+  IN UINT32                   MaxPacketSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  CMD_TRB_EVALU_CONTX   CmdTrbEvalu;\r
+  EVT_TRB_COMMAND       *EvtTrb;\r
+  INPUT_CONTEXT         *InputContext;\r
+\r
+  ASSERT (UsbDevContext[SlotId].SlotId != 0);\r
+\r
+  //\r
+  // 4.6.7 Evaluate Context\r
+  //\r
+  InputContext = UsbDevContext[SlotId].InputContext;\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT1;\r
+  InputContext->EP[0].MaxPacketSize         = MaxPacketSize;\r
+\r
+  ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
+  CmdTrbEvalu.PtrLo    = XHC_LOW_32BIT (InputContext);\r
+  CmdTrbEvalu.PtrHi    = XHC_HIGH_32BIT (InputContext);\r
+  CmdTrbEvalu.CycleBit = 1;\r
+  CmdTrbEvalu.Type     = TRB_TYPE_EVALU_CONTXT;\r
+  CmdTrbEvalu.SlotId   = UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
+  Status = XhcCmdTransfer (\r
+             Xhc,\r
+             (TRB *) (UINTN) &CmdTrbEvalu,\r
+             XHC_GENERIC_TIMEOUT,\r
+             (TRB **) (UINTN) &EvtTrb\r
+             );\r
+  ASSERT (!EFI_ERROR(Status));\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  PortNum       The total number of downstream port supported by the hub.\r
+  @param  TTT           The TT think time of the hub device.\r
+  @param  MTT           The multi-TT of the hub device.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcConfigHubContext (\r
+  IN USB_XHCI_DEV             *Xhc,\r
+  IN UINT8                    SlotId,\r
+  IN UINT8                    PortNum,\r
+  IN UINT8                    TTT,\r
+  IN UINT8                    MTT\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+\r
+  EVT_TRB_COMMAND       *EvtTrb;\r
+  INPUT_CONTEXT         *InputContext;\r
+  DEVICE_CONTEXT        *OutputDevContxt;\r
+  CMD_CFG_ED            CmdTrbCfgEP;\r
+\r
+  ASSERT (UsbDevContext[SlotId].SlotId != 0);\r
+  InputContext    = UsbDevContext[SlotId].InputContext;\r
+  OutputDevContxt = UsbDevContext[SlotId].OutputDevContxt;\r
+\r
+  //\r
+  // 4.6.7 Evaluate Context\r
+  //\r
+  ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
+\r
+  InputContext->InputControlContext.Dword2 |= BIT0;\r
+\r
+  //\r
+  // Copy the slot context from OutputContext to Input context\r
+  //\r
+  CopyMem(&(InputContext->Slot), &(OutputDevContxt->Slot), sizeof (SLOT_CONTEXT));\r
+  InputContext->Slot.Hub     = 1;\r
+  InputContext->Slot.PortNum = PortNum;\r
+  InputContext->Slot.TTT     = TTT;\r
+  InputContext->Slot.MTT     = MTT;\r
+\r
+  ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
+  CmdTrbCfgEP.PtrLo    = XHC_LOW_32BIT (InputContext);\r
+  CmdTrbCfgEP.PtrHi    = XHC_HIGH_32BIT (InputContext);\r
+  CmdTrbCfgEP.CycleBit = 1;\r
+  CmdTrbCfgEP.Type     = TRB_TYPE_CON_ENDPOINT;\r
+  CmdTrbCfgEP.SlotId   = UsbDevContext[SlotId].SlotId;\r
+  DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
+  Status = XhcCmdTransfer (\r
+              Xhc,\r
+              (TRB *) (UINTN) &CmdTrbCfgEP,\r
+              XHC_GENERIC_TIMEOUT,\r
+              (TRB **) (UINTN) &EvtTrb\r
+              );\r
+  ASSERT (!EFI_ERROR(Status));\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h
new file mode 100644 (file)
index 0000000..64f6f79
--- /dev/null
@@ -0,0 +1,1117 @@
+/** @file\r
+\r
+  This file contains the definition for XHCI host controller schedule routines.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+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
+#ifndef _EFI_XHCI_SCHED_H_\r
+#define _EFI_XHCI_SCHED_H_\r
+\r
+#define XHC_URB_SIG      SIGNATURE_32 ('U', 'S', 'B', 'R')\r
+\r
+//\r
+// Transfer types, used in URB to identify the transfer type\r
+//\r
+#define XHC_CTRL_TRANSFER                     0x01\r
+#define XHC_BULK_TRANSFER                     0x02\r
+#define XHC_INT_TRANSFER_SYNC                 0x04\r
+#define XHC_INT_TRANSFER_ASYNC                0x08\r
+#define XHC_INT_ONLY_TRANSFER_ASYNC           0x10\r
+\r
+//\r
+// 6.4.6 TRB Types\r
+//\r
+#define TRB_TYPE_NORMAL                       1\r
+#define TRB_TYPE_SETUP_STAGE                  2\r
+#define TRB_TYPE_DATA_STAGE                   3\r
+#define TRB_TYPE_STATUS_STAGE                 4\r
+#define TRB_TYPE_ISOCH                        5\r
+#define TRB_TYPE_LINK                         6\r
+#define TRB_TYPE_EVENT_DATA                   7\r
+#define TRB_TYPE_NO_OP                        8\r
+#define TRB_TYPE_EN_SLOT                      9\r
+#define TRB_TYPE_DIS_SLOT                     10\r
+#define TRB_TYPE_ADDRESS_DEV                  11\r
+#define TRB_TYPE_CON_ENDPOINT                 12\r
+#define TRB_TYPE_EVALU_CONTXT                 13\r
+#define TRB_TYPE_RESET_ENDPOINT               14\r
+#define TRB_TYPE_STOP_ENDPOINT                15\r
+#define TRB_TYPE_SET_TR_DEQUE                 16\r
+#define TRB_TYPE_RESET_DEV                    17\r
+#define TRB_TYPE_GET_PORT_BANW                21\r
+#define TRB_TYPE_FORCE_HEADER                 22\r
+#define TRB_TYPE_NO_OP_COMMAND                23\r
+#define TRB_TYPE_TRANS_EVENT                  32\r
+#define TRB_TYPE_COMMAND_COMPLT_EVENT         33\r
+#define TRB_TYPE_PORT_STATUS_CHANGE_EVENT     34\r
+#define TRB_TYPE_HOST_CONTROLLER_EVENT        37\r
+#define TRB_TYPE_DEVICE_NOTIFI_EVENT          38\r
+#define TRB_TYPE_MFINDEX_WRAP_EVENT           39\r
+\r
+//\r
+// Endpoint Type (EP Type).\r
+//\r
+#define ED_NOT_VALID                          0\r
+#define ED_ISOCH_OUT                          1\r
+#define ED_BULK_OUT                           2\r
+#define ED_INTERRUPT_OUT                      3\r
+#define ED_CONTROL_BIDIR                      4\r
+#define ED_ISOCH_IN                           5\r
+#define ED_BULK_IN                            6\r
+#define ED_INTERRUPT_IN                       7\r
+\r
+//\r
+// 6.4.5 TRB Completion Codes\r
+//\r
+#define TRB_COMPLETION_INVALID                0\r
+#define TRB_COMPLETION_SUCCESS                1\r
+#define TRB_COMPLETION_DATA_BUFFER_ERROR      2\r
+#define TRB_COMPLETION_BABBLE_ERROR           3\r
+#define TRB_COMPLETION_USB_TRANSACTION_ERROR  4\r
+#define TRB_COMPLETION_TRB_ERROR              5\r
+#define TRB_COMPLETION_STALL_ERROR            6\r
+#define TRB_COMPLETION_SHORT_PACKET           13\r
+\r
+//\r
+// USB device RouteChart record\r
+//\r
+typedef union _USB_DEV_TOPOLOGY {\r
+  UINT32 Dword;\r
+  struct {\r
+    UINT32 RouteString:20; ///< The tier concatenation of down stream port\r
+    UINT32 RootPortNum:8;  ///< The root port number of the chain\r
+    UINT32 TierNum:4;      ///< The Tier the device reside\r
+  } Field;\r
+} USB_DEV_ROUTE;\r
+\r
+//\r
+// Endpoint address and its capabilities\r
+//\r
+typedef struct _USB_ENDPOINT {\r
+  UINT8                     DevAddr;\r
+  UINT8                     EpAddr;\r
+  EFI_USB_DATA_DIRECTION    Direction;\r
+  UINT8                     DevSpeed;\r
+  UINTN                     MaxPacket;\r
+  UINTN                     Type;\r
+} USB_ENDPOINT;\r
+\r
+//\r
+// Command TRB\r
+//\r
+typedef struct _TRB {\r
+  UINT32                    Dword1;\r
+  UINT32                    Dword2;\r
+  UINT32                    Dword3;\r
+  UINT32                    CycleBit:1;\r
+  UINT32                    RsvdZ1:9;\r
+  UINT32                    Type:6;\r
+  UINT32                    RsvdZ2:16;\r
+} TRB;\r
+\r
+typedef struct _TRANSFER_RING {\r
+  VOID                      *RingSeg0;\r
+  UINTN                     TrbNumber;\r
+  TRB                       *RingEnqueue;\r
+  TRB                       *RingDequeue;\r
+  UINT32                    RingPCS;\r
+} TRANSFER_RING;\r
+\r
+typedef struct _EVENT_RING {\r
+  UINT32                    EventInterrupter;\r
+  VOID                      *ERSTBase;\r
+  VOID                      *EventRingSeg0;\r
+  UINTN                     TrbNumber;\r
+  TRB                       *EventRingEnqueue;\r
+  TRB                       *EventRingDequeue;\r
+  UINT32                    EventRingCCS;\r
+} EVENT_RING;\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
+  // Usb Device URB related information\r
+  //\r
+  USB_ENDPOINT                    Ep;\r
+  EFI_USB_DEVICE_REQUEST          *Request;\r
+  VOID                            *Data;\r
+  UINTN                           DataLen;\r
+  EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;\r
+  VOID                            *Context;\r
+  //\r
+  // Execute result\r
+  //\r
+  UINT32                          Result;\r
+  //\r
+  // completed data length\r
+  //\r
+  UINTN                           Completed;\r
+  //\r
+  // Command/Tranfer Ring info\r
+  //\r
+  TRANSFER_RING                   *Ring;\r
+  TRB                             *TrbStart;\r
+  TRB                             *TrbEnd;\r
+  UINTN                           TrbNum;\r
+  EVENT_RING                      *EvtRing;\r
+  TRB                             *EvtTrbStart;\r
+} URB;\r
+\r
+//\r
+// 5.5.2 Interrupter Register Set\r
+//\r
+typedef struct _INTERRUPTER_REGISTER_SET {\r
+  UINT32                    InterrupterManagement;\r
+  UINT32                    InterrupterModeration;\r
+  UINT32                    RingSegTableSize:16;\r
+  UINT32                    RsvdZ1:16;\r
+  UINT32                    RsvdZ2;\r
+  UINT32                    BasePtrLo;\r
+  UINT32                    BasePtrHi;\r
+  UINT32                    DequeLo;\r
+  UINT32                    DequeHi;\r
+} INTERRUPTER_REGISTER_SET;\r
+\r
+//\r
+// Host Controller Runtime Registers\r
+//\r
+typedef struct _HC_RUNTIME_REGS {\r
+  UINT32                    MicroframeIndex;\r
+  UINT32                    RsvdZ1;\r
+  UINT64                    RsvdZ2;\r
+  UINT64                    RsvdZ3;\r
+  UINT64                    RsvdZ4;\r
+  INTERRUPTER_REGISTER_SET  IR[1];\r
+} HC_RUNTIME_REGS;\r
+\r
+//\r
+// 6.5 Event Ring Segment Table\r
+// The Event Ring Segment Table is used to define multi-segment Event Rings and to enable runtime\r
+// expansion and shrinking of the Event Ring. The location of the Event Ring Segment Table is defined by the\r
+// Event Ring Segment Table Base Address Register (5.5.2.3.2). The size of the Event Ring Segment Table\r
+// is defined by the Event Ring Segment Table Base Size Register (5.5.2.3.1).\r
+//\r
+typedef struct _EVENT_RING_SEG_TABLE_ENTRY {\r
+  UINT32                  PtrLo;\r
+  UINT32                  PtrHi;\r
+  UINT32                  RingTrbSize:16;\r
+  UINT32                  RsvdZ1:16;\r
+  UINT32                  RsvdZ2;\r
+} EVENT_RING_SEG_TABLE_ENTRY;\r
+\r
+//\r
+// 6.4.1.1 Normal TRB\r
+// A Normal TRB is used in several ways; exclusively on Bulk and Interrupt Transfer Rings for normal and\r
+// Scatter/Gather operations, to define additional data buffers for Scatter/Gather operations on Isoch Transfer\r
+// Rings, and to define the Data stage information for Control Transfer Rings.\r
+//\r
+typedef struct _TRANSFER_TRB_NORMAL {\r
+  UINT32                  TRBPtrLo;\r
+  UINT32                  TRBPtrHi;\r
+  UINT32                  Lenth:17;\r
+  UINT32                  TDSize:5;\r
+  UINT32                  IntTarget:10;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  ENT:1;\r
+  UINT32                  ISP:1;\r
+  UINT32                  NS:1;\r
+  UINT32                  CH:1;\r
+  UINT32                  IOC:1;\r
+  UINT32                  IDT:1;\r
+  UINT32                  RsvdZ1:2;\r
+  UINT32                  BEI:1;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ2:16;\r
+} TRANSFER_TRB_NORMAL;\r
+\r
+//\r
+// 6.4.1.2.1 Setup Stage TRB\r
+// A Setup Stage TRB is created by system software to initiate a USB Setup packet on a control endpoint.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_SETUP{\r
+  UINT32                  bmRequestType:8;\r
+  UINT32                  bRequest:8;\r
+  UINT32                  wValue:16;\r
+\r
+  UINT32                  wIndex:16;\r
+  UINT32                  wLength:16;\r
+\r
+  UINT32                  Lenth:17;\r
+  UINT32                  RsvdZ1:5;\r
+  UINT32                  IntTarget:10;\r
+\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ2:4;\r
+  UINT32                  IOC:1;\r
+  UINT32                  IDT:1;\r
+  UINT32                  RsvdZ3:3;\r
+  UINT32                  Type:6;\r
+  UINT32                  TRT:2;\r
+  UINT32                  RsvdZ4:14;\r
+} TRANSFER_TRB_CONTROL_SETUP;\r
+\r
+//\r
+// 6.4.1.2.2 Data Stage TRB\r
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_DATA {\r
+  UINT32                  TRBPtrLo;\r
+  UINT32                  TRBPtrHi;\r
+  UINT32                  Lenth:17;\r
+  UINT32                  TDSize:5;\r
+  UINT32                  IntTarget:10;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  ENT:1;\r
+  UINT32                  ISP:1;\r
+  UINT32                  NS:1;\r
+  UINT32                  CH:1;\r
+  UINT32                  IOC:1;\r
+  UINT32                  IDT:1;\r
+  UINT32                  RsvdZ1:3;\r
+  UINT32                  Type:6;\r
+  UINT32                  DIR:1;\r
+  UINT32                  RsvdZ2:15;\r
+} TRANSFER_TRB_CONTROL_DATA;\r
+\r
+//\r
+// 6.4.1.2.2 Data Stage TRB\r
+// A Data Stage TRB is used generate the Data stage transaction of a USB Control transfer.\r
+//\r
+typedef struct _TRANSFER_TRB_CONTROL_STATUS {\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  RsvdZ3:22;\r
+  UINT32                  IntTarget:10;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  ENT:1;\r
+  UINT32                  RsvdZ4:2;\r
+  UINT32                  CH:1;\r
+  UINT32                  IOC:1;\r
+  UINT32                  RsvdZ5:4;\r
+  UINT32                  Type:6;\r
+  UINT32                  DIR:1;\r
+  UINT32                  RsvdZ6:15;\r
+} TRANSFER_TRB_CONTROL_STATUS;\r
+\r
+//\r
+// 6.4.2.1 Transfer Event TRB\r
+// A Transfer Event provides the completion status associated with a Transfer TRB. Refer to section 4.11.3.1\r
+// for more information on the use and operation of Transfer Events.\r
+//\r
+typedef struct _EVT_TRB_TRANSFER {\r
+  UINT32                  TRBPtrLo;\r
+  UINT32                  TRBPtrHi;\r
+  UINT32                  Lenth:24;\r
+  UINT32                  Completcode:8;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ1:1;\r
+  UINT32                  ED:1;\r
+  UINT32                  RsvdZ2:7;\r
+  UINT32                  Type:6;\r
+  UINT32                  EndpointID:5;\r
+  UINT32                  RsvdZ3:3;\r
+  UINT32                  SlotId:8;\r
+} EVT_TRB_TRANSFER;\r
+\r
+//\r
+// 6.4.2.2 Command Completion Event TRB\r
+// A Command Completion Event TRB shall be generated by the xHC when a command completes on the\r
+// Command Ring. Refer to section 4.11.4 for more information on the use of Command Completion Events.\r
+//\r
+typedef struct _EVT_TRB_COMMAND {\r
+  UINT32                  TRBPtrLo;\r
+  UINT32                  TRBPtrHi;\r
+  UINT32                  RsvdZ2:24;\r
+  UINT32                  Completcode:8;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ3:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  VFID:8;\r
+  UINT32                  SlotId:8;\r
+} EVT_TRB_COMMAND;\r
+\r
+//\r
+// 6.4.2.3 Port Status Change Event TRB\r
+//\r
+typedef struct _EVT_TRB_PORT {\r
+  UINT32                  RsvdZ1:24;\r
+  UINT32                  PortID:8;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  RsvdZ3:24;\r
+  UINT32                  Completcode:8;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ4:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ5:16;\r
+} EVT_TRB_PORT;\r
+\r
+//\r
+// 6.4.3.1 No Op Command TRB\r
+// The No Op Command TRB provides a simple means for verifying the operation of the Command Ring\r
+//  mechanisms offered by the xHCI.\r
+//\r
+typedef struct _CMD_TRB_NO_OP {\r
+  UINT32                  RsvdZ0;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ3:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ4:16;\r
+} CMD_TRB_NO_OP;\r
+\r
+//\r
+// 6.4.3.2 Enable Slot Command TRB\r
+// The Enable Slot Command TRB causes the xHC to select an available Device Slot and return the ID of the\r
+// selected slot to the host in a Command Completion Event.\r
+//\r
+typedef struct _CMD_TRB_EN_SLOT {\r
+  UINT32                  RsvdZ0;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ3:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ4:16;\r
+} CMD_TRB_EN_SLOT;\r
+\r
+//\r
+// 6.4.3.3 Disable Slot Command TRB\r
+// The Disable Slot Command TRB releases any bandwidth assigned to the disabled slot and frees any\r
+// internal xHC resources assigned to the slot.\r
+//\r
+typedef struct _CMD_TRB_DIS_SLOT {\r
+  UINT32                  RsvdZ0;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ3:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ4:8;\r
+  UINT32                  SlotId:8;\r
+} CMD_TRB_DIS_SLOT;\r
+\r
+typedef struct _CMD_TRB_RESET_PORT {\r
+  UINT32                  RsvdZ0;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ3:8;\r
+  UINT32                  Tsp:1;\r
+  UINT32                  Type:6;\r
+  UINT32                  Endpoint:5;\r
+  UINT32                  RsvdZ4:3;\r
+  UINT32                  SlotId:8;\r
+} CMD_TRB_RESET_PORT;\r
+\r
+//\r
+// 6.4.3.4 Address Device Command TRB\r
+// The Address Device Command TRB transitions the selected Device Context from the Default to the\r
+// Addressed state and causes the xHC to select an address for the USB device in the Default State and\r
+// issue a SET_ADDRESS request to the USB device.\r
+//\r
+typedef struct _CMD_TRB_ADDR_DEV {\r
+  UINT32                  PtrLo;\r
+  UINT32                  PtrHi;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ2:8;\r
+  UINT32                  BSR:1;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ3:8;\r
+  UINT32                  SlotId:8;\r
+} CMD_TRB_ADDR_DEV;\r
+\r
+//\r
+// 6.4.3.5 Configure Endpoint Command TRB\r
+// The Configure Endpoint Command TRB evaluates the bandwidth and resource requirements of the\r
+// endpoints selected by the command.\r
+//\r
+typedef struct _CMD_CFG_ED {\r
+  UINT32                  PtrLo;\r
+  UINT32                  PtrHi;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ2:8;\r
+  UINT32                  DC:1;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ3:8;\r
+  UINT32                  SlotId:8;\r
+} CMD_CFG_ED;\r
+\r
+//\r
+// 6.4.3.6 Evaluate Context Command TRB\r
+// The Evaluate Context Command TRB is used by system software to inform the xHC that the selected\r
+// Context data structures in the Device Context have been modified by system software and that the xHC\r
+// shall evaluate any changes\r
+//\r
+typedef struct _CMD_TRB_EVALU_CONTX {\r
+  UINT32                  PtrLo;\r
+  UINT32                  PtrHi;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ2:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ3:8;\r
+  UINT32                  SlotId:8;\r
+} CMD_TRB_EVALU_CONTX;\r
+\r
+//\r
+// 6.4.3.7 Reset Endpoint Command TRB\r
+// The Reset Endpoint Command TRB is used by system software to reset a specified Transfer Ring\r
+//\r
+typedef struct _CMD_TRB_RESET_ED {\r
+  UINT32                  RsvdZ0;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ3:8;\r
+  UINT32                  TSP:1;\r
+  UINT32                  Type:6;\r
+  UINT32                  EDID:5;\r
+  UINT32                  RsvdZ4:3;\r
+  UINT32                  SlotId:8;\r
+} CMD_TRB_RESET_ED;\r
+\r
+//\r
+// 6.4.3.8 Stop Endpoint Command TRB\r
+// The Stop Endpoint Command TRB command allows software to stop the xHC execution of the TDs on a\r
+// Transfer Ring and temporarily take ownership of TDs that had previously been passed to the xHC.\r
+//\r
+typedef struct _CMD_TRB_STOP_ED {\r
+  UINT32                  RsvdZ0;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ3:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  EDID:5;\r
+  UINT32                  RsvdZ4:2;\r
+  UINT32                  SP:1;\r
+  UINT32                  SlotId:8;\r
+} CMD_TRB_STOP_ED;\r
+\r
+//\r
+// 6.4.3.9 Set TR Dequeue Pointer Command TRB\r
+// The Set TR Dequeue Pointer Command TRB is used by system software to modify the TR Dequeue\r
+// Pointer and DCS fields of an Endpoint or Stream Context.\r
+//\r
+typedef struct _CMD_SET_TR_DEQ {\r
+  UINT32                  PtrLo;\r
+  UINT32                  PtrHi;\r
+  UINT32                  RsvdZ1:16;\r
+  UINT32                  StreamID:16;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ2:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  Endpoint:5;\r
+  UINT32                  RsvdZ3:3;\r
+  UINT32                  SlotId:8;\r
+} CMD_SET_TR_DEQ;\r
+\r
+//\r
+// A Link TRB provides support for non-contiguous TRB Rings.\r
+//\r
+typedef struct _LNK_TRB {\r
+  UINT32                  PtrLo;\r
+  UINT32                  PtrHi;\r
+  UINT32                  RsvdZ1:22;\r
+  UINT32                  InterTarget:10;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  TC:1;\r
+  UINT32                  RsvdZ2:2;\r
+  UINT32                  CH:1;\r
+  UINT32                  IOC:1;\r
+  UINT32                  RsvdZ3:4;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ4:16;\r
+} LNK_TRB;\r
+\r
+//\r
+// A Link TRB provides support for non-contiguous TRB Rings.\r
+//\r
+typedef struct _NO_OP_TRB {\r
+  UINT32                  RsvdZ0;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  CycleBit:1;\r
+  UINT32                  RsvdZ3:9;\r
+  UINT32                  Type:6;\r
+  UINT32                  RsvdZ4:16;\r
+} CMD_NO_OP_TRB;\r
+\r
+//\r
+// 6.2.2 Slot Context\r
+//\r
+typedef struct _SLOT_CONTEXT {\r
+  UINT32                  RouteStr:20;\r
+  UINT32                  Speed:4;\r
+  UINT32                  RsvdZ1:1;\r
+  UINT32                  MTT:1;\r
+  UINT32                  Hub:1;\r
+  UINT32                  ContextEntries:5;\r
+\r
+  UINT32                  MaxExitLatency:16;\r
+  UINT32                  RootHubPortNum:8;\r
+  UINT32                  PortNum:8;\r
+\r
+  UINT32                  TTHubSlotId:8;\r
+  UINT32                  TTPortNum:8;\r
+  UINT32                  TTT:2;\r
+  UINT32                  RsvdZ2:4;\r
+  UINT32                  InterTarget:10;\r
+\r
+  UINT32                  DeviceAddress:8;\r
+  UINT32                  RsvdZ3:19;\r
+  UINT32                  SlotState:5;\r
+\r
+  UINT32                  RsvdZ4;\r
+  UINT32                  RsvdZ5;\r
+  UINT32                  RsvdZ6;\r
+  UINT32                  RsvdZ7;\r
+} SLOT_CONTEXT;\r
+\r
+//\r
+// 6.2.3 Endpoint Context\r
+//\r
+typedef struct _ENDPOINT_CONTEXT {\r
+  UINT32                  EPState:3;\r
+  UINT32                  RsvdZ1:5;\r
+  UINT32                  Mult:2;\r
+  UINT32                  MaxPStreams:5;\r
+  UINT32                  LSA:1;\r
+  UINT32                  Interval:8;\r
+  UINT32                  RsvdZ2:8;\r
+\r
+  UINT32                  RsvdZ3:1;\r
+  UINT32                  CErr:2;\r
+  UINT32                  EPType:3;\r
+  UINT32                  RsvdZ4:1;\r
+  UINT32                  HID:1;\r
+  UINT32                  MaxBurstSize:8;\r
+  UINT32                  MaxPacketSize:16;\r
+\r
+  UINT32                  PtrLo;\r
+\r
+  UINT32                  PtrHi;\r
+\r
+  UINT32                  AverageTRBLength:16;\r
+  UINT32                  MaxESITPayload:16;\r
+\r
+  UINT32                  RsvdZ5;\r
+  UINT32                  RsvdZ6;\r
+  UINT32                  RsvdZ7;\r
+} ENDPOINT_CONTEXT;\r
+\r
+//\r
+// 6.2.5.1 Input Control Context\r
+//\r
+typedef struct _INPUT_CONTRL_CONTEXT {\r
+  UINT32                  Dword1;\r
+  UINT32                  Dword2;\r
+  UINT32                  RsvdZ1;\r
+  UINT32                  RsvdZ2;\r
+  UINT32                  RsvdZ3;\r
+  UINT32                  RsvdZ4;\r
+  UINT32                  RsvdZ5;\r
+  UINT32                  RsvdZ6;\r
+} INPUT_CONTRL_CONTEXT;\r
+\r
+//\r
+// 6.2.1 Device Context\r
+//\r
+typedef struct _DEVICE_CONTEXT {\r
+  SLOT_CONTEXT            Slot;\r
+  ENDPOINT_CONTEXT        EP[31];\r
+} DEVICE_CONTEXT;\r
+\r
+//\r
+// 6.2.5 Input Context\r
+//\r
+typedef struct _INPUT_CONTEXT {\r
+  INPUT_CONTRL_CONTEXT    InputControlContext;\r
+  SLOT_CONTEXT            Slot;\r
+  ENDPOINT_CONTEXT        EP[31];\r
+} INPUT_CONTEXT;\r
+\r
+/**\r
+  Initialize the XHCI host controller for schedule.\r
+\r
+  @param  Xhc        The XHCI device to be initialized.\r
+\r
+**/\r
+VOID\r
+XhcInitSched (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  );\r
+\r
+/**\r
+  Free the resouce allocated at initializing schedule.\r
+\r
+  @param  Xhc        The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcFreeSched (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  );\r
+\r
+/**\r
+  Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  Urb           The URB to be rung.\r
+\r
+  @retval EFI_SUCCESS   Successfully ring the door bell.\r
+\r
+**/\r
+EFI_STATUS\r
+RingIntTransferDoorBell (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  URB                 *Urb\r
+  );\r
+\r
+/**\r
+  Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  CmdTransfer       The executed URB is for cmd transfer or not.\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
+XhcExecTransfer (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  BOOLEAN             CmdTransfer,\r
+  IN  URB                 *Urb,\r
+  IN  UINTN               TimeOut\r
+  );\r
+\r
+/**\r
+  Delete a single asynchronous interrupt transfer for\r
+  the device and endpoint.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  DevAddr               The address of the target device.\r
+  @param  EpNum                 The endpoint of the target.\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
+XhciDelAsyncIntTransfer (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  UINT8               DevAddr,\r
+  IN  UINT8               EpNum\r
+  );\r
+\r
+/**\r
+  Remove all the asynchronous interrupt transfers.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhciDelAllAsyncIntTransfers (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  );\r
+\r
+/**\r
+  Set Bios Ownership\r
+\r
+  @param  Xhc          The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcSetBiosOwnership (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  );\r
+\r
+/**\r
+  Clear Bios Ownership\r
+\r
+  @param  Xhc       The XHCI device.\r
+\r
+**/\r
+VOID\r
+XhcClearBiosOwnership (\r
+  IN USB_XHCI_DEV         *Xhc\r
+  );\r
+\r
+/**\r
+  Find out the slot id according to device address assigned by XHCI's Address_Device cmd.\r
+\r
+  @param  DevAddr         The device address of the target device.\r
+\r
+  @return The slot id used by the device.\r
+\r
+**/\r
+UINT8\r
+XhcDevAddrToSlotId (\r
+  IN  UINT8               DevAddr\r
+  );\r
+\r
+/**\r
+  Find out the slot id according to the device's route string.\r
+\r
+  @param  RouteString      The route string described the device location.\r
+\r
+  @return The slot id used by the device.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+XhcRouteStringToSlotId (\r
+  IN  USB_DEV_ROUTE     RouteString\r
+  );\r
+\r
+/**\r
+  Calculate the device context index by endpoint address and direction.\r
+\r
+  @param  EpAddr              The target endpoint number.\r
+  @param  Direction           The direction of the target endpoint.\r
+\r
+  @return The device context index of endpoint.\r
+\r
+**/\r
+UINT8\r
+XhcEndpointToDci (\r
+  IN  UINT8                   EpAddr,\r
+  IN  UINT8                   Direction\r
+  );\r
+\r
+/**\r
+  Ring the door bell to notify XHCI there is a transaction to be executed.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id of the target device.\r
+  @param  Dci           The device context index of the target slot or endpoint.\r
+\r
+  @retval EFI_SUCCESS   Successfully ring the door bell.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcRingDoorBell (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  IN UINT8                SlotId,\r
+  IN UINT8                Dci\r
+  );\r
+\r
+/**\r
+  Interrupt transfer periodic check handler.\r
+\r
+  @param  Event                 Interrupt event.\r
+  @param  Context               Pointer to USB_XHCI_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+XhcMonitorAsyncRequests (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  );\r
+\r
+/**\r
+  Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  ParentRouteChart      The route string pointed to the parent device if it exists.\r
+  @param  Port                  The port to be polled.\r
+  @param  PortState             The port state.\r
+\r
+  @retval EFI_SUCCESS           Successfully enable/disable device slot according to port state.\r
+  @retval Others                Should not appear.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcPollPortStatusChange (\r
+  IN  USB_XHCI_DEV*         Xhc,\r
+  IN  USB_DEV_ROUTE         ParentRouteChart,\r
+  IN  UINT8                 Port,\r
+  IN  EFI_USB_PORT_STATUS   *PortState\r
+  );\r
+\r
+/**\r
+  Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  PortNum       The total number of downstream port supported by the hub.\r
+  @param  TTT           The TT think time of the hub device.\r
+  @param  MTT           The multi-TT of the hub device.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure the hub device's slot context.\r
+\r
+**/\r
+EFI_STATUS\r
+XhcConfigHubContext (\r
+  IN USB_XHCI_DEV             *Xhc,\r
+  IN UINT8                    SlotId,\r
+  IN UINT8                    PortNum,\r
+  IN UINT8                    TTT,\r
+  IN UINT8                    MTT\r
+  );\r
+\r
+/**\r
+  Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be configured.\r
+  @param  DeviceSpeed   The device's speed.\r
+  @param  ConfigDesc    The pointer to the usb device configuration descriptor.\r
+\r
+  @retval EFI_SUCCESS   Successfully configure all the device endpoints.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSetConfigCmd (\r
+  IN USB_XHCI_DEV             *Xhc,\r
+  IN UINT8                    SlotId,\r
+  IN UINT8                    DeviceSpeed,\r
+  IN USB_CONFIG_DESCRIPTOR    *ConfigDesc\r
+  );\r
+\r
+/**\r
+  Find out the actual device address according to the requested device address from UsbBus.\r
+\r
+  @param  BusDevAddr       The requested device address by UsbBus upper driver.\r
+\r
+  @return The actual device address assigned to the device.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+XhcBusDevAddrToSlotId (\r
+  IN  UINT8       BusDevAddr\r
+  );\r
+\r
+/**\r
+  Assign and initialize the device slot for a new device.\r
+\r
+  @param  Xhc                 The XHCI device.\r
+  @param  ParentRouteChart    The route string pointed to the parent device.\r
+  @param  ParentPort          The port at which the device is located.\r
+  @param  RouteChart          The route string pointed to the device.\r
+  @param  DeviceSpeed         The device speed.\r
+\r
+  @retval EFI_SUCCESS   Successfully assign a slot to the device and assign an address to it.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcInitializeDeviceSlot (\r
+  IN  USB_XHCI_DEV              *Xhc,\r
+  IN  USB_DEV_ROUTE             ParentRouteChart,\r
+  IN  UINT16                    ParentPort,\r
+  IN  USB_DEV_ROUTE             RouteChart,\r
+  IN  UINT8                     DeviceSpeed\r
+  );\r
+\r
+/**\r
+  Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be evaluated.\r
+  @param  MaxPacketSize The max packet size supported by the device control transfer.\r
+\r
+  @retval EFI_SUCCESS   Successfully evaluate the device endpoint 0.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcEvaluateContext (\r
+  IN USB_XHCI_DEV             *Xhc,\r
+  IN UINT8                    SlotId,\r
+  IN UINT32                   MaxPacketSize\r
+  );\r
+\r
+/**\r
+  Disable the specified device slot.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  SlotId        The slot id to be disabled.\r
+\r
+  @retval EFI_SUCCESS   Successfully disable the device slot.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcDisableSlotCmd (\r
+  IN USB_XHCI_DEV             *Xhc,\r
+  IN UINT8                    SlotId\r
+  );\r
+\r
+/**\r
+  Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Xhc         The XHCI device.\r
+  @param  TrsRing     The transfer ring to sync.\r
+\r
+  @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSyncTrsRing (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  TRANSFER_RING           *TrsRing\r
+  );\r
+\r
+/**\r
+  Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
+\r
+  @param  Xhc         The XHCI device.\r
+  @param  EvtRing     The event ring to sync.\r
+\r
+  @retval EFI_SUCCESS The event ring is synchronized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSyncEventRing (\r
+  IN USB_XHCI_DEV         *Xhc,\r
+  EVENT_RING              *EvtRing\r
+  );\r
+\r
+/**\r
+  Check if there is a new generated event.\r
+\r
+  @param  Xhc           The XHCI device.\r
+  @param  EvtRing       The event ring to check.\r
+  @param  NewEvtTrb     The new event TRB found.\r
+\r
+  @retval EFI_SUCCESS   Found a new event TRB at the event ring.\r
+  @retval EFI_NOT_READY The event ring has no new event.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcCheckNewEvent (\r
+  IN  USB_XHCI_DEV            *Xhc,\r
+  IN  EVENT_RING              *EvtRing,\r
+  OUT TRB                     **NewEvtTrb\r
+  );\r
+\r
+/**\r
+  Create XHCI transfer ring.\r
+\r
+  @param  Xhc               The XHCI device.\r
+  @param  TrbNum            The number of TRB in the ring.\r
+  @param  TransferRing           The created transfer ring.\r
+\r
+**/\r
+VOID\r
+CreateTransferRing (\r
+  IN  USB_XHCI_DEV          *Xhc,\r
+  IN  UINTN                 TrbNum,\r
+  OUT TRANSFER_RING         *TransferRing\r
+  );\r
+\r
+/**\r
+  Create XHCI event ring.\r
+\r
+  @param  Xhc                 The XHCI device.\r
+  @param  EventInterrupter    The interrupter of event.\r
+  @param  EventRing           The created event ring.\r
+\r
+**/\r
+VOID\r
+CreateEventRing (\r
+  IN  USB_XHCI_DEV          *Xhc,\r
+  IN  UINT8                 EventInterrupter,\r
+  OUT EVENT_RING            *EventRing\r
+  );\r
+\r
+/**\r
+  System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
+  condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
+  Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
+  reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
+  Stopped to the Running state.\r
+\r
+  @param  Xhc                   The XHCI device.\r
+  @param  Urb                   The urb which makes the endpoint halted.\r
+\r
+  @retval EFI_SUCCESS           The recovery is successful.\r
+  @retval Others                Failed to recovery halted endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcRecoverHaltedEndpoint (\r
+  IN  USB_XHCI_DEV        *Xhc,\r
+  IN  URB                 *Urb\r
+  );\r
+\r
+/**\r
+  Create a new URB for a new transaction.\r
+\r
+  @param  Xhc       The XHCI device\r
+  @param  DevAddr   The device address\r
+  @param  EpAddr    Endpoint addrress\r
+  @param  DevSpeed  The device speed\r
+  @param  MaxPacket The max packet length of the endpoint\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
+\r
+  @return Created URB or NULL\r
+\r
+**/\r
+URB*\r
+XhcCreateUrb (\r
+  IN USB_XHCI_DEV                       *Xhc,\r
+  IN UINT8                              DevAddr,\r
+  IN UINT8                              EpAddr,\r
+  IN UINT8                              DevSpeed,\r
+  IN UINTN                              MaxPacket,\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
+  );\r
+\r
+/**\r
+  Create a transfer TRB.\r
+\r
+  @param  Xhc     The XHCI device\r
+  @param  Urb     The urb used to construct the transfer TRB.\r
+\r
+  @return Created TRB or NULL\r
+\r
+**/\r
+EFI_STATUS\r
+XhcCreateTransferTrb (\r
+  IN USB_XHCI_DEV                 *Xhc,\r
+  IN URB                          *Urb\r
+  );\r
+\r
+#endif\r
index 64aa9d954592ef429106a35de7bca99b63a4deca..b592913bd3b2e80bc0a51437dcfbd7cb13cf3dc3 100644 (file)
@@ -45,6 +45,7 @@ EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {
   NULL\r
 };\r
 \r
+UINT16 mMaxUsbDeviceNum = USB_MAX_DEVICES;\r
 \r
 /**\r
   USB_IO function to execute a control transfer. This\r
@@ -111,7 +112,7 @@ UsbIoControlTransfer (
     // Clear TT buffer when CTRL/BULK split transaction failes\r
     // Clear the TRANSLATOR TT buffer, not parent's buffer\r
     //\r
-    ASSERT (Dev->Translator.TranslatorHubAddress < USB_MAX_DEVICES);\r
+    ASSERT (Dev->Translator.TranslatorHubAddress < mMaxUsbDeviceNum);\r
     if (Dev->Translator.TranslatorHubAddress != 0) {\r
       UsbHubCtrlClearTTBuffer (\r
         Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
@@ -284,7 +285,7 @@ UsbIoBulkTransfer (
     // Clear TT buffer when CTRL/BULK split transaction failes.\r
     // Clear the TRANSLATOR TT buffer, not parent's buffer\r
     //\r
-    ASSERT (Dev->Translator.TranslatorHubAddress < USB_MAX_DEVICES);\r
+    ASSERT (Dev->Translator.TranslatorHubAddress < mMaxUsbDeviceNum);\r
     if (Dev->Translator.TranslatorHubAddress != 0) {\r
       UsbHubCtrlClearTTBuffer (\r
         Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
@@ -966,6 +967,16 @@ UsbBusBuildProtocol (
     goto CLOSE_HC;\r
   }\r
 \r
+  if (!EFI_ERROR (Status)) {\r
+    if (UsbBus->Usb2Hc->MajorRevision == 0x3) {\r
+      //\r
+      // The EFI_USB2_HC_PROTOCOL is produced for XHCI support.\r
+      // Then its max supported devices are 256.\r
+      //\r
+      mMaxUsbDeviceNum = 256;\r
+    }\r
+  }\r
+\r
   UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r
   UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r
 \r
@@ -1011,6 +1022,7 @@ UsbBusBuildProtocol (
   RootHub->Bus            = UsbBus;\r
   RootHub->NumOfInterface = 1;\r
   RootHub->Interfaces[0]  = RootIf;\r
+  RootHub->Tier           = 0;\r
   RootIf->Signature       = USB_INTERFACE_SIGNATURE;\r
   RootIf->Device          = RootHub;\r
   RootIf->DevicePath      = UsbBus->DevicePath;\r
@@ -1434,7 +1446,7 @@ UsbBusControllerDriverStop (
 \r
   mUsbRootHubApi.Release (RootIf);\r
 \r
-  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
+  for (Index = 1; Index < mMaxUsbDeviceNum; Index++) {\r
     if (Bus->Devices[Index] != NULL) {\r
       UsbRemoveDevice (Bus->Devices[Index]);\r
     }\r
index c41c1272fc840a58c47cb596d618553f7744495e..ce041b9f792f08fe4a4cc72de9ce321ada655e03 100644 (file)
@@ -167,7 +167,7 @@ struct _USB_DEVICE {
   //\r
   UINT8                     Speed;\r
   UINT8                     Address;\r
-  UINT                    MaxPacket0;\r
+  UINT32                    MaxPacket0;\r
 \r
   //\r
   // The device's descriptors and its configuration\r
@@ -189,6 +189,7 @@ struct _USB_DEVICE {
   UINT8                     ParentAddr;\r
   USB_INTERFACE             *ParentIf;\r
   UINT8                     ParentPort;       // Start at 0\r
+  UINT8                     Tier;\r
 };\r
 \r
 //\r
@@ -249,7 +250,7 @@ struct _USB_BUS {
   // An array of device that is on the bus. Devices[0] is\r
   // for root hub. Device with address i is at Devices[i].\r
   //\r
-  USB_DEVICE                *Devices[USB_MAX_DEVICES];\r
+  USB_DEVICE                *Devices[256];\r
 \r
   //\r
   // USB Bus driver need to control the recursive connect policy of the bus, only those wanted\r
@@ -746,6 +747,7 @@ UsbBusControllerDriverStop (
   IN EFI_HANDLE                   *ChildHandleBuffer\r
   );\r
 \r
+extern UINT16                         mMaxUsbDeviceNum;\r
 extern EFI_USB_IO_PROTOCOL            mUsbIoProtocol;\r
 extern EFI_DRIVER_BINDING_PROTOCOL    mUsbBusDriverBinding;\r
 extern EFI_COMPONENT_NAME_PROTOCOL    mUsbBusComponentName;\r
index 55fe5c873c7ea9cca1473fab0abc5ad8a499b739..529b136188ace95104d6dfb9e069e0c9b202c165 100644 (file)
@@ -527,12 +527,14 @@ UsbGetMaxPacketSize0 (
   // Get the first 8 bytes of the device descriptor which contains\r
   // max packet size for endpoint 0, which is at least 8.\r
   //\r
-  UsbDev->MaxPacket0 = 8;\r
-\r
   for (Index = 0; Index < 3; Index++) {\r
     Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_DEVICE, 0, 0, &DevDesc, 8);\r
 \r
     if (!EFI_ERROR (Status)) {\r
+      if ((DevDesc.BcdUSB == 0x0300) && (DevDesc.MaxPacketSize0 == 9)) {\r
+        UsbDev->MaxPacket0 = 1 << 9;\r
+        return EFI_SUCCESS;\r
+      }\r
       UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0;\r
       return EFI_SUCCESS;\r
     }\r
index a6dc1c0c29d52f5d1d7c29d7bfc9068a917e5b4c..b004212fa27bf208ff6fbeeac3eb5ddb09a24366 100644 (file)
@@ -2,7 +2,7 @@
 \r
     Usb bus enumeration support.\r
 \r
-Copyright (c) 2007 - 2008, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>\r
 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
@@ -15,7 +15,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "UsbBus.h"\r
 \r
-\r
 /**\r
   Return the endpoint descriptor in this interface.\r
 \r
@@ -234,6 +233,7 @@ UsbCreateDevice (
   Device->ParentAddr  = ParentIf->Device->Address;\r
   Device->ParentIf    = ParentIf;\r
   Device->ParentPort  = ParentPort;\r
+  Device->Tier        = ParentIf->Device->Tier + 1;\r
   return Device;\r
 }\r
 \r
@@ -540,7 +540,7 @@ UsbRemoveDevice (
   USB_BUS                 *Bus;\r
   USB_DEVICE              *Child;\r
   EFI_STATUS              Status;\r
-  UINT8                   Index;\r
+  UINTN                   Index;\r
 \r
   Bus = Device->Bus;\r
 \r
@@ -548,7 +548,7 @@ UsbRemoveDevice (
   // Remove all the devices on its downstream ports. Search from devices[1].\r
   // Devices[0] is the root hub.\r
   //\r
-  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
+  for (Index = 1; Index < mMaxUsbDeviceNum; Index++) {\r
     Child = Bus->Devices[Index];\r
 \r
     if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {\r
@@ -567,7 +567,7 @@ UsbRemoveDevice (
 \r
   DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));\r
 \r
-  ASSERT (Device->Address < USB_MAX_DEVICES);\r
+  ASSERT (Device->Address < mMaxUsbDeviceNum);\r
   Bus->Devices[Device->Address] = NULL;\r
   UsbFreeDevice (Device);\r
 \r
@@ -599,7 +599,7 @@ UsbFindChild (
   //\r
   // Start checking from device 1, device 0 is the root hub\r
   //\r
-  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
+  for (Index = 1; Index < mMaxUsbDeviceNum; Index++) {\r
     Device = Bus->Devices[Index];\r
 \r
     if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&\r
@@ -635,11 +635,11 @@ UsbEnumerateNewDev (
   USB_DEVICE              *Child;\r
   USB_DEVICE              *Parent;\r
   EFI_USB_PORT_STATUS     PortState;\r
-  UINT8                   Address;\r
+  UINTN                   Address;\r
   UINT8                   Config;\r
   EFI_STATUS              Status;\r
 \r
-  Address = USB_MAX_DEVICES;\r
+  Address = mMaxUsbDeviceNum;\r
   Parent  = HubIf->Device;\r
   Bus     = Parent->Bus;\r
   HubApi  = HubIf->HubApi;\r
@@ -679,14 +679,21 @@ UsbEnumerateNewDev (
     goto ON_ERROR;\r
   }\r
 \r
-  if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
-    Child->Speed = EFI_USB_SPEED_LOW;\r
-\r
+  if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: No device presented at port %d\n", Port));\r
+    goto ON_ERROR;\r
+  } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_SUPER_SPEED)){\r
+    Child->Speed      = EFI_USB_SPEED_SUPER;\r
+    Child->MaxPacket0 = 512;\r
   } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {\r
-    Child->Speed = EFI_USB_SPEED_HIGH;\r
-\r
+    Child->Speed      = EFI_USB_SPEED_HIGH;\r
+    Child->MaxPacket0 = 64;\r
+  } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
+    Child->Speed      = EFI_USB_SPEED_LOW;\r
+    Child->MaxPacket0 = 8;\r
   } else {\r
-    Child->Speed = EFI_USB_SPEED_FULL;\r
+    Child->Speed      = EFI_USB_SPEED_FULL;\r
+    Child->MaxPacket0 = 8;\r
   }\r
 \r
   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));\r
@@ -719,50 +726,50 @@ UsbEnumerateNewDev (
   // a time) , and ready to respond to control transfer at EP 0.\r
   //\r
 \r
-  //\r
-  // Host sends a Get_Descriptor request to learn the max packet\r
-  // size of default pipe (only part of the device's descriptor).\r
-  //\r
-  Status = UsbGetMaxPacketSize0 (Child);\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));\r
-    goto ON_ERROR;\r
-  }\r
-\r
-  DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));\r
-\r
   //\r
   // Host assigns an address to the device. Device completes the\r
   // status stage with default address, then switches to new address.\r
   // ADDRESS state. Address zero is reserved for root hub.\r
   //\r
-  for (Address = 1; Address < USB_MAX_DEVICES; Address++) {\r
+  for (Address = 1; Address < mMaxUsbDeviceNum; Address++) {\r
     if (Bus->Devices[Address] == NULL) {\r
       break;\r
     }\r
   }\r
 \r
-  if (Address == USB_MAX_DEVICES) {\r
+  if (Address == mMaxUsbDeviceNum) {\r
     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));\r
 \r
     Status = EFI_ACCESS_DENIED;\r
     goto ON_ERROR;\r
   }\r
 \r
+  Status                = UsbSetAddress (Child, (UINT8)Address);\r
+  Child->Address        = (UINT8)Address;\r
   Bus->Devices[Address] = Child;\r
-  Status                = UsbSetAddress (Child, Address);\r
-  Child->Address        = Address;\r
 \r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));\r
     goto ON_ERROR;\r
   }\r
-  \r
+\r
   gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);\r
 \r
   DEBUG ((EFI_D_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));\r
 \r
+  //\r
+  // Host sends a Get_Descriptor request to learn the max packet\r
+  // size of default pipe (only part of the device's descriptor).\r
+  //\r
+  Status = UsbGetMaxPacketSize0 (Child);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));\r
+\r
   //\r
   // Host learns about the device's abilities by requesting device's\r
   // entire descriptions.\r
@@ -801,7 +808,7 @@ UsbEnumerateNewDev (
   return EFI_SUCCESS;\r
 \r
 ON_ERROR:\r
-  if (Address != USB_MAX_DEVICES) {\r
+  if (Address != mMaxUsbDeviceNum) {\r
     Bus->Devices[Address] = NULL;\r
   }\r
 \r
@@ -848,12 +855,16 @@ UsbEnumeratePort (
     return Status;\r
   }\r
 \r
-  if (PortState.PortChangeStatus == 0) {\r
+  //\r
+  // Only handle connection/enable/overcurrent/reset change.\r
+  // Usb super speed hub may report other changes, such as warm reset change. Ignore them.\r
+  //\r
+  if ((PortState.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %x, change - %x on %p\n",\r
-              Port, PortState.PortStatus, PortState.PortChangeStatus, HubIf));\r
+  DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",\r
+              Port, PortState.PortChangeStatus, PortState.PortStatus, HubIf));\r
 \r
   //\r
   // This driver only process two kinds of events now: over current and\r
index 21270b80808030b308c65177ed83a48c20a11591..2dfc5751d55d032b3d45959ee8834f00bde4bb25 100644 (file)
@@ -22,19 +22,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 // bits determine whether hub will report the port in changed\r
 // bit maps.\r
 //\r
-#define USB_HUB_MAP_SIZE  5\r
-\r
-USB_CHANGE_FEATURE_MAP  mHubFeatureMap[USB_HUB_MAP_SIZE] = {\r
+USB_CHANGE_FEATURE_MAP  mHubFeatureMap[] = {\r
   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},\r
   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},\r
   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},\r
   {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},\r
-  {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange},\r
+  {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange}\r
 };\r
 \r
-#define USB_ROOT_HUB_MAP_SIZE 5\r
-\r
-USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[USB_ROOT_HUB_MAP_SIZE] = {\r
+USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[] = {\r
   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},\r
   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},\r
   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},\r
@@ -47,7 +43,38 @@ USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[USB_ROOT_HUB_MAP_SIZE] = {
 // is related to an interface, these requests are sent\r
 // to the control endpoint of the device.\r
 //\r
+/**\r
+  USB hub control transfer to set the hub depth.\r
+\r
+  @param  HubDev                The device of the hub.\r
+  @param  Depth                 The depth to set.\r
+\r
+  @retval EFI_SUCCESS           Depth of the hub is set.\r
+  @retval Others                Failed to set the depth.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHubCtrlSetHubDepth (\r
+  IN  USB_DEVICE          *HubDev,\r
+  IN  UINT16              Depth\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
 \r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_HUB,\r
+             USB_HUB_REQ_SET_DEPTH,\r
+             Depth,\r
+             0,\r
+             NULL,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
 \r
 /**\r
   USB hub control transfer to clear the hub feature.\r
@@ -173,6 +200,41 @@ UsbHubCtrlClearTTBuffer (
   return Status;\r
 }\r
 \r
+/**\r
+  Usb hub control transfer to get the super speed hub descriptor.\r
+\r
+  @param  HubDev                The hub device.\r
+  @param  Buf                   The buffer to hold the descriptor.\r
+  @param  Len                   The length to retrieve.\r
+\r
+  @retval EFI_SUCCESS           The hub descriptor is retrieved.\r
+  @retval Others                Failed to retrieve the hub descriptor.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHubCtrlGetSuperSpeedHubDesc (\r
+  IN  USB_DEVICE          *HubDev,\r
+  OUT VOID                *Buf\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  \r
+  Status = EFI_INVALID_PARAMETER;\r
+  \r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbDataIn,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_HUB,\r
+             USB_HUB_REQ_GET_DESC,\r
+             (UINT16) (USB_DESC_TYPE_HUB_SUPER_SPEED << 8),\r
+             0,\r
+             Buf,\r
+             32\r
+             );\r
+\r
+  return Status;\r
+}\r
 \r
 /**\r
   Usb hub control transfer to get the hub descriptor.\r
@@ -414,19 +476,27 @@ UsbHubReadDesc (
 {\r
   EFI_STATUS              Status;\r
 \r
-  //\r
-  // First get the hub descriptor length\r
-  //\r
-  Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);\r
+  if (HubDev->Speed == EFI_USB_SPEED_SUPER) {\r
+    //\r
+    // Get the super speed hub descriptor\r
+    //\r
+    Status = UsbHubCtrlGetSuperSpeedHubDesc (HubDev, HubDesc);\r
+  } else {\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+    //\r
+    // First get the hub descriptor length\r
+    //\r
+    Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);\r
 \r
-  //\r
-  // Get the whole hub descriptor\r
-  //\r
-  Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Get the whole hub descriptor\r
+    //\r
+    Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -629,6 +699,7 @@ UsbHubInit (
   EFI_STATUS              Status;\r
   UINT8                   Index;\r
   UINT8                   NumEndpoints;\r
+  UINT16                  Depth;\r
 \r
   //\r
   // Locate the interrupt endpoint for port change map\r
@@ -666,6 +737,37 @@ UsbHubInit (
 \r
   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));\r
 \r
+  //\r
+  // OK, set IsHub to TRUE. Now usb bus can handle this device\r
+  // as a working HUB. If failed eariler, bus driver will not\r
+  // recognize it as a hub. Other parts of the bus should be able\r
+  // to work.\r
+  //\r
+  HubIf->IsHub  = TRUE;\r
+  HubIf->HubApi = &mUsbHubApi;\r
+  HubIf->HubEp  = EpDesc;\r
+\r
+  if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {\r
+    Depth = (UINT16)(HubIf->Device->Tier - 1);\r
+    DEBUG ((EFI_D_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));\r
+    UsbHubCtrlSetHubDepth (HubIf->Device, Depth);\r
+    \r
+    for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
+      UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);\r
+    }    \r
+  } else {\r
+    //\r
+    // Feed power to all the hub ports. It should be ok\r
+    // for both gang/individual powered hubs.\r
+    //\r
+    for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
+      UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);\r
+    }\r
+\r
+    gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
+    UsbHubAckHubStatus (HubIf->Device);\r
+  }\r
+\r
   //\r
   // Create an event to enumerate the hub's port. On\r
   //\r
@@ -712,27 +814,6 @@ UsbHubInit (
     return Status;\r
   }\r
 \r
-  //\r
-  // OK, set IsHub to TRUE. Now usb bus can handle this device\r
-  // as a working HUB. If failed eariler, bus driver will not\r
-  // recognize it as a hub. Other parts of the bus should be able\r
-  // to work.\r
-  //\r
-  HubIf->IsHub  = TRUE;\r
-  HubIf->HubApi = &mUsbHubApi;\r
-  HubIf->HubEp  = EpDesc;\r
-\r
-  //\r
-  // Feed power to all the hub ports. It should be ok\r
-  // for both gang/individual powered hubs.\r
-  //\r
-  for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
-    UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);\r
-  }\r
-\r
-  gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);\r
-  UsbHubAckHubStatus (HubIf->Device);\r
-\r
   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));\r
   return Status;\r
 }\r
@@ -764,6 +845,12 @@ UsbHubGetPortStatus (
 \r
   Status  = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);\r
 \r
+  //\r
+  // Mark the USB_PORT_STAT_SUPER_SPEED bit if SuperSpeed\r
+  //\r
+  if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {\r
+    PortState->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
+  } \r
   return Status;\r
 }\r
 \r
@@ -799,7 +886,7 @@ UsbHubClearPortChange (
   // It may lead to extra port state report. USB bus should\r
   // be able to handle this.\r
   //\r
-  for (Index = 0; Index < USB_HUB_MAP_SIZE; Index++) {\r
+  for (Index = 0; Index < sizeof (mHubFeatureMap) / sizeof (mHubFeatureMap[0]); Index++) {\r
     Map = &mHubFeatureMap[Index];\r
 \r
     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
@@ -1091,7 +1178,7 @@ UsbRootHubClearPortChange (
   // It may lead to extra port state report. USB bus should\r
   // be able to handle this.\r
   //\r
-  for (Index = 0; Index < USB_ROOT_HUB_MAP_SIZE; Index++) {\r
+  for (Index = 0; Index < sizeof (mRootHubFeatureMap) / sizeof (mRootHubFeatureMap[0]); Index++) {\r
     Map = &mRootHubFeatureMap[Index];\r
 \r
     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
index 1a6ebdd6caf4ec17b54b0e6a41395c7a01e21bf0..c7ee16db468c67ea1beec4900c65c173c2553d62 100644 (file)
@@ -23,6 +23,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 \r
 #define USB_DESC_TYPE_HUB     0x29\r
+\r
+#define USB_DESC_TYPE_HUB_SUPER_SPEED  0x2a\r
+\r
 //\r
 // Hub class control transfer target\r
 //\r
@@ -40,6 +43,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define USB_HUB_REQ_RESET_TT        9\r
 #define USB_HUB_REQ_GET_TT_STATE    10\r
 #define USB_HUB_REQ_STOP_TT         11\r
+\r
+#define USB_HUB_REQ_SET_DEPTH       12\r
+\r
 //\r
 // USB hub class feature selector\r
 //\r
@@ -50,6 +56,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define USB_HUB_PORT_SUSPEND        2\r
 #define USB_HUB_PORT_OVER_CURRENT   3\r
 #define USB_HUB_PORT_RESET          4\r
+\r
+#define USB_HUB_PORT_LINK_STATE     5\r
+\r
 #define USB_HUB_PORT_POWER          8\r
 #define USB_HUB_PORT_LOW_SPEED      9\r
 #define USB_HUB_C_PORT_CONNECT      16\r
@@ -59,6 +68,17 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define USB_HUB_C_PORT_RESET        20\r
 #define USB_HUB_PORT_TEST           21\r
 #define USB_HUB_PORT_INDICATOR      22\r
+\r
+#define USB_HUB_C_PORT_LINK_STATE     25\r
+#define USB_HUB_PORT_REMOTE_WAKE_MASK 27\r
+#define USB_HUB_BH_PORT_RESET         28\r
+#define USB_HUB_C_BH_PORT_RESET       29\r
+\r
+//\r
+// Constant value for Port Status & Port Change Status of SuperSpeed port\r
+//\r
+#define USB_SS_PORT_STAT_C_BH_RESET         0x0020\r
+#define USB_SS_PORT_STAT_C_PORT_LINK_STATE  0x0040\r
 //\r
 // USB hub power control method. In gang power control\r
 //\r
@@ -94,6 +114,19 @@ typedef struct {
   UINT8           HubContrCurrent;\r
   UINT8           Filler[16];\r
 } EFI_USB_HUB_DESCRIPTOR;\r
+\r
+typedef struct {\r
+  UINT8           Length;\r
+  UINT8           DescType;\r
+  UINT8           NumPorts;\r
+  UINT16          HubCharacter;\r
+  UINT8           PwrOn2PwrGood;\r
+  UINT8           HubContrCurrent;\r
+  UINT8           HubHdrDecLat;\r
+  UINT8           HubDelay;\r
+  UINT8           DeviceRemovable;\r
+} EFI_USB_SUPER_SPEED_HUB_DESCRIPTOR;\r
+\r
 #pragma pack()\r
 \r
 \r
index 67c13444d1ead5086d1eab49d0e05182fc81a1c2..89fa0b405d62ab3b2752abd7702db66136b0ccf3 100644 (file)
 \r
   MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf\r
   MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
+  MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf\r
   MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf\r
   MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf\r
   MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf\r