]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
MdeModulePkg: Enable port power if port power control feature is supported by EHCI
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / Ehci.c
index 9d181351a2fedd37a8020d74fe965ff04ea9f0bf..c141803c388071bab53b82cb7c7ade936e588abf 100644 (file)
@@ -1,7 +1,17 @@
-/** @file\r
+/** @file  \r
+  The Ehci controller driver.\r
 \r
-Copyright (c) 2006 - 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\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
+  Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached\r
+  to the EHCI controller before the UHCI driver attaches to the companion UHCI controller. \r
+  This way avoids the control transfer on a shared port between EHCI and companion host\r
+  controller when UHCI gets attached earlier than EHCI and a USB 2.0 device inserts.\r
+\r
+Copyright (c) 2006 - 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
@@ -9,15 +19,6 @@ http://opensource.org/licenses/bsd-license.php
 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
-Module Name:\r
-\r
-    Ehci.c\r
-\r
-Abstract:\r
-\r
-\r
-Revision History\r
-\r
 **/\r
 \r
 \r
@@ -43,21 +44,29 @@ USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {
   {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}\r
 };\r
 \r
+EFI_DRIVER_BINDING_PROTOCOL\r
+gEhciDriverBinding = {\r
+  EhcDriverBindingSupported,\r
+  EhcDriverBindingStart,\r
+  EhcDriverBindingStop,\r
+  0x30,\r
+  NULL,\r
+  NULL\r
+};\r
 \r
 /**\r
-  Retrieves the capablility of root hub ports.\r
+  Retrieves the capability of root hub ports.\r
 \r
-  @param  This                 This EFI_USB_HC_PROTOCOL instance.\r
-  @param  MaxSpeed             Max speed supported by the controller\r
-  @param  PortNumber           Number of the root hub ports.\r
-  @param  Is64BitCapable       Whether the controller supports 64-bit memory\r
-                               addressing.\r
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.\r
+  @param  MaxSpeed              Max speed supported by the controller.\r
+  @param  PortNumber            Number of the root hub ports.\r
+  @param  Is64BitCapable        Whether the controller supports 64-bit memory\r
+                                addressing.\r
 \r
-  @return EFI_SUCCESS           : host controller capability were retrieved successfully.\r
-  @return EFI_INVALID_PARAMETER : Either of the three capability pointer is NULL\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcGetCapability (\r
@@ -91,17 +100,16 @@ EhcGetCapability (
 /**\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
+  @param  This                  This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  Attributes            A bit mask of the reset operation to perform.\r
 \r
-  @return EFI_SUCCESS           : The reset operation succeeded.\r
-  @return EFI_INVALID_PARAMETER : Attributes is not valid.\r
-  @return EFI_UNSUPPOURTED      : The type of reset specified by Attributes is\r
-  @return not currently supported by the host controller.\r
-  @return EFI_DEVICE_ERROR      : Host controller isn't halted to reset.\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcReset (\r
@@ -170,22 +178,21 @@ ON_EXIT:
 /**\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
+  @param  This                   This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  State                  Variable to return the current host controller\r
+                                 state.\r
 \r
-  @return EFI_SUCCESS           : Host controller state was returned in State.\r
-  @return EFI_INVALID_PARAMETER : State is NULL.\r
-  @return EFI_DEVICE_ERROR      : An error was encountered while attempting to\r
-  @return retrieve the host controller's current state.\r
+  @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
-STATIC\r
 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
@@ -214,16 +221,15 @@ EhcGetState (
 /**\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
+  @param  This                  This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  State                 The state of the host controller that will be set.\r
 \r
-  @return EFI_SUCCESS           : The USB host controller was successfully placed\r
-  @return in the state specified by State.\r
-  @return EFI_INVALID_PARAMETER : State is invalid.\r
-  @return EFI_DEVICE_ERROR      : Failed to set the state due to device error.\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcSetState (\r
@@ -290,24 +296,23 @@ EhcSetState (
 /**\r
   Retrieves the current status of a USB root hub port.\r
 \r
-  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
-  @param  PortNumber           The root hub port to retrieve the state from.   This\r
-                               value is zero-based.\r
-  @param  PortStatus           Variable to receive the port state\r
+  @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
-  @return EFI_SUCCESS           : The status of the USB root hub port specified\r
-  @return by PortNumber was returned in PortStatus.\r
-  @return EFI_INVALID_PARAMETER : PortNumber is invalid.\r
-  @return EFI_DEVICE_ERROR      : Can't read register\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcGetRootHubPortStatus (\r
-  IN  CONST EFI_USB2_HC_PROTOCOL  *This,\r
-  IN  CONST UINT8                 PortNumber,\r
-  OUT       EFI_USB_PORT_STATUS   *PortStatus\r
+  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
@@ -382,16 +387,15 @@ ON_EXIT:
 /**\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
+  @param  This                  This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  PortNumber            Root hub port to set.\r
+  @param  PortFeature           Feature to set.\r
 \r
-  @return EFI_SUCCESS           : The feature specified by PortFeature was set\r
-  @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
-  @return EFI_DEVICE_ERROR      : Can't read register\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcSetRootHubPortFeature (\r
@@ -465,9 +469,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
@@ -490,19 +497,18 @@ ON_EXIT:
 /**\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
+  @param  This                  A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+  @param  PortNumber            Specifies the root hub port whose feature is\r
+                                requested to be cleared.\r
+  @param  PortFeature           Indicates the feature selector associated with the\r
+                                feature clear request.\r
 \r
-  @return EFI_SUCCESS           : The feature specified by PortFeature was cleared\r
-  @return for the USB root hub port specified by PortNumber.\r
-  @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
-  @return EFI_DEVICE_ERROR      : Can't read register\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcClearRootHubPortFeature (\r
@@ -595,6 +601,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
@@ -617,28 +631,27 @@ ON_EXIT:
 /**\r
   Submits control transfer to a target USB device.\r
 \r
-  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
-  @param  DeviceAddress        The target device address\r
-  @param  DeviceSpeed          Target device speed.\r
-  @param  MaximumPacketLength  Maximum packet size the default control transfer\r
-                               endpoint is capable of sending or receiving.\r
-  @param  Request              USB device request to send\r
-  @param  TransferDirection    Specifies the data direction for the data stage\r
-  @param  Data                 Data buffer to be transmitted or received from USB\r
-                               device.\r
-  @param  DataLength           The size (in bytes) of the data buffer\r
-  @param  TimeOut              Indicates the maximum timeout, in millisecond,\r
-  @param  Translator           Transaction translator to be used by this device.\r
-  @param  TransferResult       Return the result of this control transfer.\r
-\r
-  @return EFI_SUCCESS           : Transfer was completed successfully.\r
-  @return EFI_OUT_OF_RESOURCES  : The transfer failed due to lack of resources.\r
-  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
-  @return EFI_TIMEOUT           : Transfer failed due to timeout.\r
-  @return EFI_DEVICE_ERROR      : Transfer failed due to host controller or device error.\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcControlTransfer (\r
@@ -775,35 +788,33 @@ ON_EXIT:
 /**\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
+  @param  This                  This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  DeviceAddress         Target device address.\r
+  @param  EndPointAddress       Endpoint number and its direction in bit 7.\r
+  @param  DeviceSpeed           Device speed, Low speed device doesn't support bulk\r
+                                transfer.\r
+  @param  MaximumPacketLength   Maximum packet size the endpoint is capable of\r
+                                sending or receiving.\r
+  @param  DataBuffersNumber     Number of data buffers prepared for the transfer.\r
+  @param  Data                  Array of pointers to the buffers of data to transmit\r
                                 from or receive into.\r
-  @param  DataLength           The lenght of the data buffer\r
-  @param  DataToggle           On input, the initial data toggle for the transfer;\r
-                               On output, it is updated to to next data toggle to\r
-                               use                        of the subsequent bulk\r
-                               transfer.\r
-  @param  Translator           A pointr to the transaction translator data.\r
-  @param  TimeOut              Indicates the maximum time, in millisecond, which\r
-                               the transfer is allowed to complete.\r
-  @param  TransferResult       A pointer to the detailed result information of the\r
-                               bulk transfer.\r
-\r
-  @return EFI_SUCCESS           : The transfer was completed successfully.\r
-  @return EFI_OUT_OF_RESOURCES  : The transfer failed due to lack of resource.\r
-  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
-  @return EFI_TIMEOUT           : The transfer failed due to timeout.\r
-  @return EFI_DEVICE_ERROR      : The transfer failed due to host controller error.\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcBulkTransfer (\r
@@ -918,32 +929,31 @@ ON_EXIT:
   Submits an asynchronous interrupt transfer to an\r
   interrupt endpoint of a USB device.\r
 \r
-  @param  This                 This EFI_USB2_HC_PROTOCOL instance.\r
-  @param  DeviceAddress        Target device address\r
-  @param  EndPointAddress      Endpoint number and its direction encoded in bit 7\r
-  @param  DeviceSpeed          Indicates device speed.\r
-  @param  MaximumPacketLength  Maximum packet size the target endpoint is capable\r
-  @param  IsNewTransfer        If TRUE, to submit an new asynchronous interrupt\r
-                               transfer If FALSE, to remove the specified\r
-                               asynchronous interrupt\r
-  @param  DataToggle           On input, the initial data toggle to use; on output,\r
-                               it is updated to indicate the next data toggle\r
-  @param  PollingInterval      The he interval, in milliseconds, that the transfer\r
-                               is polled.\r
-  @param  DataLength           The length of data to receive at the rate specified\r
-                               by  PollingInterval.\r
-  @param  Translator           Transaction translator to use.\r
-  @param  CallBackFunction     Function to call at the rate specified by\r
-                               PollingInterval\r
-  @param  Context              Context to CallBackFunction.\r
-\r
-  @return EFI_SUCCESS           : The request has been successfully submitted or canceled.\r
-  @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
-  @return EFI_OUT_OF_RESOURCES  : The request failed due to a lack of resources.\r
-  @return EFI_DEVICE_ERROR      : The transfer failed due to host controller error.\r
+  @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
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcAsyncInterruptTransfer (\r
@@ -1067,30 +1077,29 @@ ON_EXIT:
   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
+  @param  This                  This EFI_USB2_HC_PROTOCOL instance.\r
+  @param  DeviceAddress         Target device address.\r
+  @param  EndPointAddress       Endpoint number and its direction encoded in bit 7\r
+  @param  DeviceSpeed           Indicates device speed.\r
+  @param  MaximumPacketLength   Maximum packet size the target endpoint is capable\r
+                                of sending or receiving.\r
+  @param  Data                  Buffer of data that will be transmitted to  USB\r
+                                device or received from USB device.\r
+  @param  DataLength            On input, the size, in bytes, of the data buffer; On\r
+                                output, the number of bytes transferred.\r
+  @param  DataToggle            On input, the initial data toggle to use; on output,\r
+                                it is updated to indicate the next data toggle.\r
+  @param  TimeOut               Maximum time, in second, to complete.\r
+  @param  Translator            Transaction translator to use.\r
+  @param  TransferResult        Variable to receive the transfer result.\r
+\r
+  @return EFI_SUCCESS           The transfer was completed successfully.\r
+  @return EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.\r
+  @return EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @return EFI_TIMEOUT           The transfer failed due to timeout.\r
+  @return EFI_DEVICE_ERROR      The failed due to host controller or device error\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcSyncInterruptTransfer (\r
@@ -1201,8 +1210,8 @@ ON_EXIT:
   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  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
@@ -1211,14 +1220,13 @@ ON_EXIT:
   @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  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
+  @param  TransferResult       Variable to receive the transfer result.\r
 \r
-  @return EFI_UNSUPPORTED : Isochronous transfer is unsupported.\r
+  @return EFI_UNSUPPORTED      Isochronous transfer is unsupported.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcIsochronousTransfer (\r
@@ -1242,8 +1250,8 @@ EhcIsochronousTransfer (
   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  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
@@ -1252,16 +1260,15 @@ EhcIsochronousTransfer (
   @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  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  IsochronousCallBack  Function to be called when the transfer complete.\r
   @param  Context              Context passed to the call back function as\r
-                               parameter\r
+                               parameter.\r
 \r
-  @return EFI_UNSUPPORTED : Isochronous transfer isn't supported\r
+  @return EFI_UNSUPPORTED      Isochronous transfer isn't supported.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 EhcAsyncIsochronousTransfer (\r
@@ -1281,29 +1288,22 @@ EhcAsyncIsochronousTransfer (
   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
+  @return EFI_SUCCESS       Success.\r
+          EFI_DEVICE_ERROR  Fail.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 EhcDriverEntryPoint (\r
   IN EFI_HANDLE           ImageHandle,\r
   IN EFI_SYSTEM_TABLE     *SystemTable\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Entry point for EFI drivers.\r
-\r
-Arguments:\r
-\r
-  ImageHandle - EFI_HANDLE\r
-  SystemTable - EFI_SYSTEM_TABLE\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS         Success\r
-  EFI_DEVICE_ERROR    Fail\r
-\r
---*/\r
 {\r
   return EfiLibInstallDriverBindingComponentName2 (\r
            ImageHandle,\r
@@ -1322,11 +1322,11 @@ Returns:
   be supported.\r
 \r
   @param  This                 Protocol instance pointer.\r
-  @param  Controlle            Handle of device to test\r
-  @param  RemainingDevicePath  Not used\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
+  @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
@@ -1360,7 +1360,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
@@ -1373,9 +1373,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))) {\r
 \r
     Status = EFI_UNSUPPORTED;\r
   }\r
