2 The XHCI controller driver.
4 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 // The device context array which supports up to 255 devices, entry 0 is reserved and should not be used.
20 USB_DEV_CONTEXT UsbDevContext
[256];
23 // Two arrays used to translate the XHCI port state (change)
24 // to the UEFI protocol's port state (change).
26 USB_PORT_STATE_MAP mUsbPortStateMap
[] = {
27 {XHC_PORTSC_CCS
, USB_PORT_STAT_CONNECTION
},
28 {XHC_PORTSC_PED
, USB_PORT_STAT_ENABLE
},
29 {XHC_PORTSC_OCA
, USB_PORT_STAT_OVERCURRENT
},
30 {XHC_PORTSC_RESET
, USB_PORT_STAT_RESET
}
33 USB_PORT_STATE_MAP mUsbPortChangeMap
[] = {
34 {XHC_PORTSC_CSC
, USB_PORT_STAT_C_CONNECTION
},
35 {XHC_PORTSC_PEC
, USB_PORT_STAT_C_ENABLE
},
36 {XHC_PORTSC_OCC
, USB_PORT_STAT_C_OVERCURRENT
},
37 {XHC_PORTSC_PRC
, USB_PORT_STAT_C_RESET
}
40 EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding
= {
41 XhcDriverBindingSupported
,
42 XhcDriverBindingStart
,
50 Retrieves the capability of root hub ports.
52 @param This The EFI_USB2_HC_PROTOCOL instance.
53 @param MaxSpeed Max speed supported by the controller.
54 @param PortNumber Number of the root hub ports.
55 @param Is64BitCapable Whether the controller supports 64-bit memory
58 @retval EFI_SUCCESS Host controller capability were retrieved successfully.
59 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
65 IN EFI_USB2_HC_PROTOCOL
*This
,
67 OUT UINT8
*PortNumber
,
68 OUT UINT8
*Is64BitCapable
74 if ((MaxSpeed
== NULL
) || (PortNumber
== NULL
) || (Is64BitCapable
== NULL
)) {
75 return EFI_INVALID_PARAMETER
;
78 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
80 Xhc
= XHC_FROM_THIS (This
);
81 *MaxSpeed
= EFI_USB_SPEED_SUPER
;
82 *PortNumber
= (UINT8
) (Xhc
->HcSParams1
.Data
.MaxPorts
);
83 *Is64BitCapable
= (UINT8
) (Xhc
->HcCParams
.Data
.Ac64
);
84 DEBUG ((EFI_D_INFO
, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber
, *Is64BitCapable
));
86 gBS
->RestoreTPL (OldTpl
);
93 Provides software reset for the USB host controller.
95 @param This This EFI_USB2_HC_PROTOCOL instance.
96 @param Attributes A bit mask of the reset operation to perform.
98 @retval EFI_SUCCESS The reset operation succeeded.
99 @retval EFI_INVALID_PARAMETER Attributes is not valid.
100 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
101 not currently supported by the host controller.
102 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
108 IN EFI_USB2_HC_PROTOCOL
*This
,
116 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
118 Xhc
= XHC_FROM_THIS (This
);
120 switch (Attributes
) {
121 case EFI_USB_HC_RESET_GLOBAL
:
123 // Flow through, same behavior as Host Controller Reset
125 case EFI_USB_HC_RESET_HOST_CONTROLLER
:
127 // Host Controller must be Halt when Reset it
129 if (!XhcIsHalt (Xhc
)) {
130 Status
= XhcHaltHC (Xhc
, XHC_GENERIC_TIMEOUT
);
132 if (EFI_ERROR (Status
)) {
133 Status
= EFI_DEVICE_ERROR
;
138 Status
= XhcResetHC (Xhc
, XHC_RESET_TIMEOUT
);
139 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_CNR
)));
141 if (EFI_ERROR (Status
)) {
145 // Clean up the asynchronous transfers, currently only
146 // interrupt supports asynchronous operation.
148 XhciDelAllAsyncIntTransfers (Xhc
);
154 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG
:
155 case EFI_USB_HC_RESET_HOST_WITH_DEBUG
:
156 Status
= EFI_UNSUPPORTED
;
160 Status
= EFI_INVALID_PARAMETER
;
164 DEBUG ((EFI_D_INFO
, "XhcReset: status %r\n", Status
));
165 gBS
->RestoreTPL (OldTpl
);
172 Retrieve the current state of the USB host controller.
174 @param This This EFI_USB2_HC_PROTOCOL instance.
175 @param State Variable to return the current host controller
178 @retval EFI_SUCCESS Host controller state was returned in State.
179 @retval EFI_INVALID_PARAMETER State is NULL.
180 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
181 retrieve the host controller's current state.
187 IN EFI_USB2_HC_PROTOCOL
*This
,
188 OUT EFI_USB_HC_STATE
*State
195 return EFI_INVALID_PARAMETER
;
198 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
200 Xhc
= XHC_FROM_THIS (This
);
202 if (XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
)) {
203 *State
= EfiUsbHcStateHalt
;
205 *State
= EfiUsbHcStateOperational
;
208 DEBUG ((EFI_D_INFO
, "XhcGetState: current state %d\n", *State
));
209 gBS
->RestoreTPL (OldTpl
);
215 Sets the USB host controller to a specific state.
217 @param This This EFI_USB2_HC_PROTOCOL instance.
218 @param State The state of the host controller that will be set.
220 @retval EFI_SUCCESS The USB host controller was successfully placed
221 in the state specified by State.
222 @retval EFI_INVALID_PARAMETER State is invalid.
223 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
229 IN EFI_USB2_HC_PROTOCOL
*This
,
230 IN EFI_USB_HC_STATE State
235 EFI_USB_HC_STATE CurState
;
238 Status
= XhcGetState (This
, &CurState
);
240 if (EFI_ERROR (Status
)) {
241 return EFI_DEVICE_ERROR
;
244 if (CurState
== State
) {
248 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
250 Xhc
= XHC_FROM_THIS (This
);
253 case EfiUsbHcStateHalt
:
254 Status
= XhcHaltHC (Xhc
, XHC_GENERIC_TIMEOUT
);
257 case EfiUsbHcStateOperational
:
258 if (XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HSE
)) {
259 Status
= EFI_DEVICE_ERROR
;
264 // Software must not write a one to this field unless the host controller
265 // is in the Halted state. Doing so will yield undefined results.
266 // refers to Spec[XHCI1.0-2.3.1]
268 if (!XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_HALT
)) {
269 Status
= EFI_DEVICE_ERROR
;
273 Status
= XhcRunHC (Xhc
, XHC_GENERIC_TIMEOUT
);
276 case EfiUsbHcStateSuspend
:
277 Status
= EFI_UNSUPPORTED
;
281 Status
= EFI_INVALID_PARAMETER
;
284 DEBUG ((EFI_D_INFO
, "XhcSetState: status %r\n", Status
));
285 gBS
->RestoreTPL (OldTpl
);
291 Retrieves the current status of a USB root hub port.
293 @param This This EFI_USB2_HC_PROTOCOL instance.
294 @param PortNumber The root hub port to retrieve the state from.
295 This value is zero-based.
296 @param PortStatus Variable to receive the port state.
298 @retval EFI_SUCCESS The status of the USB root hub port specified.
299 by PortNumber was returned in PortStatus.
300 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
301 @retval EFI_DEVICE_ERROR Can't read register.
306 XhcGetRootHubPortStatus (
307 IN EFI_USB2_HC_PROTOCOL
*This
,
309 OUT EFI_USB_PORT_STATUS
*PortStatus
319 USB_DEV_ROUTE ParentRouteChart
;
322 if (PortStatus
== NULL
) {
323 return EFI_INVALID_PARAMETER
;
326 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
328 Xhc
= XHC_FROM_THIS (This
);
329 Status
= EFI_SUCCESS
;
331 TotalPort
= Xhc
->HcSParams1
.Data
.MaxPorts
;
333 if (PortNumber
>= TotalPort
) {
334 Status
= EFI_INVALID_PARAMETER
;
338 Offset
= (UINT32
) (XHC_PORTSC_OFFSET
+ (0x10 * PortNumber
));
339 PortStatus
->PortStatus
= 0;
340 PortStatus
->PortChangeStatus
= 0;
342 State
= XhcReadOpReg (Xhc
, Offset
);
345 // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.
347 switch ((State
& XHC_PORTSC_PS
) >> 10) {
349 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
353 PortStatus
->PortStatus
|= USB_PORT_STAT_HIGH_SPEED
;
357 PortStatus
->PortStatus
|= USB_PORT_STAT_SUPER_SPEED
;
365 // Convert the XHCI port/port change state to UEFI status
367 MapSize
= sizeof (mUsbPortStateMap
) / sizeof (USB_PORT_STATE_MAP
);
369 for (Index
= 0; Index
< MapSize
; Index
++) {
370 if (XHC_BIT_IS_SET (State
, mUsbPortStateMap
[Index
].HwState
)) {
371 PortStatus
->PortStatus
= (UINT16
) (PortStatus
->PortStatus
| mUsbPortStateMap
[Index
].UefiState
);
375 // Bit5~8 reflects its current link state.
377 if ((State
& XHC_PORTSC_PLS
) >> 5 == 3) {
378 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
381 MapSize
= sizeof (mUsbPortChangeMap
) / sizeof (USB_PORT_STATE_MAP
);
383 for (Index
= 0; Index
< MapSize
; Index
++) {
384 if (XHC_BIT_IS_SET (State
, mUsbPortChangeMap
[Index
].HwState
)) {
385 PortStatus
->PortChangeStatus
= (UINT16
) (PortStatus
->PortChangeStatus
| mUsbPortChangeMap
[Index
].UefiState
);
390 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
391 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
393 ParentRouteChart
.Dword
= 0;
394 XhcPollPortStatusChange (Xhc
, ParentRouteChart
, PortNumber
, PortStatus
);
397 gBS
->RestoreTPL (OldTpl
);
403 Sets a feature for the specified root hub port.
405 @param This This EFI_USB2_HC_PROTOCOL instance.
406 @param PortNumber Root hub port to set.
407 @param PortFeature Feature to set.
409 @retval EFI_SUCCESS The feature specified by PortFeature was set.
410 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
411 @retval EFI_DEVICE_ERROR Can't read register.
416 XhcSetRootHubPortFeature (
417 IN EFI_USB2_HC_PROTOCOL
*This
,
419 IN EFI_USB_PORT_FEATURE PortFeature
427 USB_DEV_ROUTE RouteChart
;
431 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
433 Xhc
= XHC_FROM_THIS (This
);
434 Status
= EFI_SUCCESS
;
436 TotalPort
= (Xhc
->HcSParams1
.Data
.MaxPorts
);
438 if (PortNumber
>= TotalPort
) {
439 Status
= EFI_INVALID_PARAMETER
;
443 Offset
= (UINT32
) (XHC_PORTSC_OFFSET
+ (0x10 * PortNumber
));
444 State
= XhcReadOpReg (Xhc
, Offset
);
447 // Mask off the port status change bits, these bits are
450 State
&= ~ (BIT1
| BIT17
| BIT18
| BIT19
| BIT20
| BIT21
| BIT22
| BIT23
);
452 switch (PortFeature
) {
453 case EfiUsbPortEnable
:
455 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
456 // A port may be disabled by software writing a '1' to this flag.
458 Status
= EFI_SUCCESS
;
461 case EfiUsbPortSuspend
:
462 State
|= XHC_PORTSC_LWS
;
463 XhcWriteOpReg (Xhc
, Offset
, State
);
464 State
&= ~XHC_PORTSC_PLS
;
466 XhcWriteOpReg (Xhc
, Offset
, State
);
469 case EfiUsbPortReset
:
470 DEBUG ((EFI_D_INFO
, "XhcUsbPortReset!\n"));
472 // Make sure Host Controller not halt before reset it
474 if (XhcIsHalt (Xhc
)) {
475 Status
= XhcRunHC (Xhc
, XHC_GENERIC_TIMEOUT
);
477 if (EFI_ERROR (Status
)) {
478 DEBUG ((EFI_D_INFO
, "XhcSetRootHubPortFeature :failed to start HC - %r\n", Status
));
483 RouteChart
.Field
.RouteString
= 0;
484 RouteChart
.Field
.RootPortNum
= PortNumber
+ 1;
485 RouteChart
.Field
.TierNum
= 1;
487 // BUGBUG: If the port reset operation happens after the usb super speed device is enabled,
488 // The subsequent configuration, such as getting device descriptor, will fail.
489 // So here a workaround is introduced to skip the reset operation if the device is enabled.
491 SlotId
= XhcRouteStringToSlotId (RouteChart
);
494 // 4.3.1 Resetting a Root Hub Port
495 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
497 State
|= XHC_PORTSC_RESET
;
498 XhcWriteOpReg (Xhc
, Offset
, State
);
499 XhcWaitOpRegBit(Xhc
, Offset
, XHC_PORTSC_PRC
, TRUE
, XHC_GENERIC_TIMEOUT
);
503 case EfiUsbPortPower
:
505 // Not supported, ignore the operation
507 Status
= EFI_SUCCESS
;
510 case EfiUsbPortOwner
:
512 // XHCI root hub port don't has the owner bit, ignore the operation
514 Status
= EFI_SUCCESS
;
518 Status
= EFI_INVALID_PARAMETER
;
522 DEBUG ((EFI_D_INFO
, "XhcSetRootHubPortFeature: status %r\n", Status
));
523 gBS
->RestoreTPL (OldTpl
);
530 Clears a feature for the specified root hub port.
532 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
533 @param PortNumber Specifies the root hub port whose feature is
534 requested to be cleared.
535 @param PortFeature Indicates the feature selector associated with the
536 feature clear request.
538 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
539 for the USB root hub port specified by PortNumber.
540 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
541 @retval EFI_DEVICE_ERROR Can't read register.
546 XhcClearRootHubPortFeature (
547 IN EFI_USB2_HC_PROTOCOL
*This
,
549 IN EFI_USB_PORT_FEATURE PortFeature
559 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
561 Xhc
= XHC_FROM_THIS (This
);
562 Status
= EFI_SUCCESS
;
564 TotalPort
= (Xhc
->HcSParams1
.Data
.MaxPorts
);
566 if (PortNumber
>= TotalPort
) {
567 Status
= EFI_INVALID_PARAMETER
;
571 Offset
= XHC_PORTSC_OFFSET
+ (0x10 * PortNumber
);
574 // Mask off the port status change bits, these bits are
577 State
= XhcReadOpReg (Xhc
, Offset
);
578 State
&= ~ (BIT1
| BIT17
| BIT18
| BIT19
| BIT20
| BIT21
| BIT22
| BIT23
);
580 switch (PortFeature
) {
581 case EfiUsbPortEnable
:
583 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
584 // A port may be disabled by software writing a '1' to this flag.
586 State
|= XHC_PORTSC_PED
;
587 State
&= ~XHC_PORTSC_RESET
;
588 XhcWriteOpReg (Xhc
, Offset
, State
);
591 case EfiUsbPortSuspend
:
592 State
|= XHC_PORTSC_LWS
;
593 XhcWriteOpReg (Xhc
, Offset
, State
);
594 State
&= ~XHC_PORTSC_PLS
;
595 XhcWriteOpReg (Xhc
, Offset
, State
);
598 case EfiUsbPortReset
:
600 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
601 // Register bits indicate status when read, a clear bit may be set by
602 // writing a '1'. Writing a '0' to RW1S bits has no effect.
606 case EfiUsbPortOwner
:
608 // XHCI root hub port don't has the owner bit, ignore the operation
612 case EfiUsbPortConnectChange
:
614 // Clear connect status change
616 State
|= XHC_PORTSC_CSC
;
617 XhcWriteOpReg (Xhc
, Offset
, State
);
620 case EfiUsbPortEnableChange
:
622 // Clear enable status change
624 State
|= XHC_PORTSC_PEC
;
625 XhcWriteOpReg (Xhc
, Offset
, State
);
628 case EfiUsbPortOverCurrentChange
:
630 // Clear PortOverCurrent change
632 State
|= XHC_PORTSC_OCC
;
633 XhcWriteOpReg (Xhc
, Offset
, State
);
636 case EfiUsbPortResetChange
:
638 // Clear Port Reset change
640 State
|= XHC_PORTSC_PRC
;
641 XhcWriteOpReg (Xhc
, Offset
, State
);
644 case EfiUsbPortPower
:
645 case EfiUsbPortSuspendChange
:
647 // Not supported or not related operation
652 Status
= EFI_INVALID_PARAMETER
;
657 DEBUG ((EFI_D_INFO
, "XhcClearRootHubPortFeature: status %r\n", Status
));
658 gBS
->RestoreTPL (OldTpl
);
665 Submits control transfer to a target USB device.
667 @param This This EFI_USB2_HC_PROTOCOL instance.
668 @param DeviceAddress The target device address.
669 @param DeviceSpeed Target device speed.
670 @param MaximumPacketLength Maximum packet size the default control transfer
671 endpoint is capable of sending or receiving.
672 @param Request USB device request to send.
673 @param TransferDirection Specifies the data direction for the data stage
674 @param Data Data buffer to be transmitted or received from USB
676 @param DataLength The size (in bytes) of the data buffer.
677 @param TimeOut Indicates the maximum timeout, in millisecond.
678 @param Translator Transaction translator to be used by this device.
679 @param TransferResult Return the result of this control transfer.
681 @retval EFI_SUCCESS Transfer was completed successfully.
682 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
683 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
684 @retval EFI_TIMEOUT Transfer failed due to timeout.
685 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
691 IN EFI_USB2_HC_PROTOCOL
*This
,
692 IN UINT8 DeviceAddress
,
693 IN UINT8 DeviceSpeed
,
694 IN UINTN MaximumPacketLength
,
695 IN EFI_USB_DEVICE_REQUEST
*Request
,
696 IN EFI_USB_DATA_DIRECTION TransferDirection
,
698 IN OUT UINTN
*DataLength
,
700 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
701 OUT UINT32
*TransferResult
709 UINT8 DescriptorType
;
714 EFI_USB_HUB_DESCRIPTOR
*HubDesc
;
717 EFI_STATUS RecoveryStatus
;
719 EFI_USB_PORT_STATUS PortStatus
;
723 // Validate parameters
725 if ((Request
== NULL
) || (TransferResult
== NULL
)) {
726 return EFI_INVALID_PARAMETER
;
729 if ((TransferDirection
!= EfiUsbDataIn
) &&
730 (TransferDirection
!= EfiUsbDataOut
) &&
731 (TransferDirection
!= EfiUsbNoData
)) {
732 return EFI_INVALID_PARAMETER
;
735 if ((TransferDirection
== EfiUsbNoData
) &&
736 ((Data
!= NULL
) || (*DataLength
!= 0))) {
737 return EFI_INVALID_PARAMETER
;
740 if ((TransferDirection
!= EfiUsbNoData
) &&
741 ((Data
== NULL
) || (*DataLength
== 0))) {
742 return EFI_INVALID_PARAMETER
;
745 if ((MaximumPacketLength
!= 8) && (MaximumPacketLength
!= 16) &&
746 (MaximumPacketLength
!= 32) && (MaximumPacketLength
!= 64) &&
747 (MaximumPacketLength
!= 512)
749 return EFI_INVALID_PARAMETER
;
752 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) {
753 return EFI_INVALID_PARAMETER
;
756 if ((DeviceSpeed
== EFI_USB_SPEED_SUPER
) && (MaximumPacketLength
!= 512)) {
757 return EFI_INVALID_PARAMETER
;
760 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
762 Xhc
= XHC_FROM_THIS (This
);
764 Status
= EFI_DEVICE_ERROR
;
765 *TransferResult
= EFI_USB_ERR_SYSTEM
;
767 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
768 DEBUG ((EFI_D_ERROR
, "XhcControlTransfer: HC halted at entrance\n"));
773 // Check if the device is still enabled before every transaction.
775 SlotId
= XhcBusDevAddrToSlotId (DeviceAddress
);
781 // Acquire the actual device address assigned by XHCI's Address_Device cmd.
783 XhciDevAddr
= UsbDevContext
[SlotId
].XhciDevAddr
;
786 // Hook the Set_Address request from UsbBus.
787 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
789 if (Request
->Request
== USB_REQ_SET_ADDRESS
) {
791 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
792 // This way is used to clean the history to avoid using wrong device address by XhcAsyncInterruptTransfer().
794 for (Index
= 0; Index
< 255; Index
++) {
795 if (!UsbDevContext
[Index
+ 1].Enabled
&&
796 (UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
797 (UsbDevContext
[Index
+ 1].BusDevAddr
== (UINT8
)Request
->Value
)) {
798 UsbDevContext
[Index
+ 1].BusDevAddr
= 0;
802 // The actual device address has been assigned by XHCI during initializing the device slot.
803 // So we just need establish the mapping relationship between the device address requested from UsbBus
804 // and the actual device address assigned by XHCI. The the following invocations through EFI_USB2_HC_PROTOCOL interface
805 // can find out the actual device address by it.
807 UsbDevContext
[SlotId
].BusDevAddr
= (UINT8
)Request
->Value
;
808 Status
= EFI_SUCCESS
;
813 // BUGBUG: If the port reset operation happens after the usb super speed device is enabled,
814 // The subsequent configuration, such as getting device descriptor, will fail.
815 // So here a workaround is introduced to skip the reset operation if the device is enabled.
817 if ((Request
->Request
== USB_REQ_SET_FEATURE
) &&
818 (Request
->Value
== EfiUsbPortReset
)) {
819 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
820 Status
= EFI_SUCCESS
;
826 // Create a new URB, insert it into the asynchronous
827 // schedule list, then poll the execution status.
828 // Note that we encode the direction in address although default control
829 // endpoint is bidirectional. XhcCreateUrb expects this
830 // combination of Ep addr and its direction.
832 Endpoint
= (UINT8
) (0 | ((TransferDirection
== EfiUsbDataIn
) ? 0x80 : 0));
848 DEBUG ((EFI_D_ERROR
, "XhcControlTransfer: failed to create URB"));
849 Status
= EFI_OUT_OF_RESOURCES
;
852 ASSERT (Urb
->EvtRing
== &Xhc
->CtrlTrEventRing
);
853 Status
= XhcExecTransfer (Xhc
, FALSE
, Urb
, TimeOut
);
856 // Get the status from URB. The result is updated in XhcCheckUrbResult
857 // which is called by XhcExecTransfer
859 *TransferResult
= Urb
->Result
;
860 *DataLength
= Urb
->Completed
;
862 if (*TransferResult
== EFI_USB_NOERROR
) {
863 Status
= EFI_SUCCESS
;
864 } else if ((*TransferResult
== EFI_USB_ERR_STALL
) ||
865 (*TransferResult
== EFI_USB_ERR_TIMEOUT
)) {
866 RecoveryStatus
= XhcRecoverHaltedEndpoint(Xhc
, Urb
);
867 ASSERT_EFI_ERROR (RecoveryStatus
);
872 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
873 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
874 // Hook Set_Config request from UsbBus as we need configure device endpoint.
876 if (Request
->Request
== USB_REQ_GET_DESCRIPTOR
) {
877 DescriptorType
= (UINT8
)(Request
->Value
>> 8);
878 if ((DescriptorType
== USB_DESC_TYPE_DEVICE
) && (*DataLength
== sizeof (EFI_USB_DEVICE_DESCRIPTOR
))) {
880 // Store a copy of device scriptor as hub device need this info to configure endpoint.
882 CopyMem (&UsbDevContext
[SlotId
].DevDesc
, Data
, *DataLength
);
883 if (UsbDevContext
[SlotId
].DevDesc
.BcdUSB
== 0x0300) {
885 // If it's a usb3.0 device, then its max packet size is a 2^n.
887 MaxPacket0
= 1 << UsbDevContext
[SlotId
].DevDesc
.MaxPacketSize0
;
889 MaxPacket0
= UsbDevContext
[SlotId
].DevDesc
.MaxPacketSize0
;
891 UsbDevContext
[SlotId
].ConfDesc
= AllocateZeroPool (UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
* sizeof (EFI_USB_CONFIG_DESCRIPTOR
*));
892 Status
= XhcEvaluateContext (Xhc
, SlotId
, MaxPacket0
);
893 ASSERT_EFI_ERROR (Status
);
894 } else if ((DescriptorType
== USB_DESC_TYPE_CONFIG
) && (*DataLength
== ((UINT16
*)Data
)[1])) {
896 // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd.
898 Index
= (UINT8
)Request
->Value
;
899 ASSERT (Index
< UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
);
900 UsbDevContext
[SlotId
].ConfDesc
[Index
] = AllocateZeroPool(*DataLength
);
901 CopyMem (UsbDevContext
[SlotId
].ConfDesc
[Index
], Data
, *DataLength
);
902 } else if (((DescriptorType
== USB_DESC_TYPE_HUB
) ||
903 (DescriptorType
== USB_DESC_TYPE_HUB_SUPER_SPEED
))) {
904 HubDesc
= (EFI_USB_HUB_DESCRIPTOR
*)Data
;
906 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
908 TTT
= (UINT8
)((HubDesc
->HubCharacter
& (BIT5
| BIT6
)) >> 5);
909 if (UsbDevContext
[SlotId
].DevDesc
.DeviceProtocol
== 2) {
911 // BUGBUG: Don't support multi-TT feature for super speed hub.
919 Status
= XhcConfigHubContext (
927 } else if (Request
->Request
== USB_REQ_SET_CONFIG
) {
929 // Hook Set_Config request from UsbBus as we need configure device endpoint.
931 for (Index
= 0; Index
< UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
932 if (UsbDevContext
[SlotId
].ConfDesc
[Index
]->ConfigurationValue
== (UINT8
)Request
->Value
) {
933 XhcSetConfigCmd (Xhc
, SlotId
, DeviceSpeed
, UsbDevContext
[SlotId
].ConfDesc
[Index
]);
937 } else if (Request
->Request
== USB_REQ_GET_STATUS
) {
939 // Hook Get_Status request from UsbBus to keep track of the port status change.
941 State
= *(UINT32
*)Data
;
942 PortStatus
.PortStatus
= 0;
943 PortStatus
.PortChangeStatus
= 0;
945 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
947 // For super speed hub, its bit10~12 presents the attached device speed.
949 if ((*(UINT32
*)Data
& XHC_PORTSC_PS
) >> 10 == 0) {
950 PortStatus
.PortStatus
|= USB_PORT_STAT_SUPER_SPEED
;
952 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
954 // For high speed hub, its bit9~10 presents the attached device speed.
956 if (XHC_BIT_IS_SET (*(UINT32
*)Data
, BIT9
)) {
957 PortStatus
.PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
958 } else if (XHC_BIT_IS_SET (*(UINT32
*)Data
, BIT10
)) {
959 PortStatus
.PortStatus
|= USB_PORT_STAT_HIGH_SPEED
;
966 // Convert the XHCI port/port change state to UEFI status
968 MapSize
= sizeof (mUsbPortStateMap
) / sizeof (USB_PORT_STATE_MAP
);
969 for (Index
= 0; Index
< MapSize
; Index
++) {
970 if (XHC_BIT_IS_SET (*(UINT32
*)Data
, mUsbPortStateMap
[Index
].HwState
)) {
971 PortStatus
.PortStatus
= (UINT16
) (PortStatus
.PortStatus
| mUsbPortStateMap
[Index
].UefiState
);
974 MapSize
= sizeof (mUsbPortChangeMap
) / sizeof (USB_PORT_STATE_MAP
);
976 for (Index
= 0; Index
< MapSize
; Index
++) {
977 if (XHC_BIT_IS_SET (*(UINT32
*)Data
, mUsbPortChangeMap
[Index
].HwState
)) {
978 PortStatus
.PortChangeStatus
= (UINT16
) (PortStatus
.PortChangeStatus
| mUsbPortChangeMap
[Index
].UefiState
);
982 XhcPollPortStatusChange (Xhc
, UsbDevContext
[SlotId
].RouteString
, (UINT8
)Request
->Index
, &PortStatus
);
990 if (EFI_ERROR (Status
)) {
991 DEBUG ((EFI_D_ERROR
, "XhcControlTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
994 gBS
->RestoreTPL (OldTpl
);
1001 Submits bulk transfer to a bulk endpoint of a USB device.
1003 @param This This EFI_USB2_HC_PROTOCOL instance.
1004 @param DeviceAddress Target device address.
1005 @param EndPointAddress Endpoint number and its direction in bit 7.
1006 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
1008 @param MaximumPacketLength Maximum packet size the endpoint is capable of
1009 sending or receiving.
1010 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1011 @param Data Array of pointers to the buffers of data to transmit
1012 from or receive into.
1013 @param DataLength The lenght of the data buffer.
1014 @param DataToggle On input, the initial data toggle for the transfer;
1015 On output, it is updated to to next data toggle to
1016 use of the subsequent bulk transfer.
1017 @param TimeOut Indicates the maximum time, in millisecond, which
1018 the transfer is allowed to complete.
1019 @param Translator A pointr to the transaction translator data.
1020 @param TransferResult A pointer to the detailed result information of the
1023 @retval EFI_SUCCESS The transfer was completed successfully.
1024 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1025 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1026 @retval EFI_TIMEOUT The transfer failed due to timeout.
1027 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
1033 IN EFI_USB2_HC_PROTOCOL
*This
,
1034 IN UINT8 DeviceAddress
,
1035 IN UINT8 EndPointAddress
,
1036 IN UINT8 DeviceSpeed
,
1037 IN UINTN MaximumPacketLength
,
1038 IN UINT8 DataBuffersNumber
,
1039 IN OUT VOID
*Data
[EFI_USB_MAX_BULK_BUFFER_NUM
],
1040 IN OUT UINTN
*DataLength
,
1041 IN OUT UINT8
*DataToggle
,
1043 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1044 OUT UINT32
*TransferResult
1052 EFI_STATUS RecoveryStatus
;
1056 // Validate the parameters
1058 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
1059 (Data
== NULL
) || (Data
[0] == NULL
) || (TransferResult
== NULL
)) {
1060 return EFI_INVALID_PARAMETER
;
1063 if ((*DataToggle
!= 0) && (*DataToggle
!= 1)) {
1064 return EFI_INVALID_PARAMETER
;
1067 if ((DeviceSpeed
== EFI_USB_SPEED_LOW
) ||
1068 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
1069 ((EFI_USB_SPEED_HIGH
== DeviceSpeed
) && (MaximumPacketLength
> 512)) ||
1070 ((EFI_USB_SPEED_SUPER
== DeviceSpeed
) && (MaximumPacketLength
> 1024))) {
1071 return EFI_INVALID_PARAMETER
;
1074 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1076 Xhc
= XHC_FROM_THIS (This
);
1078 *TransferResult
= EFI_USB_ERR_SYSTEM
;
1079 Status
= EFI_DEVICE_ERROR
;
1081 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1082 DEBUG ((EFI_D_ERROR
, "XhcBulkTransfer: HC is halted\n"));
1087 // Check if the device is still enabled before every transaction.
1089 SlotId
= XhcBusDevAddrToSlotId (DeviceAddress
);
1095 // Acquire the actual device address assigned by XHCI's Address_Device cmd.
1097 XhciDevAddr
= UsbDevContext
[SlotId
].XhciDevAddr
;
1100 // Create a new URB, insert it into the asynchronous
1101 // schedule list, then poll the execution status.
1103 Urb
= XhcCreateUrb (
1108 MaximumPacketLength
,
1118 DEBUG ((EFI_D_ERROR
, "XhcBulkTransfer: failed to create URB\n"));
1119 Status
= EFI_OUT_OF_RESOURCES
;
1123 ASSERT (Urb
->EvtRing
== &Xhc
->BulkTrEventRing
);
1125 Status
= XhcExecTransfer (Xhc
, FALSE
, Urb
, TimeOut
);
1127 *TransferResult
= Urb
->Result
;
1128 *DataLength
= Urb
->Completed
;
1130 if (*TransferResult
== EFI_USB_NOERROR
) {
1131 Status
= EFI_SUCCESS
;
1132 } else if ((*TransferResult
== EFI_USB_ERR_STALL
) ||
1133 (*TransferResult
== EFI_USB_ERR_TIMEOUT
)) {
1134 RecoveryStatus
= XhcRecoverHaltedEndpoint(Xhc
, Urb
);
1135 ASSERT_EFI_ERROR (RecoveryStatus
);
1142 if (EFI_ERROR (Status
)) {
1143 DEBUG ((EFI_D_ERROR
, "XhcBulkTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
1145 gBS
->RestoreTPL (OldTpl
);
1151 Submits an asynchronous interrupt transfer to an
1152 interrupt endpoint of a USB device.
1154 @param This This EFI_USB2_HC_PROTOCOL instance.
1155 @param DeviceAddress Target device address.
1156 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1157 @param DeviceSpeed Indicates device speed.
1158 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1159 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
1160 transfer If FALSE, to remove the specified
1161 asynchronous interrupt.
1162 @param DataToggle On input, the initial data toggle to use; on output,
1163 it is updated to indicate the next data toggle.
1164 @param PollingInterval The he interval, in milliseconds, that the transfer
1166 @param DataLength The length of data to receive at the rate specified
1168 @param Translator Transaction translator to use.
1169 @param CallBackFunction Function to call at the rate specified by
1171 @param Context Context to CallBackFunction.
1173 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
1174 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1175 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
1176 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
1181 XhcAsyncInterruptTransfer (
1182 IN EFI_USB2_HC_PROTOCOL
*This
,
1183 IN UINT8 DeviceAddress
,
1184 IN UINT8 EndPointAddress
,
1185 IN UINT8 DeviceSpeed
,
1186 IN UINTN MaximumPacketLength
,
1187 IN BOOLEAN IsNewTransfer
,
1188 IN OUT UINT8
*DataToggle
,
1189 IN UINTN PollingInterval
,
1190 IN UINTN DataLength
,
1191 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1192 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction
,
1193 IN VOID
*Context OPTIONAL
1206 // Validate parameters
1208 if (!XHCI_IS_DATAIN (EndPointAddress
)) {
1209 return EFI_INVALID_PARAMETER
;
1212 if (IsNewTransfer
) {
1213 if (DataLength
== 0) {
1214 return EFI_INVALID_PARAMETER
;
1217 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1218 return EFI_INVALID_PARAMETER
;
1221 if ((PollingInterval
> 255) || (PollingInterval
< 1)) {
1222 return EFI_INVALID_PARAMETER
;
1226 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1228 Xhc
= XHC_FROM_THIS (This
);
1231 // Delete Async interrupt transfer request.
1233 if (!IsNewTransfer
) {
1235 // The delete request may happen after device is detached.
1237 for (Index
= 0; Index
< 255; Index
++) {
1238 if ((UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1239 (UsbDevContext
[Index
+ 1].BusDevAddr
== DeviceAddress
)) {
1245 Status
= EFI_INVALID_PARAMETER
;
1250 // Acquire the actual device address assigned by XHCI's Address_Device cmd.
1252 XhciDevAddr
= UsbDevContext
[Index
+ 1].XhciDevAddr
;
1254 Status
= XhciDelAsyncIntTransfer (Xhc
, XhciDevAddr
, EndPointAddress
);
1255 DEBUG ((EFI_D_INFO
, "XhcAsyncInterruptTransfer: remove old transfer, Status = %r\n", Status
));
1259 Status
= EFI_SUCCESS
;
1261 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1262 DEBUG ((EFI_D_ERROR
, "XhcAsyncInterruptTransfer: HC is halt\n"));
1263 Status
= EFI_DEVICE_ERROR
;
1268 // Check if the device is still enabled before every transaction.
1270 SlotId
= XhcBusDevAddrToSlotId (DeviceAddress
);
1276 // Acquire the actual device address assigned by XHCI's Address_Device cmd.
1278 XhciDevAddr
= UsbDevContext
[SlotId
].XhciDevAddr
;
1280 Data
= AllocatePool (DataLength
);
1283 DEBUG ((EFI_D_ERROR
, "XhcAsyncInterruptTransfer: failed to allocate buffer\n"));
1284 Status
= EFI_OUT_OF_RESOURCES
;
1288 Urb
= XhcCreateUrb (
1293 MaximumPacketLength
,
1294 XHC_INT_TRANSFER_ASYNC
,
1303 DEBUG ((EFI_D_ERROR
, "XhcAsyncInterruptTransfer: failed to create URB\n"));
1305 Status
= EFI_OUT_OF_RESOURCES
;
1309 ASSERT (Urb
->EvtRing
== &Xhc
->AsynIntTrEventRing
);
1311 InsertHeadList (&Xhc
->AsyncIntTransfers
, &Urb
->UrbList
);
1313 // Ring the doorbell
1315 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1318 gBS
->RestoreTPL (OldTpl
);
1325 Submits synchronous interrupt transfer to an interrupt endpoint
1328 @param This This EFI_USB2_HC_PROTOCOL instance.
1329 @param DeviceAddress Target device address.
1330 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1331 @param DeviceSpeed Indicates device speed.
1332 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1333 of sending or receiving.
1334 @param Data Buffer of data that will be transmitted to USB
1335 device or received from USB device.
1336 @param DataLength On input, the size, in bytes, of the data buffer; On
1337 output, the number of bytes transferred.
1338 @param DataToggle On input, the initial data toggle to use; on output,
1339 it is updated to indicate the next data toggle.
1340 @param TimeOut Maximum time, in second, to complete.
1341 @param Translator Transaction translator to use.
1342 @param TransferResult Variable to receive the transfer result.
1344 @return EFI_SUCCESS The transfer was completed successfully.
1345 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1346 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1347 @return EFI_TIMEOUT The transfer failed due to timeout.
1348 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1353 XhcSyncInterruptTransfer (
1354 IN EFI_USB2_HC_PROTOCOL
*This
,
1355 IN UINT8 DeviceAddress
,
1356 IN UINT8 EndPointAddress
,
1357 IN UINT8 DeviceSpeed
,
1358 IN UINTN MaximumPacketLength
,
1360 IN OUT UINTN
*DataLength
,
1361 IN OUT UINT8
*DataToggle
,
1363 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1364 OUT UINT32
*TransferResult
1372 EFI_STATUS RecoveryStatus
;
1376 // Validates parameters
1378 if ((DataLength
== NULL
) || (*DataLength
== 0) ||
1379 (Data
== NULL
) || (TransferResult
== NULL
)) {
1380 return EFI_INVALID_PARAMETER
;
1383 if (!XHCI_IS_DATAIN (EndPointAddress
)) {
1384 return EFI_INVALID_PARAMETER
;
1387 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
1388 return EFI_INVALID_PARAMETER
;
1391 if (((DeviceSpeed
== EFI_USB_SPEED_LOW
) && (MaximumPacketLength
!= 8)) ||
1392 ((DeviceSpeed
== EFI_USB_SPEED_FULL
) && (MaximumPacketLength
> 64)) ||
1393 ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) && (MaximumPacketLength
> 3072))) {
1394 return EFI_INVALID_PARAMETER
;
1397 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1399 Xhc
= XHC_FROM_THIS (This
);
1401 *TransferResult
= EFI_USB_ERR_SYSTEM
;
1402 Status
= EFI_DEVICE_ERROR
;
1404 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1405 DEBUG ((EFI_D_ERROR
, "EhcSyncInterruptTransfer: HC is halt\n"));
1410 // Check if the device is still enabled before every transaction.
1412 SlotId
= XhcBusDevAddrToSlotId (DeviceAddress
);
1418 // Acquire the actual device address assigned by XHCI's Address_Device cmd.
1420 XhciDevAddr
= UsbDevContext
[SlotId
].XhciDevAddr
;
1422 Urb
= XhcCreateUrb (
1427 MaximumPacketLength
,
1428 XHC_INT_TRANSFER_SYNC
,
1437 DEBUG ((EFI_D_ERROR
, "XhcSyncInterruptTransfer: failed to create URB\n"));
1438 Status
= EFI_OUT_OF_RESOURCES
;
1442 Status
= XhcExecTransfer (Xhc
, FALSE
, Urb
, TimeOut
);
1444 *TransferResult
= Urb
->Result
;
1445 *DataLength
= Urb
->Completed
;
1447 if (*TransferResult
== EFI_USB_NOERROR
) {
1448 Status
= EFI_SUCCESS
;
1449 } else if ((*TransferResult
== EFI_USB_ERR_STALL
) ||
1450 (*TransferResult
== EFI_USB_ERR_TIMEOUT
)) {
1451 RecoveryStatus
= XhcRecoverHaltedEndpoint(Xhc
, Urb
);
1452 ASSERT_EFI_ERROR (RecoveryStatus
);
1458 if (EFI_ERROR (Status
)) {
1459 DEBUG ((EFI_D_ERROR
, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status
, *TransferResult
));
1461 gBS
->RestoreTPL (OldTpl
);
1468 Submits isochronous transfer to a target USB device.
1470 @param This This EFI_USB2_HC_PROTOCOL instance.
1471 @param DeviceAddress Target device address.
1472 @param EndPointAddress End point address with its direction.
1473 @param DeviceSpeed Device speed, Low speed device doesn't support this
1475 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1476 sending or receiving.
1477 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1478 @param Data Array of pointers to the buffers of data that will
1479 be transmitted to USB device or received from USB
1481 @param DataLength The size, in bytes, of the data buffer.
1482 @param Translator Transaction translator to use.
1483 @param TransferResult Variable to receive the transfer result.
1485 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1490 XhcIsochronousTransfer (
1491 IN EFI_USB2_HC_PROTOCOL
*This
,
1492 IN UINT8 DeviceAddress
,
1493 IN UINT8 EndPointAddress
,
1494 IN UINT8 DeviceSpeed
,
1495 IN UINTN MaximumPacketLength
,
1496 IN UINT8 DataBuffersNumber
,
1497 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1498 IN UINTN DataLength
,
1499 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1500 OUT UINT32
*TransferResult
1503 return EFI_UNSUPPORTED
;
1508 Submits Async isochronous transfer to a target USB device.
1510 @param This This EFI_USB2_HC_PROTOCOL instance.
1511 @param DeviceAddress Target device address.
1512 @param EndPointAddress End point address with its direction.
1513 @param DeviceSpeed Device speed, Low speed device doesn't support this
1515 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1516 sending or receiving.
1517 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1518 @param Data Array of pointers to the buffers of data that will
1519 be transmitted to USB device or received from USB
1521 @param DataLength The size, in bytes, of the data buffer.
1522 @param Translator Transaction translator to use.
1523 @param IsochronousCallBack Function to be called when the transfer complete.
1524 @param Context Context passed to the call back function as
1527 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1532 XhcAsyncIsochronousTransfer (
1533 IN EFI_USB2_HC_PROTOCOL
*This
,
1534 IN UINT8 DeviceAddress
,
1535 IN UINT8 EndPointAddress
,
1536 IN UINT8 DeviceSpeed
,
1537 IN UINTN MaximumPacketLength
,
1538 IN UINT8 DataBuffersNumber
,
1539 IN OUT VOID
*Data
[EFI_USB_MAX_ISO_BUFFER_NUM
],
1540 IN UINTN DataLength
,
1541 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Translator
,
1542 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack
,
1546 return EFI_UNSUPPORTED
;
1550 Entry point for EFI drivers.
1552 @param ImageHandle EFI_HANDLE.
1553 @param SystemTable EFI_SYSTEM_TABLE.
1555 @retval EFI_SUCCESS Success.
1556 @retval Others Fail.
1561 XhcDriverEntryPoint (
1562 IN EFI_HANDLE ImageHandle
,
1563 IN EFI_SYSTEM_TABLE
*SystemTable
1566 return EfiLibInstallDriverBindingComponentName2 (
1569 &gXhciDriverBinding
,
1571 &gXhciComponentName
,
1572 &gXhciComponentName2
1578 Test to see if this driver supports ControllerHandle. Any
1579 ControllerHandle that has Usb2HcProtocol installed will
1582 @param This Protocol instance pointer.
1583 @param Controller Handle of device to test.
1584 @param RemainingDevicePath Not used.
1586 @return EFI_SUCCESS This driver supports this device.
1587 @return EFI_UNSUPPORTED This driver does not support this device.
1592 XhcDriverBindingSupported (
1593 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1594 IN EFI_HANDLE Controller
,
1595 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1599 EFI_PCI_IO_PROTOCOL
*PciIo
;
1600 USB_CLASSC UsbClassCReg
;
1603 // Test whether there is PCI IO Protocol attached on the controller handle.
1605 Status
= gBS
->OpenProtocol (
1607 &gEfiPciIoProtocolGuid
,
1609 This
->DriverBindingHandle
,
1611 EFI_OPEN_PROTOCOL_BY_DRIVER
1614 if (EFI_ERROR (Status
)) {
1615 return EFI_UNSUPPORTED
;
1618 Status
= PciIo
->Pci
.Read (
1621 PCI_CLASSCODE_OFFSET
,
1622 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1626 if (EFI_ERROR (Status
)) {
1627 Status
= EFI_UNSUPPORTED
;
1632 // Test whether the controller belongs to Xhci type
1634 if ((UsbClassCReg
.BaseCode
!= PCI_CLASS_SERIAL
) ||
1635 (UsbClassCReg
.SubClassCode
!= PCI_CLASS_SERIAL_USB
) ||
1636 (UsbClassCReg
.ProgInterface
!= PCI_IF_XHCI
)) {
1637 Status
= EFI_UNSUPPORTED
;
1641 gBS
->CloseProtocol (
1643 &gEfiPciIoProtocolGuid
,
1644 This
->DriverBindingHandle
,
1652 Create and initialize a USB_XHCI_DEV.
1654 @param PciIo The PciIo on this device.
1655 @param OriginalPciAttributes Original PCI attributes.
1657 @return The allocated and initialized USB_XHCI_DEV structure if created,
1663 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1664 IN UINT64 OriginalPciAttributes
1672 ZeroMem (UsbDevContext
, sizeof (UsbDevContext
));
1674 Xhc
= AllocateZeroPool (sizeof (USB_XHCI_DEV
));
1681 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1683 Xhc
->Signature
= USB_XHCI_DEV_SIGNATURE
;
1685 Xhc
->Usb2Hc
.GetCapability
= XhcGetCapability
;
1686 Xhc
->Usb2Hc
.Reset
= XhcReset
;
1687 Xhc
->Usb2Hc
.GetState
= XhcGetState
;
1688 Xhc
->Usb2Hc
.SetState
= XhcSetState
;
1689 Xhc
->Usb2Hc
.ControlTransfer
= XhcControlTransfer
;
1690 Xhc
->Usb2Hc
.BulkTransfer
= XhcBulkTransfer
;
1691 Xhc
->Usb2Hc
.AsyncInterruptTransfer
= XhcAsyncInterruptTransfer
;
1692 Xhc
->Usb2Hc
.SyncInterruptTransfer
= XhcSyncInterruptTransfer
;
1693 Xhc
->Usb2Hc
.IsochronousTransfer
= XhcIsochronousTransfer
;
1694 Xhc
->Usb2Hc
.AsyncIsochronousTransfer
= XhcAsyncIsochronousTransfer
;
1695 Xhc
->Usb2Hc
.GetRootHubPortStatus
= XhcGetRootHubPortStatus
;
1696 Xhc
->Usb2Hc
.SetRootHubPortFeature
= XhcSetRootHubPortFeature
;
1697 Xhc
->Usb2Hc
.ClearRootHubPortFeature
= XhcClearRootHubPortFeature
;
1698 Xhc
->Usb2Hc
.MajorRevision
= 0x3;
1699 Xhc
->Usb2Hc
.MinorRevision
= 0x0;
1702 Xhc
->OriginalPciAttributes
= OriginalPciAttributes
;
1704 InitializeListHead (&Xhc
->AsyncIntTransfers
);
1707 // Be caution that the Offset passed to XhcReadCapReg() should be Dword align
1709 Xhc
->CapLength
= XhcReadCapReg8 (Xhc
, XHC_CAPLENGTH_OFFSET
);
1710 Xhc
->HcSParams1
.Dword
= XhcReadCapReg (Xhc
, XHC_HCSPARAMS1_OFFSET
);
1711 Xhc
->HcSParams2
.Dword
= XhcReadCapReg (Xhc
, XHC_HCSPARAMS2_OFFSET
);
1712 Xhc
->HcCParams
.Dword
= XhcReadCapReg (Xhc
, XHC_HCCPARAMS_OFFSET
);
1713 Xhc
->DBOff
= XhcReadCapReg (Xhc
, XHC_DBOFF_OFFSET
);
1714 Xhc
->RTSOff
= XhcReadCapReg (Xhc
, XHC_RTSOFF_OFFSET
);
1717 // This PageSize field defines the page size supported by the xHC implementation.
1718 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1719 // if bit 0 is Set, the xHC supports 4k byte page sizes.
1721 PageSize
= XhcReadOpReg(Xhc
, XHC_PAGESIZE_OFFSET
) & XHC_PAGESIZE_MASK
;
1722 Xhc
->PageSize
= 1 << (HighBitSet32(PageSize
) + 12);
1723 ASSERT (Xhc
->PageSize
== 0x1000);
1725 ExtCapReg
= (UINT16
) (Xhc
->HcCParams
.Data
.ExtCapReg
);
1726 Xhc
->ExtCapRegBase
= ExtCapReg
<< 2;
1727 Xhc
->UsbLegSupOffset
= XhcGetLegSupCapAddr (Xhc
);
1729 DEBUG ((EFI_D_INFO
, "XhcCreateUsb3Hc: capability length 0x%x\n", Xhc
->CapLength
));
1730 DEBUG ((EFI_D_INFO
, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc
->HcSParams1
));
1731 DEBUG ((EFI_D_INFO
, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc
->HcSParams2
));
1732 DEBUG ((EFI_D_INFO
, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc
->HcCParams
));
1733 DEBUG ((EFI_D_INFO
, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc
->DBOff
));
1734 DEBUG ((EFI_D_INFO
, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc
->RTSOff
));
1735 DEBUG ((EFI_D_INFO
, "XhcCreateUsb3Hc: Xhc->UsbLegSupOffset 0x%x\n", Xhc
->UsbLegSupOffset
));
1738 // Create AsyncRequest Polling Timer
1740 Status
= gBS
->CreateEvent (
1741 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1743 XhcMonitorAsyncRequests
,
1748 if (EFI_ERROR (Status
)) {
1760 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1762 @param Event Pointer to this event
1763 @param Context Event hanlder private data
1768 XhcExitBootService (
1775 EFI_PCI_IO_PROTOCOL
*PciIo
;
1777 Xhc
= (USB_XHCI_DEV
*) Context
;
1781 // Stop AsyncRequest Polling timer then stop the XHCI driver
1782 // and uninstall the XHCI protocl.
1784 gBS
->SetTimer (Xhc
->PollTimer
, TimerCancel
, XHC_ASYNC_POLL_INTERVAL
);
1785 XhcHaltHC (Xhc
, XHC_GENERIC_TIMEOUT
);
1787 if (Xhc
->PollTimer
!= NULL
) {
1788 gBS
->CloseEvent (Xhc
->PollTimer
);
1792 // Restore original PCI attributes
1796 EfiPciIoAttributeOperationSet
,
1797 Xhc
->OriginalPciAttributes
,
1801 XhcClearBiosOwnership (Xhc
);
1805 Starting the Usb XHCI Driver.
1807 @param This Protocol instance pointer.
1808 @param Controller Handle of device to test.
1809 @param RemainingDevicePath Not used.
1811 @return EFI_SUCCESS supports this device.
1812 @return EFI_UNSUPPORTED do not support this device.
1813 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1814 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1819 XhcDriverBindingStart (
1820 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1821 IN EFI_HANDLE Controller
,
1822 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1826 EFI_PCI_IO_PROTOCOL
*PciIo
;
1828 UINT64 OriginalPciAttributes
;
1829 BOOLEAN PciAttributesSaved
;
1833 // Open the PciIo Protocol, then enable the USB host controller
1835 Status
= gBS
->OpenProtocol (
1837 &gEfiPciIoProtocolGuid
,
1839 This
->DriverBindingHandle
,
1841 EFI_OPEN_PROTOCOL_BY_DRIVER
1844 if (EFI_ERROR (Status
)) {
1848 PciAttributesSaved
= FALSE
;
1850 // Save original PCI attributes
1852 Status
= PciIo
->Attributes (
1854 EfiPciIoAttributeOperationGet
,
1856 &OriginalPciAttributes
1859 if (EFI_ERROR (Status
)) {
1862 PciAttributesSaved
= TRUE
;
1864 Status
= PciIo
->Attributes (
1866 EfiPciIoAttributeOperationSupported
,
1870 if (!EFI_ERROR (Status
)) {
1871 Supports
&= EFI_PCI_DEVICE_ENABLE
;
1872 Status
= PciIo
->Attributes (
1874 EfiPciIoAttributeOperationEnable
,
1880 if (EFI_ERROR (Status
)) {
1881 DEBUG ((EFI_D_ERROR
, "XhcDriverBindingStart: failed to enable controller\n"));
1886 // Create then install USB2_HC_PROTOCOL
1888 Xhc
= XhcCreateUsbHc (PciIo
, OriginalPciAttributes
);
1891 DEBUG ((EFI_D_ERROR
, "XhcDriverBindingStart: failed to create USB2_HC\n"));
1892 return EFI_OUT_OF_RESOURCES
;
1895 XhcSetBiosOwnership (Xhc
);
1897 XhcResetHC (Xhc
, XHC_RESET_TIMEOUT
);
1898 ASSERT (XhcIsHalt (Xhc
));
1901 // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag
1902 // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.
1904 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc
, XHC_USBSTS_OFFSET
, XHC_USBSTS_CNR
)));
1907 // Initialize the schedule
1912 // Start the Host Controller
1914 XhcRunHC(Xhc
, XHC_GENERIC_TIMEOUT
);
1917 // Start the asynchronous interrupt monitor
1919 Status
= gBS
->SetTimer (Xhc
->PollTimer
, TimerPeriodic
, XHC_ASYNC_POLL_INTERVAL
);
1920 if (EFI_ERROR (Status
)) {
1921 DEBUG ((EFI_D_ERROR
, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));
1922 XhcHaltHC (Xhc
, XHC_GENERIC_TIMEOUT
);
1927 // Create event to stop the HC when exit boot service.
1929 Status
= gBS
->CreateEventEx (
1934 &gEfiEventExitBootServicesGuid
,
1935 &Xhc
->ExitBootServiceEvent
1937 if (EFI_ERROR (Status
)) {
1942 // Install the component name protocol, don't fail the start
1943 // because of something for display.
1947 gXhciComponentName
.SupportedLanguages
,
1948 &Xhc
->ControllerNameTable
,
1949 L
"eXtensible Host Controller (USB 3.0)",
1954 gXhciComponentName2
.SupportedLanguages
,
1955 &Xhc
->ControllerNameTable
,
1956 L
"eXtensible Host Controller (USB 3.0)",
1960 Status
= gBS
->InstallProtocolInterface (
1962 &gEfiUsb2HcProtocolGuid
,
1963 EFI_NATIVE_INTERFACE
,
1966 if (EFI_ERROR (Status
)) {
1967 DEBUG ((EFI_D_ERROR
, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1971 DEBUG ((EFI_D_INFO
, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller
));
1975 gBS
->CloseEvent (Xhc
->PollTimer
);
1980 if (PciAttributesSaved
) {
1982 // Restore original PCI attributes
1986 EfiPciIoAttributeOperationSet
,
1987 OriginalPciAttributes
,
1992 gBS
->CloseProtocol (
1994 &gEfiPciIoProtocolGuid
,
1995 This
->DriverBindingHandle
,
2004 Stop this driver on ControllerHandle. Support stoping any child handles
2005 created by this driver.
2007 @param This Protocol instance pointer.
2008 @param Controller Handle of device to stop driver on.
2009 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
2010 @param ChildHandleBuffer List of handles for the children we need to stop.
2012 @return EFI_SUCCESS Success.
2013 @return EFI_DEVICE_ERROR Fail.
2018 XhcDriverBindingStop (
2019 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2020 IN EFI_HANDLE Controller
,
2021 IN UINTN NumberOfChildren
,
2022 IN EFI_HANDLE
*ChildHandleBuffer
2026 EFI_USB2_HC_PROTOCOL
*Usb2Hc
;
2027 EFI_PCI_IO_PROTOCOL
*PciIo
;
2031 // Test whether the Controller handler passed in is a valid
2032 // Usb controller handle that should be supported, if not,
2033 // return the error status directly
2035 Status
= gBS
->OpenProtocol (
2037 &gEfiUsb2HcProtocolGuid
,
2039 This
->DriverBindingHandle
,
2041 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2044 if (EFI_ERROR (Status
)) {
2048 Xhc
= XHC_FROM_THIS (Usb2Hc
);
2052 // Stop AsyncRequest Polling timer then stop the XHCI driver
2053 // and uninstall the XHCI protocl.
2055 gBS
->SetTimer (Xhc
->PollTimer
, TimerCancel
, XHC_ASYNC_POLL_INTERVAL
);
2056 XhcHaltHC (Xhc
, XHC_GENERIC_TIMEOUT
);
2057 XhcClearBiosOwnership (Xhc
);
2059 Status
= gBS
->UninstallProtocolInterface (
2061 &gEfiUsb2HcProtocolGuid
,
2065 if (EFI_ERROR (Status
)) {
2069 if (Xhc
->PollTimer
!= NULL
) {
2070 gBS
->CloseEvent (Xhc
->PollTimer
);
2073 if (Xhc
->ExitBootServiceEvent
!= NULL
) {
2074 gBS
->CloseEvent (Xhc
->ExitBootServiceEvent
);
2077 XhciDelAllAsyncIntTransfers (Xhc
);
2080 if (Xhc
->ControllerNameTable
) {
2081 FreeUnicodeStringTable (Xhc
->ControllerNameTable
);
2085 // Restore original PCI attributes
2089 EfiPciIoAttributeOperationSet
,
2090 Xhc
->OriginalPciAttributes
,
2094 gBS
->CloseProtocol (
2096 &gEfiPciIoProtocolGuid
,
2097 This
->DriverBindingHandle
,