/** @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
-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
-Module Name:\r
-\r
- Ehci.c\r
-\r
-Abstract:\r
-\r
-\r
-Revision History\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
{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
\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
- EHC_DEBUG (("EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
+ DEBUG ((EFI_D_INFO, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
\r
gBS->RestoreTPL (OldTpl);\r
return EFI_SUCCESS;\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
+ @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
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
//\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_TIME);\r
+ Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
\r
if (EFI_ERROR (Status)) {\r
Status = EFI_DEVICE_ERROR;\r
EhcAckAllInterrupt (Ehc);\r
EhcFreeSched (Ehc);\r
\r
- Status = EhcResetHC (Ehc, EHC_STALL_1_SECOND);\r
+ Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
\r
if (EFI_ERROR (Status)) {\r
goto ON_EXIT;\r
}\r
\r
ON_EXIT:\r
- EHC_DEBUG (("EhcReset: exit status %r\n", Status));\r
+ DEBUG ((EFI_D_INFO, "EhcReset: exit status %r\n", Status));\r
gBS->RestoreTPL (OldTpl);\r
return Status;\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
+ @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
\r
gBS->RestoreTPL (OldTpl);\r
\r
- EHC_DEBUG (("EhcGetState: current state %d\n", *State));\r
+ DEBUG ((EFI_D_INFO, "EhcGetState: current state %d\n", *State));\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
+ @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
\r
switch (State) {\r
case EfiUsbHcStateHalt:\r
- Status = EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+ Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
break;\r
\r
case EfiUsbHcStateOperational:\r
break;\r
}\r
\r
- Status = EhcRunHC (Ehc, EHC_GENERIC_TIME);\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[EHCI1.0-2.3.1]\r
+ //\r
+ if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+\r
+ Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);\r
break;\r
\r
case EfiUsbHcStateSuspend:\r
Status = EFI_INVALID_PARAMETER;\r
}\r
\r
- EHC_DEBUG (("EhcSetState: exit status %r\n", Status));\r
+ DEBUG ((EFI_D_INFO, "EhcSetState: exit status %r\n", Status));\r
gBS->RestoreTPL (OldTpl);\r
return Status;\r
}\r
/**\r
Retrieves the current status of a USB root hub port.\r
\r
- @param This This EFI_USB2_HC_PROTOCOL instance.\r
- @param PortNumber The root hub port to retrieve the state from. This\r
- value is zero-based.\r
- @param PortStatus Variable to receive the port state\r
+ @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
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
/**\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
// Make sure Host Controller not halt before reset it\r
//\r
if (EhcIsHalt (Ehc)) {\r
- Status = EhcRunHC (Ehc, EHC_GENERIC_TIME);\r
+ Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);\r
\r
if (EFI_ERROR (Status)) {\r
- EHC_DEBUG (("EhcSetRootHubPortFeature :failed to start HC - %r\n", Status));\r
+ DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status));\r
break;\r
}\r
}\r
\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
}\r
\r
ON_EXIT:\r
- EHC_DEBUG (("EhcSetRootHubPortFeature: exit status %r\n", Status));\r
+ DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status));\r
\r
gBS->RestoreTPL (OldTpl);\r
return Status;\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
+ @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
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
}\r
\r
ON_EXIT:\r
- EHC_DEBUG (("EhcClearRootHubPortFeature: exit status %r\n", Status));\r
+ DEBUG ((EFI_D_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status));\r
gBS->RestoreTPL (OldTpl);\r
return Status;\r
}\r
/**\r
Submits control transfer to a target USB device.\r
\r
- @param This This EFI_USB2_HC_PROTOCOL instance.\r
- @param DeviceAddress The target device address\r
- @param DeviceSpeed Target device speed.\r
- @param MaximumPacketLength Maximum packet size the default control transfer\r
- endpoint is capable of sending or receiving.\r
- @param Request USB device request to send\r
- @param TransferDirection Specifies the data direction for the data stage\r
- @param Data Data buffer to be transmitted or received from USB\r
- device.\r
- @param DataLength The size (in bytes) of the data buffer\r
- @param TimeOut Indicates the maximum timeout, in millisecond,\r
- @param Translator Transaction translator to be used by this device.\r
- @param TransferResult Return the result of this control transfer.\r
-\r
- @return EFI_SUCCESS : Transfer was completed successfully.\r
- @return EFI_OUT_OF_RESOURCES : The transfer failed due to lack of resources.\r
- @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
- @return EFI_TIMEOUT : Transfer failed due to timeout.\r
- @return EFI_DEVICE_ERROR : Transfer failed due to host controller or device error.\r
+ @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
*TransferResult = EFI_USB_ERR_SYSTEM;\r
\r
if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
- EHC_ERROR (("EhcControlTransfer: HC halted at entrance\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcControlTransfer: HC halted at entrance\n"));\r
\r
EhcAckAllInterrupt (Ehc);\r
goto ON_EXIT;\r
);\r
\r
if (Urb == NULL) {\r
- EHC_ERROR (("EhcControlTransfer: failed to create URB"));\r
+ DEBUG ((EFI_D_ERROR, "EhcControlTransfer: failed to create URB"));\r
\r
Status = EFI_OUT_OF_RESOURCES;\r
goto ON_EXIT;\r
gBS->RestoreTPL (OldTpl);\r
\r
if (EFI_ERROR (Status)) {\r
- EHC_ERROR (("EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+ DEBUG ((EFI_D_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
}\r
\r
return Status;\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
+ @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
Status = EFI_DEVICE_ERROR;\r
\r
if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
- EHC_ERROR (("EhcBulkTransfer: HC is halted\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: HC is halted\n"));\r
\r
EhcAckAllInterrupt (Ehc);\r
goto ON_EXIT;\r
);\r
\r
if (Urb == NULL) {\r
- EHC_ERROR (("EhcBulkTransfer: failed to create URB\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: failed to create URB\n"));\r
\r
Status = EFI_OUT_OF_RESOURCES;\r
goto ON_EXIT;\r
gBS->RestoreTPL (OldTpl);\r
\r
if (EFI_ERROR (Status)) {\r
- EHC_ERROR (("EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+ DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
}\r
\r
return Status;\r
Submits an asynchronous interrupt transfer to an\r
interrupt endpoint of a USB device.\r
\r
- @param This This EFI_USB2_HC_PROTOCOL instance.\r
- @param DeviceAddress Target device address\r
- @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
- @param DeviceSpeed Indicates device speed.\r
- @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
- @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt\r
- transfer If FALSE, to remove the specified\r
- asynchronous interrupt\r
- @param DataToggle On input, the initial data toggle to use; on output,\r
- it is updated to indicate the next data toggle\r
- @param PollingInterval The he interval, in milliseconds, that the transfer\r
- is polled.\r
- @param DataLength The length of data to receive at the rate specified\r
- by PollingInterval.\r
- @param Translator Transaction translator to use.\r
- @param CallBackFunction Function to call at the rate specified by\r
- PollingInterval\r
- @param Context Context to CallBackFunction.\r
-\r
- @return EFI_SUCCESS : The request has been successfully submitted or canceled.\r
- @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
- @return EFI_OUT_OF_RESOURCES : The request failed due to a lack of resources.\r
- @return EFI_DEVICE_ERROR : The transfer failed due to host controller error.\r
+ @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
URB *Urb;\r
EFI_TPL OldTpl;\r
EFI_STATUS Status;\r
- UINT8 *Data;\r
\r
//\r
// Validate parameters\r
if (!IsNewTransfer) {\r
Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);\r
\r
- EHC_DEBUG (("EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));\r
+ DEBUG ((EFI_D_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));\r
goto ON_EXIT;\r
}\r
\r
Status = EFI_SUCCESS;\r
\r
if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
- EHC_ERROR (("EhcAsyncInterruptTransfer: HC is halt\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n"));\r
EhcAckAllInterrupt (Ehc);\r
\r
Status = EFI_DEVICE_ERROR;\r
\r
EhcAckAllInterrupt (Ehc);\r
\r
- Data = AllocatePool (DataLength);\r
-\r
- if (Data == NULL) {\r
- EHC_ERROR (("EhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
-\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- Urb = EhcCreateUrb (\r
+ Urb = EhciInsertAsyncIntTransfer (\r
Ehc,\r
DeviceAddress,\r
EndPointAddress,\r
*DataToggle,\r
MaximumPacketLength,\r
Translator,\r
- EHC_INT_TRANSFER_ASYNC,\r
- NULL,\r
- Data,\r
DataLength,\r
CallBackFunction,\r
Context,\r
);\r
\r
if (Urb == NULL) {\r
- EHC_ERROR (("EhcAsyncInterruptTransfer: failed to create URB\n"));\r
-\r
- gBS->FreePool (Data);\r
Status = EFI_OUT_OF_RESOURCES;\r
goto ON_EXIT;\r
}\r
\r
- //\r
- // New asynchronous transfer must inserted to the head.\r
- // Check the comments in EhcMoniteAsyncRequests\r
- //\r
- EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
- InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);\r
-\r
ON_EXIT:\r
Ehc->PciIo->Flush (Ehc->PciIo);\r
gBS->RestoreTPL (OldTpl);\r
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
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
Status = EFI_DEVICE_ERROR;\r
\r
if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
- EHC_ERROR (("EhcSyncInterruptTransfer: HC is halt\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));\r
\r
EhcAckAllInterrupt (Ehc);\r
goto ON_EXIT;\r
);\r
\r
if (Urb == NULL) {\r
- EHC_ERROR (("EhcSyncInterruptTransfer: failed to create URB\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n"));\r
\r
Status = EFI_OUT_OF_RESOURCES;\r
goto ON_EXIT;\r
Status = EFI_SUCCESS;\r
}\r
\r
+ EhcFreeUrb (Ehc, Urb);\r
ON_EXIT:\r
Ehc->PciIo->Flush (Ehc->PciIo);\r
gBS->RestoreTPL (OldTpl);\r
\r
if (EFI_ERROR (Status)) {\r
- EHC_ERROR (("EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+ DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
}\r
\r
return Status;\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 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
@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
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
@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
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 EfiLibInstallAllDriverProtocols (\r
+ return EfiLibInstallDriverBindingComponentName2 (\r
ImageHandle,\r
SystemTable,\r
&gEhciDriverBinding,\r
ImageHandle,\r
&gEhciComponentName,\r
- NULL,\r
- NULL\r
+ &gEhciComponentName2\r
);\r
}\r
\r
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
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
//\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
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
+ Create and initialize a USB2_HC_DEV.\r
\r
- @param PciIo The PciIo on this device\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\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
+ 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
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->PciIo = PciIo;\r
+ Ehc->DevicePath = DevicePath;\r
+ Ehc->OriginalPciAttributes = OriginalPciAttributes;\r
\r
InitializeListHead (&Ehc->AsyncIntTransfers);\r
\r
Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);\r
Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;\r
\r
- EHC_DEBUG (("EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));\r
+ 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
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
+ 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
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
);\r
\r
if (EFI_ERROR (Status)) {\r
- EHC_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
+ //\r
Status = PciIo->Attributes (\r
PciIo,\r
- EfiPciIoAttributeOperationEnable,\r
- EFI_PCI_DEVICE_ENABLE,\r
- NULL\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 &= (UINT64)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, "EhcDriverBindingStart: failed to enable controller\n"));\r
+ 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
- EHC_ERROR (("EhcDriverBindingStart: failed to enable controller\n"));\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);\r
+ Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, OriginalPciAttributes);\r
\r
if (Ehc == NULL) {\r
- EHC_ERROR (("EhcDriverBindingStart: failed to create USB2_HC\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));\r
\r
Status = EFI_OUT_OF_RESOURCES;\r
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
);\r
\r
if (EFI_ERROR (Status)) {\r
- EHC_ERROR (("EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
goto FREE_POOL;\r
}\r
\r
//\r
- // Robustnesss improvement such as for UoL\r
+ // Robustnesss improvement such as for Duet platform\r
+ // Default is not required.\r
//\r
- EhcClearLegacySupport (Ehc);\r
- EhcResetHC (Ehc, EHC_STALL_1_SECOND);\r
+ if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
+ EhcClearLegacySupport (Ehc);\r
+ }\r
+\r
+ if (!EhcIsDebugPortInUse (Ehc, NULL)) {\r
+ EhcResetHC (Ehc, EHC_RESET_TIMEOUT);\r
+ }\r
\r
Status = EhcInitHC (Ehc);\r
\r
if (EFI_ERROR (Status)) {\r
- EHC_ERROR (("EhcDriverBindingStart: failed to init host controller\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));\r
goto UNINSTALL_USBHC;\r
}\r
\r
//\r
// Start the asynchronous interrupt monitor\r
//\r
- Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_TIME);\r
+ Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);\r
\r
if (EFI_ERROR (Status)) {\r
- EHC_ERROR (("EhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
+ DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
+\r
+ EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);\r
+ goto UNINSTALL_USBHC;\r
+ }\r
\r
- EhcHaltHC (Ehc, EHC_GENERIC_TIME);\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
// Install the component name protocol, don't fail the start\r
// because of something for display.\r
//\r
- AddUnicodeString (\r
+ AddUnicodeString2 (\r
"eng",\r
gEhciComponentName.SupportedLanguages,\r
&Ehc->ControllerNameTable,\r
- L"Enhanced Host Controller (USB 2.0)"\r
+ L"Enhanced Host Controller (USB 2.0)",\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gEhciComponentName2.SupportedLanguages,\r
+ &Ehc->ControllerNameTable,\r
+ L"Enhanced Host Controller (USB 2.0)",\r
+ FALSE\r
);\r
\r
- EHC_DEBUG (("EhcDriverBindingStart: EHCI started for controller @ %x\n", Controller));\r
+\r
+ DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));\r
return EFI_SUCCESS;\r
\r
UNINSTALL_USBHC:\r
gBS->FreePool (Ehc);\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
\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
- @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
Ehc = EHC_FROM_THIS (Usb2Hc);\r
PciIo = Ehc->PciIo;\r
\r
- //\r
- // Stop AsyncRequest Polling timer then stop the EHCI driver\r
- // and uninstall the EHCI protocl.\r
- //\r
- gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_TIME);\r
- EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
-\r
Status = gBS->UninstallProtocolInterface (\r
Controller,\r
&gEfiUsb2HcProtocolGuid,\r
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) {\r
+ if (Ehc->ControllerNameTable != NULL) {\r
FreeUnicodeStringTable (Ehc->ControllerNameTable);\r
}\r
\r
//\r
- // Disable the USB Host Controller\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
PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationDisable,\r
- EFI_PCI_DEVICE_ENABLE,\r
- NULL\r
- );\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ Ehc->OriginalPciAttributes,\r
+ NULL\r
+ );\r
\r
gBS->CloseProtocol (\r
Controller,\r
Controller\r
);\r
\r
- gBS->FreePool (Ehc);\r
- return Status;\r
+ FreePool (Ehc);\r
+\r
+ 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