2 The Ehci controller driver.
4 EhciDxe driver is responsible for managing the behavior of EHCI controller.
5 It implements the interfaces of monitoring the status of all ports and transferring
6 Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.
8 Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached
9 to the EHCI controller before a UHCI or OHCI driver attaches to the companion UHCI or
10 OHCI controller. This way avoids the control transfer on a shared port between EHCI
11 and companion host controller when UHCI or OHCI gets attached earlier than EHCI and a
12 USB 2.0 device inserts.
14 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
15 SPDX-License-Identifier: BSD-2-Clause-Patent
22 // Two arrays used to translate the EHCI port state (change)
23 // to the UEFI protocol's port state (change).
25 USB_PORT_STATE_MAP mUsbPortStateMap
[] = {
26 { PORTSC_CONN
, USB_PORT_STAT_CONNECTION
},
27 { PORTSC_ENABLED
, USB_PORT_STAT_ENABLE
},
28 { PORTSC_SUSPEND
, USB_PORT_STAT_SUSPEND
},
29 { PORTSC_OVERCUR
, USB_PORT_STAT_OVERCURRENT
},
30 { PORTSC_RESET
, USB_PORT_STAT_RESET
},
31 { PORTSC_POWER
, USB_PORT_STAT_POWER
},
32 { PORTSC_OWNER
, USB_PORT_STAT_OWNER
}
35 USB_PORT_STATE_MAP mUsbPortChangeMap
[] = {
36 { PORTSC_CONN_CHANGE
, USB_PORT_STAT_C_CONNECTION
},
37 { PORTSC_ENABLE_CHANGE
, USB_PORT_STAT_C_ENABLE
},
38 { PORTSC_OVERCUR_CHANGE
, USB_PORT_STAT_C_OVERCURRENT
}
41 EFI_DRIVER_BINDING_PROTOCOL
42 gEhciDriverBinding
= {
43 EhcDriverBindingSupported
,
44 EhcDriverBindingStart
,
52 Retrieves the capability of root hub ports.
54 @param This This EFI_USB_HC_PROTOCOL instance.
55 @param MaxSpeed Max speed supported by the controller.
56 @param PortNumber Number of the root hub ports.
57 @param Is64BitCapable Whether the controller supports 64-bit memory
60 @retval EFI_SUCCESS Host controller capability were retrieved successfully.
61 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
67 IN EFI_USB2_HC_PROTOCOL
*This
,
69 OUT UINT8
*PortNumber
,
70 OUT UINT8
*Is64BitCapable
76 if ((MaxSpeed
== NULL
) || (PortNumber
== NULL
) || (Is64BitCapable
== NULL
)) {
77 return EFI_INVALID_PARAMETER
;
80 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
81 Ehc
= EHC_FROM_THIS (This
);
83 *MaxSpeed
= EFI_USB_SPEED_HIGH
;
84 *PortNumber
= (UINT8
)(Ehc
->HcStructParams
& HCSP_NPORTS
);
85 *Is64BitCapable
= (UINT8
)Ehc
->Support64BitDma
;
87 DEBUG ((DEBUG_INFO
, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber
, *Is64BitCapable
));
89 gBS
->RestoreTPL (OldTpl
);
94 Provides software reset for the USB host controller.
96 @param This This EFI_USB2_HC_PROTOCOL instance.
97 @param Attributes A bit mask of the reset operation to perform.
99 @retval EFI_SUCCESS The reset operation succeeded.
100 @retval EFI_INVALID_PARAMETER Attributes is not valid.
101 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
102 not currently supported by the host controller.
103 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
109 IN EFI_USB2_HC_PROTOCOL
*This
,
117 Ehc
= EHC_FROM_THIS (This
);
119 if (Ehc
->DevicePath
!= NULL
) {
121 // Report Status Code to indicate reset happens
123 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
125 (EFI_IO_BUS_USB
| EFI_IOB_PC_RESET
),
130 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
132 switch (Attributes
) {
133 case EFI_USB_HC_RESET_GLOBAL
:
135 // Flow through, same behavior as Host Controller Reset
137 case EFI_USB_HC_RESET_HOST_CONTROLLER
:
139 // Host Controller must be Halt when Reset it
141 if (EhcIsDebugPortInUse (Ehc
, NULL
)) {
142 Status
= EFI_SUCCESS
;
146 if (!EhcIsHalt (Ehc
)) {
147 Status
= EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
149 if (EFI_ERROR (Status
)) {
150 Status
= EFI_DEVICE_ERROR
;
156 // Clean up the asynchronous transfers, currently only
157 // interrupt supports asynchronous operation.
159 EhciDelAllAsyncIntTransfers (Ehc
);
160 EhcAckAllInterrupt (Ehc
);
163 Status
= EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
165 if (EFI_ERROR (Status
)) {
169 Status
= EhcInitHC (Ehc
);
172 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG
:
173 case EFI_USB_HC_RESET_HOST_WITH_DEBUG
:
174 Status
= EFI_UNSUPPORTED
;
178 Status
= EFI_INVALID_PARAMETER
;
182 DEBUG ((DEBUG_INFO
, "EhcReset: exit status %r\n", Status
));
183 gBS
->RestoreTPL (OldTpl
);
188 Retrieve the current state of the USB host controller.
190 @param This This EFI_USB2_HC_PROTOCOL instance.
191 @param State Variable to return the current host controller
194 @retval EFI_SUCCESS Host controller state was returned in State.
195 @retval EFI_INVALID_PARAMETER State is NULL.
196 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
197 retrieve the host controller's current state.
203 IN EFI_USB2_HC_PROTOCOL
*This
,
204 OUT EFI_USB_HC_STATE
*State
211 return EFI_INVALID_PARAMETER
;
214 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
215 Ehc
= EHC_FROM_THIS (This
);
217 if (EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
218 *State
= EfiUsbHcStateHalt
;
220 *State
= EfiUsbHcStateOperational
;
223 gBS
->RestoreTPL (OldTpl
);
225 DEBUG ((DEBUG_INFO
, "EhcGetState: current state %d\n", *State
));
230 Sets the USB host controller to a specific state.
232 @param This This EFI_USB2_HC_PROTOCOL instance.
233 @param State The state of the host controller that will be set.
235 @retval EFI_SUCCESS The USB host controller was successfully placed
236 in the state specified by State.
237 @retval EFI_INVALID_PARAMETER State is invalid.
238 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
244 IN EFI_USB2_HC_PROTOCOL
*This
,
245 IN EFI_USB_HC_STATE State
251 EFI_USB_HC_STATE CurState
;
253 Status
= EhcGetState (This
, &CurState
);
255 if (EFI_ERROR (Status
)) {
256 return EFI_DEVICE_ERROR
;
259 if (CurState
== State
) {
263 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
264 Ehc
= EHC_FROM_THIS (This
);
267 case EfiUsbHcStateHalt
:
268 Status
= EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
271 case EfiUsbHcStateOperational
:
272 if (EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_SYS_ERROR
)) {
273 Status
= EFI_DEVICE_ERROR
;
278 // Software must not write a one to this field unless the host controller
279 // is in the Halted state. Doing so will yield undefined results.
280 // refers to Spec[EHCI1.0-2.3.1]
282 if (!EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
283 Status
= EFI_DEVICE_ERROR
;
287 Status
= EhcRunHC (Ehc
, EHC_GENERIC_TIMEOUT
);
290 case EfiUsbHcStateSuspend
:
291 Status
= EFI_UNSUPPORTED
;
295 Status
= EFI_INVALID_PARAMETER
;
298 DEBUG ((DEBUG_INFO
, "EhcSetState: exit status %r\n", Status
));
299 gBS
->RestoreTPL (OldTpl
);
304 Retrieves the current status of a USB root hub port.
306 @param This This EFI_USB2_HC_PROTOCOL instance.
307 @param PortNumber The root hub port to retrieve the state from.
308 This value is zero-based.
309 @param PortStatus Variable to receive the port state.
311 @retval EFI_SUCCESS The status of the USB root hub port specified.
312 by PortNumber was returned in PortStatus.
313 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
314 @retval EFI_DEVICE_ERROR Can't read register.
319 EhcGetRootHubPortStatus (
320 IN EFI_USB2_HC_PROTOCOL
*This
,
322 OUT EFI_USB_PORT_STATUS
*PortStatus
334 if (PortStatus
== NULL
) {
335 return EFI_INVALID_PARAMETER
;
338 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
340 Ehc
= EHC_FROM_THIS (This
);
341 Status
= EFI_SUCCESS
;
343 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
345 if (PortNumber
>= TotalPort
) {
346 Status
= EFI_INVALID_PARAMETER
;
350 Offset
= (UINT32
)(EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
));
351 PortStatus
->PortStatus
= 0;
352 PortStatus
->PortChangeStatus
= 0;
354 if (EhcIsDebugPortInUse (Ehc
, &PortNumber
)) {
358 State
= EhcReadOpReg (Ehc
, Offset
);
361 // Identify device speed. If in K state, it is low speed.
362 // If the port is enabled after reset, the device is of
363 // high speed. The USB bus driver should retrieve the actual
364 // port speed after reset.
366 if (EHC_BIT_IS_SET (State
, PORTSC_LINESTATE_K
)) {
367 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
368 } else if (EHC_BIT_IS_SET (State
, PORTSC_ENABLED
)) {
369 PortStatus
->PortStatus
|= USB_PORT_STAT_HIGH_SPEED
;
373 // Convert the EHCI port/port change state to UEFI status
375 MapSize
= sizeof (mUsbPortStateMap
) / sizeof (USB_PORT_STATE_MAP
);
377 for (Index
= 0; Index
< MapSize
; Index
++) {
378 if (EHC_BIT_IS_SET (State
, mUsbPortStateMap
[Index
].HwState
)) {
379 PortStatus
->PortStatus
= (UINT16
)(PortStatus
->PortStatus
| mUsbPortStateMap
[Index
].UefiState
);
383 MapSize
= sizeof (mUsbPortChangeMap
) / sizeof (USB_PORT_STATE_MAP
);
385 for (Index
= 0; Index
< MapSize
; Index
++) {
386 if (EHC_BIT_IS_SET (State
, mUsbPortChangeMap
[Index
].HwState
)) {
387 PortStatus
->PortChangeStatus
= (UINT16
)(PortStatus
->PortChangeStatus
| mUsbPortChangeMap
[Index
].UefiState
);
392 gBS
->RestoreTPL (OldTpl
);
397 Sets a feature for the specified root hub port.
399 @param This This EFI_USB2_HC_PROTOCOL instance.
400 @param PortNumber Root hub port to set.
401 @param PortFeature Feature to set.
403 @retval EFI_SUCCESS The feature specified by PortFeature was set.
404 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
405 @retval EFI_DEVICE_ERROR Can't read register.
410 EhcSetRootHubPortFeature (
411 IN EFI_USB2_HC_PROTOCOL
*This
,
413 IN EFI_USB_PORT_FEATURE PortFeature
423 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
424 Ehc
= EHC_FROM_THIS (This
);
425 Status
= EFI_SUCCESS
;
427 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
429 if (PortNumber
>= TotalPort
) {
430 Status
= EFI_INVALID_PARAMETER
;
434 Offset
= (UINT32
)(EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
));
435 State
= EhcReadOpReg (Ehc
, Offset
);
438 // Mask off the port status change bits, these bits are
441 State
&= ~PORTSC_CHANGE_MASK
;
443 switch (PortFeature
) {
444 case EfiUsbPortEnable
:
446 // Sofeware can't set this bit, Port can only be enable by
447 // EHCI as a part of the reset and enable
449 State
|= PORTSC_ENABLED
;
450 EhcWriteOpReg (Ehc
, Offset
, State
);
453 case EfiUsbPortSuspend
:
454 State
|= PORTSC_SUSPEND
;
455 EhcWriteOpReg (Ehc
, Offset
, State
);
458 case EfiUsbPortReset
:
460 // Make sure Host Controller not halt before reset it
462 if (EhcIsHalt (Ehc
)) {
463 Status
= EhcRunHC (Ehc
, EHC_GENERIC_TIMEOUT
);
465 if (EFI_ERROR (Status
)) {
466 DEBUG ((DEBUG_INFO
, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status
));
472 // Set one to PortReset bit must also set zero to PortEnable bit
474 State
|= PORTSC_RESET
;
475 State
&= ~PORTSC_ENABLED
;
476 EhcWriteOpReg (Ehc
, Offset
, State
);
479 case EfiUsbPortPower
:
481 // Set port power bit when PPC is 1
483 if ((Ehc
->HcCapParams
& HCSP_PPC
) == HCSP_PPC
) {
484 State
|= PORTSC_POWER
;
485 EhcWriteOpReg (Ehc
, Offset
, State
);
490 case EfiUsbPortOwner
:
491 State
|= PORTSC_OWNER
;
492 EhcWriteOpReg (Ehc
, Offset
, State
);
496 Status
= EFI_INVALID_PARAMETER
;
500 DEBUG ((DEBUG_INFO
, "EhcSetRootHubPortFeature: exit status %r\n", Status
));
502 gBS
->RestoreTPL (OldTpl
);
507 Clears a feature for the specified root hub port.
509 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
510 @param PortNumber Specifies the root hub port whose feature is
511 requested to be cleared.
512 @param PortFeature Indicates the feature selector associated with the
513 feature clear request.
515 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
516 for the USB root hub port specified by PortNumber.
517 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
518 @retval EFI_DEVICE_ERROR Can't read register.
523 EhcClearRootHubPortFeature (
524 IN EFI_USB2_HC_PROTOCOL
*This
,
526 IN EFI_USB_PORT_FEATURE PortFeature
536 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
537 Ehc
= EHC_FROM_THIS (This
);
538 Status
= EFI_SUCCESS
;
540 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
542 if (PortNumber
>= TotalPort
) {
543 Status
= EFI_INVALID_PARAMETER
;
547 Offset
= EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
);
548 State
= EhcReadOpReg (Ehc
, Offset
);
549 State
&= ~PORTSC_CHANGE_MASK
;
551 switch (PortFeature
) {
552 case EfiUsbPortEnable
:
554 // Clear PORT_ENABLE feature means disable port.
556 State
&= ~PORTSC_ENABLED
;
557 EhcWriteOpReg (Ehc
, Offset
, State
);
560 case EfiUsbPortSuspend
:
562 // A write of zero to this bit is ignored by the host
563 // controller. The host controller will unconditionally
564 // set this bit to a zero when:
565 // 1. software sets the Forct Port Resume bit to a zero from a one.
566 // 2. software sets the Port Reset bit to a one frome a zero.
568 State
&= ~PORSTSC_RESUME
;
569 EhcWriteOpReg (Ehc
, Offset
, State
);
572 case EfiUsbPortReset
:
574 // Clear PORT_RESET means clear the reset signal.
576 State
&= ~PORTSC_RESET
;
577 EhcWriteOpReg (Ehc
, Offset
, State
);
580 case EfiUsbPortOwner
:
582 // Clear port owner means this port owned by EHC
584 State
&= ~PORTSC_OWNER
;
585 EhcWriteOpReg (Ehc
, Offset
, State
);
588 case EfiUsbPortConnectChange
:
590 // Clear connect status change
592 State
|= PORTSC_CONN_CHANGE
;
593 EhcWriteOpReg (Ehc
, Offset
, State
);
596 case EfiUsbPortEnableChange
:
598 // Clear enable status change
600 State
|= PORTSC_ENABLE_CHANGE
;
601 EhcWriteOpReg (Ehc
, Offset
, State
);
604 case EfiUsbPortOverCurrentChange
:
606 // Clear PortOverCurrent change
608 State
|= PORTSC_OVERCUR_CHANGE
;
609 EhcWriteOpReg (Ehc
, Offset
, State
);
612 case EfiUsbPortPower
:
614 // Clear port power bit when PPC is 1
616 if ((Ehc
->HcCapParams
& HCSP_PPC
) == HCSP_PPC
) {
617 State
&= ~PORTSC_POWER
;
618 EhcWriteOpReg (Ehc
, Offset
, State
);
622 case EfiUsbPortSuspendChange
:
623 case EfiUsbPortResetChange
:
625 // Not supported or not related operation
630 Status
= EFI_INVALID_PARAMETER
;
635 DEBUG ((DEBUG_INFO
, "EhcClearRootHubPortFeature: exit status %r\n", Status
));
636 gBS
->RestoreTPL (OldTpl
);
641 Submits control transfer to a target USB device.
643 @param This This EFI_USB2_HC_PROTOCOL instance.
644 @param DeviceAddress The target device address.
645 @param DeviceSpeed Target device speed.
646 @param MaximumPacketLength Maximum packet size the default control transfer
647 endpoint is capable of sending or receiving.
648 @param Request USB device request to send.
649 @param TransferDirection Specifies the data direction for the data stage
650 @param Data Data buffer to be transmitted or received from USB
652 @param DataLength The size (in bytes) of the data buffer.
653 @param TimeOut Indicates the maximum timeout, in millisecond.
654 @param Translator Transaction translator to be used by this device.
655 @param TransferResult Return the result of this control transfer.
657 @retval EFI_SUCCESS Transfer was completed successfully.
658 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
659 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
660 @retval EFI_TIMEOUT Transfer failed due to timeout.
661 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
667 IN EFI_USB2_HC_PROTOCOL
*This
,
668 IN UINT8 DeviceAddress
,
669 IN UINT8 DeviceSpeed
,
670 IN UINTN MaximumPacketLength
,
671 IN EFI_USB_DEVICE_REQUEST
*Request
,
672 IN EFI_USB_DATA_DIRECTION TransferDirection
,
674 IN OUT UINTN
*DataLength
,
676 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
677 OUT UINT32
*TransferResult
687 // Validate parameters
689 if ((Request
== NULL
) || (TransferResult
== NULL
)) {
690 return EFI_INVALID_PARAMETER
;
693 if ((TransferDirection
!= EfiUsbDataIn
) &&
694 (TransferDirection
!= EfiUsbDataOut
) &&
695 (TransferDirection
!= EfiUsbNoData
))
697 return EFI_INVALID_PARAMETER
;
700 if ((TransferDirection
== EfiUsbNoData
) &&
701 ((Data
!= NULL
) || (*DataLength
!= 0)))
703 return EFI_INVALID_PARAMETER
;
706 if ((TransferDirection
!= EfiUsbNoData
) &&
707 ((Data
== NULL
) || (*DataLength
== 0)))
709 return EFI_INVALID_PARAMETER
;
712 if ((MaximumPacketLength
!= 8) && (MaximumPacketLength
!= 16) &&
713 (MaximumPacketLength
!= 32) && (MaximumPacketLength
!= 64))
715 return EFI_INVALID_PARAMETER
;
718 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) {
719 return EFI_INVALID_PARAMETER
;
722 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
723 Ehc
= EHC_FROM_THIS (This
);
725 Status
= EFI_DEVICE_ERROR
;
726 *TransferResult
= EFI_USB_ERR_SYSTEM
;
728 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
729 DEBUG ((DEBUG_ERROR
, "EhcControlTransfer: HC halted at entrance\n"));
731 EhcAckAllInterrupt (Ehc
);
735 EhcAckAllInterrupt (Ehc
);
738 // Create a new URB, insert it into the asynchronous
739 // schedule list, then poll the execution status.
742 // Encode the direction in address, although default control
743 // endpoint is bidirectional. EhcCreateUrb expects this
744 // combination of Ep addr and its direction.
746 Endpoint
= (UINT8
)(0 | ((TransferDirection
== EfiUsbDataIn
) ? 0x80 : 0));
765 DEBUG ((DEBUG_ERROR
, "EhcControlTransfer: failed to create URB"));
767 Status
= EFI_OUT_OF_RESOURCES
;
771 EhcLinkQhToAsync (Ehc
, Urb
->Qh
);
772 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
773 EhcUnlinkQhFromAsync (Ehc
, Urb
->Qh
);
776 // Get the status from URB. The result is updated in EhcCheckUrbResult
777 // which is called by EhcExecTransfer
779 *TransferResult
= Urb
->Result
;
780 *DataLength
= Urb
->Completed
;
782 if (*TransferResult
== EFI_USB_NOERROR
) {
783 Status
= EFI_SUCCESS
;
786 EhcAckAllInterrupt (Ehc
);
787 EhcFreeUrb (Ehc
, Urb
);
790 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
791 gBS
->RestoreTPL (OldTpl
);
793 if (EFI_ERROR (Status
)) {
794 DEBUG ((DEBUG_ERROR
, "EhcControlTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
801 Submits bulk transfer to a bulk endpoint of a USB device.
803 @param This This EFI_USB2_HC_PROTOCOL instance.
804 @param DeviceAddress Target device address.
805 @param EndPointAddress Endpoint number and its direction in bit 7.
806 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
808 @param MaximumPacketLength Maximum packet size the endpoint is capable of
809 sending or receiving.
810 @param DataBuffersNumber Number of data buffers prepared for the transfer.
811 @param Data Array of pointers to the buffers of data to transmit
812 from or receive into.
813 @param DataLength The lenght of the data buffer.
814 @param DataToggle On input, the initial data toggle for the transfer;
815 On output, it is updated to to next data toggle to
816 use of the subsequent bulk transfer.
817 @param TimeOut Indicates the maximum time, in millisecond, which
818 the transfer is allowed to complete.
819 @param Translator A pointr to the transaction translator data.
820 @param TransferResult A pointer to the detailed result information of the
823 @retval EFI_SUCCESS The transfer was completed successfully.
824 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
825 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
826 @retval EFI_TIMEOUT The transfer failed due to timeout.
827 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
833 IN EFI_USB2_HC_PROTOCOL
*This
,
834 IN UINT8 DeviceAddress
,
835 IN UINT8 EndPointAddress
,
836 IN UINT8 DeviceSpeed
,
837 IN UINTN MaximumPacketLength
,
838 IN UINT8 DataBuffersNumber
,
839 IN OUT VOID
*Data
[EFI_USB_MAX_BULK_BUFFER_NUM
],
840 IN OUT UINTN
*DataLength
,
841 IN OUT UINT8
*DataToggle
,
843 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
844 OUT UINT32
*TransferResult
853 // Validate the parameters
855 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
856 (Data
== NULL
) || (Data
[0] == NULL
) || (TransferResult
== NULL
))
858 return EFI_INVALID_PARAMETER
;
861 if ((*DataToggle
!= 0) && (*DataToggle
!= 1)) {
862 return EFI_INVALID_PARAMETER
;
865 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) ||
866 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
867 ((EFI_USB_SPEED_HIGH
== DeviceSpeed
) && (MaximumPacketLength
> 512)))
869 return EFI_INVALID_PARAMETER
;
872 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
873 Ehc
= EHC_FROM_THIS (This
);
875 *TransferResult
= EFI_USB_ERR_SYSTEM
;
876 Status
= EFI_DEVICE_ERROR
;
878 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
879 DEBUG ((DEBUG_ERROR
, "EhcBulkTransfer: HC is halted\n"));
881 EhcAckAllInterrupt (Ehc
);
885 EhcAckAllInterrupt (Ehc
);
888 // Create a new URB, insert it into the asynchronous
889 // schedule list, then poll the execution status.
909 DEBUG ((DEBUG_ERROR
, "EhcBulkTransfer: failed to create URB\n"));
911 Status
= EFI_OUT_OF_RESOURCES
;
915 EhcLinkQhToAsync (Ehc
, Urb
->Qh
);
916 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
917 EhcUnlinkQhFromAsync (Ehc
, Urb
->Qh
);
919 *TransferResult
= Urb
->Result
;
920 *DataLength
= Urb
->Completed
;
921 *DataToggle
= Urb
->DataToggle
;
923 if (*TransferResult
== EFI_USB_NOERROR
) {
924 Status
= EFI_SUCCESS
;
927 EhcAckAllInterrupt (Ehc
);
928 EhcFreeUrb (Ehc
, Urb
);
931 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
932 gBS
->RestoreTPL (OldTpl
);
934 if (EFI_ERROR (Status
)) {
935 DEBUG ((DEBUG_ERROR
, "EhcBulkTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
942 Submits an asynchronous interrupt transfer to an
943 interrupt endpoint of a USB device.
945 @param This This EFI_USB2_HC_PROTOCOL instance.
946 @param DeviceAddress Target device address.
947 @param EndPointAddress Endpoint number and its direction encoded in bit 7
948 @param DeviceSpeed Indicates device speed.
949 @param MaximumPacketLength Maximum packet size the target endpoint is capable
950 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
951 transfer If FALSE, to remove the specified
952 asynchronous interrupt.
953 @param DataToggle On input, the initial data toggle to use; on output,
954 it is updated to indicate the next data toggle.
955 @param PollingInterval The he interval, in milliseconds, that the transfer
957 @param DataLength The length of data to receive at the rate specified
959 @param Translator Transaction translator to use.
960 @param CallBackFunction Function to call at the rate specified by
962 @param Context Context to CallBackFunction.
964 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
965 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
966 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
967 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
972 EhcAsyncInterruptTransfer (
973 IN EFI_USB2_HC_PROTOCOL
*This
,
974 IN UINT8 DeviceAddress
,
975 IN UINT8 EndPointAddress
,
976 IN UINT8 DeviceSpeed
,
977 IN UINTN MaximumPacketLength
,
978 IN BOOLEAN IsNewTransfer
,
979 IN OUT UINT8
*DataToggle
,
980 IN UINTN PollingInterval
,
982 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
983 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction
,
984 IN VOID
*Context OPTIONAL
993 // Validate parameters
995 if (!EHCI_IS_DATAIN (EndPointAddress
)) {
996 return EFI_INVALID_PARAMETER
;
1000 if (DataLength
== 0) {
1001 return EFI_INVALID_PARAMETER
;
1004 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1005 return EFI_INVALID_PARAMETER
;
1008 if ((PollingInterval
> 255) || (PollingInterval
< 1)) {
1009 return EFI_INVALID_PARAMETER
;
1013 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
1014 Ehc
= EHC_FROM_THIS (This
);
1017 // Delete Async interrupt transfer request. DataToggle will return
1018 // the next data toggle to use.
1020 if (!IsNewTransfer
) {
1021 Status
= EhciDelAsyncIntTransfer (Ehc
, DeviceAddress
, EndPointAddress
, DataToggle
);
1023 DEBUG ((DEBUG_INFO
, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status
));
1027 Status
= EFI_SUCCESS
;
1029 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
1030 DEBUG ((DEBUG_ERROR
, "EhcAsyncInterruptTransfer: HC is halt\n"));
1031 EhcAckAllInterrupt (Ehc
);
1033 Status
= EFI_DEVICE_ERROR
;
1037 EhcAckAllInterrupt (Ehc
);
1039 Urb
= EhciInsertAsyncIntTransfer (
1045 MaximumPacketLength
,
1054 Status
= EFI_OUT_OF_RESOURCES
;
1059 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
1060 gBS
->RestoreTPL (OldTpl
);
1066 Submits synchronous interrupt transfer to an interrupt endpoint
1069 @param This This EFI_USB2_HC_PROTOCOL instance.
1070 @param DeviceAddress Target device address.
1071 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1072 @param DeviceSpeed Indicates device speed.
1073 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1074 of sending or receiving.
1075 @param Data Buffer of data that will be transmitted to USB
1076 device or received from USB device.
1077 @param DataLength On input, the size, in bytes, of the data buffer; On
1078 output, the number of bytes transferred.
1079 @param DataToggle On input, the initial data toggle to use; on output,
1080 it is updated to indicate the next data toggle.
1081 @param TimeOut Maximum time, in second, to complete.
1082 @param Translator Transaction translator to use.
1083 @param TransferResult Variable to receive the transfer result.
1085 @return EFI_SUCCESS The transfer was completed successfully.
1086 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1087 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1088 @return EFI_TIMEOUT The transfer failed due to timeout.
1089 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1094 EhcSyncInterruptTransfer (
1095 IN EFI_USB2_HC_PROTOCOL
*This
,
1096 IN UINT8 DeviceAddress
,
1097 IN UINT8 EndPointAddress
,
1098 IN UINT8 DeviceSpeed
,
1099 IN UINTN MaximumPacketLength
,
1101 IN OUT UINTN
*DataLength
,
1102 IN OUT UINT8
*DataToggle
,
1104 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1105 OUT UINT32
*TransferResult
1114 // Validates parameters
1116 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
1117 (Data
== NULL
) || (TransferResult
== NULL
))
1119 return EFI_INVALID_PARAMETER
;
1122 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1123 return EFI_INVALID_PARAMETER
;
1126 if (((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) ||
1127 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
1128 ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) && (MaximumPacketLength
> 3072)))
1130 return EFI_INVALID_PARAMETER
;
1133 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
1134 Ehc
= EHC_FROM_THIS (This
);
1136 *TransferResult
= EFI_USB_ERR_SYSTEM
;
1137 Status
= EFI_DEVICE_ERROR
;
1139 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
1140 DEBUG ((DEBUG_ERROR
, "EhcSyncInterruptTransfer: HC is halt\n"));
1142 EhcAckAllInterrupt (Ehc
);
1146 EhcAckAllInterrupt (Ehc
);
1148 Urb
= EhcCreateUrb (
1154 MaximumPacketLength
,
1156 EHC_INT_TRANSFER_SYNC
,
1166 DEBUG ((DEBUG_ERROR
, "EhcSyncInterruptTransfer: failed to create URB\n"));
1168 Status
= EFI_OUT_OF_RESOURCES
;
1172 EhcLinkQhToPeriod (Ehc
, Urb
->Qh
);
1173 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
1174 EhcUnlinkQhFromPeriod (Ehc
, Urb
->Qh
);
1176 *TransferResult
= Urb
->Result
;
1177 *DataLength
= Urb
->Completed
;
1178 *DataToggle
= Urb
->DataToggle
;
1180 if (*TransferResult
== EFI_USB_NOERROR
) {
1181 Status
= EFI_SUCCESS
;
1184 EhcFreeUrb (Ehc
, Urb
);
1186 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
1187 gBS
->RestoreTPL (OldTpl
);
1189 if (EFI_ERROR (Status
)) {
1190 DEBUG ((DEBUG_ERROR
, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
1197 Submits isochronous transfer to a target USB device.
1199 @param This This EFI_USB2_HC_PROTOCOL instance.
1200 @param DeviceAddress Target device address.
1201 @param EndPointAddress End point address with its direction.
1202 @param DeviceSpeed Device speed, Low speed device doesn't support this
1204 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1205 sending or receiving.
1206 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1207 @param Data Array of pointers to the buffers of data that will
1208 be transmitted to USB device or received from USB
1210 @param DataLength The size, in bytes, of the data buffer.
1211 @param Translator Transaction translator to use.
1212 @param TransferResult Variable to receive the transfer result.
1214 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1219 EhcIsochronousTransfer (
1220 IN EFI_USB2_HC_PROTOCOL
*This
,
1221 IN UINT8 DeviceAddress
,
1222 IN UINT8 EndPointAddress
,
1223 IN UINT8 DeviceSpeed
,
1224 IN UINTN MaximumPacketLength
,
1225 IN UINT8 DataBuffersNumber
,
1226 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1227 IN UINTN DataLength
,
1228 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1229 OUT UINT32
*TransferResult
1232 return EFI_UNSUPPORTED
;
1236 Submits Async isochronous transfer to a target USB device.
1238 @param This This EFI_USB2_HC_PROTOCOL instance.
1239 @param DeviceAddress Target device address.
1240 @param EndPointAddress End point address with its direction.
1241 @param DeviceSpeed Device speed, Low speed device doesn't support this
1243 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1244 sending or receiving.
1245 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1246 @param Data Array of pointers to the buffers of data that will
1247 be transmitted to USB device or received from USB
1249 @param DataLength The size, in bytes, of the data buffer.
1250 @param Translator Transaction translator to use.
1251 @param IsochronousCallBack Function to be called when the transfer complete.
1252 @param Context Context passed to the call back function as
1255 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1260 EhcAsyncIsochronousTransfer (
1261 IN EFI_USB2_HC_PROTOCOL
*This
,
1262 IN UINT8 DeviceAddress
,
1263 IN UINT8 EndPointAddress
,
1264 IN UINT8 DeviceSpeed
,
1265 IN UINTN MaximumPacketLength
,
1266 IN UINT8 DataBuffersNumber
,
1267 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1268 IN UINTN DataLength
,
1269 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1270 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack
,
1274 return EFI_UNSUPPORTED
;
1278 Entry point for EFI drivers.
1280 @param ImageHandle EFI_HANDLE.
1281 @param SystemTable EFI_SYSTEM_TABLE.
1283 @return EFI_SUCCESS Success.
1284 EFI_DEVICE_ERROR Fail.
1289 EhcDriverEntryPoint (
1290 IN EFI_HANDLE ImageHandle
,
1291 IN EFI_SYSTEM_TABLE
*SystemTable
1294 return EfiLibInstallDriverBindingComponentName2 (
1297 &gEhciDriverBinding
,
1299 &gEhciComponentName
,
1300 &gEhciComponentName2
1305 Test to see if this driver supports ControllerHandle. Any
1306 ControllerHandle that has Usb2HcProtocol installed will
1309 @param This Protocol instance pointer.
1310 @param Controller Handle of device to test.
1311 @param RemainingDevicePath Not used.
1313 @return EFI_SUCCESS This driver supports this device.
1314 @return EFI_UNSUPPORTED This driver does not support this device.
1319 EhcDriverBindingSupported (
1320 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1321 IN EFI_HANDLE Controller
,
1322 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1326 EFI_PCI_IO_PROTOCOL
*PciIo
;
1327 USB_CLASSC UsbClassCReg
;
1330 // Test whether there is PCI IO Protocol attached on the controller handle.
1332 Status
= gBS
->OpenProtocol (
1334 &gEfiPciIoProtocolGuid
,
1336 This
->DriverBindingHandle
,
1338 EFI_OPEN_PROTOCOL_BY_DRIVER
1341 if (EFI_ERROR (Status
)) {
1342 return EFI_UNSUPPORTED
;
1345 Status
= PciIo
->Pci
.Read (
1348 PCI_CLASSCODE_OFFSET
,
1349 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1353 if (EFI_ERROR (Status
)) {
1354 Status
= EFI_UNSUPPORTED
;
1359 // Test whether the controller belongs to Ehci type
1361 if ( (UsbClassCReg
.BaseCode
!= PCI_CLASS_SERIAL
) || (UsbClassCReg
.SubClassCode
!= PCI_CLASS_SERIAL_USB
)
1362 || ((UsbClassCReg
.ProgInterface
!= PCI_IF_EHCI
) && (UsbClassCReg
.ProgInterface
!= PCI_IF_UHCI
) && (UsbClassCReg
.ProgInterface
!= PCI_IF_OHCI
)))
1364 Status
= EFI_UNSUPPORTED
;
1368 gBS
->CloseProtocol (
1370 &gEfiPciIoProtocolGuid
,
1371 This
->DriverBindingHandle
,
1379 Get the usb debug port related information.
1381 @param Ehc The EHCI device.
1383 @retval RETURN_SUCCESS Get debug port number, bar and offset successfully.
1384 @retval Others The usb host controller does not supported usb debug port capability.
1388 EhcGetUsbDebugPortInfo (
1392 EFI_PCI_IO_PROTOCOL
*PciIo
;
1394 UINT8 CapabilityPtr
;
1399 ASSERT (Ehc
->PciIo
!= NULL
);
1403 // Detect if the EHCI host controller support Capaility Pointer.
1405 Status
= PciIo
->Pci
.Read (
1408 PCI_PRIMARY_STATUS_OFFSET
,
1413 if (EFI_ERROR (Status
)) {
1417 if ((PciStatus
& EFI_PCI_STATUS_CAPABILITY
) == 0) {
1419 // The Pci Device Doesn't Support Capability Pointer.
1421 return EFI_UNSUPPORTED
;
1425 // Get Pointer To Capability List
1427 Status
= PciIo
->Pci
.Read (
1430 PCI_CAPBILITY_POINTER_OFFSET
,
1435 if (EFI_ERROR (Status
)) {
1440 // Find Capability ID 0xA, Which Is For Debug Port
1442 while (CapabilityPtr
!= 0) {
1443 Status
= PciIo
->Pci
.Read (
1451 if (EFI_ERROR (Status
)) {
1455 if (CapabilityId
== EHC_DEBUG_PORT_CAP_ID
) {
1459 Status
= PciIo
->Pci
.Read (
1467 if (EFI_ERROR (Status
)) {
1473 // No Debug Port Capability Found
1475 if (CapabilityPtr
== 0) {
1476 return EFI_UNSUPPORTED
;
1480 // Get The Base Address Of Debug Port Register In Debug Port Capability Register
1482 Status
= PciIo
->Pci
.Read (
1490 if (EFI_ERROR (Status
)) {
1494 Ehc
->DebugPortOffset
= DebugPort
& 0x1FFF;
1495 Ehc
->DebugPortBarNum
= (UINT8
)((DebugPort
>> 13) - 1);
1496 Ehc
->DebugPortNum
= (UINT8
)((Ehc
->HcStructParams
& 0x00F00000) >> 20);
1502 Create and initialize a USB2_HC_DEV.
1504 @param PciIo The PciIo on this device.
1505 @param DevicePath The device path of host controller.
1506 @param OriginalPciAttributes Original PCI attributes.
1508 @return The allocated and initialized USB2_HC_DEV structure if created,
1514 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1515 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1516 IN UINT64 OriginalPciAttributes
1522 Ehc
= AllocateZeroPool (sizeof (USB2_HC_DEV
));
1529 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1531 Ehc
->Signature
= USB2_HC_DEV_SIGNATURE
;
1533 Ehc
->Usb2Hc
.GetCapability
= EhcGetCapability
;
1534 Ehc
->Usb2Hc
.Reset
= EhcReset
;
1535 Ehc
->Usb2Hc
.GetState
= EhcGetState
;
1536 Ehc
->Usb2Hc
.SetState
= EhcSetState
;
1537 Ehc
->Usb2Hc
.ControlTransfer
= EhcControlTransfer
;
1538 Ehc
->Usb2Hc
.BulkTransfer
= EhcBulkTransfer
;
1539 Ehc
->Usb2Hc
.AsyncInterruptTransfer
= EhcAsyncInterruptTransfer
;
1540 Ehc
->Usb2Hc
.SyncInterruptTransfer
= EhcSyncInterruptTransfer
;
1541 Ehc
->Usb2Hc
.IsochronousTransfer
= EhcIsochronousTransfer
;
1542 Ehc
->Usb2Hc
.AsyncIsochronousTransfer
= EhcAsyncIsochronousTransfer
;
1543 Ehc
->Usb2Hc
.GetRootHubPortStatus
= EhcGetRootHubPortStatus
;
1544 Ehc
->Usb2Hc
.SetRootHubPortFeature
= EhcSetRootHubPortFeature
;
1545 Ehc
->Usb2Hc
.ClearRootHubPortFeature
= EhcClearRootHubPortFeature
;
1546 Ehc
->Usb2Hc
.MajorRevision
= 0x2;
1547 Ehc
->Usb2Hc
.MinorRevision
= 0x0;
1550 Ehc
->DevicePath
= DevicePath
;
1551 Ehc
->OriginalPciAttributes
= OriginalPciAttributes
;
1553 InitializeListHead (&Ehc
->AsyncIntTransfers
);
1555 Ehc
->HcStructParams
= EhcReadCapRegister (Ehc
, EHC_HCSPARAMS_OFFSET
);
1556 Ehc
->HcCapParams
= EhcReadCapRegister (Ehc
, EHC_HCCPARAMS_OFFSET
);
1557 Ehc
->CapLen
= EhcReadCapRegister (Ehc
, EHC_CAPLENGTH_OFFSET
) & 0x0FF;
1559 DEBUG ((DEBUG_INFO
, "EhcCreateUsb2Hc: capability length %d\n", Ehc
->CapLen
));
1562 // EHCI Controllers with a CapLen of 0 are ignored.
1564 if (Ehc
->CapLen
== 0) {
1565 gBS
->FreePool (Ehc
);
1569 EhcGetUsbDebugPortInfo (Ehc
);
1572 // Create AsyncRequest Polling Timer
1574 Status
= gBS
->CreateEvent (
1575 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1577 EhcMonitorAsyncRequests
,
1582 if (EFI_ERROR (Status
)) {
1583 gBS
->FreePool (Ehc
);
1591 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1593 @param Event Pointer to this event
1594 @param Context Event handler private data
1599 EhcExitBootService (
1607 Ehc
= (USB2_HC_DEV
*)Context
;
1610 // Reset the Host Controller
1612 EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
1616 Starting the Usb EHCI Driver.
1618 @param This Protocol instance pointer.
1619 @param Controller Handle of device to test.
1620 @param RemainingDevicePath Not used.
1622 @return EFI_SUCCESS supports this device.
1623 @return EFI_UNSUPPORTED do not support this device.
1624 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1625 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1630 EhcDriverBindingStart (
1631 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1632 IN EFI_HANDLE Controller
,
1633 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1638 EFI_PCI_IO_PROTOCOL
*PciIo
;
1639 EFI_PCI_IO_PROTOCOL
*Instance
;
1641 UINT64 OriginalPciAttributes
;
1642 BOOLEAN PciAttributesSaved
;
1643 USB_CLASSC UsbClassCReg
;
1644 EFI_HANDLE
*HandleBuffer
;
1645 UINTN NumberOfHandles
;
1647 UINTN CompanionSegmentNumber
;
1648 UINTN CompanionBusNumber
;
1649 UINTN CompanionDeviceNumber
;
1650 UINTN CompanionFunctionNumber
;
1651 UINTN EhciSegmentNumber
;
1652 UINTN EhciBusNumber
;
1653 UINTN EhciDeviceNumber
;
1654 UINTN EhciFunctionNumber
;
1655 EFI_DEVICE_PATH_PROTOCOL
*HcDevicePath
;
1658 // Open the PciIo Protocol, then enable the USB host controller
1660 Status
= gBS
->OpenProtocol (
1662 &gEfiPciIoProtocolGuid
,
1664 This
->DriverBindingHandle
,
1666 EFI_OPEN_PROTOCOL_BY_DRIVER
1669 if (EFI_ERROR (Status
)) {
1674 // Open Device Path Protocol for on USB host controller
1676 HcDevicePath
= NULL
;
1677 Status
= gBS
->OpenProtocol (
1679 &gEfiDevicePathProtocolGuid
,
1680 (VOID
**)&HcDevicePath
,
1681 This
->DriverBindingHandle
,
1683 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1686 PciAttributesSaved
= FALSE
;
1688 // Save original PCI attributes
1690 Status
= PciIo
->Attributes (
1692 EfiPciIoAttributeOperationGet
,
1694 &OriginalPciAttributes
1697 if (EFI_ERROR (Status
)) {
1701 PciAttributesSaved
= TRUE
;
1703 Status
= PciIo
->Attributes (
1705 EfiPciIoAttributeOperationSupported
,
1709 if (!EFI_ERROR (Status
)) {
1710 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1711 Status
= PciIo
->Attributes (
1713 EfiPciIoAttributeOperationEnable
,
1719 if (EFI_ERROR (Status
)) {
1720 DEBUG ((DEBUG_ERROR
, "EhcDriverBindingStart: failed to enable controller\n"));
1725 // Get the Pci device class code.
1727 Status
= PciIo
->Pci
.Read (
1730 PCI_CLASSCODE_OFFSET
,
1731 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1735 if (EFI_ERROR (Status
)) {
1736 Status
= EFI_UNSUPPORTED
;
1741 // Determine if the device is UHCI or OHCI host controller or not. If yes, then find out the
1742 // companion usb ehci host controller and force EHCI driver get attached to it before
1743 // UHCI or OHCI driver attaches to UHCI or OHCI host controller.
1745 if (((UsbClassCReg
.ProgInterface
== PCI_IF_UHCI
) || (UsbClassCReg
.ProgInterface
== PCI_IF_OHCI
)) &&
1746 (UsbClassCReg
.BaseCode
== PCI_CLASS_SERIAL
) &&
1747 (UsbClassCReg
.SubClassCode
== PCI_CLASS_SERIAL_USB
))
1749 Status
= PciIo
->GetLocation (
1751 &CompanionSegmentNumber
,
1752 &CompanionBusNumber
,
1753 &CompanionDeviceNumber
,
1754 &CompanionFunctionNumber
1756 if (EFI_ERROR (Status
)) {
1760 Status
= gBS
->LocateHandleBuffer (
1762 &gEfiPciIoProtocolGuid
,
1767 if (EFI_ERROR (Status
)) {
1771 for (Index
= 0; Index
< NumberOfHandles
; Index
++) {
1773 // Get the device path on this handle
1775 Status
= gBS
->HandleProtocol (
1776 HandleBuffer
[Index
],
1777 &gEfiPciIoProtocolGuid
,
1780 ASSERT_EFI_ERROR (Status
);
1782 Status
= Instance
->Pci
.Read (
1785 PCI_CLASSCODE_OFFSET
,
1786 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1790 if (EFI_ERROR (Status
)) {
1791 Status
= EFI_UNSUPPORTED
;
1795 if ((UsbClassCReg
.ProgInterface
== PCI_IF_EHCI
) &&
1796 (UsbClassCReg
.BaseCode
== PCI_CLASS_SERIAL
) &&
1797 (UsbClassCReg
.SubClassCode
== PCI_CLASS_SERIAL_USB
))
1799 Status
= Instance
->GetLocation (
1806 if (EFI_ERROR (Status
)) {
1811 // Currently, the judgment on the companion usb host controller is through the
1812 // same bus number, which may vary on different platform.
1814 if (EhciBusNumber
== CompanionBusNumber
) {
1815 gBS
->CloseProtocol (
1817 &gEfiPciIoProtocolGuid
,
1818 This
->DriverBindingHandle
,
1821 EhcDriverBindingStart (This
, HandleBuffer
[Index
], NULL
);
1826 Status
= EFI_NOT_FOUND
;
1831 // Create then install USB2_HC_PROTOCOL
1833 Ehc
= EhcCreateUsb2Hc (PciIo
, HcDevicePath
, OriginalPciAttributes
);
1836 DEBUG ((DEBUG_ERROR
, "EhcDriverBindingStart: failed to create USB2_HC\n"));
1838 Status
= EFI_OUT_OF_RESOURCES
;
1843 // Enable 64-bit DMA support in the PCI layer if this controller
1846 if (EHC_BIT_IS_SET (Ehc
->HcCapParams
, HCCP_64BIT
)) {
1847 Status
= PciIo
->Attributes (
1849 EfiPciIoAttributeOperationEnable
,
1850 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
1853 if (!EFI_ERROR (Status
)) {
1854 Ehc
->Support64BitDma
= TRUE
;
1858 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
1866 Status
= gBS
->InstallProtocolInterface (
1868 &gEfiUsb2HcProtocolGuid
,
1869 EFI_NATIVE_INTERFACE
,
1873 if (EFI_ERROR (Status
)) {
1874 DEBUG ((DEBUG_ERROR
, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1879 // Robustnesss improvement such as for Duet platform
1880 // Default is not required.
1882 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport
)) {
1883 EhcClearLegacySupport (Ehc
);
1886 if (!EhcIsDebugPortInUse (Ehc
, NULL
)) {
1887 EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
1890 Status
= EhcInitHC (Ehc
);
1892 if (EFI_ERROR (Status
)) {
1893 DEBUG ((DEBUG_ERROR
, "EhcDriverBindingStart: failed to init host controller\n"));
1894 goto UNINSTALL_USBHC
;
1898 // Start the asynchronous interrupt monitor
1900 Status
= gBS
->SetTimer (Ehc
->PollTimer
, TimerPeriodic
, EHC_ASYNC_POLL_INTERVAL
);
1902 if (EFI_ERROR (Status
)) {
1903 DEBUG ((DEBUG_ERROR
, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
1905 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
1906 goto UNINSTALL_USBHC
;
1910 // Create event to stop the HC when exit boot service.
1912 Status
= gBS
->CreateEventEx (
1917 &gEfiEventExitBootServicesGuid
,
1918 &Ehc
->ExitBootServiceEvent
1920 if (EFI_ERROR (Status
)) {
1921 goto UNINSTALL_USBHC
;
1925 // Install the component name protocol, don't fail the start
1926 // because of something for display.
1930 gEhciComponentName
.SupportedLanguages
,
1931 &Ehc
->ControllerNameTable
,
1932 L
"Enhanced Host Controller (USB 2.0)",
1937 gEhciComponentName2
.SupportedLanguages
,
1938 &Ehc
->ControllerNameTable
,
1939 L
"Enhanced Host Controller (USB 2.0)",
1943 DEBUG ((DEBUG_INFO
, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller
));
1947 gBS
->UninstallProtocolInterface (
1949 &gEfiUsb2HcProtocolGuid
,
1955 gBS
->CloseEvent (Ehc
->PollTimer
);
1956 gBS
->FreePool (Ehc
);
1959 if (PciAttributesSaved
) {
1961 // Restore original PCI attributes
1965 EfiPciIoAttributeOperationSet
,
1966 OriginalPciAttributes
,
1971 gBS
->CloseProtocol (
1973 &gEfiPciIoProtocolGuid
,
1974 This
->DriverBindingHandle
,
1982 Stop this driver on ControllerHandle. Support stopping any child handles
1983 created by this driver.
1985 @param This Protocol instance pointer.
1986 @param Controller Handle of device to stop driver on.
1987 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1988 @param ChildHandleBuffer List of handles for the children we need to stop.
1990 @return EFI_SUCCESS Success.
1991 @return EFI_DEVICE_ERROR Fail.
1996 EhcDriverBindingStop (
1997 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1998 IN EFI_HANDLE Controller
,
1999 IN UINTN NumberOfChildren
,
2000 IN EFI_HANDLE
*ChildHandleBuffer
2004 EFI_USB2_HC_PROTOCOL
*Usb2Hc
;
2005 EFI_PCI_IO_PROTOCOL
*PciIo
;
2009 // Test whether the Controller handler passed in is a valid
2010 // Usb controller handle that should be supported, if not,
2011 // return the error status directly
2013 Status
= gBS
->OpenProtocol (
2015 &gEfiUsb2HcProtocolGuid
,
2017 This
->DriverBindingHandle
,
2019 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2022 if (EFI_ERROR (Status
)) {
2026 Ehc
= EHC_FROM_THIS (Usb2Hc
);
2029 Status
= gBS
->UninstallProtocolInterface (
2031 &gEfiUsb2HcProtocolGuid
,
2035 if (EFI_ERROR (Status
)) {
2040 // Stop AsyncRequest Polling timer then stop the EHCI driver
2041 // and uninstall the EHCI protocl.
2043 gBS
->SetTimer (Ehc
->PollTimer
, TimerCancel
, EHC_ASYNC_POLL_INTERVAL
);
2044 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
2046 if (Ehc
->PollTimer
!= NULL
) {
2047 gBS
->CloseEvent (Ehc
->PollTimer
);
2050 if (Ehc
->ExitBootServiceEvent
!= NULL
) {
2051 gBS
->CloseEvent (Ehc
->ExitBootServiceEvent
);
2056 if (Ehc
->ControllerNameTable
!= NULL
) {
2057 FreeUnicodeStringTable (Ehc
->ControllerNameTable
);
2061 // Disable routing of all ports to EHCI controller, so all ports are
2062 // routed back to the UHCI or OHCI controller.
2064 EhcClearOpRegBit (Ehc
, EHC_CONFIG_FLAG_OFFSET
, CONFIGFLAG_ROUTE_EHC
);
2067 // Restore original PCI attributes
2071 EfiPciIoAttributeOperationSet
,
2072 Ehc
->OriginalPciAttributes
,
2076 gBS
->CloseProtocol (
2078 &gEfiPciIoProtocolGuid
,
2079 This
->DriverBindingHandle
,