]> 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 c6c7e5a5195efc38e96803e778f5917c0c154f91..bdd9c27db562aa204b120247be751269e27d2bec 100644 (file)
@@ -1,15 +1,18 @@
 /** @file\r
-  \r
   The Ehci controller driver.\r
 \r
-Copyright (c) 2006 - 2009, 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
@@ -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
@@ -1355,7 +1364,7 @@ EhcDriverBindingSupported (
   // Test whether the controller belongs to Ehci type\r
   //\r
   if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)\r
-      || ((UsbClassCReg.PI != PCI_IF_EHCI) && (UsbClassCReg.PI !=PCI_IF_UHCI))) {\r
+      || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface != PCI_IF_UHCI) && (UsbClassCReg.ProgInterface != PCI_IF_OHCI))) {\r
 \r
     Status = EFI_UNSUPPORTED;\r
   }\r
@@ -1371,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
@@ -1384,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
@@ -1419,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
@@ -1429,12 +1564,22 @@ 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
+                  TPL_NOTIFY,\r
                   EhcMonitorAsyncRequests,\r
                   Ehc,\r
                   &Ehc->PollTimer\r
@@ -1452,7 +1597,7 @@ EhcCreateUsb2Hc (
   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
+  @param  Context                 Event handler private data\r
 \r
 **/\r
 VOID\r
@@ -1468,11 +1613,9 @@ EhcExitBootService (
   Ehc = (USB2_HC_DEV *) Context;\r
 \r
   //\r
-  // Stop the Host Controller\r
+  // Reset the Host Controller\r
   //\r
-  EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
-\r
-  return;\r
+  EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
 }\r
 \r
 \r
@@ -1508,14 +1651,15 @@ EhcDriverBindingStart (
   EFI_HANDLE              *HandleBuffer;\r
   UINTN                   NumberOfHandles;\r
   UINTN                   Index;\r
-  UINTN                   UhciSegmentNumber;\r
-  UINTN                   UhciBusNumber;\r
-  UINTN                   UhciDeviceNumber;\r
-  UINTN                   UhciFunctionNumber;\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
@@ -1533,6 +1677,19 @@ EhcDriverBindingStart (
     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
@@ -1556,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
@@ -1570,6 +1727,9 @@ 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
@@ -1582,16 +1742,20 @@ EhcDriverBindingStart (
     Status = EFI_UNSUPPORTED;\r
     goto CLOSE_PCIIO;\r
   }\r
-\r
-  if ((UsbClassCReg.PI == PCI_IF_UHCI) &&\r
-       (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && \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
-                    &UhciSegmentNumber,\r
-                    &UhciBusNumber,\r
-                    &UhciDeviceNumber,\r
-                    &UhciFunctionNumber\r
+                    &CompanionSegmentNumber,\r
+                    &CompanionBusNumber,\r
+                    &CompanionDeviceNumber,\r
+                    &CompanionFunctionNumber\r
                     );\r
     if (EFI_ERROR (Status)) {\r
       goto CLOSE_PCIIO;\r
@@ -1632,8 +1796,8 @@ EhcDriverBindingStart (
         goto CLOSE_PCIIO;\r
       }\r
 \r
-      if ((UsbClassCReg.PI == PCI_IF_EHCI) &&\r
-           (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && \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
@@ -1645,7 +1809,11 @@ EhcDriverBindingStart (
         if (EFI_ERROR (Status)) {\r
           goto CLOSE_PCIIO;\r
         }\r
-        if (EhciBusNumber == UhciBusNumber) {\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
@@ -1663,7 +1831,7 @@ EhcDriverBindingStart (
   //\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
@@ -1672,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
@@ -1685,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
@@ -1787,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
@@ -1834,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
@@ -1851,6 +2035,13 @@ 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
@@ -1865,6 +2056,12 @@ EhcDriverBindingStop (
     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