@@ -1393,16 +1392,15 @@ ON_EXIT:
 \r
 \r
 /**\r
-  Create and initialize a USB2_HC_DEV\r
+  Create and initialize a USB2_HC_DEV.\r
 \r
-  @param  PciIo                  The PciIo on this device\r
-  @param  OriginalPciAttributes  Original PCI attributes\r
+  @param  PciIo                  The PciIo on this device.\r
+  @param  OriginalPciAttributes  Original PCI attributes.\r
 \r
-  @return The allocated and initialized USB2_HC_DEV structure\r
-  @return if created, otherwise NULL.\r
+  @return  The allocated and initialized USB2_HC_DEV structure if created,\r
+           otherwise NULL.\r
 \r
 **/\r
-STATIC\r
 USB2_HC_DEV *\r
 EhcCreateUsb2Hc (\r
   IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
@@ -1436,8 +1434,8 @@ EhcCreateUsb2Hc (
   Ehc->Usb2Hc.GetRootHubPortStatus      = EhcGetRootHubPortStatus;\r
   Ehc->Usb2Hc.SetRootHubPortFeature     = EhcSetRootHubPortFeature;\r
   Ehc->Usb2Hc.ClearRootHubPortFeature   = EhcClearRootHubPortFeature;\r
-  Ehc->Usb2Hc.MajorRevision             = 0x1;\r
-  Ehc->Usb2Hc.MinorRevision             = 0x1;\r
+  Ehc->Usb2Hc.MajorRevision             = 0x2;\r
+  Ehc->Usb2Hc.MinorRevision             = 0x0;\r
 \r
   Ehc->PciIo                 = PciIo;\r
   Ehc->OriginalPciAttributes = OriginalPciAttributes;\r
@@ -1450,13 +1448,21 @@ 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
   //\r
   // Create AsyncRequest Polling Timer\r
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
                   TPL_CALLBACK,\r
-                  EhcMoniteAsyncRequests,\r
+                  EhcMonitorAsyncRequests,\r
                   Ehc,\r
                   &Ehc->PollTimer\r
                   );\r
@@ -1469,18 +1475,43 @@ 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 hanlder 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
+  Starting the Usb EHCI Driver.\r
 \r
   @param  This                 Protocol instance pointer.\r
-  @param  Controller           Handle of device to test\r
-  @param  RemainingDevicePath  Not used\r
+  @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
+  @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
@@ -1494,9 +1525,22 @@ 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                   UhciSegmentNumber;\r
+  UINTN                   UhciBusNumber;\r
+  UINTN                   UhciDeviceNumber;\r
+  UINTN                   UhciFunctionNumber;\r
+  UINTN                   EhciSegmentNumber;\r
+  UINTN                   EhciBusNumber;\r
+  UINTN                   EhciDeviceNumber;\r
+  UINTN                   EhciFunctionNumber;\r
 \r
   //\r
   // Open the PciIo Protocol, then enable the USB host controller\r
@@ -1511,8 +1555,7 @@ 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
   PciAttributesSaved = FALSE;\r
@@ -1552,6 +1595,107 @@ 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 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 driver attaches to UHCI host controller.\r
+  //\r
+  if ((UsbClassCReg.ProgInterface == PCI_IF_UHCI) &&\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
+                    );\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 == UhciBusNumber) {\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
@@ -1577,7 +1721,7 @@ 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
@@ -1604,6 +1748,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
@@ -1624,7 +1783,7 @@ EhcDriverBindingStart (
     );\r
 \r
 \r
-  DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %x\n", Controller));\r
+  DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));\r
   return EFI_SUCCESS;\r
 \r
 UNINSTALL_USBHC:\r
@@ -1640,7 +1799,7 @@ FREE_POOL:
   gBS->FreePool (Ehc);\r
 \r
 CLOSE_PCIIO:\r
-  if (PciAttributesSaved == TRUE) {\r
+  if (PciAttributesSaved) {\r
     //\r
     // Restore original PCI attributes\r
     //\r
@@ -1668,12 +1827,12 @@ CLOSE_PCIIO:
   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  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
+  @return EFI_SUCCESS          Success.\r
+  @return EFI_DEVICE_ERROR     Fail.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1732,12 +1891,22 @@ EhcDriverBindingStop (
     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) {\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 controller.\r
+  //\r
+  EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);\r
+\r
   //\r
   // Restore original PCI attributes\r
   //\r
@@ -1760,12 +1929,3 @@ EhcDriverBindingStop (
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_DRIVER_BINDING_PROTOCOL\r
-gEhciDriverBinding = {\r
-  EhcDriverBindingSupported,\r
-  EhcDriverBindingStart,\r
-  EhcDriverBindingStop,\r
-  0x10,\r
-  NULL,\r
-  NULL\r
-};\r