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 This program and the accompanying materials
16 are licensed and made available under the terms and conditions of the BSD License
17 which accompanies this distribution. The full text of the license may be found at
18 http://opensource.org/licenses/bsd-license.php
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
29 // Two arrays used to translate the EHCI port state (change)
30 // to the UEFI protocol's port state (change).
32 USB_PORT_STATE_MAP mUsbPortStateMap
[] = {
33 {PORTSC_CONN
, USB_PORT_STAT_CONNECTION
},
34 {PORTSC_ENABLED
, USB_PORT_STAT_ENABLE
},
35 {PORTSC_SUSPEND
, USB_PORT_STAT_SUSPEND
},
36 {PORTSC_OVERCUR
, USB_PORT_STAT_OVERCURRENT
},
37 {PORTSC_RESET
, USB_PORT_STAT_RESET
},
38 {PORTSC_POWER
, USB_PORT_STAT_POWER
},
39 {PORTSC_OWNER
, USB_PORT_STAT_OWNER
}
42 USB_PORT_STATE_MAP mUsbPortChangeMap
[] = {
43 {PORTSC_CONN_CHANGE
, USB_PORT_STAT_C_CONNECTION
},
44 {PORTSC_ENABLE_CHANGE
, USB_PORT_STAT_C_ENABLE
},
45 {PORTSC_OVERCUR_CHANGE
, USB_PORT_STAT_C_OVERCURRENT
}
48 EFI_DRIVER_BINDING_PROTOCOL
49 gEhciDriverBinding
= {
50 EhcDriverBindingSupported
,
51 EhcDriverBindingStart
,
59 Retrieves the capability of root hub ports.
61 @param This This EFI_USB_HC_PROTOCOL instance.
62 @param MaxSpeed Max speed supported by the controller.
63 @param PortNumber Number of the root hub ports.
64 @param Is64BitCapable Whether the controller supports 64-bit memory
67 @retval EFI_SUCCESS Host controller capability were retrieved successfully.
68 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
74 IN EFI_USB2_HC_PROTOCOL
*This
,
76 OUT UINT8
*PortNumber
,
77 OUT UINT8
*Is64BitCapable
83 if ((MaxSpeed
== NULL
) || (PortNumber
== NULL
) || (Is64BitCapable
== NULL
)) {
84 return EFI_INVALID_PARAMETER
;
87 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
88 Ehc
= EHC_FROM_THIS (This
);
90 *MaxSpeed
= EFI_USB_SPEED_HIGH
;
91 *PortNumber
= (UINT8
) (Ehc
->HcStructParams
& HCSP_NPORTS
);
92 *Is64BitCapable
= (UINT8
) Ehc
->Support64BitDma
;
94 DEBUG ((EFI_D_INFO
, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber
, *Is64BitCapable
));
96 gBS
->RestoreTPL (OldTpl
);
102 Provides software reset for the USB host controller.
104 @param This This EFI_USB2_HC_PROTOCOL instance.
105 @param Attributes A bit mask of the reset operation to perform.
107 @retval EFI_SUCCESS The reset operation succeeded.
108 @retval EFI_INVALID_PARAMETER Attributes is not valid.
109 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
110 not currently supported by the host controller.
111 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
117 IN EFI_USB2_HC_PROTOCOL
*This
,
125 Ehc
= EHC_FROM_THIS (This
);
127 if (Ehc
->DevicePath
!= NULL
) {
129 // Report Status Code to indicate reset happens
131 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
133 (EFI_IO_BUS_USB
| EFI_IOB_PC_RESET
),
138 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
140 switch (Attributes
) {
141 case EFI_USB_HC_RESET_GLOBAL
:
143 // Flow through, same behavior as Host Controller Reset
145 case EFI_USB_HC_RESET_HOST_CONTROLLER
:
147 // Host Controller must be Halt when Reset it
149 if (EhcIsDebugPortInUse (Ehc
, NULL
)) {
150 Status
= EFI_SUCCESS
;
154 if (!EhcIsHalt (Ehc
)) {
155 Status
= EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
157 if (EFI_ERROR (Status
)) {
158 Status
= EFI_DEVICE_ERROR
;
164 // Clean up the asynchronous transfers, currently only
165 // interrupt supports asynchronous operation.
167 EhciDelAllAsyncIntTransfers (Ehc
);
168 EhcAckAllInterrupt (Ehc
);
171 Status
= EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
173 if (EFI_ERROR (Status
)) {
177 Status
= EhcInitHC (Ehc
);
180 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG
:
181 case EFI_USB_HC_RESET_HOST_WITH_DEBUG
:
182 Status
= EFI_UNSUPPORTED
;
186 Status
= EFI_INVALID_PARAMETER
;
190 DEBUG ((EFI_D_INFO
, "EhcReset: exit status %r\n", Status
));
191 gBS
->RestoreTPL (OldTpl
);
197 Retrieve the current state of the USB host controller.
199 @param This This EFI_USB2_HC_PROTOCOL instance.
200 @param State Variable to return the current host controller
203 @retval EFI_SUCCESS Host controller state was returned in State.
204 @retval EFI_INVALID_PARAMETER State is NULL.
205 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
206 retrieve the host controller's current state.
212 IN EFI_USB2_HC_PROTOCOL
*This
,
213 OUT EFI_USB_HC_STATE
*State
220 return EFI_INVALID_PARAMETER
;
223 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
224 Ehc
= EHC_FROM_THIS (This
);
226 if (EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
227 *State
= EfiUsbHcStateHalt
;
229 *State
= EfiUsbHcStateOperational
;
232 gBS
->RestoreTPL (OldTpl
);
234 DEBUG ((EFI_D_INFO
, "EhcGetState: current state %d\n", *State
));
240 Sets the USB host controller to a specific state.
242 @param This This EFI_USB2_HC_PROTOCOL instance.
243 @param State The state of the host controller that will be set.
245 @retval EFI_SUCCESS The USB host controller was successfully placed
246 in the state specified by State.
247 @retval EFI_INVALID_PARAMETER State is invalid.
248 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
254 IN EFI_USB2_HC_PROTOCOL
*This
,
255 IN EFI_USB_HC_STATE State
261 EFI_USB_HC_STATE CurState
;
263 Status
= EhcGetState (This
, &CurState
);
265 if (EFI_ERROR (Status
)) {
266 return EFI_DEVICE_ERROR
;
269 if (CurState
== State
) {
273 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
274 Ehc
= EHC_FROM_THIS (This
);
277 case EfiUsbHcStateHalt
:
278 Status
= EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
281 case EfiUsbHcStateOperational
:
282 if (EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_SYS_ERROR
)) {
283 Status
= EFI_DEVICE_ERROR
;
288 // Software must not write a one to this field unless the host controller
289 // is in the Halted state. Doing so will yield undefined results.
290 // refers to Spec[EHCI1.0-2.3.1]
292 if (!EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
293 Status
= EFI_DEVICE_ERROR
;
297 Status
= EhcRunHC (Ehc
, EHC_GENERIC_TIMEOUT
);
300 case EfiUsbHcStateSuspend
:
301 Status
= EFI_UNSUPPORTED
;
305 Status
= EFI_INVALID_PARAMETER
;
308 DEBUG ((EFI_D_INFO
, "EhcSetState: exit status %r\n", Status
));
309 gBS
->RestoreTPL (OldTpl
);
315 Retrieves the current status of a USB root hub port.
317 @param This This EFI_USB2_HC_PROTOCOL instance.
318 @param PortNumber The root hub port to retrieve the state from.
319 This value is zero-based.
320 @param PortStatus Variable to receive the port state.
322 @retval EFI_SUCCESS The status of the USB root hub port specified.
323 by PortNumber was returned in PortStatus.
324 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
325 @retval EFI_DEVICE_ERROR Can't read register.
330 EhcGetRootHubPortStatus (
331 IN EFI_USB2_HC_PROTOCOL
*This
,
333 OUT EFI_USB_PORT_STATUS
*PortStatus
345 if (PortStatus
== NULL
) {
346 return EFI_INVALID_PARAMETER
;
349 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
351 Ehc
= EHC_FROM_THIS (This
);
352 Status
= EFI_SUCCESS
;
354 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
356 if (PortNumber
>= TotalPort
) {
357 Status
= EFI_INVALID_PARAMETER
;
361 Offset
= (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
));
362 PortStatus
->PortStatus
= 0;
363 PortStatus
->PortChangeStatus
= 0;
365 if (EhcIsDebugPortInUse (Ehc
, &PortNumber
)) {
369 State
= EhcReadOpReg (Ehc
, Offset
);
372 // Identify device speed. If in K state, it is low speed.
373 // If the port is enabled after reset, the device is of
374 // high speed. The USB bus driver should retrieve the actual
375 // port speed after reset.
377 if (EHC_BIT_IS_SET (State
, PORTSC_LINESTATE_K
)) {
378 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
380 } else if (EHC_BIT_IS_SET (State
, PORTSC_ENABLED
)) {
381 PortStatus
->PortStatus
|= USB_PORT_STAT_HIGH_SPEED
;
385 // Convert the EHCI port/port change state to UEFI status
387 MapSize
= sizeof (mUsbPortStateMap
) / sizeof (USB_PORT_STATE_MAP
);
389 for (Index
= 0; Index
< MapSize
; Index
++) {
390 if (EHC_BIT_IS_SET (State
, mUsbPortStateMap
[Index
].HwState
)) {
391 PortStatus
->PortStatus
= (UINT16
) (PortStatus
->PortStatus
| mUsbPortStateMap
[Index
].UefiState
);
395 MapSize
= sizeof (mUsbPortChangeMap
) / sizeof (USB_PORT_STATE_MAP
);
397 for (Index
= 0; Index
< MapSize
; Index
++) {
398 if (EHC_BIT_IS_SET (State
, mUsbPortChangeMap
[Index
].HwState
)) {
399 PortStatus
->PortChangeStatus
= (UINT16
) (PortStatus
->PortChangeStatus
| mUsbPortChangeMap
[Index
].UefiState
);
404 gBS
->RestoreTPL (OldTpl
);
410 Sets a feature for the specified root hub port.
412 @param This This EFI_USB2_HC_PROTOCOL instance.
413 @param PortNumber Root hub port to set.
414 @param PortFeature Feature to set.
416 @retval EFI_SUCCESS The feature specified by PortFeature was set.
417 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
418 @retval EFI_DEVICE_ERROR Can't read register.
423 EhcSetRootHubPortFeature (
424 IN EFI_USB2_HC_PROTOCOL
*This
,
426 IN EFI_USB_PORT_FEATURE PortFeature
436 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
437 Ehc
= EHC_FROM_THIS (This
);
438 Status
= EFI_SUCCESS
;
440 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
442 if (PortNumber
>= TotalPort
) {
443 Status
= EFI_INVALID_PARAMETER
;
447 Offset
= (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
));
448 State
= EhcReadOpReg (Ehc
, Offset
);
451 // Mask off the port status change bits, these bits are
454 State
&= ~PORTSC_CHANGE_MASK
;
456 switch (PortFeature
) {
457 case EfiUsbPortEnable
:
459 // Sofeware can't set this bit, Port can only be enable by
460 // EHCI as a part of the reset and enable
462 State
|= PORTSC_ENABLED
;
463 EhcWriteOpReg (Ehc
, Offset
, State
);
466 case EfiUsbPortSuspend
:
467 State
|= PORTSC_SUSPEND
;
468 EhcWriteOpReg (Ehc
, Offset
, State
);
471 case EfiUsbPortReset
:
473 // Make sure Host Controller not halt before reset it
475 if (EhcIsHalt (Ehc
)) {
476 Status
= EhcRunHC (Ehc
, EHC_GENERIC_TIMEOUT
);
478 if (EFI_ERROR (Status
)) {
479 DEBUG ((EFI_D_INFO
, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status
));
485 // Set one to PortReset bit must also set zero to PortEnable bit
487 State
|= PORTSC_RESET
;
488 State
&= ~PORTSC_ENABLED
;
489 EhcWriteOpReg (Ehc
, Offset
, State
);
492 case EfiUsbPortPower
:
494 // Set port power bit when PPC is 1
496 if ((Ehc
->HcCapParams
& HCSP_PPC
) == HCSP_PPC
) {
497 State
|= PORTSC_POWER
;
498 EhcWriteOpReg (Ehc
, Offset
, State
);
502 case EfiUsbPortOwner
:
503 State
|= PORTSC_OWNER
;
504 EhcWriteOpReg (Ehc
, Offset
, State
);
508 Status
= EFI_INVALID_PARAMETER
;
512 DEBUG ((EFI_D_INFO
, "EhcSetRootHubPortFeature: exit status %r\n", Status
));
514 gBS
->RestoreTPL (OldTpl
);
520 Clears a feature for the specified root hub port.
522 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
523 @param PortNumber Specifies the root hub port whose feature is
524 requested to be cleared.
525 @param PortFeature Indicates the feature selector associated with the
526 feature clear request.
528 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
529 for the USB root hub port specified by PortNumber.
530 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
531 @retval EFI_DEVICE_ERROR Can't read register.
536 EhcClearRootHubPortFeature (
537 IN EFI_USB2_HC_PROTOCOL
*This
,
539 IN EFI_USB_PORT_FEATURE PortFeature
549 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
550 Ehc
= EHC_FROM_THIS (This
);
551 Status
= EFI_SUCCESS
;
553 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
555 if (PortNumber
>= TotalPort
) {
556 Status
= EFI_INVALID_PARAMETER
;
560 Offset
= EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
);
561 State
= EhcReadOpReg (Ehc
, Offset
);
562 State
&= ~PORTSC_CHANGE_MASK
;
564 switch (PortFeature
) {
565 case EfiUsbPortEnable
:
567 // Clear PORT_ENABLE feature means disable port.
569 State
&= ~PORTSC_ENABLED
;
570 EhcWriteOpReg (Ehc
, Offset
, State
);
573 case EfiUsbPortSuspend
:
575 // A write of zero to this bit is ignored by the host
576 // controller. The host controller will unconditionally
577 // set this bit to a zero when:
578 // 1. software sets the Forct Port Resume bit to a zero from a one.
579 // 2. software sets the Port Reset bit to a one frome a zero.
581 State
&= ~PORSTSC_RESUME
;
582 EhcWriteOpReg (Ehc
, Offset
, State
);
585 case EfiUsbPortReset
:
587 // Clear PORT_RESET means clear the reset signal.
589 State
&= ~PORTSC_RESET
;
590 EhcWriteOpReg (Ehc
, Offset
, State
);
593 case EfiUsbPortOwner
:
595 // Clear port owner means this port owned by EHC
597 State
&= ~PORTSC_OWNER
;
598 EhcWriteOpReg (Ehc
, Offset
, State
);
601 case EfiUsbPortConnectChange
:
603 // Clear connect status change
605 State
|= PORTSC_CONN_CHANGE
;
606 EhcWriteOpReg (Ehc
, Offset
, State
);
609 case EfiUsbPortEnableChange
:
611 // Clear enable status change
613 State
|= PORTSC_ENABLE_CHANGE
;
614 EhcWriteOpReg (Ehc
, Offset
, State
);
617 case EfiUsbPortOverCurrentChange
:
619 // Clear PortOverCurrent change
621 State
|= PORTSC_OVERCUR_CHANGE
;
622 EhcWriteOpReg (Ehc
, Offset
, State
);
625 case EfiUsbPortPower
:
627 // Clear port power bit when PPC is 1
629 if ((Ehc
->HcCapParams
& HCSP_PPC
) == HCSP_PPC
) {
630 State
&= ~PORTSC_POWER
;
631 EhcWriteOpReg (Ehc
, Offset
, State
);
634 case EfiUsbPortSuspendChange
:
635 case EfiUsbPortResetChange
:
637 // Not supported or not related operation
642 Status
= EFI_INVALID_PARAMETER
;
647 DEBUG ((EFI_D_INFO
, "EhcClearRootHubPortFeature: exit status %r\n", Status
));
648 gBS
->RestoreTPL (OldTpl
);
654 Submits control transfer to a target USB device.
656 @param This This EFI_USB2_HC_PROTOCOL instance.
657 @param DeviceAddress The target device address.
658 @param DeviceSpeed Target device speed.
659 @param MaximumPacketLength Maximum packet size the default control transfer
660 endpoint is capable of sending or receiving.
661 @param Request USB device request to send.
662 @param TransferDirection Specifies the data direction for the data stage
663 @param Data Data buffer to be transmitted or received from USB
665 @param DataLength The size (in bytes) of the data buffer.
666 @param TimeOut Indicates the maximum timeout, in millisecond.
667 @param Translator Transaction translator to be used by this device.
668 @param TransferResult Return the result of this control transfer.
670 @retval EFI_SUCCESS Transfer was completed successfully.
671 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
672 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
673 @retval EFI_TIMEOUT Transfer failed due to timeout.
674 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
680 IN EFI_USB2_HC_PROTOCOL
*This
,
681 IN UINT8 DeviceAddress
,
682 IN UINT8 DeviceSpeed
,
683 IN UINTN MaximumPacketLength
,
684 IN EFI_USB_DEVICE_REQUEST
*Request
,
685 IN EFI_USB_DATA_DIRECTION TransferDirection
,
687 IN OUT UINTN
*DataLength
,
689 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
690 OUT UINT32
*TransferResult
700 // Validate parameters
702 if ((Request
== NULL
) || (TransferResult
== NULL
)) {
703 return EFI_INVALID_PARAMETER
;
706 if ((TransferDirection
!= EfiUsbDataIn
) &&
707 (TransferDirection
!= EfiUsbDataOut
) &&
708 (TransferDirection
!= EfiUsbNoData
)) {
709 return EFI_INVALID_PARAMETER
;
712 if ((TransferDirection
== EfiUsbNoData
) &&
713 ((Data
!= NULL
) || (*DataLength
!= 0))) {
714 return EFI_INVALID_PARAMETER
;
717 if ((TransferDirection
!= EfiUsbNoData
) &&
718 ((Data
== NULL
) || (*DataLength
== 0))) {
719 return EFI_INVALID_PARAMETER
;
722 if ((MaximumPacketLength
!= 8) && (MaximumPacketLength
!= 16) &&
723 (MaximumPacketLength
!= 32) && (MaximumPacketLength
!= 64)) {
724 return EFI_INVALID_PARAMETER
;
727 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) {
728 return EFI_INVALID_PARAMETER
;
731 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
732 Ehc
= EHC_FROM_THIS (This
);
734 Status
= EFI_DEVICE_ERROR
;
735 *TransferResult
= EFI_USB_ERR_SYSTEM
;
737 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
738 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: HC halted at entrance\n"));
740 EhcAckAllInterrupt (Ehc
);
744 EhcAckAllInterrupt (Ehc
);
747 // Create a new URB, insert it into the asynchronous
748 // schedule list, then poll the execution status.
751 // Encode the direction in address, although default control
752 // endpoint is bidirectional. EhcCreateUrb expects this
753 // combination of Ep addr and its direction.
755 Endpoint
= (UINT8
) (0 | ((TransferDirection
== EfiUsbDataIn
) ? 0x80 : 0));
775 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: failed to create URB"));
777 Status
= EFI_OUT_OF_RESOURCES
;
781 EhcLinkQhToAsync (Ehc
, Urb
->Qh
);
782 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
783 EhcUnlinkQhFromAsync (Ehc
, Urb
->Qh
);
786 // Get the status from URB. The result is updated in EhcCheckUrbResult
787 // which is called by EhcExecTransfer
789 *TransferResult
= Urb
->Result
;
790 *DataLength
= Urb
->Completed
;
792 if (*TransferResult
== EFI_USB_NOERROR
) {
793 Status
= EFI_SUCCESS
;
796 EhcAckAllInterrupt (Ehc
);
797 EhcFreeUrb (Ehc
, Urb
);
800 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
801 gBS
->RestoreTPL (OldTpl
);
803 if (EFI_ERROR (Status
)) {
804 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
812 Submits bulk transfer to a bulk endpoint of a USB device.
814 @param This This EFI_USB2_HC_PROTOCOL instance.
815 @param DeviceAddress Target device address.
816 @param EndPointAddress Endpoint number and its direction in bit 7.
817 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
819 @param MaximumPacketLength Maximum packet size the endpoint is capable of
820 sending or receiving.
821 @param DataBuffersNumber Number of data buffers prepared for the transfer.
822 @param Data Array of pointers to the buffers of data to transmit
823 from or receive into.
824 @param DataLength The lenght of the data buffer.
825 @param DataToggle On input, the initial data toggle for the transfer;
826 On output, it is updated to to next data toggle to
827 use of the subsequent bulk transfer.
828 @param TimeOut Indicates the maximum time, in millisecond, which
829 the transfer is allowed to complete.
830 @param Translator A pointr to the transaction translator data.
831 @param TransferResult A pointer to the detailed result information of the
834 @retval EFI_SUCCESS The transfer was completed successfully.
835 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
836 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
837 @retval EFI_TIMEOUT The transfer failed due to timeout.
838 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
844 IN EFI_USB2_HC_PROTOCOL
*This
,
845 IN UINT8 DeviceAddress
,
846 IN UINT8 EndPointAddress
,
847 IN UINT8 DeviceSpeed
,
848 IN UINTN MaximumPacketLength
,
849 IN UINT8 DataBuffersNumber
,
850 IN OUT VOID
*Data
[EFI_USB_MAX_BULK_BUFFER_NUM
],
851 IN OUT UINTN
*DataLength
,
852 IN OUT UINT8
*DataToggle
,
854 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
855 OUT UINT32
*TransferResult
864 // Validate the parameters
866 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
867 (Data
== NULL
) || (Data
[0] == NULL
) || (TransferResult
== NULL
)) {
868 return EFI_INVALID_PARAMETER
;
871 if ((*DataToggle
!= 0) && (*DataToggle
!= 1)) {
872 return EFI_INVALID_PARAMETER
;
875 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) ||
876 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
877 ((EFI_USB_SPEED_HIGH
== DeviceSpeed
) && (MaximumPacketLength
> 512))) {
878 return EFI_INVALID_PARAMETER
;
881 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
882 Ehc
= EHC_FROM_THIS (This
);
884 *TransferResult
= EFI_USB_ERR_SYSTEM
;
885 Status
= EFI_DEVICE_ERROR
;
887 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
888 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: HC is halted\n"));
890 EhcAckAllInterrupt (Ehc
);
894 EhcAckAllInterrupt (Ehc
);
897 // Create a new URB, insert it into the asynchronous
898 // schedule list, then poll the execution status.
919 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: failed to create URB\n"));
921 Status
= EFI_OUT_OF_RESOURCES
;
925 EhcLinkQhToAsync (Ehc
, Urb
->Qh
);
926 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
927 EhcUnlinkQhFromAsync (Ehc
, Urb
->Qh
);
929 *TransferResult
= Urb
->Result
;
930 *DataLength
= Urb
->Completed
;
931 *DataToggle
= Urb
->DataToggle
;
933 if (*TransferResult
== EFI_USB_NOERROR
) {
934 Status
= EFI_SUCCESS
;
937 EhcAckAllInterrupt (Ehc
);
938 EhcFreeUrb (Ehc
, Urb
);
941 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
942 gBS
->RestoreTPL (OldTpl
);
944 if (EFI_ERROR (Status
)) {
945 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
953 Submits an asynchronous interrupt transfer to an
954 interrupt endpoint of a USB device.
956 @param This This EFI_USB2_HC_PROTOCOL instance.
957 @param DeviceAddress Target device address.
958 @param EndPointAddress Endpoint number and its direction encoded in bit 7
959 @param DeviceSpeed Indicates device speed.
960 @param MaximumPacketLength Maximum packet size the target endpoint is capable
961 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
962 transfer If FALSE, to remove the specified
963 asynchronous interrupt.
964 @param DataToggle On input, the initial data toggle to use; on output,
965 it is updated to indicate the next data toggle.
966 @param PollingInterval The he interval, in milliseconds, that the transfer
968 @param DataLength The length of data to receive at the rate specified
970 @param Translator Transaction translator to use.
971 @param CallBackFunction Function to call at the rate specified by
973 @param Context Context to CallBackFunction.
975 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
976 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
977 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
978 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
983 EhcAsyncInterruptTransfer (
984 IN EFI_USB2_HC_PROTOCOL
* This
,
985 IN UINT8 DeviceAddress
,
986 IN UINT8 EndPointAddress
,
987 IN UINT8 DeviceSpeed
,
988 IN UINTN MaximumPacketLength
,
989 IN BOOLEAN IsNewTransfer
,
990 IN OUT UINT8
*DataToggle
,
991 IN UINTN PollingInterval
,
993 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
* Translator
,
994 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction
,
995 IN VOID
*Context OPTIONAL
1004 // Validate parameters
1006 if (!EHCI_IS_DATAIN (EndPointAddress
)) {
1007 return EFI_INVALID_PARAMETER
;
1010 if (IsNewTransfer
) {
1011 if (DataLength
== 0) {
1012 return EFI_INVALID_PARAMETER
;
1015 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1016 return EFI_INVALID_PARAMETER
;
1019 if ((PollingInterval
> 255) || (PollingInterval
< 1)) {
1020 return EFI_INVALID_PARAMETER
;
1024 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
1025 Ehc
= EHC_FROM_THIS (This
);
1028 // Delete Async interrupt transfer request. DataToggle will return
1029 // the next data toggle to use.
1031 if (!IsNewTransfer
) {
1032 Status
= EhciDelAsyncIntTransfer (Ehc
, DeviceAddress
, EndPointAddress
, DataToggle
);
1034 DEBUG ((EFI_D_INFO
, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status
));
1038 Status
= EFI_SUCCESS
;
1040 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
1041 DEBUG ((EFI_D_ERROR
, "EhcAsyncInterruptTransfer: HC is halt\n"));
1042 EhcAckAllInterrupt (Ehc
);
1044 Status
= EFI_DEVICE_ERROR
;
1048 EhcAckAllInterrupt (Ehc
);
1050 Urb
= EhciInsertAsyncIntTransfer (
1056 MaximumPacketLength
,
1065 Status
= EFI_OUT_OF_RESOURCES
;
1070 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
1071 gBS
->RestoreTPL (OldTpl
);
1078 Submits synchronous interrupt transfer to an interrupt endpoint
1081 @param This This EFI_USB2_HC_PROTOCOL instance.
1082 @param DeviceAddress Target device address.
1083 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1084 @param DeviceSpeed Indicates device speed.
1085 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1086 of sending or receiving.
1087 @param Data Buffer of data that will be transmitted to USB
1088 device or received from USB device.
1089 @param DataLength On input, the size, in bytes, of the data buffer; On
1090 output, the number of bytes transferred.
1091 @param DataToggle On input, the initial data toggle to use; on output,
1092 it is updated to indicate the next data toggle.
1093 @param TimeOut Maximum time, in second, to complete.
1094 @param Translator Transaction translator to use.
1095 @param TransferResult Variable to receive the transfer result.
1097 @return EFI_SUCCESS The transfer was completed successfully.
1098 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1099 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1100 @return EFI_TIMEOUT The transfer failed due to timeout.
1101 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1106 EhcSyncInterruptTransfer (
1107 IN EFI_USB2_HC_PROTOCOL
*This
,
1108 IN UINT8 DeviceAddress
,
1109 IN UINT8 EndPointAddress
,
1110 IN UINT8 DeviceSpeed
,
1111 IN UINTN MaximumPacketLength
,
1113 IN OUT UINTN
*DataLength
,
1114 IN OUT UINT8
*DataToggle
,
1116 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1117 OUT UINT32
*TransferResult
1126 // Validates parameters
1128 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
1129 (Data
== NULL
) || (TransferResult
== NULL
)) {
1130 return EFI_INVALID_PARAMETER
;
1133 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1134 return EFI_INVALID_PARAMETER
;
1137 if (((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) ||
1138 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
1139 ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) && (MaximumPacketLength
> 3072))) {
1140 return EFI_INVALID_PARAMETER
;
1143 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
1144 Ehc
= EHC_FROM_THIS (This
);
1146 *TransferResult
= EFI_USB_ERR_SYSTEM
;
1147 Status
= EFI_DEVICE_ERROR
;
1149 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
1150 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: HC is halt\n"));
1152 EhcAckAllInterrupt (Ehc
);
1156 EhcAckAllInterrupt (Ehc
);
1158 Urb
= EhcCreateUrb (
1164 MaximumPacketLength
,
1166 EHC_INT_TRANSFER_SYNC
,
1177 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: failed to create URB\n"));
1179 Status
= EFI_OUT_OF_RESOURCES
;
1183 EhcLinkQhToPeriod (Ehc
, Urb
->Qh
);
1184 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
1185 EhcUnlinkQhFromPeriod (Ehc
, Urb
->Qh
);
1187 *TransferResult
= Urb
->Result
;
1188 *DataLength
= Urb
->Completed
;
1189 *DataToggle
= Urb
->DataToggle
;
1191 if (*TransferResult
== EFI_USB_NOERROR
) {
1192 Status
= EFI_SUCCESS
;
1195 EhcFreeUrb (Ehc
, Urb
);
1197 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
1198 gBS
->RestoreTPL (OldTpl
);
1200 if (EFI_ERROR (Status
)) {
1201 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
1209 Submits isochronous transfer to a target USB device.
1211 @param This This EFI_USB2_HC_PROTOCOL instance.
1212 @param DeviceAddress Target device address.
1213 @param EndPointAddress End point address with its direction.
1214 @param DeviceSpeed Device speed, Low speed device doesn't support this
1216 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1217 sending or receiving.
1218 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1219 @param Data Array of pointers to the buffers of data that will
1220 be transmitted to USB device or received from USB
1222 @param DataLength The size, in bytes, of the data buffer.
1223 @param Translator Transaction translator to use.
1224 @param TransferResult Variable to receive the transfer result.
1226 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1231 EhcIsochronousTransfer (
1232 IN EFI_USB2_HC_PROTOCOL
*This
,
1233 IN UINT8 DeviceAddress
,
1234 IN UINT8 EndPointAddress
,
1235 IN UINT8 DeviceSpeed
,
1236 IN UINTN MaximumPacketLength
,
1237 IN UINT8 DataBuffersNumber
,
1238 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1239 IN UINTN DataLength
,
1240 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1241 OUT UINT32
*TransferResult
1244 return EFI_UNSUPPORTED
;
1249 Submits Async isochronous transfer to a target USB device.
1251 @param This This EFI_USB2_HC_PROTOCOL instance.
1252 @param DeviceAddress Target device address.
1253 @param EndPointAddress End point address with its direction.
1254 @param DeviceSpeed Device speed, Low speed device doesn't support this
1256 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1257 sending or receiving.
1258 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1259 @param Data Array of pointers to the buffers of data that will
1260 be transmitted to USB device or received from USB
1262 @param DataLength The size, in bytes, of the data buffer.
1263 @param Translator Transaction translator to use.
1264 @param IsochronousCallBack Function to be called when the transfer complete.
1265 @param Context Context passed to the call back function as
1268 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1273 EhcAsyncIsochronousTransfer (
1274 IN EFI_USB2_HC_PROTOCOL
*This
,
1275 IN UINT8 DeviceAddress
,
1276 IN UINT8 EndPointAddress
,
1277 IN UINT8 DeviceSpeed
,
1278 IN UINTN MaximumPacketLength
,
1279 IN UINT8 DataBuffersNumber
,
1280 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1281 IN UINTN DataLength
,
1282 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1283 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack
,
1287 return EFI_UNSUPPORTED
;
1291 Entry point for EFI drivers.
1293 @param ImageHandle EFI_HANDLE.
1294 @param SystemTable EFI_SYSTEM_TABLE.
1296 @return EFI_SUCCESS Success.
1297 EFI_DEVICE_ERROR Fail.
1302 EhcDriverEntryPoint (
1303 IN EFI_HANDLE ImageHandle
,
1304 IN EFI_SYSTEM_TABLE
*SystemTable
1307 return EfiLibInstallDriverBindingComponentName2 (
1310 &gEhciDriverBinding
,
1312 &gEhciComponentName
,
1313 &gEhciComponentName2
1319 Test to see if this driver supports ControllerHandle. Any
1320 ControllerHandle that has Usb2HcProtocol installed will
1323 @param This Protocol instance pointer.
1324 @param Controller Handle of device to test.
1325 @param RemainingDevicePath Not used.
1327 @return EFI_SUCCESS This driver supports this device.
1328 @return EFI_UNSUPPORTED This driver does not support this device.
1333 EhcDriverBindingSupported (
1334 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1335 IN EFI_HANDLE Controller
,
1336 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1340 EFI_PCI_IO_PROTOCOL
*PciIo
;
1341 USB_CLASSC UsbClassCReg
;
1344 // Test whether there is PCI IO Protocol attached on the controller handle.
1346 Status
= gBS
->OpenProtocol (
1348 &gEfiPciIoProtocolGuid
,
1350 This
->DriverBindingHandle
,
1352 EFI_OPEN_PROTOCOL_BY_DRIVER
1355 if (EFI_ERROR (Status
)) {
1356 return EFI_UNSUPPORTED
;
1359 Status
= PciIo
->Pci
.Read (
1362 PCI_CLASSCODE_OFFSET
,
1363 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1367 if (EFI_ERROR (Status
)) {
1368 Status
= EFI_UNSUPPORTED
;
1373 // Test whether the controller belongs to Ehci type
1375 if ((UsbClassCReg
.BaseCode
!= PCI_CLASS_SERIAL
) || (UsbClassCReg
.SubClassCode
!= PCI_CLASS_SERIAL_USB
)
1376 || ((UsbClassCReg
.ProgInterface
!= PCI_IF_EHCI
) && (UsbClassCReg
.ProgInterface
!= PCI_IF_UHCI
) && (UsbClassCReg
.ProgInterface
!= PCI_IF_OHCI
))) {
1378 Status
= EFI_UNSUPPORTED
;
1382 gBS
->CloseProtocol (
1384 &gEfiPciIoProtocolGuid
,
1385 This
->DriverBindingHandle
,
1393 Get the usb debug port related information.
1395 @param Ehc The EHCI device.
1397 @retval RETURN_SUCCESS Get debug port number, bar and offset successfully.
1398 @retval Others The usb host controller does not supported usb debug port capability.
1402 EhcGetUsbDebugPortInfo (
1406 EFI_PCI_IO_PROTOCOL
*PciIo
;
1408 UINT8 CapabilityPtr
;
1413 ASSERT (Ehc
->PciIo
!= NULL
);
1417 // Detect if the EHCI host controller support Capaility Pointer.
1419 Status
= PciIo
->Pci
.Read (
1422 PCI_PRIMARY_STATUS_OFFSET
,
1427 if (EFI_ERROR (Status
)) {
1431 if ((PciStatus
& EFI_PCI_STATUS_CAPABILITY
) == 0) {
1433 // The Pci Device Doesn't Support Capability Pointer.
1435 return EFI_UNSUPPORTED
;
1439 // Get Pointer To Capability List
1441 Status
= PciIo
->Pci
.Read (
1444 PCI_CAPBILITY_POINTER_OFFSET
,
1449 if (EFI_ERROR (Status
)) {
1454 // Find Capability ID 0xA, Which Is For Debug Port
1456 while (CapabilityPtr
!= 0) {
1457 Status
= PciIo
->Pci
.Read (
1465 if (EFI_ERROR (Status
)) {
1469 if (CapabilityId
== EHC_DEBUG_PORT_CAP_ID
) {
1473 Status
= PciIo
->Pci
.Read (
1481 if (EFI_ERROR (Status
)) {
1487 // No Debug Port Capability Found
1489 if (CapabilityPtr
== 0) {
1490 return EFI_UNSUPPORTED
;
1494 // Get The Base Address Of Debug Port Register In Debug Port Capability Register
1496 Status
= PciIo
->Pci
.Read (
1504 if (EFI_ERROR (Status
)) {
1508 Ehc
->DebugPortOffset
= DebugPort
& 0x1FFF;
1509 Ehc
->DebugPortBarNum
= (UINT8
)((DebugPort
>> 13) - 1);
1510 Ehc
->DebugPortNum
= (UINT8
)((Ehc
->HcStructParams
& 0x00F00000) >> 20);
1517 Create and initialize a USB2_HC_DEV.
1519 @param PciIo The PciIo on this device.
1520 @param DevicePath The device path of host controller.
1521 @param OriginalPciAttributes Original PCI attributes.
1523 @return The allocated and initialized USB2_HC_DEV structure if created,
1529 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1530 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1531 IN UINT64 OriginalPciAttributes
1537 Ehc
= AllocateZeroPool (sizeof (USB2_HC_DEV
));
1544 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1546 Ehc
->Signature
= USB2_HC_DEV_SIGNATURE
;
1548 Ehc
->Usb2Hc
.GetCapability
= EhcGetCapability
;
1549 Ehc
->Usb2Hc
.Reset
= EhcReset
;
1550 Ehc
->Usb2Hc
.GetState
= EhcGetState
;
1551 Ehc
->Usb2Hc
.SetState
= EhcSetState
;
1552 Ehc
->Usb2Hc
.ControlTransfer
= EhcControlTransfer
;
1553 Ehc
->Usb2Hc
.BulkTransfer
= EhcBulkTransfer
;
1554 Ehc
->Usb2Hc
.AsyncInterruptTransfer
= EhcAsyncInterruptTransfer
;
1555 Ehc
->Usb2Hc
.SyncInterruptTransfer
= EhcSyncInterruptTransfer
;
1556 Ehc
->Usb2Hc
.IsochronousTransfer
= EhcIsochronousTransfer
;
1557 Ehc
->Usb2Hc
.AsyncIsochronousTransfer
= EhcAsyncIsochronousTransfer
;
1558 Ehc
->Usb2Hc
.GetRootHubPortStatus
= EhcGetRootHubPortStatus
;
1559 Ehc
->Usb2Hc
.SetRootHubPortFeature
= EhcSetRootHubPortFeature
;
1560 Ehc
->Usb2Hc
.ClearRootHubPortFeature
= EhcClearRootHubPortFeature
;
1561 Ehc
->Usb2Hc
.MajorRevision
= 0x2;
1562 Ehc
->Usb2Hc
.MinorRevision
= 0x0;
1565 Ehc
->DevicePath
= DevicePath
;
1566 Ehc
->OriginalPciAttributes
= OriginalPciAttributes
;
1568 InitializeListHead (&Ehc
->AsyncIntTransfers
);
1570 Ehc
->HcStructParams
= EhcReadCapRegister (Ehc
, EHC_HCSPARAMS_OFFSET
);
1571 Ehc
->HcCapParams
= EhcReadCapRegister (Ehc
, EHC_HCCPARAMS_OFFSET
);
1572 Ehc
->CapLen
= EhcReadCapRegister (Ehc
, EHC_CAPLENGTH_OFFSET
) & 0x0FF;
1574 DEBUG ((EFI_D_INFO
, "EhcCreateUsb2Hc: capability length %d\n", Ehc
->CapLen
));
1577 // EHCI Controllers with a CapLen of 0 are ignored.
1579 if (Ehc
->CapLen
== 0) {
1580 gBS
->FreePool (Ehc
);
1584 EhcGetUsbDebugPortInfo (Ehc
);
1587 // Create AsyncRequest Polling Timer
1589 Status
= gBS
->CreateEvent (
1590 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1592 EhcMonitorAsyncRequests
,
1597 if (EFI_ERROR (Status
)) {
1598 gBS
->FreePool (Ehc
);
1606 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1608 @param Event Pointer to this event
1609 @param Context Event handler private data
1614 EhcExitBootService (
1622 Ehc
= (USB2_HC_DEV
*) Context
;
1625 // Reset the Host Controller
1627 EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
1632 Starting the Usb EHCI Driver.
1634 @param This Protocol instance pointer.
1635 @param Controller Handle of device to test.
1636 @param RemainingDevicePath Not used.
1638 @return EFI_SUCCESS supports this device.
1639 @return EFI_UNSUPPORTED do not support this device.
1640 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1641 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1646 EhcDriverBindingStart (
1647 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1648 IN EFI_HANDLE Controller
,
1649 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1654 EFI_PCI_IO_PROTOCOL
*PciIo
;
1655 EFI_PCI_IO_PROTOCOL
*Instance
;
1657 UINT64 OriginalPciAttributes
;
1658 BOOLEAN PciAttributesSaved
;
1659 USB_CLASSC UsbClassCReg
;
1660 EFI_HANDLE
*HandleBuffer
;
1661 UINTN NumberOfHandles
;
1663 UINTN CompanionSegmentNumber
;
1664 UINTN CompanionBusNumber
;
1665 UINTN CompanionDeviceNumber
;
1666 UINTN CompanionFunctionNumber
;
1667 UINTN EhciSegmentNumber
;
1668 UINTN EhciBusNumber
;
1669 UINTN EhciDeviceNumber
;
1670 UINTN EhciFunctionNumber
;
1671 EFI_DEVICE_PATH_PROTOCOL
*HcDevicePath
;
1674 // Open the PciIo Protocol, then enable the USB host controller
1676 Status
= gBS
->OpenProtocol (
1678 &gEfiPciIoProtocolGuid
,
1680 This
->DriverBindingHandle
,
1682 EFI_OPEN_PROTOCOL_BY_DRIVER
1685 if (EFI_ERROR (Status
)) {
1690 // Open Device Path Protocol for on USB host controller
1692 HcDevicePath
= NULL
;
1693 Status
= gBS
->OpenProtocol (
1695 &gEfiDevicePathProtocolGuid
,
1696 (VOID
**) &HcDevicePath
,
1697 This
->DriverBindingHandle
,
1699 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1702 PciAttributesSaved
= FALSE
;
1704 // Save original PCI attributes
1706 Status
= PciIo
->Attributes (
1708 EfiPciIoAttributeOperationGet
,
1710 &OriginalPciAttributes
1713 if (EFI_ERROR (Status
)) {
1716 PciAttributesSaved
= TRUE
;
1718 Status
= PciIo
->Attributes (
1720 EfiPciIoAttributeOperationSupported
,
1724 if (!EFI_ERROR (Status
)) {
1725 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1726 Status
= PciIo
->Attributes (
1728 EfiPciIoAttributeOperationEnable
,
1734 if (EFI_ERROR (Status
)) {
1735 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to enable controller\n"));
1740 // Get the Pci device class code.
1742 Status
= PciIo
->Pci
.Read (
1745 PCI_CLASSCODE_OFFSET
,
1746 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1750 if (EFI_ERROR (Status
)) {
1751 Status
= EFI_UNSUPPORTED
;
1755 // Determine if the device is UHCI or OHCI host controller or not. If yes, then find out the
1756 // companion usb ehci host controller and force EHCI driver get attached to it before
1757 // UHCI or OHCI driver attaches to UHCI or OHCI host controller.
1759 if ((UsbClassCReg
.ProgInterface
== PCI_IF_UHCI
|| UsbClassCReg
.ProgInterface
== PCI_IF_OHCI
) &&
1760 (UsbClassCReg
.BaseCode
== PCI_CLASS_SERIAL
) &&
1761 (UsbClassCReg
.SubClassCode
== PCI_CLASS_SERIAL_USB
)) {
1762 Status
= PciIo
->GetLocation (
1764 &CompanionSegmentNumber
,
1765 &CompanionBusNumber
,
1766 &CompanionDeviceNumber
,
1767 &CompanionFunctionNumber
1769 if (EFI_ERROR (Status
)) {
1773 Status
= gBS
->LocateHandleBuffer (
1775 &gEfiPciIoProtocolGuid
,
1780 if (EFI_ERROR (Status
)) {
1784 for (Index
= 0; Index
< NumberOfHandles
; Index
++) {
1786 // Get the device path on this handle
1788 Status
= gBS
->HandleProtocol (
1789 HandleBuffer
[Index
],
1790 &gEfiPciIoProtocolGuid
,
1793 ASSERT_EFI_ERROR (Status
);
1795 Status
= Instance
->Pci
.Read (
1798 PCI_CLASSCODE_OFFSET
,
1799 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1803 if (EFI_ERROR (Status
)) {
1804 Status
= EFI_UNSUPPORTED
;
1808 if ((UsbClassCReg
.ProgInterface
== PCI_IF_EHCI
) &&
1809 (UsbClassCReg
.BaseCode
== PCI_CLASS_SERIAL
) &&
1810 (UsbClassCReg
.SubClassCode
== PCI_CLASS_SERIAL_USB
)) {
1811 Status
= Instance
->GetLocation (
1818 if (EFI_ERROR (Status
)) {
1822 // Currently, the judgment on the companion usb host controller is through the
1823 // same bus number, which may vary on different platform.
1825 if (EhciBusNumber
== CompanionBusNumber
) {
1826 gBS
->CloseProtocol (
1828 &gEfiPciIoProtocolGuid
,
1829 This
->DriverBindingHandle
,
1832 EhcDriverBindingStart(This
, HandleBuffer
[Index
], NULL
);
1836 Status
= EFI_NOT_FOUND
;
1841 // Create then install USB2_HC_PROTOCOL
1843 Ehc
= EhcCreateUsb2Hc (PciIo
, HcDevicePath
, OriginalPciAttributes
);
1846 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to create USB2_HC\n"));
1848 Status
= EFI_OUT_OF_RESOURCES
;
1853 // Enable 64-bit DMA support in the PCI layer if this controller
1856 if (EHC_BIT_IS_SET (Ehc
->HcCapParams
, HCCP_64BIT
)) {
1857 Status
= PciIo
->Attributes (
1859 EfiPciIoAttributeOperationEnable
,
1860 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
1863 if (!EFI_ERROR (Status
)) {
1864 Ehc
->Support64BitDma
= TRUE
;
1867 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
1868 __FUNCTION__
, Controller
, Status
));
1872 Status
= gBS
->InstallProtocolInterface (
1874 &gEfiUsb2HcProtocolGuid
,
1875 EFI_NATIVE_INTERFACE
,
1879 if (EFI_ERROR (Status
)) {
1880 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1885 // Robustnesss improvement such as for Duet platform
1886 // Default is not required.
1888 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport
)) {
1889 EhcClearLegacySupport (Ehc
);
1892 if (!EhcIsDebugPortInUse (Ehc
, NULL
)) {
1893 EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
1896 Status
= EhcInitHC (Ehc
);
1898 if (EFI_ERROR (Status
)) {
1899 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to init host controller\n"));
1900 goto UNINSTALL_USBHC
;
1904 // Start the asynchronous interrupt monitor
1906 Status
= gBS
->SetTimer (Ehc
->PollTimer
, TimerPeriodic
, EHC_ASYNC_POLL_INTERVAL
);
1908 if (EFI_ERROR (Status
)) {
1909 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
1911 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
1912 goto UNINSTALL_USBHC
;
1916 // Create event to stop the HC when exit boot service.
1918 Status
= gBS
->CreateEventEx (
1923 &gEfiEventExitBootServicesGuid
,
1924 &Ehc
->ExitBootServiceEvent
1926 if (EFI_ERROR (Status
)) {
1927 goto UNINSTALL_USBHC
;
1931 // Install the component name protocol, don't fail the start
1932 // because of something for display.
1936 gEhciComponentName
.SupportedLanguages
,
1937 &Ehc
->ControllerNameTable
,
1938 L
"Enhanced Host Controller (USB 2.0)",
1943 gEhciComponentName2
.SupportedLanguages
,
1944 &Ehc
->ControllerNameTable
,
1945 L
"Enhanced Host Controller (USB 2.0)",
1950 DEBUG ((EFI_D_INFO
, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller
));
1954 gBS
->UninstallProtocolInterface (
1956 &gEfiUsb2HcProtocolGuid
,
1962 gBS
->CloseEvent (Ehc
->PollTimer
);
1963 gBS
->FreePool (Ehc
);
1966 if (PciAttributesSaved
) {
1968 // Restore original PCI attributes
1972 EfiPciIoAttributeOperationSet
,
1973 OriginalPciAttributes
,
1978 gBS
->CloseProtocol (
1980 &gEfiPciIoProtocolGuid
,
1981 This
->DriverBindingHandle
,
1990 Stop this driver on ControllerHandle. Support stopping any child handles
1991 created by this driver.
1993 @param This Protocol instance pointer.
1994 @param Controller Handle of device to stop driver on.
1995 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1996 @param ChildHandleBuffer List of handles for the children we need to stop.
1998 @return EFI_SUCCESS Success.
1999 @return EFI_DEVICE_ERROR Fail.
2004 EhcDriverBindingStop (
2005 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2006 IN EFI_HANDLE Controller
,
2007 IN UINTN NumberOfChildren
,
2008 IN EFI_HANDLE
*ChildHandleBuffer
2012 EFI_USB2_HC_PROTOCOL
*Usb2Hc
;
2013 EFI_PCI_IO_PROTOCOL
*PciIo
;
2017 // Test whether the Controller handler passed in is a valid
2018 // Usb controller handle that should be supported, if not,
2019 // return the error status directly
2021 Status
= gBS
->OpenProtocol (
2023 &gEfiUsb2HcProtocolGuid
,
2025 This
->DriverBindingHandle
,
2027 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2030 if (EFI_ERROR (Status
)) {
2034 Ehc
= EHC_FROM_THIS (Usb2Hc
);
2037 Status
= gBS
->UninstallProtocolInterface (
2039 &gEfiUsb2HcProtocolGuid
,
2043 if (EFI_ERROR (Status
)) {
2048 // Stop AsyncRequest Polling timer then stop the EHCI driver
2049 // and uninstall the EHCI protocl.
2051 gBS
->SetTimer (Ehc
->PollTimer
, TimerCancel
, EHC_ASYNC_POLL_INTERVAL
);
2052 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
2054 if (Ehc
->PollTimer
!= NULL
) {
2055 gBS
->CloseEvent (Ehc
->PollTimer
);
2058 if (Ehc
->ExitBootServiceEvent
!= NULL
) {
2059 gBS
->CloseEvent (Ehc
->ExitBootServiceEvent
);
2064 if (Ehc
->ControllerNameTable
!= NULL
) {
2065 FreeUnicodeStringTable (Ehc
->ControllerNameTable
);
2069 // Disable routing of all ports to EHCI controller, so all ports are
2070 // routed back to the UHCI or OHCI controller.
2072 EhcClearOpRegBit (Ehc
, EHC_CONFIG_FLAG_OFFSET
, CONFIGFLAG_ROUTE_EHC
);
2075 // Restore original PCI attributes
2079 EfiPciIoAttributeOperationSet
,
2080 Ehc
->OriginalPciAttributes
,
2084 gBS
->CloseProtocol (
2086 &gEfiPciIoProtocolGuid
,
2087 This
->DriverBindingHandle
,