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 the UHCI driver attaches to the companion UHCI controller.
10 This way avoids the control transfer on a shared port between EHCI and companion host
11 controller when UHCI gets attached earlier than EHCI and a USB 2.0 device inserts.
13 Copyright (c) 2006 - 2009, Intel Corporation
14 All rights reserved. This program and the accompanying materials
15 are licensed and made available under the terms and conditions of the BSD License
16 which accompanies this distribution. The full text of the license may be found at
17 http://opensource.org/licenses/bsd-license.php
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
28 // Two arrays used to translate the EHCI port state (change)
29 // to the UEFI protocol's port state (change).
31 USB_PORT_STATE_MAP mUsbPortStateMap
[] = {
32 {PORTSC_CONN
, USB_PORT_STAT_CONNECTION
},
33 {PORTSC_ENABLED
, USB_PORT_STAT_ENABLE
},
34 {PORTSC_SUSPEND
, USB_PORT_STAT_SUSPEND
},
35 {PORTSC_OVERCUR
, USB_PORT_STAT_OVERCURRENT
},
36 {PORTSC_RESET
, USB_PORT_STAT_RESET
},
37 {PORTSC_POWER
, USB_PORT_STAT_POWER
},
38 {PORTSC_OWNER
, USB_PORT_STAT_OWNER
}
41 USB_PORT_STATE_MAP mUsbPortChangeMap
[] = {
42 {PORTSC_CONN_CHANGE
, USB_PORT_STAT_C_CONNECTION
},
43 {PORTSC_ENABLE_CHANGE
, USB_PORT_STAT_C_ENABLE
},
44 {PORTSC_OVERCUR_CHANGE
, USB_PORT_STAT_C_OVERCURRENT
}
47 EFI_DRIVER_BINDING_PROTOCOL
48 gEhciDriverBinding
= {
49 EhcDriverBindingSupported
,
50 EhcDriverBindingStart
,
58 Retrieves the capability of root hub ports.
60 @param This This EFI_USB_HC_PROTOCOL instance.
61 @param MaxSpeed Max speed supported by the controller.
62 @param PortNumber Number of the root hub ports.
63 @param Is64BitCapable Whether the controller supports 64-bit memory
66 @retval EFI_SUCCESS Host controller capability were retrieved successfully.
67 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
73 IN EFI_USB2_HC_PROTOCOL
*This
,
75 OUT UINT8
*PortNumber
,
76 OUT UINT8
*Is64BitCapable
82 if ((MaxSpeed
== NULL
) || (PortNumber
== NULL
) || (Is64BitCapable
== NULL
)) {
83 return EFI_INVALID_PARAMETER
;
86 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
87 Ehc
= EHC_FROM_THIS (This
);
89 *MaxSpeed
= EFI_USB_SPEED_HIGH
;
90 *PortNumber
= (UINT8
) (Ehc
->HcStructParams
& HCSP_NPORTS
);
91 *Is64BitCapable
= (UINT8
) (Ehc
->HcCapParams
& HCCP_64BIT
);
93 DEBUG ((EFI_D_INFO
, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber
, *Is64BitCapable
));
95 gBS
->RestoreTPL (OldTpl
);
101 Provides software reset for the USB host controller.
103 @param This This EFI_USB2_HC_PROTOCOL instance.
104 @param Attributes A bit mask of the reset operation to perform.
106 @retval EFI_SUCCESS The reset operation succeeded.
107 @retval EFI_INVALID_PARAMETER Attributes is not valid.
108 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
109 not currently supported by the host controller.
110 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
116 IN EFI_USB2_HC_PROTOCOL
*This
,
124 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
125 Ehc
= EHC_FROM_THIS (This
);
127 switch (Attributes
) {
128 case EFI_USB_HC_RESET_GLOBAL
:
130 // Flow through, same behavior as Host Controller Reset
132 case EFI_USB_HC_RESET_HOST_CONTROLLER
:
134 // Host Controller must be Halt when Reset it
136 if (!EhcIsHalt (Ehc
)) {
137 Status
= EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
139 if (EFI_ERROR (Status
)) {
140 Status
= EFI_DEVICE_ERROR
;
146 // Clean up the asynchronous transfers, currently only
147 // interrupt supports asynchronous operation.
149 EhciDelAllAsyncIntTransfers (Ehc
);
150 EhcAckAllInterrupt (Ehc
);
153 Status
= EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
155 if (EFI_ERROR (Status
)) {
159 Status
= EhcInitHC (Ehc
);
162 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG
:
163 case EFI_USB_HC_RESET_HOST_WITH_DEBUG
:
164 Status
= EFI_UNSUPPORTED
;
168 Status
= EFI_INVALID_PARAMETER
;
172 DEBUG ((EFI_D_INFO
, "EhcReset: exit status %r\n", Status
));
173 gBS
->RestoreTPL (OldTpl
);
179 Retrieve the current state of the USB host controller.
181 @param This This EFI_USB2_HC_PROTOCOL instance.
182 @param State Variable to return the current host controller
185 @retval EFI_SUCCESS Host controller state was returned in State.
186 @retval EFI_INVALID_PARAMETER State is NULL.
187 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
188 retrieve the host controller's current state.
194 IN CONST EFI_USB2_HC_PROTOCOL
*This
,
195 OUT EFI_USB_HC_STATE
*State
202 return EFI_INVALID_PARAMETER
;
205 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
206 Ehc
= EHC_FROM_THIS (This
);
208 if (EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
209 *State
= EfiUsbHcStateHalt
;
211 *State
= EfiUsbHcStateOperational
;
214 gBS
->RestoreTPL (OldTpl
);
216 DEBUG ((EFI_D_INFO
, "EhcGetState: current state %d\n", *State
));
222 Sets the USB host controller to a specific state.
224 @param This This EFI_USB2_HC_PROTOCOL instance.
225 @param State The state of the host controller that will be set.
227 @retval EFI_SUCCESS The USB host controller was successfully placed
228 in the state specified by State.
229 @retval EFI_INVALID_PARAMETER State is invalid.
230 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
236 IN EFI_USB2_HC_PROTOCOL
*This
,
237 IN EFI_USB_HC_STATE State
243 EFI_USB_HC_STATE CurState
;
245 Status
= EhcGetState (This
, &CurState
);
247 if (EFI_ERROR (Status
)) {
248 return EFI_DEVICE_ERROR
;
251 if (CurState
== State
) {
255 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
256 Ehc
= EHC_FROM_THIS (This
);
259 case EfiUsbHcStateHalt
:
260 Status
= EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
263 case EfiUsbHcStateOperational
:
264 if (EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_SYS_ERROR
)) {
265 Status
= EFI_DEVICE_ERROR
;
270 // Software must not write a one to this field unless the host controller
271 // is in the Halted state. Doing so will yield undefined results.
272 // refers to Spec[EHCI1.0-2.3.1]
274 if (!EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
275 Status
= EFI_DEVICE_ERROR
;
279 Status
= EhcRunHC (Ehc
, EHC_GENERIC_TIMEOUT
);
282 case EfiUsbHcStateSuspend
:
283 Status
= EFI_UNSUPPORTED
;
287 Status
= EFI_INVALID_PARAMETER
;
290 DEBUG ((EFI_D_INFO
, "EhcSetState: exit status %r\n", Status
));
291 gBS
->RestoreTPL (OldTpl
);
297 Retrieves the current status of a USB root hub port.
299 @param This This EFI_USB2_HC_PROTOCOL instance.
300 @param PortNumber The root hub port to retrieve the state from.
301 This value is zero-based.
302 @param PortStatus Variable to receive the port state.
304 @retval EFI_SUCCESS The status of the USB root hub port specified.
305 by PortNumber was returned in PortStatus.
306 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
307 @retval EFI_DEVICE_ERROR Can't read register.
312 EhcGetRootHubPortStatus (
313 IN CONST EFI_USB2_HC_PROTOCOL
*This
,
314 IN CONST UINT8 PortNumber
,
315 OUT EFI_USB_PORT_STATUS
*PortStatus
327 if (PortStatus
== NULL
) {
328 return EFI_INVALID_PARAMETER
;
331 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
333 Ehc
= EHC_FROM_THIS (This
);
334 Status
= EFI_SUCCESS
;
336 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
338 if (PortNumber
>= TotalPort
) {
339 Status
= EFI_INVALID_PARAMETER
;
343 Offset
= (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
));
344 PortStatus
->PortStatus
= 0;
345 PortStatus
->PortChangeStatus
= 0;
347 State
= EhcReadOpReg (Ehc
, Offset
);
350 // Identify device speed. If in K state, it is low speed.
351 // If the port is enabled after reset, the device is of
352 // high speed. The USB bus driver should retrieve the actual
353 // port speed after reset.
355 if (EHC_BIT_IS_SET (State
, PORTSC_LINESTATE_K
)) {
356 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
358 } else if (EHC_BIT_IS_SET (State
, PORTSC_ENABLED
)) {
359 PortStatus
->PortStatus
|= USB_PORT_STAT_HIGH_SPEED
;
363 // Convert the EHCI port/port change state to UEFI status
365 MapSize
= sizeof (mUsbPortStateMap
) / sizeof (USB_PORT_STATE_MAP
);
367 for (Index
= 0; Index
< MapSize
; Index
++) {
368 if (EHC_BIT_IS_SET (State
, mUsbPortStateMap
[Index
].HwState
)) {
369 PortStatus
->PortStatus
= (UINT16
) (PortStatus
->PortStatus
| mUsbPortStateMap
[Index
].UefiState
);
373 MapSize
= sizeof (mUsbPortChangeMap
) / sizeof (USB_PORT_STATE_MAP
);
375 for (Index
= 0; Index
< MapSize
; Index
++) {
376 if (EHC_BIT_IS_SET (State
, mUsbPortChangeMap
[Index
].HwState
)) {
377 PortStatus
->PortChangeStatus
= (UINT16
) (PortStatus
->PortChangeStatus
| mUsbPortChangeMap
[Index
].UefiState
);
382 gBS
->RestoreTPL (OldTpl
);
388 Sets a feature for the specified root hub port.
390 @param This This EFI_USB2_HC_PROTOCOL instance.
391 @param PortNumber Root hub port to set.
392 @param PortFeature Feature to set.
394 @retval EFI_SUCCESS The feature specified by PortFeature was set.
395 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
396 @retval EFI_DEVICE_ERROR Can't read register.
401 EhcSetRootHubPortFeature (
402 IN EFI_USB2_HC_PROTOCOL
*This
,
404 IN EFI_USB_PORT_FEATURE PortFeature
414 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
415 Ehc
= EHC_FROM_THIS (This
);
416 Status
= EFI_SUCCESS
;
418 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
420 if (PortNumber
>= TotalPort
) {
421 Status
= EFI_INVALID_PARAMETER
;
425 Offset
= (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
));
426 State
= EhcReadOpReg (Ehc
, Offset
);
429 // Mask off the port status change bits, these bits are
432 State
&= ~PORTSC_CHANGE_MASK
;
434 switch (PortFeature
) {
435 case EfiUsbPortEnable
:
437 // Sofeware can't set this bit, Port can only be enable by
438 // EHCI as a part of the reset and enable
440 State
|= PORTSC_ENABLED
;
441 EhcWriteOpReg (Ehc
, Offset
, State
);
444 case EfiUsbPortSuspend
:
445 State
|= PORTSC_SUSPEND
;
446 EhcWriteOpReg (Ehc
, Offset
, State
);
449 case EfiUsbPortReset
:
451 // Make sure Host Controller not halt before reset it
453 if (EhcIsHalt (Ehc
)) {
454 Status
= EhcRunHC (Ehc
, EHC_GENERIC_TIMEOUT
);
456 if (EFI_ERROR (Status
)) {
457 DEBUG ((EFI_D_INFO
, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status
));
463 // Set one to PortReset bit must also set zero to PortEnable bit
465 State
|= PORTSC_RESET
;
466 State
&= ~PORTSC_ENABLED
;
467 EhcWriteOpReg (Ehc
, Offset
, State
);
470 case EfiUsbPortPower
:
472 // Not supported, ignore the operation
474 Status
= EFI_SUCCESS
;
477 case EfiUsbPortOwner
:
478 State
|= PORTSC_OWNER
;
479 EhcWriteOpReg (Ehc
, Offset
, State
);
483 Status
= EFI_INVALID_PARAMETER
;
487 DEBUG ((EFI_D_INFO
, "EhcSetRootHubPortFeature: exit status %r\n", Status
));
489 gBS
->RestoreTPL (OldTpl
);
495 Clears a feature for the specified root hub port.
497 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
498 @param PortNumber Specifies the root hub port whose feature is
499 requested to be cleared.
500 @param PortFeature Indicates the feature selector associated with the
501 feature clear request.
503 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
504 for the USB root hub port specified by PortNumber.
505 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
506 @retval EFI_DEVICE_ERROR Can't read register.
511 EhcClearRootHubPortFeature (
512 IN EFI_USB2_HC_PROTOCOL
*This
,
514 IN EFI_USB_PORT_FEATURE PortFeature
524 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
525 Ehc
= EHC_FROM_THIS (This
);
526 Status
= EFI_SUCCESS
;
528 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
530 if (PortNumber
>= TotalPort
) {
531 Status
= EFI_INVALID_PARAMETER
;
535 Offset
= EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
);
536 State
= EhcReadOpReg (Ehc
, Offset
);
537 State
&= ~PORTSC_CHANGE_MASK
;
539 switch (PortFeature
) {
540 case EfiUsbPortEnable
:
542 // Clear PORT_ENABLE feature means disable port.
544 State
&= ~PORTSC_ENABLED
;
545 EhcWriteOpReg (Ehc
, Offset
, State
);
548 case EfiUsbPortSuspend
:
550 // A write of zero to this bit is ignored by the host
551 // controller. The host controller will unconditionally
552 // set this bit to a zero when:
553 // 1. software sets the Forct Port Resume bit to a zero from a one.
554 // 2. software sets the Port Reset bit to a one frome a zero.
556 State
&= ~PORSTSC_RESUME
;
557 EhcWriteOpReg (Ehc
, Offset
, State
);
560 case EfiUsbPortReset
:
562 // Clear PORT_RESET means clear the reset signal.
564 State
&= ~PORTSC_RESET
;
565 EhcWriteOpReg (Ehc
, Offset
, State
);
568 case EfiUsbPortOwner
:
570 // Clear port owner means this port owned by EHC
572 State
&= ~PORTSC_OWNER
;
573 EhcWriteOpReg (Ehc
, Offset
, State
);
576 case EfiUsbPortConnectChange
:
578 // Clear connect status change
580 State
|= PORTSC_CONN_CHANGE
;
581 EhcWriteOpReg (Ehc
, Offset
, State
);
584 case EfiUsbPortEnableChange
:
586 // Clear enable status change
588 State
|= PORTSC_ENABLE_CHANGE
;
589 EhcWriteOpReg (Ehc
, Offset
, State
);
592 case EfiUsbPortOverCurrentChange
:
594 // Clear PortOverCurrent change
596 State
|= PORTSC_OVERCUR_CHANGE
;
597 EhcWriteOpReg (Ehc
, Offset
, State
);
600 case EfiUsbPortPower
:
601 case EfiUsbPortSuspendChange
:
602 case EfiUsbPortResetChange
:
604 // Not supported or not related operation
609 Status
= EFI_INVALID_PARAMETER
;
614 DEBUG ((EFI_D_INFO
, "EhcClearRootHubPortFeature: exit status %r\n", Status
));
615 gBS
->RestoreTPL (OldTpl
);
621 Submits control transfer to a target USB device.
623 @param This This EFI_USB2_HC_PROTOCOL instance.
624 @param DeviceAddress The target device address.
625 @param DeviceSpeed Target device speed.
626 @param MaximumPacketLength Maximum packet size the default control transfer
627 endpoint is capable of sending or receiving.
628 @param Request USB device request to send.
629 @param TransferDirection Specifies the data direction for the data stage
630 @param Data Data buffer to be transmitted or received from USB
632 @param DataLength The size (in bytes) of the data buffer.
633 @param TimeOut Indicates the maximum timeout, in millisecond.
634 @param Translator Transaction translator to be used by this device.
635 @param TransferResult Return the result of this control transfer.
637 @retval EFI_SUCCESS Transfer was completed successfully.
638 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
639 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
640 @retval EFI_TIMEOUT Transfer failed due to timeout.
641 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
647 IN EFI_USB2_HC_PROTOCOL
*This
,
648 IN UINT8 DeviceAddress
,
649 IN UINT8 DeviceSpeed
,
650 IN UINTN MaximumPacketLength
,
651 IN EFI_USB_DEVICE_REQUEST
*Request
,
652 IN EFI_USB_DATA_DIRECTION TransferDirection
,
654 IN OUT UINTN
*DataLength
,
656 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
657 OUT UINT32
*TransferResult
667 // Validate parameters
669 if ((Request
== NULL
) || (TransferResult
== NULL
)) {
670 return EFI_INVALID_PARAMETER
;
673 if ((TransferDirection
!= EfiUsbDataIn
) &&
674 (TransferDirection
!= EfiUsbDataOut
) &&
675 (TransferDirection
!= EfiUsbNoData
)) {
676 return EFI_INVALID_PARAMETER
;
679 if ((TransferDirection
== EfiUsbNoData
) &&
680 ((Data
!= NULL
) || (*DataLength
!= 0))) {
681 return EFI_INVALID_PARAMETER
;
684 if ((TransferDirection
!= EfiUsbNoData
) &&
685 ((Data
== NULL
) || (*DataLength
== 0))) {
686 return EFI_INVALID_PARAMETER
;
689 if ((MaximumPacketLength
!= 8) && (MaximumPacketLength
!= 16) &&
690 (MaximumPacketLength
!= 32) && (MaximumPacketLength
!= 64)) {
691 return EFI_INVALID_PARAMETER
;
694 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) {
695 return EFI_INVALID_PARAMETER
;
698 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
699 Ehc
= EHC_FROM_THIS (This
);
701 Status
= EFI_DEVICE_ERROR
;
702 *TransferResult
= EFI_USB_ERR_SYSTEM
;
704 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
705 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: HC halted at entrance\n"));
707 EhcAckAllInterrupt (Ehc
);
711 EhcAckAllInterrupt (Ehc
);
714 // Create a new URB, insert it into the asynchronous
715 // schedule list, then poll the execution status.
718 // Encode the direction in address, although default control
719 // endpoint is bidirectional. EhcCreateUrb expects this
720 // combination of Ep addr and its direction.
722 Endpoint
= (UINT8
) (0 | ((TransferDirection
== EfiUsbDataIn
) ? 0x80 : 0));
741 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: failed to create URB"));
743 Status
= EFI_OUT_OF_RESOURCES
;
747 EhcLinkQhToAsync (Ehc
, Urb
->Qh
);
748 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
749 EhcUnlinkQhFromAsync (Ehc
, Urb
->Qh
);
752 // Get the status from URB. The result is updated in EhcCheckUrbResult
753 // which is called by EhcExecTransfer
755 *TransferResult
= Urb
->Result
;
756 *DataLength
= Urb
->Completed
;
758 if (*TransferResult
== EFI_USB_NOERROR
) {
759 Status
= EFI_SUCCESS
;
762 EhcAckAllInterrupt (Ehc
);
763 EhcFreeUrb (Ehc
, Urb
);
766 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
767 gBS
->RestoreTPL (OldTpl
);
769 if (EFI_ERROR (Status
)) {
770 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
778 Submits bulk transfer to a bulk endpoint of a USB device.
780 @param This This EFI_USB2_HC_PROTOCOL instance.
781 @param DeviceAddress Target device address.
782 @param EndPointAddress Endpoint number and its direction in bit 7.
783 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
785 @param MaximumPacketLength Maximum packet size the endpoint is capable of
786 sending or receiving.
787 @param DataBuffersNumber Number of data buffers prepared for the transfer.
788 @param Data Array of pointers to the buffers of data to transmit
789 from or receive into.
790 @param DataLength The lenght of the data buffer.
791 @param DataToggle On input, the initial data toggle for the transfer;
792 On output, it is updated to to next data toggle to
793 use of the subsequent bulk transfer.
794 @param TimeOut Indicates the maximum time, in millisecond, which
795 the transfer is allowed to complete.
796 @param Translator A pointr to the transaction translator data.
797 @param TransferResult A pointer to the detailed result information of the
800 @retval EFI_SUCCESS The transfer was completed successfully.
801 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
802 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
803 @retval EFI_TIMEOUT The transfer failed due to timeout.
804 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
810 IN EFI_USB2_HC_PROTOCOL
*This
,
811 IN UINT8 DeviceAddress
,
812 IN UINT8 EndPointAddress
,
813 IN UINT8 DeviceSpeed
,
814 IN UINTN MaximumPacketLength
,
815 IN UINT8 DataBuffersNumber
,
816 IN OUT VOID
*Data
[EFI_USB_MAX_BULK_BUFFER_NUM
],
817 IN OUT UINTN
*DataLength
,
818 IN OUT UINT8
*DataToggle
,
820 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
821 OUT UINT32
*TransferResult
830 // Validate the parameters
832 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
833 (Data
== NULL
) || (Data
[0] == NULL
) || (TransferResult
== NULL
)) {
834 return EFI_INVALID_PARAMETER
;
837 if ((*DataToggle
!= 0) && (*DataToggle
!= 1)) {
838 return EFI_INVALID_PARAMETER
;
841 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) ||
842 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
843 ((EFI_USB_SPEED_HIGH
== DeviceSpeed
) && (MaximumPacketLength
> 512))) {
844 return EFI_INVALID_PARAMETER
;
847 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
848 Ehc
= EHC_FROM_THIS (This
);
850 *TransferResult
= EFI_USB_ERR_SYSTEM
;
851 Status
= EFI_DEVICE_ERROR
;
853 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
854 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: HC is halted\n"));
856 EhcAckAllInterrupt (Ehc
);
860 EhcAckAllInterrupt (Ehc
);
863 // Create a new URB, insert it into the asynchronous
864 // schedule list, then poll the execution status.
884 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: failed to create URB\n"));
886 Status
= EFI_OUT_OF_RESOURCES
;
890 EhcLinkQhToAsync (Ehc
, Urb
->Qh
);
891 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
892 EhcUnlinkQhFromAsync (Ehc
, Urb
->Qh
);
894 *TransferResult
= Urb
->Result
;
895 *DataLength
= Urb
->Completed
;
896 *DataToggle
= Urb
->DataToggle
;
898 if (*TransferResult
== EFI_USB_NOERROR
) {
899 Status
= EFI_SUCCESS
;
902 EhcAckAllInterrupt (Ehc
);
903 EhcFreeUrb (Ehc
, Urb
);
906 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
907 gBS
->RestoreTPL (OldTpl
);
909 if (EFI_ERROR (Status
)) {
910 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
918 Submits an asynchronous interrupt transfer to an
919 interrupt endpoint of a USB device.
921 @param This This EFI_USB2_HC_PROTOCOL instance.
922 @param DeviceAddress Target device address.
923 @param EndPointAddress Endpoint number and its direction encoded in bit 7
924 @param DeviceSpeed Indicates device speed.
925 @param MaximumPacketLength Maximum packet size the target endpoint is capable
926 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
927 transfer If FALSE, to remove the specified
928 asynchronous interrupt.
929 @param DataToggle On input, the initial data toggle to use; on output,
930 it is updated to indicate the next data toggle.
931 @param PollingInterval The he interval, in milliseconds, that the transfer
933 @param DataLength The length of data to receive at the rate specified
935 @param Translator Transaction translator to use.
936 @param CallBackFunction Function to call at the rate specified by
938 @param Context Context to CallBackFunction.
940 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
941 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
942 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
943 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
948 EhcAsyncInterruptTransfer (
949 IN EFI_USB2_HC_PROTOCOL
* This
,
950 IN UINT8 DeviceAddress
,
951 IN UINT8 EndPointAddress
,
952 IN UINT8 DeviceSpeed
,
953 IN UINTN MaximumPacketLength
,
954 IN BOOLEAN IsNewTransfer
,
955 IN OUT UINT8
*DataToggle
,
956 IN UINTN PollingInterval
,
958 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
* Translator
,
959 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction
,
960 IN VOID
*Context OPTIONAL
970 // Validate parameters
972 if (!EHCI_IS_DATAIN (EndPointAddress
)) {
973 return EFI_INVALID_PARAMETER
;
977 if (DataLength
== 0) {
978 return EFI_INVALID_PARAMETER
;
981 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
982 return EFI_INVALID_PARAMETER
;
985 if ((PollingInterval
> 255) || (PollingInterval
< 1)) {
986 return EFI_INVALID_PARAMETER
;
990 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
991 Ehc
= EHC_FROM_THIS (This
);
994 // Delete Async interrupt transfer request. DataToggle will return
995 // the next data toggle to use.
997 if (!IsNewTransfer
) {
998 Status
= EhciDelAsyncIntTransfer (Ehc
, DeviceAddress
, EndPointAddress
, DataToggle
);
1000 DEBUG ((EFI_D_INFO
, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status
));
1004 Status
= EFI_SUCCESS
;
1006 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
1007 DEBUG ((EFI_D_ERROR
, "EhcAsyncInterruptTransfer: HC is halt\n"));
1008 EhcAckAllInterrupt (Ehc
);
1010 Status
= EFI_DEVICE_ERROR
;
1014 EhcAckAllInterrupt (Ehc
);
1016 Data
= AllocatePool (DataLength
);
1019 DEBUG ((EFI_D_ERROR
, "EhcAsyncInterruptTransfer: failed to allocate buffer\n"));
1021 Status
= EFI_OUT_OF_RESOURCES
;
1025 Urb
= EhcCreateUrb (
1031 MaximumPacketLength
,
1033 EHC_INT_TRANSFER_ASYNC
,
1043 DEBUG ((EFI_D_ERROR
, "EhcAsyncInterruptTransfer: failed to create URB\n"));
1045 gBS
->FreePool (Data
);
1046 Status
= EFI_OUT_OF_RESOURCES
;
1051 // New asynchronous transfer must inserted to the head.
1052 // Check the comments in EhcMoniteAsyncRequests
1054 EhcLinkQhToPeriod (Ehc
, Urb
->Qh
);
1055 InsertHeadList (&Ehc
->AsyncIntTransfers
, &Urb
->UrbList
);
1058 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
1059 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
)) {
1118 return EFI_INVALID_PARAMETER
;
1121 if (!EHCI_IS_DATAIN (EndPointAddress
)) {
1122 return EFI_INVALID_PARAMETER
;
1125 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1126 return EFI_INVALID_PARAMETER
;
1129 if (((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) ||
1130 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
1131 ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) && (MaximumPacketLength
> 3072))) {
1132 return EFI_INVALID_PARAMETER
;
1135 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
1136 Ehc
= EHC_FROM_THIS (This
);
1138 *TransferResult
= EFI_USB_ERR_SYSTEM
;
1139 Status
= EFI_DEVICE_ERROR
;
1141 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
1142 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: HC is halt\n"));
1144 EhcAckAllInterrupt (Ehc
);
1148 EhcAckAllInterrupt (Ehc
);
1150 Urb
= EhcCreateUrb (
1156 MaximumPacketLength
,
1158 EHC_INT_TRANSFER_SYNC
,
1168 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: failed to create URB\n"));
1170 Status
= EFI_OUT_OF_RESOURCES
;
1174 EhcLinkQhToPeriod (Ehc
, Urb
->Qh
);
1175 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
1176 EhcUnlinkQhFromPeriod (Ehc
, Urb
->Qh
);
1178 *TransferResult
= Urb
->Result
;
1179 *DataLength
= Urb
->Completed
;
1180 *DataToggle
= Urb
->DataToggle
;
1182 if (*TransferResult
== EFI_USB_NOERROR
) {
1183 Status
= EFI_SUCCESS
;
1187 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
1188 gBS
->RestoreTPL (OldTpl
);
1190 if (EFI_ERROR (Status
)) {
1191 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
1199 Submits isochronous transfer to a target USB device.
1201 @param This This EFI_USB2_HC_PROTOCOL instance.
1202 @param DeviceAddress Target device address.
1203 @param EndPointAddress End point address with its direction.
1204 @param DeviceSpeed Device speed, Low speed device doesn't support this
1206 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1207 sending or receiving.
1208 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1209 @param Data Array of pointers to the buffers of data that will
1210 be transmitted to USB device or received from USB
1212 @param DataLength The size, in bytes, of the data buffer.
1213 @param Translator Transaction translator to use.
1214 @param TransferResult Variable to receive the transfer result.
1216 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1221 EhcIsochronousTransfer (
1222 IN EFI_USB2_HC_PROTOCOL
*This
,
1223 IN UINT8 DeviceAddress
,
1224 IN UINT8 EndPointAddress
,
1225 IN UINT8 DeviceSpeed
,
1226 IN UINTN MaximumPacketLength
,
1227 IN UINT8 DataBuffersNumber
,
1228 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1229 IN UINTN DataLength
,
1230 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1231 OUT UINT32
*TransferResult
1234 return EFI_UNSUPPORTED
;
1239 Submits Async isochronous transfer to a target USB device.
1241 @param This This EFI_USB2_HC_PROTOCOL instance.
1242 @param DeviceAddress Target device address.
1243 @param EndPointAddress End point address with its direction.
1244 @param DeviceSpeed Device speed, Low speed device doesn't support this
1246 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1247 sending or receiving.
1248 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1249 @param Data Array of pointers to the buffers of data that will
1250 be transmitted to USB device or received from USB
1252 @param DataLength The size, in bytes, of the data buffer.
1253 @param Translator Transaction translator to use.
1254 @param IsochronousCallBack Function to be called when the transfer complete.
1255 @param Context Context passed to the call back function as
1258 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1263 EhcAsyncIsochronousTransfer (
1264 IN EFI_USB2_HC_PROTOCOL
*This
,
1265 IN UINT8 DeviceAddress
,
1266 IN UINT8 EndPointAddress
,
1267 IN UINT8 DeviceSpeed
,
1268 IN UINTN MaximumPacketLength
,
1269 IN UINT8 DataBuffersNumber
,
1270 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1271 IN UINTN DataLength
,
1272 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1273 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack
,
1277 return EFI_UNSUPPORTED
;
1281 Entry point for EFI drivers.
1283 @param ImageHandle EFI_HANDLE.
1284 @param SystemTable EFI_SYSTEM_TABLE.
1286 @return EFI_SUCCESS Success.
1287 EFI_DEVICE_ERROR Fail.
1292 EhcDriverEntryPoint (
1293 IN EFI_HANDLE ImageHandle
,
1294 IN EFI_SYSTEM_TABLE
*SystemTable
1297 return EfiLibInstallDriverBindingComponentName2 (
1300 &gEhciDriverBinding
,
1302 &gEhciComponentName
,
1303 &gEhciComponentName2
1309 Test to see if this driver supports ControllerHandle. Any
1310 ControllerHandle that has Usb2HcProtocol installed will
1313 @param This Protocol instance pointer.
1314 @param Controller Handle of device to test.
1315 @param RemainingDevicePath Not used.
1317 @return EFI_SUCCESS This driver supports this device.
1318 @return EFI_UNSUPPORTED This driver does not support this device.
1323 EhcDriverBindingSupported (
1324 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1325 IN EFI_HANDLE Controller
,
1326 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1330 EFI_PCI_IO_PROTOCOL
*PciIo
;
1331 USB_CLASSC UsbClassCReg
;
1334 // Test whether there is PCI IO Protocol attached on the controller handle.
1336 Status
= gBS
->OpenProtocol (
1338 &gEfiPciIoProtocolGuid
,
1340 This
->DriverBindingHandle
,
1342 EFI_OPEN_PROTOCOL_BY_DRIVER
1345 if (EFI_ERROR (Status
)) {
1346 return EFI_UNSUPPORTED
;
1349 Status
= PciIo
->Pci
.Read (
1352 PCI_CLASSCODE_OFFSET
,
1353 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1357 if (EFI_ERROR (Status
)) {
1358 Status
= EFI_UNSUPPORTED
;
1363 // Test whether the controller belongs to Ehci type
1365 if ((UsbClassCReg
.BaseCode
!= PCI_CLASS_SERIAL
) || (UsbClassCReg
.SubClassCode
!= PCI_CLASS_SERIAL_USB
)
1366 || ((UsbClassCReg
.PI
!= PCI_IF_EHCI
) && (UsbClassCReg
.PI
!=PCI_IF_UHCI
))) {
1368 Status
= EFI_UNSUPPORTED
;
1372 gBS
->CloseProtocol (
1374 &gEfiPciIoProtocolGuid
,
1375 This
->DriverBindingHandle
,
1384 Create and initialize a USB2_HC_DEV.
1386 @param PciIo The PciIo on this device.
1387 @param OriginalPciAttributes Original PCI attributes.
1389 @return The allocated and initialized USB2_HC_DEV structure if created,
1395 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1396 IN UINT64 OriginalPciAttributes
1402 Ehc
= AllocateZeroPool (sizeof (USB2_HC_DEV
));
1409 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1411 Ehc
->Signature
= USB2_HC_DEV_SIGNATURE
;
1413 Ehc
->Usb2Hc
.GetCapability
= EhcGetCapability
;
1414 Ehc
->Usb2Hc
.Reset
= EhcReset
;
1415 Ehc
->Usb2Hc
.GetState
= EhcGetState
;
1416 Ehc
->Usb2Hc
.SetState
= EhcSetState
;
1417 Ehc
->Usb2Hc
.ControlTransfer
= EhcControlTransfer
;
1418 Ehc
->Usb2Hc
.BulkTransfer
= EhcBulkTransfer
;
1419 Ehc
->Usb2Hc
.AsyncInterruptTransfer
= EhcAsyncInterruptTransfer
;
1420 Ehc
->Usb2Hc
.SyncInterruptTransfer
= EhcSyncInterruptTransfer
;
1421 Ehc
->Usb2Hc
.IsochronousTransfer
= EhcIsochronousTransfer
;
1422 Ehc
->Usb2Hc
.AsyncIsochronousTransfer
= EhcAsyncIsochronousTransfer
;
1423 Ehc
->Usb2Hc
.GetRootHubPortStatus
= EhcGetRootHubPortStatus
;
1424 Ehc
->Usb2Hc
.SetRootHubPortFeature
= EhcSetRootHubPortFeature
;
1425 Ehc
->Usb2Hc
.ClearRootHubPortFeature
= EhcClearRootHubPortFeature
;
1426 Ehc
->Usb2Hc
.MajorRevision
= 0x2;
1427 Ehc
->Usb2Hc
.MinorRevision
= 0x0;
1430 Ehc
->OriginalPciAttributes
= OriginalPciAttributes
;
1432 InitializeListHead (&Ehc
->AsyncIntTransfers
);
1434 Ehc
->HcStructParams
= EhcReadCapRegister (Ehc
, EHC_HCSPARAMS_OFFSET
);
1435 Ehc
->HcCapParams
= EhcReadCapRegister (Ehc
, EHC_HCCPARAMS_OFFSET
);
1436 Ehc
->CapLen
= EhcReadCapRegister (Ehc
, EHC_CAPLENGTH_OFFSET
) & 0x0FF;
1438 DEBUG ((EFI_D_INFO
, "EhcCreateUsb2Hc: capability length %d\n", Ehc
->CapLen
));
1441 // Create AsyncRequest Polling Timer
1443 Status
= gBS
->CreateEvent (
1444 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1446 EhcMonitorAsyncRequests
,
1451 if (EFI_ERROR (Status
)) {
1452 gBS
->FreePool (Ehc
);
1460 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1462 @param Event Pointer to this event
1463 @param Context Event hanlder private data
1468 EhcExitBootService (
1476 Ehc
= (USB2_HC_DEV
*) Context
;
1479 // Stop the Host Controller
1481 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
1488 Starting the Usb EHCI Driver.
1490 @param This Protocol instance pointer.
1491 @param Controller Handle of device to test.
1492 @param RemainingDevicePath Not used.
1494 @return EFI_SUCCESS supports this device.
1495 @return EFI_UNSUPPORTED do not support this device.
1496 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1497 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1502 EhcDriverBindingStart (
1503 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1504 IN EFI_HANDLE Controller
,
1505 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1510 EFI_PCI_IO_PROTOCOL
*PciIo
;
1511 EFI_PCI_IO_PROTOCOL
*Instance
;
1513 UINT64 OriginalPciAttributes
;
1514 BOOLEAN PciAttributesSaved
;
1515 USB_CLASSC UsbClassCReg
;
1516 EFI_HANDLE
*HandleBuffer
;
1517 UINTN NumberOfHandles
;
1519 UINTN UhciSegmentNumber
;
1520 UINTN UhciBusNumber
;
1521 UINTN UhciDeviceNumber
;
1522 UINTN UhciFunctionNumber
;
1523 UINTN EhciSegmentNumber
;
1524 UINTN EhciBusNumber
;
1525 UINTN EhciDeviceNumber
;
1526 UINTN EhciFunctionNumber
;
1529 // Open the PciIo Protocol, then enable the USB host controller
1531 Status
= gBS
->OpenProtocol (
1533 &gEfiPciIoProtocolGuid
,
1535 This
->DriverBindingHandle
,
1537 EFI_OPEN_PROTOCOL_BY_DRIVER
1540 if (EFI_ERROR (Status
)) {
1544 PciAttributesSaved
= FALSE
;
1546 // Save original PCI attributes
1548 Status
= PciIo
->Attributes (
1550 EfiPciIoAttributeOperationGet
,
1552 &OriginalPciAttributes
1555 if (EFI_ERROR (Status
)) {
1558 PciAttributesSaved
= TRUE
;
1560 Status
= PciIo
->Attributes (
1562 EfiPciIoAttributeOperationSupported
,
1566 if (!EFI_ERROR (Status
)) {
1567 Supports
&= EFI_PCI_DEVICE_ENABLE
;
1568 Status
= PciIo
->Attributes (
1570 EfiPciIoAttributeOperationEnable
,
1576 if (EFI_ERROR (Status
)) {
1577 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to enable controller\n"));
1582 // Get the Pci device class code.
1584 Status
= PciIo
->Pci
.Read (
1587 PCI_CLASSCODE_OFFSET
,
1588 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1592 if (EFI_ERROR (Status
)) {
1593 Status
= EFI_UNSUPPORTED
;
1597 // determine if the device is UHCI host controller or not. If yes, then find out the
1598 // companion usb ehci host controller and force EHCI driver get attached to it before
1599 // UHCI driver attaches to UHCI host controller.
1601 if ((UsbClassCReg
.PI
== PCI_IF_UHCI
) &&
1602 (UsbClassCReg
.BaseCode
== PCI_CLASS_SERIAL
) &&
1603 (UsbClassCReg
.SubClassCode
== PCI_CLASS_SERIAL_USB
)) {
1604 Status
= PciIo
->GetLocation (
1611 if (EFI_ERROR (Status
)) {
1615 Status
= gBS
->LocateHandleBuffer (
1617 &gEfiPciIoProtocolGuid
,
1622 if (EFI_ERROR (Status
)) {
1626 for (Index
= 0; Index
< NumberOfHandles
; Index
++) {
1628 // Get the device path on this handle
1630 Status
= gBS
->HandleProtocol (
1631 HandleBuffer
[Index
],
1632 &gEfiPciIoProtocolGuid
,
1635 ASSERT_EFI_ERROR (Status
);
1637 Status
= Instance
->Pci
.Read (
1640 PCI_CLASSCODE_OFFSET
,
1641 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1645 if (EFI_ERROR (Status
)) {
1646 Status
= EFI_UNSUPPORTED
;
1650 if ((UsbClassCReg
.PI
== PCI_IF_EHCI
) &&
1651 (UsbClassCReg
.BaseCode
== PCI_CLASS_SERIAL
) &&
1652 (UsbClassCReg
.SubClassCode
== PCI_CLASS_SERIAL_USB
)) {
1653 Status
= Instance
->GetLocation (
1660 if (EFI_ERROR (Status
)) {
1664 // Currently, the judgment on the companion usb host controller is through the
1665 // same bus number, which may vary on different platform.
1667 if (EhciBusNumber
== UhciBusNumber
) {
1668 gBS
->CloseProtocol (
1670 &gEfiPciIoProtocolGuid
,
1671 This
->DriverBindingHandle
,
1674 EhcDriverBindingStart(This
, HandleBuffer
[Index
], NULL
);
1678 Status
= EFI_NOT_FOUND
;
1683 // Create then install USB2_HC_PROTOCOL
1685 Ehc
= EhcCreateUsb2Hc (PciIo
, OriginalPciAttributes
);
1688 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to create USB2_HC\n"));
1690 Status
= EFI_OUT_OF_RESOURCES
;
1694 Status
= gBS
->InstallProtocolInterface (
1696 &gEfiUsb2HcProtocolGuid
,
1697 EFI_NATIVE_INTERFACE
,
1701 if (EFI_ERROR (Status
)) {
1702 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1707 // Robustnesss improvement such as for UoL
1708 // Default is not required.
1710 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport
)) {
1711 EhcClearLegacySupport (Ehc
);
1713 EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
1715 Status
= EhcInitHC (Ehc
);
1717 if (EFI_ERROR (Status
)) {
1718 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to init host controller\n"));
1719 goto UNINSTALL_USBHC
;
1723 // Start the asynchronous interrupt monitor
1725 Status
= gBS
->SetTimer (Ehc
->PollTimer
, TimerPeriodic
, EHC_ASYNC_POLL_INTERVAL
);
1727 if (EFI_ERROR (Status
)) {
1728 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
1730 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
1731 goto UNINSTALL_USBHC
;
1735 // Create event to stop the HC when exit boot service.
1737 Status
= gBS
->CreateEventEx (
1742 &gEfiEventExitBootServicesGuid
,
1743 &Ehc
->ExitBootServiceEvent
1745 if (EFI_ERROR (Status
)) {
1746 goto UNINSTALL_USBHC
;
1750 // Install the component name protocol, don't fail the start
1751 // because of something for display.
1755 gEhciComponentName
.SupportedLanguages
,
1756 &Ehc
->ControllerNameTable
,
1757 L
"Enhanced Host Controller (USB 2.0)",
1762 gEhciComponentName2
.SupportedLanguages
,
1763 &Ehc
->ControllerNameTable
,
1764 L
"Enhanced Host Controller (USB 2.0)",
1769 DEBUG ((EFI_D_INFO
, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller
));
1773 gBS
->UninstallProtocolInterface (
1775 &gEfiUsb2HcProtocolGuid
,
1781 gBS
->CloseEvent (Ehc
->PollTimer
);
1782 gBS
->FreePool (Ehc
);
1785 if (PciAttributesSaved
) {
1787 // Restore original PCI attributes
1791 EfiPciIoAttributeOperationSet
,
1792 OriginalPciAttributes
,
1797 gBS
->CloseProtocol (
1799 &gEfiPciIoProtocolGuid
,
1800 This
->DriverBindingHandle
,
1809 Stop this driver on ControllerHandle. Support stoping any child handles
1810 created by this driver.
1812 @param This Protocol instance pointer.
1813 @param Controller Handle of device to stop driver on.
1814 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1815 @param ChildHandleBuffer List of handles for the children we need to stop.
1817 @return EFI_SUCCESS Success.
1818 @return EFI_DEVICE_ERROR Fail.
1823 EhcDriverBindingStop (
1824 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1825 IN EFI_HANDLE Controller
,
1826 IN UINTN NumberOfChildren
,
1827 IN EFI_HANDLE
*ChildHandleBuffer
1831 EFI_USB2_HC_PROTOCOL
*Usb2Hc
;
1832 EFI_PCI_IO_PROTOCOL
*PciIo
;
1836 // Test whether the Controller handler passed in is a valid
1837 // Usb controller handle that should be supported, if not,
1838 // return the error status directly
1840 Status
= gBS
->OpenProtocol (
1842 &gEfiUsb2HcProtocolGuid
,
1844 This
->DriverBindingHandle
,
1846 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1849 if (EFI_ERROR (Status
)) {
1853 Ehc
= EHC_FROM_THIS (Usb2Hc
);
1857 // Stop AsyncRequest Polling timer then stop the EHCI driver
1858 // and uninstall the EHCI protocl.
1860 gBS
->SetTimer (Ehc
->PollTimer
, TimerCancel
, EHC_ASYNC_POLL_INTERVAL
);
1861 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
1863 Status
= gBS
->UninstallProtocolInterface (
1865 &gEfiUsb2HcProtocolGuid
,
1869 if (EFI_ERROR (Status
)) {
1873 if (Ehc
->PollTimer
!= NULL
) {
1874 gBS
->CloseEvent (Ehc
->PollTimer
);
1877 if (Ehc
->ExitBootServiceEvent
!= NULL
) {
1878 gBS
->CloseEvent (Ehc
->ExitBootServiceEvent
);
1883 if (Ehc
->ControllerNameTable
!= NULL
) {
1884 FreeUnicodeStringTable (Ehc
->ControllerNameTable
);
1888 // Restore original PCI attributes
1892 EfiPciIoAttributeOperationSet
,
1893 Ehc
->OriginalPciAttributes
,
1897 gBS
->CloseProtocol (
1899 &gEfiPciIoProtocolGuid
,
1900 This
->DriverBindingHandle
,