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 - 2015, 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
,
124 UINT32 DbgCtrlStatus
;
126 Ehc
= EHC_FROM_THIS (This
);
128 if (Ehc
->DevicePath
!= NULL
) {
130 // Report Status Code to indicate reset happens
132 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
134 (EFI_IO_BUS_USB
| EFI_IOB_PC_RESET
),
139 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
141 switch (Attributes
) {
142 case EFI_USB_HC_RESET_GLOBAL
:
144 // Flow through, same behavior as Host Controller Reset
146 case EFI_USB_HC_RESET_HOST_CONTROLLER
:
148 // Host Controller must be Halt when Reset it
150 if (Ehc
->DebugPortNum
!= 0) {
151 DbgCtrlStatus
= EhcReadDbgRegister(Ehc
, 0);
152 if ((DbgCtrlStatus
& (USB_DEBUG_PORT_IN_USE
| USB_DEBUG_PORT_OWNER
)) == (USB_DEBUG_PORT_IN_USE
| USB_DEBUG_PORT_OWNER
)) {
153 Status
= EFI_SUCCESS
;
158 if (!EhcIsHalt (Ehc
)) {
159 Status
= EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
161 if (EFI_ERROR (Status
)) {
162 Status
= EFI_DEVICE_ERROR
;
168 // Clean up the asynchronous transfers, currently only
169 // interrupt supports asynchronous operation.
171 EhciDelAllAsyncIntTransfers (Ehc
);
172 EhcAckAllInterrupt (Ehc
);
175 Status
= EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
177 if (EFI_ERROR (Status
)) {
181 Status
= EhcInitHC (Ehc
);
184 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG
:
185 case EFI_USB_HC_RESET_HOST_WITH_DEBUG
:
186 Status
= EFI_UNSUPPORTED
;
190 Status
= EFI_INVALID_PARAMETER
;
194 DEBUG ((EFI_D_INFO
, "EhcReset: exit status %r\n", Status
));
195 gBS
->RestoreTPL (OldTpl
);
201 Retrieve the current state of the USB host controller.
203 @param This This EFI_USB2_HC_PROTOCOL instance.
204 @param State Variable to return the current host controller
207 @retval EFI_SUCCESS Host controller state was returned in State.
208 @retval EFI_INVALID_PARAMETER State is NULL.
209 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
210 retrieve the host controller's current state.
216 IN EFI_USB2_HC_PROTOCOL
*This
,
217 OUT EFI_USB_HC_STATE
*State
224 return EFI_INVALID_PARAMETER
;
227 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
228 Ehc
= EHC_FROM_THIS (This
);
230 if (EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
231 *State
= EfiUsbHcStateHalt
;
233 *State
= EfiUsbHcStateOperational
;
236 gBS
->RestoreTPL (OldTpl
);
238 DEBUG ((EFI_D_INFO
, "EhcGetState: current state %d\n", *State
));
244 Sets the USB host controller to a specific state.
246 @param This This EFI_USB2_HC_PROTOCOL instance.
247 @param State The state of the host controller that will be set.
249 @retval EFI_SUCCESS The USB host controller was successfully placed
250 in the state specified by State.
251 @retval EFI_INVALID_PARAMETER State is invalid.
252 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
258 IN EFI_USB2_HC_PROTOCOL
*This
,
259 IN EFI_USB_HC_STATE State
265 EFI_USB_HC_STATE CurState
;
267 Status
= EhcGetState (This
, &CurState
);
269 if (EFI_ERROR (Status
)) {
270 return EFI_DEVICE_ERROR
;
273 if (CurState
== State
) {
277 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
278 Ehc
= EHC_FROM_THIS (This
);
281 case EfiUsbHcStateHalt
:
282 Status
= EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
285 case EfiUsbHcStateOperational
:
286 if (EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_SYS_ERROR
)) {
287 Status
= EFI_DEVICE_ERROR
;
292 // Software must not write a one to this field unless the host controller
293 // is in the Halted state. Doing so will yield undefined results.
294 // refers to Spec[EHCI1.0-2.3.1]
296 if (!EHC_REG_BIT_IS_SET (Ehc
, EHC_USBSTS_OFFSET
, USBSTS_HALT
)) {
297 Status
= EFI_DEVICE_ERROR
;
301 Status
= EhcRunHC (Ehc
, EHC_GENERIC_TIMEOUT
);
304 case EfiUsbHcStateSuspend
:
305 Status
= EFI_UNSUPPORTED
;
309 Status
= EFI_INVALID_PARAMETER
;
312 DEBUG ((EFI_D_INFO
, "EhcSetState: exit status %r\n", Status
));
313 gBS
->RestoreTPL (OldTpl
);
319 Retrieves the current status of a USB root hub port.
321 @param This This EFI_USB2_HC_PROTOCOL instance.
322 @param PortNumber The root hub port to retrieve the state from.
323 This value is zero-based.
324 @param PortStatus Variable to receive the port state.
326 @retval EFI_SUCCESS The status of the USB root hub port specified.
327 by PortNumber was returned in PortStatus.
328 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
329 @retval EFI_DEVICE_ERROR Can't read register.
334 EhcGetRootHubPortStatus (
335 IN EFI_USB2_HC_PROTOCOL
*This
,
337 OUT EFI_USB_PORT_STATUS
*PortStatus
348 UINT32 DbgCtrlStatus
;
350 if (PortStatus
== NULL
) {
351 return EFI_INVALID_PARAMETER
;
354 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
356 Ehc
= EHC_FROM_THIS (This
);
357 Status
= EFI_SUCCESS
;
359 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
361 if (PortNumber
>= TotalPort
) {
362 Status
= EFI_INVALID_PARAMETER
;
366 Offset
= (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
));
367 PortStatus
->PortStatus
= 0;
368 PortStatus
->PortChangeStatus
= 0;
370 if ((Ehc
->DebugPortNum
!= 0) && (PortNumber
== (Ehc
->DebugPortNum
- 1))) {
371 DbgCtrlStatus
= EhcReadDbgRegister(Ehc
, 0);
372 if ((DbgCtrlStatus
& (USB_DEBUG_PORT_IN_USE
| USB_DEBUG_PORT_OWNER
)) == (USB_DEBUG_PORT_IN_USE
| USB_DEBUG_PORT_OWNER
)) {
377 State
= EhcReadOpReg (Ehc
, Offset
);
380 // Identify device speed. If in K state, it is low speed.
381 // If the port is enabled after reset, the device is of
382 // high speed. The USB bus driver should retrieve the actual
383 // port speed after reset.
385 if (EHC_BIT_IS_SET (State
, PORTSC_LINESTATE_K
)) {
386 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
388 } else if (EHC_BIT_IS_SET (State
, PORTSC_ENABLED
)) {
389 PortStatus
->PortStatus
|= USB_PORT_STAT_HIGH_SPEED
;
393 // Convert the EHCI port/port change state to UEFI status
395 MapSize
= sizeof (mUsbPortStateMap
) / sizeof (USB_PORT_STATE_MAP
);
397 for (Index
= 0; Index
< MapSize
; Index
++) {
398 if (EHC_BIT_IS_SET (State
, mUsbPortStateMap
[Index
].HwState
)) {
399 PortStatus
->PortStatus
= (UINT16
) (PortStatus
->PortStatus
| mUsbPortStateMap
[Index
].UefiState
);
403 MapSize
= sizeof (mUsbPortChangeMap
) / sizeof (USB_PORT_STATE_MAP
);
405 for (Index
= 0; Index
< MapSize
; Index
++) {
406 if (EHC_BIT_IS_SET (State
, mUsbPortChangeMap
[Index
].HwState
)) {
407 PortStatus
->PortChangeStatus
= (UINT16
) (PortStatus
->PortChangeStatus
| mUsbPortChangeMap
[Index
].UefiState
);
412 gBS
->RestoreTPL (OldTpl
);
418 Sets a feature for the specified root hub port.
420 @param This This EFI_USB2_HC_PROTOCOL instance.
421 @param PortNumber Root hub port to set.
422 @param PortFeature Feature to set.
424 @retval EFI_SUCCESS The feature specified by PortFeature was set.
425 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
426 @retval EFI_DEVICE_ERROR Can't read register.
431 EhcSetRootHubPortFeature (
432 IN EFI_USB2_HC_PROTOCOL
*This
,
434 IN EFI_USB_PORT_FEATURE PortFeature
444 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
445 Ehc
= EHC_FROM_THIS (This
);
446 Status
= EFI_SUCCESS
;
448 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
450 if (PortNumber
>= TotalPort
) {
451 Status
= EFI_INVALID_PARAMETER
;
455 Offset
= (UINT32
) (EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
));
456 State
= EhcReadOpReg (Ehc
, Offset
);
459 // Mask off the port status change bits, these bits are
462 State
&= ~PORTSC_CHANGE_MASK
;
464 switch (PortFeature
) {
465 case EfiUsbPortEnable
:
467 // Sofeware can't set this bit, Port can only be enable by
468 // EHCI as a part of the reset and enable
470 State
|= PORTSC_ENABLED
;
471 EhcWriteOpReg (Ehc
, Offset
, State
);
474 case EfiUsbPortSuspend
:
475 State
|= PORTSC_SUSPEND
;
476 EhcWriteOpReg (Ehc
, Offset
, State
);
479 case EfiUsbPortReset
:
481 // Make sure Host Controller not halt before reset it
483 if (EhcIsHalt (Ehc
)) {
484 Status
= EhcRunHC (Ehc
, EHC_GENERIC_TIMEOUT
);
486 if (EFI_ERROR (Status
)) {
487 DEBUG ((EFI_D_INFO
, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status
));
493 // Set one to PortReset bit must also set zero to PortEnable bit
495 State
|= PORTSC_RESET
;
496 State
&= ~PORTSC_ENABLED
;
497 EhcWriteOpReg (Ehc
, Offset
, State
);
500 case EfiUsbPortPower
:
502 // Set port power bit when PPC is 1
504 if ((Ehc
->HcCapParams
& HCSP_PPC
) == HCSP_PPC
) {
505 State
|= PORTSC_POWER
;
506 EhcWriteOpReg (Ehc
, Offset
, State
);
510 case EfiUsbPortOwner
:
511 State
|= PORTSC_OWNER
;
512 EhcWriteOpReg (Ehc
, Offset
, State
);
516 Status
= EFI_INVALID_PARAMETER
;
520 DEBUG ((EFI_D_INFO
, "EhcSetRootHubPortFeature: exit status %r\n", Status
));
522 gBS
->RestoreTPL (OldTpl
);
528 Clears a feature for the specified root hub port.
530 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
531 @param PortNumber Specifies the root hub port whose feature is
532 requested to be cleared.
533 @param PortFeature Indicates the feature selector associated with the
534 feature clear request.
536 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
537 for the USB root hub port specified by PortNumber.
538 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
539 @retval EFI_DEVICE_ERROR Can't read register.
544 EhcClearRootHubPortFeature (
545 IN EFI_USB2_HC_PROTOCOL
*This
,
547 IN EFI_USB_PORT_FEATURE PortFeature
557 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
558 Ehc
= EHC_FROM_THIS (This
);
559 Status
= EFI_SUCCESS
;
561 TotalPort
= (Ehc
->HcStructParams
& HCSP_NPORTS
);
563 if (PortNumber
>= TotalPort
) {
564 Status
= EFI_INVALID_PARAMETER
;
568 Offset
= EHC_PORT_STAT_OFFSET
+ (4 * PortNumber
);
569 State
= EhcReadOpReg (Ehc
, Offset
);
570 State
&= ~PORTSC_CHANGE_MASK
;
572 switch (PortFeature
) {
573 case EfiUsbPortEnable
:
575 // Clear PORT_ENABLE feature means disable port.
577 State
&= ~PORTSC_ENABLED
;
578 EhcWriteOpReg (Ehc
, Offset
, State
);
581 case EfiUsbPortSuspend
:
583 // A write of zero to this bit is ignored by the host
584 // controller. The host controller will unconditionally
585 // set this bit to a zero when:
586 // 1. software sets the Forct Port Resume bit to a zero from a one.
587 // 2. software sets the Port Reset bit to a one frome a zero.
589 State
&= ~PORSTSC_RESUME
;
590 EhcWriteOpReg (Ehc
, Offset
, State
);
593 case EfiUsbPortReset
:
595 // Clear PORT_RESET means clear the reset signal.
597 State
&= ~PORTSC_RESET
;
598 EhcWriteOpReg (Ehc
, Offset
, State
);
601 case EfiUsbPortOwner
:
603 // Clear port owner means this port owned by EHC
605 State
&= ~PORTSC_OWNER
;
606 EhcWriteOpReg (Ehc
, Offset
, State
);
609 case EfiUsbPortConnectChange
:
611 // Clear connect status change
613 State
|= PORTSC_CONN_CHANGE
;
614 EhcWriteOpReg (Ehc
, Offset
, State
);
617 case EfiUsbPortEnableChange
:
619 // Clear enable status change
621 State
|= PORTSC_ENABLE_CHANGE
;
622 EhcWriteOpReg (Ehc
, Offset
, State
);
625 case EfiUsbPortOverCurrentChange
:
627 // Clear PortOverCurrent change
629 State
|= PORTSC_OVERCUR_CHANGE
;
630 EhcWriteOpReg (Ehc
, Offset
, State
);
633 case EfiUsbPortPower
:
635 // Clear port power bit when PPC is 1
637 if ((Ehc
->HcCapParams
& HCSP_PPC
) == HCSP_PPC
) {
638 State
&= ~PORTSC_POWER
;
639 EhcWriteOpReg (Ehc
, Offset
, State
);
642 case EfiUsbPortSuspendChange
:
643 case EfiUsbPortResetChange
:
645 // Not supported or not related operation
650 Status
= EFI_INVALID_PARAMETER
;
655 DEBUG ((EFI_D_INFO
, "EhcClearRootHubPortFeature: exit status %r\n", Status
));
656 gBS
->RestoreTPL (OldTpl
);
662 Submits control transfer to a target USB device.
664 @param This This EFI_USB2_HC_PROTOCOL instance.
665 @param DeviceAddress The target device address.
666 @param DeviceSpeed Target device speed.
667 @param MaximumPacketLength Maximum packet size the default control transfer
668 endpoint is capable of sending or receiving.
669 @param Request USB device request to send.
670 @param TransferDirection Specifies the data direction for the data stage
671 @param Data Data buffer to be transmitted or received from USB
673 @param DataLength The size (in bytes) of the data buffer.
674 @param TimeOut Indicates the maximum timeout, in millisecond.
675 @param Translator Transaction translator to be used by this device.
676 @param TransferResult Return the result of this control transfer.
678 @retval EFI_SUCCESS Transfer was completed successfully.
679 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
680 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
681 @retval EFI_TIMEOUT Transfer failed due to timeout.
682 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
688 IN EFI_USB2_HC_PROTOCOL
*This
,
689 IN UINT8 DeviceAddress
,
690 IN UINT8 DeviceSpeed
,
691 IN UINTN MaximumPacketLength
,
692 IN EFI_USB_DEVICE_REQUEST
*Request
,
693 IN EFI_USB_DATA_DIRECTION TransferDirection
,
695 IN OUT UINTN
*DataLength
,
697 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
698 OUT UINT32
*TransferResult
708 // Validate parameters
710 if ((Request
== NULL
) || (TransferResult
== NULL
)) {
711 return EFI_INVALID_PARAMETER
;
714 if ((TransferDirection
!= EfiUsbDataIn
) &&
715 (TransferDirection
!= EfiUsbDataOut
) &&
716 (TransferDirection
!= EfiUsbNoData
)) {
717 return EFI_INVALID_PARAMETER
;
720 if ((TransferDirection
== EfiUsbNoData
) &&
721 ((Data
!= NULL
) || (*DataLength
!= 0))) {
722 return EFI_INVALID_PARAMETER
;
725 if ((TransferDirection
!= EfiUsbNoData
) &&
726 ((Data
== NULL
) || (*DataLength
== 0))) {
727 return EFI_INVALID_PARAMETER
;
730 if ((MaximumPacketLength
!= 8) && (MaximumPacketLength
!= 16) &&
731 (MaximumPacketLength
!= 32) && (MaximumPacketLength
!= 64)) {
732 return EFI_INVALID_PARAMETER
;
735 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) {
736 return EFI_INVALID_PARAMETER
;
739 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
740 Ehc
= EHC_FROM_THIS (This
);
742 Status
= EFI_DEVICE_ERROR
;
743 *TransferResult
= EFI_USB_ERR_SYSTEM
;
745 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
746 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: HC halted at entrance\n"));
748 EhcAckAllInterrupt (Ehc
);
752 EhcAckAllInterrupt (Ehc
);
755 // Create a new URB, insert it into the asynchronous
756 // schedule list, then poll the execution status.
759 // Encode the direction in address, although default control
760 // endpoint is bidirectional. EhcCreateUrb expects this
761 // combination of Ep addr and its direction.
763 Endpoint
= (UINT8
) (0 | ((TransferDirection
== EfiUsbDataIn
) ? 0x80 : 0));
782 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: failed to create URB"));
784 Status
= EFI_OUT_OF_RESOURCES
;
788 EhcLinkQhToAsync (Ehc
, Urb
->Qh
);
789 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
790 EhcUnlinkQhFromAsync (Ehc
, Urb
->Qh
);
793 // Get the status from URB. The result is updated in EhcCheckUrbResult
794 // which is called by EhcExecTransfer
796 *TransferResult
= Urb
->Result
;
797 *DataLength
= Urb
->Completed
;
799 if (*TransferResult
== EFI_USB_NOERROR
) {
800 Status
= EFI_SUCCESS
;
803 EhcAckAllInterrupt (Ehc
);
804 EhcFreeUrb (Ehc
, Urb
);
807 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
808 gBS
->RestoreTPL (OldTpl
);
810 if (EFI_ERROR (Status
)) {
811 DEBUG ((EFI_D_ERROR
, "EhcControlTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
819 Submits bulk transfer to a bulk endpoint of a USB device.
821 @param This This EFI_USB2_HC_PROTOCOL instance.
822 @param DeviceAddress Target device address.
823 @param EndPointAddress Endpoint number and its direction in bit 7.
824 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
826 @param MaximumPacketLength Maximum packet size the endpoint is capable of
827 sending or receiving.
828 @param DataBuffersNumber Number of data buffers prepared for the transfer.
829 @param Data Array of pointers to the buffers of data to transmit
830 from or receive into.
831 @param DataLength The lenght of the data buffer.
832 @param DataToggle On input, the initial data toggle for the transfer;
833 On output, it is updated to to next data toggle to
834 use of the subsequent bulk transfer.
835 @param TimeOut Indicates the maximum time, in millisecond, which
836 the transfer is allowed to complete.
837 @param Translator A pointr to the transaction translator data.
838 @param TransferResult A pointer to the detailed result information of the
841 @retval EFI_SUCCESS The transfer was completed successfully.
842 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
843 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
844 @retval EFI_TIMEOUT The transfer failed due to timeout.
845 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
851 IN EFI_USB2_HC_PROTOCOL
*This
,
852 IN UINT8 DeviceAddress
,
853 IN UINT8 EndPointAddress
,
854 IN UINT8 DeviceSpeed
,
855 IN UINTN MaximumPacketLength
,
856 IN UINT8 DataBuffersNumber
,
857 IN OUT VOID
*Data
[EFI_USB_MAX_BULK_BUFFER_NUM
],
858 IN OUT UINTN
*DataLength
,
859 IN OUT UINT8
*DataToggle
,
861 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
862 OUT UINT32
*TransferResult
871 // Validate the parameters
873 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
874 (Data
== NULL
) || (Data
[0] == NULL
) || (TransferResult
== NULL
)) {
875 return EFI_INVALID_PARAMETER
;
878 if ((*DataToggle
!= 0) && (*DataToggle
!= 1)) {
879 return EFI_INVALID_PARAMETER
;
882 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) ||
883 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
884 ((EFI_USB_SPEED_HIGH
== DeviceSpeed
) && (MaximumPacketLength
> 512))) {
885 return EFI_INVALID_PARAMETER
;
888 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
889 Ehc
= EHC_FROM_THIS (This
);
891 *TransferResult
= EFI_USB_ERR_SYSTEM
;
892 Status
= EFI_DEVICE_ERROR
;
894 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
895 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: HC is halted\n"));
897 EhcAckAllInterrupt (Ehc
);
901 EhcAckAllInterrupt (Ehc
);
904 // Create a new URB, insert it into the asynchronous
905 // schedule list, then poll the execution status.
925 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: failed to create URB\n"));
927 Status
= EFI_OUT_OF_RESOURCES
;
931 EhcLinkQhToAsync (Ehc
, Urb
->Qh
);
932 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
933 EhcUnlinkQhFromAsync (Ehc
, Urb
->Qh
);
935 *TransferResult
= Urb
->Result
;
936 *DataLength
= Urb
->Completed
;
937 *DataToggle
= Urb
->DataToggle
;
939 if (*TransferResult
== EFI_USB_NOERROR
) {
940 Status
= EFI_SUCCESS
;
943 EhcAckAllInterrupt (Ehc
);
944 EhcFreeUrb (Ehc
, Urb
);
947 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
948 gBS
->RestoreTPL (OldTpl
);
950 if (EFI_ERROR (Status
)) {
951 DEBUG ((EFI_D_ERROR
, "EhcBulkTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
959 Submits an asynchronous interrupt transfer to an
960 interrupt endpoint of a USB device.
962 @param This This EFI_USB2_HC_PROTOCOL instance.
963 @param DeviceAddress Target device address.
964 @param EndPointAddress Endpoint number and its direction encoded in bit 7
965 @param DeviceSpeed Indicates device speed.
966 @param MaximumPacketLength Maximum packet size the target endpoint is capable
967 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
968 transfer If FALSE, to remove the specified
969 asynchronous interrupt.
970 @param DataToggle On input, the initial data toggle to use; on output,
971 it is updated to indicate the next data toggle.
972 @param PollingInterval The he interval, in milliseconds, that the transfer
974 @param DataLength The length of data to receive at the rate specified
976 @param Translator Transaction translator to use.
977 @param CallBackFunction Function to call at the rate specified by
979 @param Context Context to CallBackFunction.
981 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
982 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
983 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
984 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
989 EhcAsyncInterruptTransfer (
990 IN EFI_USB2_HC_PROTOCOL
* This
,
991 IN UINT8 DeviceAddress
,
992 IN UINT8 EndPointAddress
,
993 IN UINT8 DeviceSpeed
,
994 IN UINTN MaximumPacketLength
,
995 IN BOOLEAN IsNewTransfer
,
996 IN OUT UINT8
*DataToggle
,
997 IN UINTN PollingInterval
,
999 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
* Translator
,
1000 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction
,
1001 IN VOID
*Context OPTIONAL
1011 // Validate parameters
1013 if (!EHCI_IS_DATAIN (EndPointAddress
)) {
1014 return EFI_INVALID_PARAMETER
;
1017 if (IsNewTransfer
) {
1018 if (DataLength
== 0) {
1019 return EFI_INVALID_PARAMETER
;
1022 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1023 return EFI_INVALID_PARAMETER
;
1026 if ((PollingInterval
> 255) || (PollingInterval
< 1)) {
1027 return EFI_INVALID_PARAMETER
;
1031 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
1032 Ehc
= EHC_FROM_THIS (This
);
1035 // Delete Async interrupt transfer request. DataToggle will return
1036 // the next data toggle to use.
1038 if (!IsNewTransfer
) {
1039 Status
= EhciDelAsyncIntTransfer (Ehc
, DeviceAddress
, EndPointAddress
, DataToggle
);
1041 DEBUG ((EFI_D_INFO
, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status
));
1045 Status
= EFI_SUCCESS
;
1047 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
1048 DEBUG ((EFI_D_ERROR
, "EhcAsyncInterruptTransfer: HC is halt\n"));
1049 EhcAckAllInterrupt (Ehc
);
1051 Status
= EFI_DEVICE_ERROR
;
1055 EhcAckAllInterrupt (Ehc
);
1057 Data
= AllocatePool (DataLength
);
1060 DEBUG ((EFI_D_ERROR
, "EhcAsyncInterruptTransfer: failed to allocate buffer\n"));
1062 Status
= EFI_OUT_OF_RESOURCES
;
1066 Urb
= EhcCreateUrb (
1072 MaximumPacketLength
,
1074 EHC_INT_TRANSFER_ASYNC
,
1084 DEBUG ((EFI_D_ERROR
, "EhcAsyncInterruptTransfer: failed to create URB\n"));
1086 gBS
->FreePool (Data
);
1087 Status
= EFI_OUT_OF_RESOURCES
;
1092 // New asynchronous transfer must inserted to the head.
1093 // Check the comments in EhcMoniteAsyncRequests
1095 EhcLinkQhToPeriod (Ehc
, Urb
->Qh
);
1096 InsertHeadList (&Ehc
->AsyncIntTransfers
, &Urb
->UrbList
);
1099 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
1100 gBS
->RestoreTPL (OldTpl
);
1107 Submits synchronous interrupt transfer to an interrupt endpoint
1110 @param This This EFI_USB2_HC_PROTOCOL instance.
1111 @param DeviceAddress Target device address.
1112 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1113 @param DeviceSpeed Indicates device speed.
1114 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1115 of sending or receiving.
1116 @param Data Buffer of data that will be transmitted to USB
1117 device or received from USB device.
1118 @param DataLength On input, the size, in bytes, of the data buffer; On
1119 output, the number of bytes transferred.
1120 @param DataToggle On input, the initial data toggle to use; on output,
1121 it is updated to indicate the next data toggle.
1122 @param TimeOut Maximum time, in second, to complete.
1123 @param Translator Transaction translator to use.
1124 @param TransferResult Variable to receive the transfer result.
1126 @return EFI_SUCCESS The transfer was completed successfully.
1127 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1128 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1129 @return EFI_TIMEOUT The transfer failed due to timeout.
1130 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1135 EhcSyncInterruptTransfer (
1136 IN EFI_USB2_HC_PROTOCOL
*This
,
1137 IN UINT8 DeviceAddress
,
1138 IN UINT8 EndPointAddress
,
1139 IN UINT8 DeviceSpeed
,
1140 IN UINTN MaximumPacketLength
,
1142 IN OUT UINTN
*DataLength
,
1143 IN OUT UINT8
*DataToggle
,
1145 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1146 OUT UINT32
*TransferResult
1155 // Validates parameters
1157 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
1158 (Data
== NULL
) || (TransferResult
== NULL
)) {
1159 return EFI_INVALID_PARAMETER
;
1162 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1163 return EFI_INVALID_PARAMETER
;
1166 if (((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) ||
1167 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
1168 ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) && (MaximumPacketLength
> 3072))) {
1169 return EFI_INVALID_PARAMETER
;
1172 OldTpl
= gBS
->RaiseTPL (EHC_TPL
);
1173 Ehc
= EHC_FROM_THIS (This
);
1175 *TransferResult
= EFI_USB_ERR_SYSTEM
;
1176 Status
= EFI_DEVICE_ERROR
;
1178 if (EhcIsHalt (Ehc
) || EhcIsSysError (Ehc
)) {
1179 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: HC is halt\n"));
1181 EhcAckAllInterrupt (Ehc
);
1185 EhcAckAllInterrupt (Ehc
);
1187 Urb
= EhcCreateUrb (
1193 MaximumPacketLength
,
1195 EHC_INT_TRANSFER_SYNC
,
1205 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: failed to create URB\n"));
1207 Status
= EFI_OUT_OF_RESOURCES
;
1211 EhcLinkQhToPeriod (Ehc
, Urb
->Qh
);
1212 Status
= EhcExecTransfer (Ehc
, Urb
, TimeOut
);
1213 EhcUnlinkQhFromPeriod (Ehc
, Urb
->Qh
);
1215 *TransferResult
= Urb
->Result
;
1216 *DataLength
= Urb
->Completed
;
1217 *DataToggle
= Urb
->DataToggle
;
1219 if (*TransferResult
== EFI_USB_NOERROR
) {
1220 Status
= EFI_SUCCESS
;
1224 Ehc
->PciIo
->Flush (Ehc
->PciIo
);
1225 gBS
->RestoreTPL (OldTpl
);
1227 if (EFI_ERROR (Status
)) {
1228 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
1236 Submits 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 TransferResult Variable to receive the transfer result.
1253 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1258 EhcIsochronousTransfer (
1259 IN EFI_USB2_HC_PROTOCOL
*This
,
1260 IN UINT8 DeviceAddress
,
1261 IN UINT8 EndPointAddress
,
1262 IN UINT8 DeviceSpeed
,
1263 IN UINTN MaximumPacketLength
,
1264 IN UINT8 DataBuffersNumber
,
1265 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1266 IN UINTN DataLength
,
1267 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1268 OUT UINT32
*TransferResult
1271 return EFI_UNSUPPORTED
;
1276 Submits Async isochronous transfer to a target USB device.
1278 @param This This EFI_USB2_HC_PROTOCOL instance.
1279 @param DeviceAddress Target device address.
1280 @param EndPointAddress End point address with its direction.
1281 @param DeviceSpeed Device speed, Low speed device doesn't support this
1283 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1284 sending or receiving.
1285 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1286 @param Data Array of pointers to the buffers of data that will
1287 be transmitted to USB device or received from USB
1289 @param DataLength The size, in bytes, of the data buffer.
1290 @param Translator Transaction translator to use.
1291 @param IsochronousCallBack Function to be called when the transfer complete.
1292 @param Context Context passed to the call back function as
1295 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1300 EhcAsyncIsochronousTransfer (
1301 IN EFI_USB2_HC_PROTOCOL
*This
,
1302 IN UINT8 DeviceAddress
,
1303 IN UINT8 EndPointAddress
,
1304 IN UINT8 DeviceSpeed
,
1305 IN UINTN MaximumPacketLength
,
1306 IN UINT8 DataBuffersNumber
,
1307 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1308 IN UINTN DataLength
,
1309 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1310 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack
,
1314 return EFI_UNSUPPORTED
;
1318 Entry point for EFI drivers.
1320 @param ImageHandle EFI_HANDLE.
1321 @param SystemTable EFI_SYSTEM_TABLE.
1323 @return EFI_SUCCESS Success.
1324 EFI_DEVICE_ERROR Fail.
1329 EhcDriverEntryPoint (
1330 IN EFI_HANDLE ImageHandle
,
1331 IN EFI_SYSTEM_TABLE
*SystemTable
1334 return EfiLibInstallDriverBindingComponentName2 (
1337 &gEhciDriverBinding
,
1339 &gEhciComponentName
,
1340 &gEhciComponentName2
1346 Test to see if this driver supports ControllerHandle. Any
1347 ControllerHandle that has Usb2HcProtocol installed will
1350 @param This Protocol instance pointer.
1351 @param Controller Handle of device to test.
1352 @param RemainingDevicePath Not used.
1354 @return EFI_SUCCESS This driver supports this device.
1355 @return EFI_UNSUPPORTED This driver does not support this device.
1360 EhcDriverBindingSupported (
1361 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1362 IN EFI_HANDLE Controller
,
1363 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1367 EFI_PCI_IO_PROTOCOL
*PciIo
;
1368 USB_CLASSC UsbClassCReg
;
1371 // Test whether there is PCI IO Protocol attached on the controller handle.
1373 Status
= gBS
->OpenProtocol (
1375 &gEfiPciIoProtocolGuid
,
1377 This
->DriverBindingHandle
,
1379 EFI_OPEN_PROTOCOL_BY_DRIVER
1382 if (EFI_ERROR (Status
)) {
1383 return EFI_UNSUPPORTED
;
1386 Status
= PciIo
->Pci
.Read (
1389 PCI_CLASSCODE_OFFSET
,
1390 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1394 if (EFI_ERROR (Status
)) {
1395 Status
= EFI_UNSUPPORTED
;
1400 // Test whether the controller belongs to Ehci type
1402 if ((UsbClassCReg
.BaseCode
!= PCI_CLASS_SERIAL
) || (UsbClassCReg
.SubClassCode
!= PCI_CLASS_SERIAL_USB
)
1403 || ((UsbClassCReg
.ProgInterface
!= PCI_IF_EHCI
) && (UsbClassCReg
.ProgInterface
!= PCI_IF_UHCI
) && (UsbClassCReg
.ProgInterface
!= PCI_IF_OHCI
))) {
1405 Status
= EFI_UNSUPPORTED
;
1409 gBS
->CloseProtocol (
1411 &gEfiPciIoProtocolGuid
,
1412 This
->DriverBindingHandle
,
1420 Get the usb debug port related information.
1422 @param Ehc The EHCI device.
1424 @retval RETURN_SUCCESS Get debug port number, bar and offset successfully.
1425 @retval Others The usb host controller does not supported usb debug port capability.
1429 EhcGetUsbDebugPortInfo (
1433 EFI_PCI_IO_PROTOCOL
*PciIo
;
1435 UINT8 CapabilityPtr
;
1440 ASSERT (Ehc
->PciIo
!= NULL
);
1444 // Detect if the EHCI host controller support Capaility Pointer.
1446 Status
= PciIo
->Pci
.Read (
1449 PCI_PRIMARY_STATUS_OFFSET
,
1454 if (EFI_ERROR (Status
)) {
1458 if ((PciStatus
& EFI_PCI_STATUS_CAPABILITY
) == 0) {
1460 // The Pci Device Doesn't Support Capability Pointer.
1462 return EFI_UNSUPPORTED
;
1466 // Get Pointer To Capability List
1468 Status
= PciIo
->Pci
.Read (
1471 PCI_CAPBILITY_POINTER_OFFSET
,
1476 if (EFI_ERROR (Status
)) {
1481 // Find Capability ID 0xA, Which Is For Debug Port
1483 while (CapabilityPtr
!= 0) {
1484 Status
= PciIo
->Pci
.Read (
1492 if (EFI_ERROR (Status
)) {
1496 if (CapabilityId
== EHC_DEBUG_PORT_CAP_ID
) {
1500 Status
= PciIo
->Pci
.Read (
1508 if (EFI_ERROR (Status
)) {
1514 // No Debug Port Capability Found
1516 if (CapabilityPtr
== 0) {
1517 return EFI_UNSUPPORTED
;
1521 // Get The Base Address Of Debug Port Register In Debug Port Capability Register
1523 Status
= PciIo
->Pci
.Read (
1531 if (EFI_ERROR (Status
)) {
1535 Ehc
->DebugPortOffset
= DebugPort
& 0x1FFF;
1536 Ehc
->DebugPortBarNum
= (UINT8
)((DebugPort
>> 13) - 1);
1537 Ehc
->DebugPortNum
= (UINT8
)((Ehc
->HcStructParams
& 0x00F00000) >> 20);
1544 Create and initialize a USB2_HC_DEV.
1546 @param PciIo The PciIo on this device.
1547 @param DevicePath The device path of host controller.
1548 @param OriginalPciAttributes Original PCI attributes.
1550 @return The allocated and initialized USB2_HC_DEV structure if created,
1556 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1557 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1558 IN UINT64 OriginalPciAttributes
1564 Ehc
= AllocateZeroPool (sizeof (USB2_HC_DEV
));
1571 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1573 Ehc
->Signature
= USB2_HC_DEV_SIGNATURE
;
1575 Ehc
->Usb2Hc
.GetCapability
= EhcGetCapability
;
1576 Ehc
->Usb2Hc
.Reset
= EhcReset
;
1577 Ehc
->Usb2Hc
.GetState
= EhcGetState
;
1578 Ehc
->Usb2Hc
.SetState
= EhcSetState
;
1579 Ehc
->Usb2Hc
.ControlTransfer
= EhcControlTransfer
;
1580 Ehc
->Usb2Hc
.BulkTransfer
= EhcBulkTransfer
;
1581 Ehc
->Usb2Hc
.AsyncInterruptTransfer
= EhcAsyncInterruptTransfer
;
1582 Ehc
->Usb2Hc
.SyncInterruptTransfer
= EhcSyncInterruptTransfer
;
1583 Ehc
->Usb2Hc
.IsochronousTransfer
= EhcIsochronousTransfer
;
1584 Ehc
->Usb2Hc
.AsyncIsochronousTransfer
= EhcAsyncIsochronousTransfer
;
1585 Ehc
->Usb2Hc
.GetRootHubPortStatus
= EhcGetRootHubPortStatus
;
1586 Ehc
->Usb2Hc
.SetRootHubPortFeature
= EhcSetRootHubPortFeature
;
1587 Ehc
->Usb2Hc
.ClearRootHubPortFeature
= EhcClearRootHubPortFeature
;
1588 Ehc
->Usb2Hc
.MajorRevision
= 0x2;
1589 Ehc
->Usb2Hc
.MinorRevision
= 0x0;
1592 Ehc
->DevicePath
= DevicePath
;
1593 Ehc
->OriginalPciAttributes
= OriginalPciAttributes
;
1595 InitializeListHead (&Ehc
->AsyncIntTransfers
);
1597 Ehc
->HcStructParams
= EhcReadCapRegister (Ehc
, EHC_HCSPARAMS_OFFSET
);
1598 Ehc
->HcCapParams
= EhcReadCapRegister (Ehc
, EHC_HCCPARAMS_OFFSET
);
1599 Ehc
->CapLen
= EhcReadCapRegister (Ehc
, EHC_CAPLENGTH_OFFSET
) & 0x0FF;
1601 DEBUG ((EFI_D_INFO
, "EhcCreateUsb2Hc: capability length %d\n", Ehc
->CapLen
));
1604 // EHCI Controllers with a CapLen of 0 are ignored.
1606 if (Ehc
->CapLen
== 0) {
1607 gBS
->FreePool (Ehc
);
1611 EhcGetUsbDebugPortInfo (Ehc
);
1614 // Create AsyncRequest Polling Timer
1616 Status
= gBS
->CreateEvent (
1617 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1619 EhcMonitorAsyncRequests
,
1624 if (EFI_ERROR (Status
)) {
1625 gBS
->FreePool (Ehc
);
1633 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1635 @param Event Pointer to this event
1636 @param Context Event handler private data
1641 EhcExitBootService (
1649 Ehc
= (USB2_HC_DEV
*) Context
;
1652 // Reset the Host Controller
1654 EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
1659 Starting the Usb EHCI Driver.
1661 @param This Protocol instance pointer.
1662 @param Controller Handle of device to test.
1663 @param RemainingDevicePath Not used.
1665 @return EFI_SUCCESS supports this device.
1666 @return EFI_UNSUPPORTED do not support this device.
1667 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1668 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1673 EhcDriverBindingStart (
1674 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1675 IN EFI_HANDLE Controller
,
1676 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1681 EFI_PCI_IO_PROTOCOL
*PciIo
;
1682 EFI_PCI_IO_PROTOCOL
*Instance
;
1684 UINT64 OriginalPciAttributes
;
1685 BOOLEAN PciAttributesSaved
;
1686 USB_CLASSC UsbClassCReg
;
1687 EFI_HANDLE
*HandleBuffer
;
1688 UINTN NumberOfHandles
;
1690 UINTN CompanionSegmentNumber
;
1691 UINTN CompanionBusNumber
;
1692 UINTN CompanionDeviceNumber
;
1693 UINTN CompanionFunctionNumber
;
1694 UINTN EhciSegmentNumber
;
1695 UINTN EhciBusNumber
;
1696 UINTN EhciDeviceNumber
;
1697 UINTN EhciFunctionNumber
;
1699 EFI_DEVICE_PATH_PROTOCOL
*HcDevicePath
;
1702 // Open the PciIo Protocol, then enable the USB host controller
1704 Status
= gBS
->OpenProtocol (
1706 &gEfiPciIoProtocolGuid
,
1708 This
->DriverBindingHandle
,
1710 EFI_OPEN_PROTOCOL_BY_DRIVER
1713 if (EFI_ERROR (Status
)) {
1718 // Open Device Path Protocol for on USB host controller
1720 HcDevicePath
= NULL
;
1721 Status
= gBS
->OpenProtocol (
1723 &gEfiDevicePathProtocolGuid
,
1724 (VOID
**) &HcDevicePath
,
1725 This
->DriverBindingHandle
,
1727 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1730 PciAttributesSaved
= FALSE
;
1732 // Save original PCI attributes
1734 Status
= PciIo
->Attributes (
1736 EfiPciIoAttributeOperationGet
,
1738 &OriginalPciAttributes
1741 if (EFI_ERROR (Status
)) {
1744 PciAttributesSaved
= TRUE
;
1746 Status
= PciIo
->Attributes (
1748 EfiPciIoAttributeOperationSupported
,
1752 if (!EFI_ERROR (Status
)) {
1753 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
1754 Status
= PciIo
->Attributes (
1756 EfiPciIoAttributeOperationEnable
,
1762 if (EFI_ERROR (Status
)) {
1763 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to enable controller\n"));
1768 // Get the Pci device class code.
1770 Status
= PciIo
->Pci
.Read (
1773 PCI_CLASSCODE_OFFSET
,
1774 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1778 if (EFI_ERROR (Status
)) {
1779 Status
= EFI_UNSUPPORTED
;
1783 // Determine if the device is UHCI or OHCI host controller or not. If yes, then find out the
1784 // companion usb ehci host controller and force EHCI driver get attached to it before
1785 // UHCI or OHCI driver attaches to UHCI or OHCI host controller.
1787 if ((UsbClassCReg
.ProgInterface
== PCI_IF_UHCI
|| UsbClassCReg
.ProgInterface
== PCI_IF_OHCI
) &&
1788 (UsbClassCReg
.BaseCode
== PCI_CLASS_SERIAL
) &&
1789 (UsbClassCReg
.SubClassCode
== PCI_CLASS_SERIAL_USB
)) {
1790 Status
= PciIo
->GetLocation (
1792 &CompanionSegmentNumber
,
1793 &CompanionBusNumber
,
1794 &CompanionDeviceNumber
,
1795 &CompanionFunctionNumber
1797 if (EFI_ERROR (Status
)) {
1801 Status
= gBS
->LocateHandleBuffer (
1803 &gEfiPciIoProtocolGuid
,
1808 if (EFI_ERROR (Status
)) {
1812 for (Index
= 0; Index
< NumberOfHandles
; Index
++) {
1814 // Get the device path on this handle
1816 Status
= gBS
->HandleProtocol (
1817 HandleBuffer
[Index
],
1818 &gEfiPciIoProtocolGuid
,
1821 ASSERT_EFI_ERROR (Status
);
1823 Status
= Instance
->Pci
.Read (
1826 PCI_CLASSCODE_OFFSET
,
1827 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1831 if (EFI_ERROR (Status
)) {
1832 Status
= EFI_UNSUPPORTED
;
1836 if ((UsbClassCReg
.ProgInterface
== PCI_IF_EHCI
) &&
1837 (UsbClassCReg
.BaseCode
== PCI_CLASS_SERIAL
) &&
1838 (UsbClassCReg
.SubClassCode
== PCI_CLASS_SERIAL_USB
)) {
1839 Status
= Instance
->GetLocation (
1846 if (EFI_ERROR (Status
)) {
1850 // Currently, the judgment on the companion usb host controller is through the
1851 // same bus number, which may vary on different platform.
1853 if (EhciBusNumber
== CompanionBusNumber
) {
1854 gBS
->CloseProtocol (
1856 &gEfiPciIoProtocolGuid
,
1857 This
->DriverBindingHandle
,
1860 EhcDriverBindingStart(This
, HandleBuffer
[Index
], NULL
);
1864 Status
= EFI_NOT_FOUND
;
1869 // Create then install USB2_HC_PROTOCOL
1871 Ehc
= EhcCreateUsb2Hc (PciIo
, HcDevicePath
, OriginalPciAttributes
);
1874 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to create USB2_HC\n"));
1876 Status
= EFI_OUT_OF_RESOURCES
;
1881 // Enable 64-bit DMA support in the PCI layer if this controller
1884 if (EHC_BIT_IS_SET (Ehc
->HcCapParams
, HCCP_64BIT
)) {
1885 Status
= PciIo
->Attributes (
1887 EfiPciIoAttributeOperationEnable
,
1888 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
1891 if (!EFI_ERROR (Status
)) {
1892 Ehc
->Support64BitDma
= TRUE
;
1895 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
1896 __FUNCTION__
, Controller
, Status
));
1900 Status
= gBS
->InstallProtocolInterface (
1902 &gEfiUsb2HcProtocolGuid
,
1903 EFI_NATIVE_INTERFACE
,
1907 if (EFI_ERROR (Status
)) {
1908 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1913 // Robustnesss improvement such as for Duet platform
1914 // Default is not required.
1916 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport
)) {
1917 EhcClearLegacySupport (Ehc
);
1920 if (Ehc
->DebugPortNum
!= 0) {
1921 State
= EhcReadDbgRegister(Ehc
, 0);
1922 if ((State
& (USB_DEBUG_PORT_IN_USE
| USB_DEBUG_PORT_OWNER
)) != (USB_DEBUG_PORT_IN_USE
| USB_DEBUG_PORT_OWNER
)) {
1923 EhcResetHC (Ehc
, EHC_RESET_TIMEOUT
);
1927 Status
= EhcInitHC (Ehc
);
1929 if (EFI_ERROR (Status
)) {
1930 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to init host controller\n"));
1931 goto UNINSTALL_USBHC
;
1935 // Start the asynchronous interrupt monitor
1937 Status
= gBS
->SetTimer (Ehc
->PollTimer
, TimerPeriodic
, EHC_ASYNC_POLL_INTERVAL
);
1939 if (EFI_ERROR (Status
)) {
1940 DEBUG ((EFI_D_ERROR
, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
1942 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
1943 goto UNINSTALL_USBHC
;
1947 // Create event to stop the HC when exit boot service.
1949 Status
= gBS
->CreateEventEx (
1954 &gEfiEventExitBootServicesGuid
,
1955 &Ehc
->ExitBootServiceEvent
1957 if (EFI_ERROR (Status
)) {
1958 goto UNINSTALL_USBHC
;
1962 // Install the component name protocol, don't fail the start
1963 // because of something for display.
1967 gEhciComponentName
.SupportedLanguages
,
1968 &Ehc
->ControllerNameTable
,
1969 L
"Enhanced Host Controller (USB 2.0)",
1974 gEhciComponentName2
.SupportedLanguages
,
1975 &Ehc
->ControllerNameTable
,
1976 L
"Enhanced Host Controller (USB 2.0)",
1981 DEBUG ((EFI_D_INFO
, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller
));
1985 gBS
->UninstallProtocolInterface (
1987 &gEfiUsb2HcProtocolGuid
,
1993 gBS
->CloseEvent (Ehc
->PollTimer
);
1994 gBS
->FreePool (Ehc
);
1997 if (PciAttributesSaved
) {
1999 // Restore original PCI attributes
2003 EfiPciIoAttributeOperationSet
,
2004 OriginalPciAttributes
,
2009 gBS
->CloseProtocol (
2011 &gEfiPciIoProtocolGuid
,
2012 This
->DriverBindingHandle
,
2021 Stop this driver on ControllerHandle. Support stopping any child handles
2022 created by this driver.
2024 @param This Protocol instance pointer.
2025 @param Controller Handle of device to stop driver on.
2026 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
2027 @param ChildHandleBuffer List of handles for the children we need to stop.
2029 @return EFI_SUCCESS Success.
2030 @return EFI_DEVICE_ERROR Fail.
2035 EhcDriverBindingStop (
2036 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2037 IN EFI_HANDLE Controller
,
2038 IN UINTN NumberOfChildren
,
2039 IN EFI_HANDLE
*ChildHandleBuffer
2043 EFI_USB2_HC_PROTOCOL
*Usb2Hc
;
2044 EFI_PCI_IO_PROTOCOL
*PciIo
;
2048 // Test whether the Controller handler passed in is a valid
2049 // Usb controller handle that should be supported, if not,
2050 // return the error status directly
2052 Status
= gBS
->OpenProtocol (
2054 &gEfiUsb2HcProtocolGuid
,
2056 This
->DriverBindingHandle
,
2058 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2061 if (EFI_ERROR (Status
)) {
2065 Ehc
= EHC_FROM_THIS (Usb2Hc
);
2068 Status
= gBS
->UninstallProtocolInterface (
2070 &gEfiUsb2HcProtocolGuid
,
2074 if (EFI_ERROR (Status
)) {
2079 // Stop AsyncRequest Polling timer then stop the EHCI driver
2080 // and uninstall the EHCI protocl.
2082 gBS
->SetTimer (Ehc
->PollTimer
, TimerCancel
, EHC_ASYNC_POLL_INTERVAL
);
2083 EhcHaltHC (Ehc
, EHC_GENERIC_TIMEOUT
);
2085 if (Ehc
->PollTimer
!= NULL
) {
2086 gBS
->CloseEvent (Ehc
->PollTimer
);
2089 if (Ehc
->ExitBootServiceEvent
!= NULL
) {
2090 gBS
->CloseEvent (Ehc
->ExitBootServiceEvent
);
2095 if (Ehc
->ControllerNameTable
!= NULL
) {
2096 FreeUnicodeStringTable (Ehc
->ControllerNameTable
);
2100 // Disable routing of all ports to EHCI controller, so all ports are
2101 // routed back to the UHCI or OHCI controller.
2103 EhcClearOpRegBit (Ehc
, EHC_CONFIG_FLAG_OFFSET
, CONFIGFLAG_ROUTE_EHC
);
2106 // Restore original PCI attributes
2110 EfiPciIoAttributeOperationSet
,
2111 Ehc
->OriginalPciAttributes
,
2115 gBS
->CloseProtocol (
2117 &gEfiPciIoProtocolGuid
,
2118 This
->DriverBindingHandle
,