]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / Ehci.c
index 0667fa645d675e83688e531025ddf126e4804034..bdd9c27db562aa204b120247be751269e27d2bec 100644 (file)
@@ -1,15 +1,18 @@
 /** @file\r
-  \r
   The Ehci controller driver.\r
 \r
-Copyright (c) 2006 - 2008, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
+  EhciDxe driver is responsible for managing the behavior of EHCI controller.\r
+  It implements the interfaces of monitoring the status of all ports and transferring\r
+  Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.\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
+  Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached\r
+  to the EHCI controller before a UHCI or OHCI driver attaches to the companion UHCI or\r
+  OHCI controller.  This way avoids the control transfer on a shared port between EHCI\r
+  and companion host controller when UHCI or OHCI gets attached earlier than EHCI and a\r
+  USB 2.0 device inserts.\r
+\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -41,7 +44,7 @@ gEhciDriverBinding = {
   EhcDriverBindingSupported,\r
   EhcDriverBindingStart,\r
   EhcDriverBindingStop,\r
-  0x10,\r
+  0x30,\r
   NULL,\r
   NULL\r
 };\r
@@ -80,7 +83,7 @@ EhcGetCapability (
 \r
   *MaxSpeed       = EFI_USB_SPEED_HIGH;\r
   *PortNumber     = (UINT8) (Ehc->HcStructParams & HCSP_NPORTS);\r
-  *Is64BitCapable = (UINT8) (Ehc->HcCapParams & HCCP_64BIT);\r
+  *Is64BitCapable = (UINT8) Ehc->Support64BitDma;\r
 \r
   DEBUG ((EFI_D_INFO, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
 \r
@@ -113,8 +116,20 @@ EhcReset (
   EFI_TPL                 OldTpl;\r
   EFI_STATUS              Status;\r
 \r
+  Ehc = EHC_FROM_THIS (This);\r
+\r
+  if (Ehc->DevicePath != NULL) {\r
+    //\r
+    // Report Status Code to indicate reset happens\r
+    //\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_PROGRESS_CODE,\r
+      (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),\r
+      Ehc->DevicePath\r
+      );\r
+  }\r
+\r
   OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
-  Ehc     = EHC_FROM_THIS (This);\r
 \r
   switch (Attributes) {\r
   case EFI_USB_HC_RESET_GLOBAL:\r
@@ -125,6 +140,11 @@ EhcReset (
     //\r
     // Host Controller must be Halt when Reset it\r
     //\r
+    if (EhcIsDebugPortInUse (Ehc, NULL)) {\r
+      Status = EFI_SUCCESS;\r
+      goto ON_EXIT;\r
+    }\r
+\r
     if (!EhcIsHalt (Ehc)) {\r
       Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
 \r
@@ -183,8 +203,8 @@ ON_EXIT:
 EFI_STATUS\r
 EFIAPI\r
 EhcGetState (\r
-  IN  CONST EFI_USB2_HC_PROTOCOL  *This,\r
-  OUT       EFI_USB_HC_STATE      *State\r
+  IN   EFI_USB2_HC_PROTOCOL  *This,\r
+  OUT  EFI_USB_HC_STATE      *State\r
   )\r
 {\r
   EFI_TPL                 OldTpl;\r
@@ -302,9 +322,9 @@ EhcSetState (
 EFI_STATUS\r
 EFIAPI\r
 EhcGetRootHubPortStatus (\r
-  IN  CONST EFI_USB2_HC_PROTOCOL  *This,\r
-  IN  CONST UINT8                 PortNumber,\r
-  OUT       EFI_USB_PORT_STATUS   *PortStatus\r
+  IN   EFI_USB2_HC_PROTOCOL  *This,\r
+  IN   UINT8                 PortNumber,\r
+  OUT  EFI_USB_PORT_STATUS   *PortStatus\r
   )\r
 {\r
   USB2_HC_DEV             *Ehc;\r
@@ -336,6 +356,10 @@ EhcGetRootHubPortStatus (
   PortStatus->PortStatus        = 0;\r
   PortStatus->PortChangeStatus  = 0;\r
 \r
+  if (EhcIsDebugPortInUse (Ehc, &PortNumber)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
   State                         = EhcReadOpReg (Ehc, Offset);\r
 \r
   //\r
@@ -461,9 +485,12 @@ EhcSetRootHubPortFeature (
 \r
   case EfiUsbPortPower:\r
     //\r
-    // Not supported, ignore the operation\r
+    // Set port power bit when PPC is 1\r
     //\r
-    Status = EFI_SUCCESS;\r
+    if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) {\r
+      State |= PORTSC_POWER;\r
+      EhcWriteOpReg (Ehc, Offset, State);\r
+    }\r
     break;\r
 \r
   case EfiUsbPortOwner:\r
@@ -590,6 +617,14 @@ EhcClearRootHubPortFeature (
     break;\r
 \r
   case EfiUsbPortPower:\r
+    //\r
+    // Clear port power bit when PPC is 1\r
+    //\r
+    if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) {\r
+      State &= ~PORTSC_POWER;\r
+      EhcWriteOpReg (Ehc, Offset, State);\r
+    }\r
+    break;\r
   case EfiUsbPortSuspendChange:\r
   case EfiUsbPortResetChange:\r
     //\r
@@ -956,7 +991,6 @@ EhcAsyncInterruptTransfer (
   URB                     *Urb;\r
   EFI_TPL                 OldTpl;\r
   EFI_STATUS              Status;\r
-  UINT8                   *Data;\r
 \r
   //\r
   // Validate parameters\r
@@ -1005,16 +1039,7 @@ EhcAsyncInterruptTransfer (
 \r
   EhcAckAllInterrupt (Ehc);\r
 \r
-  Data = AllocatePool (DataLength);\r
-\r
-  if (Data == NULL) {\r
-    DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
-\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  Urb = EhcCreateUrb (\r
+  Urb = EhciInsertAsyncIntTransfer (\r
           Ehc,\r
           DeviceAddress,\r
           EndPointAddress,\r
@@ -1022,9 +1047,6 @@ EhcAsyncInterruptTransfer (
           *DataToggle,\r
           MaximumPacketLength,\r
           Translator,\r
-          EHC_INT_TRANSFER_ASYNC,\r
-          NULL,\r
-          Data,\r
           DataLength,\r
           CallBackFunction,\r
           Context,\r
@@ -1032,20 +1054,10 @@ EhcAsyncInterruptTransfer (
           );\r
 \r
   if (Urb == NULL) {\r
-    DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to create URB\n"));\r
-\r
-    gBS->FreePool (Data);\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ON_EXIT;\r
   }\r
 \r
-  //\r
-  // New asynchronous transfer must inserted to the head.\r
-  // Check the comments in EhcMoniteAsyncRequests\r
-  //\r
-  EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
-  InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);\r
-\r
 ON_EXIT:\r
   Ehc->PciIo->Flush (Ehc->PciIo);\r
   gBS->RestoreTPL (OldTpl);\r
@@ -1110,10 +1122,6 @@ EhcSyncInterruptTransfer (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
   if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -1175,6 +1183,7 @@ EhcSyncInterruptTransfer (
     Status = EFI_SUCCESS;\r
   }\r
 \r
+  EhcFreeUrb (Ehc, Urb);\r
 ON_EXIT:\r
   Ehc->PciIo->Flush (Ehc->PciIo);\r
   gBS->RestoreTPL (OldTpl);\r
@@ -1341,7 +1350,7 @@ EhcDriverBindingSupported (
   Status = PciIo->Pci.Read (\r
                         PciIo,\r
                         EfiPciIoWidthUint8,\r
-                        EHC_PCI_CLASSC,\r
+                        PCI_CLASSCODE_OFFSET,\r
                         sizeof (USB_CLASSC) / sizeof (UINT8),\r
                         &UsbClassCReg\r
                         );\r
@@ -1354,9 +1363,8 @@ EhcDriverBindingSupported (
   //\r
   // Test whether the controller belongs to Ehci type\r
   //\r
-  if ((UsbClassCReg.BaseCode     != PCI_CLASS_SERIAL) ||\r
-      (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
-      (UsbClassCReg.PI           != EHC_PCI_CLASSC_PI)) {\r
+  if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)\r
+      || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface != PCI_IF_UHCI) && (UsbClassCReg.ProgInterface != PCI_IF_OHCI))) {\r
 \r
     Status = EFI_UNSUPPORTED;\r
   }\r
@@ -1372,11 +1380,135 @@ ON_EXIT:
   return Status;\r
 }\r
 \r
+/**\r
+  Get the usb debug port related information.\r
+\r
+  @param  Ehc                The EHCI device.\r
+\r
+  @retval RETURN_SUCCESS     Get debug port number, bar and offset successfully.\r
+  @retval Others             The usb host controller does not supported usb debug port capability.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcGetUsbDebugPortInfo (\r
+  IN  USB2_HC_DEV     *Ehc\r
+ )\r
+{\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  UINT16              PciStatus;\r
+  UINT8               CapabilityPtr;\r
+  UINT8               CapabilityId;\r
+  UINT16              DebugPort;\r
+  EFI_STATUS          Status;\r
+\r
+  ASSERT (Ehc->PciIo != NULL);\r
+  PciIo = Ehc->PciIo;\r
+\r
+  //\r
+  // Detect if the EHCI host controller support Capaility Pointer.\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        PCI_PRIMARY_STATUS_OFFSET,\r
+                        sizeof (UINT16),\r
+                        &PciStatus\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) {\r
+    //\r
+    // The Pci Device Doesn't Support Capability Pointer.\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Get Pointer To Capability List\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        PCI_CAPBILITY_POINTER_OFFSET,\r
+                        1,\r
+                        &CapabilityPtr\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Find Capability ID 0xA, Which Is For Debug Port\r
+  //\r
+  while (CapabilityPtr != 0) {\r
+    Status = PciIo->Pci.Read (\r
+                          PciIo,\r
+                          EfiPciIoWidthUint8,\r
+                          CapabilityPtr,\r
+                          1,\r
+                          &CapabilityId\r
+                          );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (CapabilityId == EHC_DEBUG_PORT_CAP_ID) {\r
+      break;\r
+    }\r
+\r
+    Status = PciIo->Pci.Read (\r
+                          PciIo,\r
+                          EfiPciIoWidthUint8,\r
+                          CapabilityPtr + 1,\r
+                          1,\r
+                          &CapabilityPtr\r
+                          );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // No Debug Port Capability Found\r
+  //\r
+  if (CapabilityPtr == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Get The Base Address Of Debug Port Register In Debug Port Capability Register\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        Ehc->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        CapabilityPtr + 2,\r
+                        sizeof (UINT16),\r
+                        &DebugPort\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Ehc->DebugPortOffset = DebugPort & 0x1FFF;\r
+  Ehc->DebugPortBarNum = (UINT8)((DebugPort >> 13) - 1);\r
+  Ehc->DebugPortNum    = (UINT8)((Ehc->HcStructParams & 0x00F00000) >> 20);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 \r
 /**\r
   Create and initialize a USB2_HC_DEV.\r
 \r
   @param  PciIo                  The PciIo on this device.\r
+  @param  DevicePath             The device path of host controller.\r
   @param  OriginalPciAttributes  Original PCI attributes.\r
 \r
   @return  The allocated and initialized USB2_HC_DEV structure if created,\r
@@ -1385,8 +1517,9 @@ ON_EXIT:
 **/\r
 USB2_HC_DEV *\r
 EhcCreateUsb2Hc (\r
-  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
-  IN UINT64               OriginalPciAttributes\r
+  IN EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
+  IN UINT64                    OriginalPciAttributes\r
   )\r
 {\r
   USB2_HC_DEV             *Ehc;\r
@@ -1420,6 +1553,7 @@ EhcCreateUsb2Hc (
   Ehc->Usb2Hc.MinorRevision             = 0x0;\r
 \r
   Ehc->PciIo                 = PciIo;\r
+  Ehc->DevicePath            = DevicePath;\r
   Ehc->OriginalPciAttributes = OriginalPciAttributes;\r
 \r
   InitializeListHead (&Ehc->AsyncIntTransfers);\r
@@ -1430,13 +1564,23 @@ EhcCreateUsb2Hc (
 \r
   DEBUG ((EFI_D_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));\r
 \r
+  //\r
+  // EHCI Controllers with a CapLen of 0 are ignored.\r
+  //\r
+  if (Ehc->CapLen == 0) {\r
+    gBS->FreePool (Ehc);\r
+    return NULL;\r
+  }\r
+\r
+  EhcGetUsbDebugPortInfo (Ehc);\r
+\r
   //\r
   // Create AsyncRequest Polling Timer\r
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
-                  EhcMoniteAsyncRequests,\r
+                  TPL_NOTIFY,\r
+                  EhcMonitorAsyncRequests,\r
                   Ehc,\r
                   &Ehc->PollTimer\r
                   );\r
@@ -1449,6 +1593,31 @@ EhcCreateUsb2Hc (
   return Ehc;\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 handler private data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EhcExitBootService (\r
+  EFI_EVENT                      Event,\r
+  VOID                           *Context\r
+  )\r
+\r
+{\r
+  USB2_HC_DEV   *Ehc;\r
+\r
+  Ehc = (USB2_HC_DEV *) Context;\r
+\r
+  //\r
+  // Reset the Host Controller\r
+  //\r
+  EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
+}\r
+\r
 \r
 /**\r
   Starting the Usb EHCI Driver.\r
@@ -1474,9 +1643,23 @@ EhcDriverBindingStart (
   EFI_STATUS              Status;\r
   USB2_HC_DEV             *Ehc;\r
   EFI_PCI_IO_PROTOCOL     *PciIo;\r
+  EFI_PCI_IO_PROTOCOL     *Instance;\r
   UINT64                  Supports;\r
   UINT64                  OriginalPciAttributes;\r
   BOOLEAN                 PciAttributesSaved;\r
+  USB_CLASSC              UsbClassCReg;\r
+  EFI_HANDLE              *HandleBuffer;\r
+  UINTN                   NumberOfHandles;\r
+  UINTN                   Index;\r
+  UINTN                   CompanionSegmentNumber;\r
+  UINTN                   CompanionBusNumber;\r
+  UINTN                   CompanionDeviceNumber;\r
+  UINTN                   CompanionFunctionNumber;\r
+  UINTN                   EhciSegmentNumber;\r
+  UINTN                   EhciBusNumber;\r
+  UINTN                   EhciDeviceNumber;\r
+  UINTN                   EhciFunctionNumber;\r
+  EFI_DEVICE_PATH_PROTOCOL  *HcDevicePath;\r
 \r
   //\r
   // Open the PciIo Protocol, then enable the USB host controller\r
@@ -1491,10 +1674,22 @@ EhcDriverBindingStart (
                   );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to open PCI_IO\n"));\r
-    return EFI_DEVICE_ERROR;\r
+    return Status;\r
   }\r
 \r
+  //\r
+  // Open Device Path Protocol for on USB host controller\r
+  //\r
+  HcDevicePath = NULL;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &HcDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
   PciAttributesSaved = FALSE;\r
   //\r
   // Save original PCI attributes\r
@@ -1518,7 +1713,7 @@ EhcDriverBindingStart (
                     &Supports\r
                     );\r
   if (!EFI_ERROR (Status)) {\r
-    Supports &= EFI_PCI_DEVICE_ENABLE;\r
+    Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
     Status = PciIo->Attributes (\r
                       PciIo,\r
                       EfiPciIoAttributeOperationEnable,\r
@@ -1532,10 +1727,111 @@ EhcDriverBindingStart (
     goto CLOSE_PCIIO;\r
   }\r
 \r
+  //\r
+  // Get the Pci device class code.\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 CLOSE_PCIIO;\r
+  }\r
+  //\r
+  // Determine if the device is UHCI or OHCI host controller or not. If yes, then find out the\r
+  // companion usb ehci host controller and force EHCI driver get attached to it before\r
+  // UHCI or OHCI driver attaches to UHCI or OHCI host controller.\r
+  //\r
+  if ((UsbClassCReg.ProgInterface == PCI_IF_UHCI || UsbClassCReg.ProgInterface == PCI_IF_OHCI) &&\r
+       (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&\r
+       (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) {\r
+    Status = PciIo->GetLocation (\r
+                    PciIo,\r
+                    &CompanionSegmentNumber,\r
+                    &CompanionBusNumber,\r
+                    &CompanionDeviceNumber,\r
+                    &CompanionFunctionNumber\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto CLOSE_PCIIO;\r
+    }\r
+\r
+    Status = gBS->LocateHandleBuffer (\r
+                    ByProtocol,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    NULL,\r
+                    &NumberOfHandles,\r
+                    &HandleBuffer\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto CLOSE_PCIIO;\r
+    }\r
+\r
+    for (Index = 0; Index < NumberOfHandles; Index++) {\r
+      //\r
+      // Get the device path on this handle\r
+      //\r
+      Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiPciIoProtocolGuid,\r
+                    (VOID **)&Instance\r
+                    );\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      Status = Instance->Pci.Read (\r
+                    Instance,\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 CLOSE_PCIIO;\r
+      }\r
+\r
+      if ((UsbClassCReg.ProgInterface == PCI_IF_EHCI) &&\r
+           (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&\r
+           (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) {\r
+        Status = Instance->GetLocation (\r
+                    Instance,\r
+                    &EhciSegmentNumber,\r
+                    &EhciBusNumber,\r
+                    &EhciDeviceNumber,\r
+                    &EhciFunctionNumber\r
+                    );\r
+        if (EFI_ERROR (Status)) {\r
+          goto CLOSE_PCIIO;\r
+        }\r
+        //\r
+        // Currently, the judgment on the companion usb host controller is through the\r
+        // same bus number, which may vary on different platform.\r
+        //\r
+        if (EhciBusNumber == CompanionBusNumber) {\r
+          gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    Controller\r
+                    );\r
+          EhcDriverBindingStart(This, HandleBuffer[Index], NULL);\r
+        }\r
+      }\r
+    }\r
+    Status = EFI_NOT_FOUND;\r
+    goto CLOSE_PCIIO;\r
+  }\r
+\r
   //\r
   // Create then install USB2_HC_PROTOCOL\r
   //\r
-  Ehc = EhcCreateUsb2Hc (PciIo, OriginalPciAttributes);\r
+  Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, OriginalPciAttributes);\r
 \r
   if (Ehc == NULL) {\r
     DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));\r
@@ -1544,6 +1840,26 @@ EhcDriverBindingStart (
     goto CLOSE_PCIIO;\r
   }\r
 \r
+  //\r
+  // Enable 64-bit DMA support in the PCI layer if this controller\r
+  // supports it.\r
+  //\r
+  if (EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT)) {\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
+                      NULL\r
+                      );\r
+    if (!EFI_ERROR (Status)) {\r
+      Ehc->Support64BitDma = TRUE;\r
+    } else {\r
+      DEBUG ((EFI_D_WARN,\r
+        "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",\r
+        __FUNCTION__, Controller, Status));\r
+    }\r
+  }\r
+\r
   Status = gBS->InstallProtocolInterface (\r
                   &Controller,\r
                   &gEfiUsb2HcProtocolGuid,\r
@@ -1557,13 +1873,16 @@ EhcDriverBindingStart (
   }\r
 \r
   //\r
-  // Robustnesss improvement such as for UoL\r
+  // Robustnesss improvement such as for Duet platform\r
   // Default is not required.\r
   //\r
   if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
     EhcClearLegacySupport (Ehc);\r
   }\r
-  EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
+\r
+  if (!EhcIsDebugPortInUse (Ehc, NULL)) {\r
+    EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
+  }\r
 \r
   Status = EhcInitHC (Ehc);\r
 \r
@@ -1584,6 +1903,21 @@ EhcDriverBindingStart (
     goto UNINSTALL_USBHC;\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
+                  EhcExitBootService,\r
+                  Ehc,\r
+                  &gEfiEventExitBootServicesGuid,\r
+                  &Ehc->ExitBootServiceEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto UNINSTALL_USBHC;\r
+  }\r
+\r
   //\r
   // Install the component name protocol, don't fail the start\r
   // because of something for display.\r
@@ -1644,7 +1978,7 @@ CLOSE_PCIIO:
 \r
 \r
 /**\r
-  Stop this driver on ControllerHandle. Support stoping any child handles\r
+  Stop this driver on ControllerHandle. Support stopping any child handles\r
   created by this driver.\r
 \r
   @param  This                 Protocol instance pointer.\r
@@ -1691,13 +2025,6 @@ EhcDriverBindingStop (
   Ehc   = EHC_FROM_THIS (Usb2Hc);\r
   PciIo = Ehc->PciIo;\r
 \r
-  //\r
-  // Stop AsyncRequest Polling timer then stop the EHCI driver\r
-  // and uninstall the EHCI protocl.\r
-  //\r
-  gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);\r
-  EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
-\r
   Status = gBS->UninstallProtocolInterface (\r
                   Controller,\r
                   &gEfiUsb2HcProtocolGuid,\r
@@ -1708,16 +2035,33 @@ EhcDriverBindingStop (
     return Status;\r
   }\r
 \r
+  //\r
+  // Stop AsyncRequest Polling timer then stop the EHCI driver\r
+  // and uninstall the EHCI protocl.\r
+  //\r
+  gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);\r
+  EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
+\r
   if (Ehc->PollTimer != NULL) {\r
     gBS->CloseEvent (Ehc->PollTimer);\r
   }\r
 \r
+  if (Ehc->ExitBootServiceEvent != NULL) {\r
+    gBS->CloseEvent (Ehc->ExitBootServiceEvent);\r
+  }\r
+\r
   EhcFreeSched (Ehc);\r
 \r
   if (Ehc->ControllerNameTable != NULL) {\r
     FreeUnicodeStringTable (Ehc->ControllerNameTable);\r
   }\r
 \r
+  //\r
+  // Disable routing of all ports to EHCI controller, so all ports are\r
+  // routed back to the UHCI or OHCI controller.\r
+  //\r
+  EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);\r
+\r
   //\r
   // Restore original PCI attributes\r
   //\r