2 PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
5 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
14 Stop the host controller.
16 @param Uhc The UHCI device.
17 @param Timeout Max time allowed.
19 @retval EFI_SUCCESS The host controller is stopped.
20 @retval EFI_TIMEOUT Failed to stop the host controller.
29 UINT16 CommandContent
;
33 CommandContent
= USBReadPortW (Uhc
, Uhc
->UsbHostControllerBaseAddress
+ USBCMD
);
34 CommandContent
&= USBCMD_RS
;
35 USBWritePortW (Uhc
, Uhc
->UsbHostControllerBaseAddress
+ USBCMD
, CommandContent
);
38 // ensure the HC is in halt status after send the stop command
39 // Timeout is in us unit.
41 for (Index
= 0; Index
< (Timeout
/ 50) + 1; Index
++) {
42 UsbSts
= USBReadPortW (Uhc
, Uhc
->UsbHostControllerBaseAddress
+ USBSTS
);
44 if ((UsbSts
& USBSTS_HCH
) == USBSTS_HCH
) {
48 MicroSecondDelay (50);
55 One notified function to stop the Host Controller at the end of PEI
57 @param[in] PeiServices Pointer to PEI Services Table.
58 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
59 caused this function to execute.
60 @param[in] Ppi Pointer to the PPI data associated with this function.
62 @retval EFI_SUCCESS The function completes successfully
68 IN EFI_PEI_SERVICES
**PeiServices
,
69 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
75 Uhc
= PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor
);
78 // Stop the Host Controller
80 UhciStopHc (Uhc
, 1000 * 1000);
86 Initializes Usb Host Controller.
88 @param FileHandle Handle of the file being invoked.
89 @param PeiServices Describes the list of possible PEI Services.
91 @retval EFI_SUCCESS PPI successfully installed.
92 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
98 IN EFI_PEI_FILE_HANDLE FileHandle
,
99 IN CONST EFI_PEI_SERVICES
**PeiServices
102 PEI_USB_CONTROLLER_PPI
*ChipSetUsbControllerPpi
;
105 UINTN ControllerType
;
109 EFI_PHYSICAL_ADDRESS TempPtr
;
112 // Shadow this PEIM to run from memory
114 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
118 Status
= PeiServicesLocatePpi (
119 &gPeiUsbControllerPpiGuid
,
122 (VOID
**)&ChipSetUsbControllerPpi
125 // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.
127 ASSERT_EFI_ERROR (Status
);
131 Status
= ChipSetUsbControllerPpi
->GetUsbController (
132 (EFI_PEI_SERVICES
**)PeiServices
,
133 ChipSetUsbControllerPpi
,
139 // When status is error, meant no controller is found
141 if (EFI_ERROR (Status
)) {
146 // This PEIM is for UHC type controller.
148 if (ControllerType
!= PEI_UHCI_CONTROLLER
) {
153 MemPages
= sizeof (USB_UHC_DEV
) / EFI_PAGE_SIZE
+ 1;
155 Status
= PeiServicesAllocatePages (
160 if (EFI_ERROR (Status
)) {
161 return EFI_OUT_OF_RESOURCES
;
164 UhcDev
= (USB_UHC_DEV
*)((UINTN
)TempPtr
);
165 UhcDev
->Signature
= USB_UHC_DEV_SIGNATURE
;
166 IoMmuInit (&UhcDev
->IoMmu
);
167 UhcDev
->UsbHostControllerBaseAddress
= (UINT32
)BaseAddress
;
170 // Init local memory management service
172 Status
= InitializeMemoryManagement (UhcDev
);
173 if (EFI_ERROR (Status
)) {
178 // Initialize Uhc's hardware
180 Status
= InitializeUsbHC (UhcDev
);
181 if (EFI_ERROR (Status
)) {
185 UhcDev
->UsbHostControllerPpi
.ControlTransfer
= UhcControlTransfer
;
186 UhcDev
->UsbHostControllerPpi
.BulkTransfer
= UhcBulkTransfer
;
187 UhcDev
->UsbHostControllerPpi
.GetRootHubPortNumber
= UhcGetRootHubPortNumber
;
188 UhcDev
->UsbHostControllerPpi
.GetRootHubPortStatus
= UhcGetRootHubPortStatus
;
189 UhcDev
->UsbHostControllerPpi
.SetRootHubPortFeature
= UhcSetRootHubPortFeature
;
190 UhcDev
->UsbHostControllerPpi
.ClearRootHubPortFeature
= UhcClearRootHubPortFeature
;
192 UhcDev
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
193 UhcDev
->PpiDescriptor
.Guid
= &gPeiUsbHostControllerPpiGuid
;
194 UhcDev
->PpiDescriptor
.Ppi
= &UhcDev
->UsbHostControllerPpi
;
196 Status
= PeiServicesInstallPpi (&UhcDev
->PpiDescriptor
);
197 if (EFI_ERROR (Status
)) {
202 UhcDev
->EndOfPeiNotifyList
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
203 UhcDev
->EndOfPeiNotifyList
.Guid
= &gEfiEndOfPeiSignalPpiGuid
;
204 UhcDev
->EndOfPeiNotifyList
.Notify
= UhcEndOfPei
;
206 PeiServicesNotifyPpi (&UhcDev
->EndOfPeiNotifyList
);
215 Submits control transfer to a target USB device.
217 @param PeiServices The pointer of EFI_PEI_SERVICES.
218 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
219 @param DeviceAddress The target device address.
220 @param DeviceSpeed Target device speed.
221 @param MaximumPacketLength Maximum packet size the default control transfer
222 endpoint is capable of sending or receiving.
223 @param Request USB device request to send.
224 @param TransferDirection Specifies the data direction for the data stage.
225 @param Data Data buffer to be transmitted or received from USB device.
226 @param DataLength The size (in bytes) of the data buffer.
227 @param TimeOut Indicates the maximum timeout, in millisecond.
228 If Timeout is 0, then the caller must wait for the function
229 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
230 @param TransferResult Return the result of this control transfer.
232 @retval EFI_SUCCESS Transfer was completed successfully.
233 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
234 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
235 @retval EFI_TIMEOUT Transfer failed due to timeout.
236 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
242 IN EFI_PEI_SERVICES
**PeiServices
,
243 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
244 IN UINT8 DeviceAddress
,
245 IN UINT8 DeviceSpeed
,
246 IN UINT8 MaximumPacketLength
,
247 IN EFI_USB_DEVICE_REQUEST
*Request
,
248 IN EFI_USB_DATA_DIRECTION TransferDirection
,
249 IN OUT VOID
*Data OPTIONAL
,
250 IN OUT UINTN
*DataLength OPTIONAL
,
252 OUT UINT32
*TransferResult
261 TD_STRUCT
*PtrSetupTD
;
262 TD_STRUCT
*PtrStatusTD
;
271 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
273 StatusReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBSTS
;
275 PktID
= INPUT_PACKET_ID
;
279 if ((Request
== NULL
) || (TransferResult
== NULL
)) {
280 return EFI_INVALID_PARAMETER
;
284 // if errors exist that cause host controller halt,
285 // then return EFI_DEVICE_ERROR.
288 if (!IsStatusOK (UhcDev
, StatusReg
)) {
289 ClearStatusReg (UhcDev
, StatusReg
);
290 *TransferResult
= EFI_USB_ERR_SYSTEM
;
291 return EFI_DEVICE_ERROR
;
294 ClearStatusReg (UhcDev
, StatusReg
);
297 // Map the Request and data for bus master access,
298 // then create a list of TD for this transfer
300 Status
= UhciMapUserRequest (UhcDev
, Request
, &RequestPhy
, &RequestMap
);
301 if (EFI_ERROR (Status
)) {
305 Status
= UhciMapUserData (UhcDev
, TransferDirection
, Data
, DataLength
, &PktID
, &DataPhy
, &DataMap
);
307 if (EFI_ERROR (Status
)) {
308 if (RequestMap
!= NULL
) {
309 IoMmuUnmap (UhcDev
->IoMmu
, RequestMap
);
316 // generate Setup Stage TD
319 PtrQH
= UhcDev
->ConfigQH
;
328 (UINT8
)sizeof (EFI_USB_DEVICE_REQUEST
),
333 // link setup TD structures to QH structure
335 LinkTDToQH (PtrQH
, PtrSetupTD
);
337 PtrPreTD
= PtrSetupTD
;
340 // Data Stage of Control Transfer
343 if (TransferDirection
== EfiUsbNoData
) {
346 DataLen
= (UINT32
)*DataLength
;
352 while (DataLen
> 0) {
354 // create TD structures and link together
359 // PacketSize is the data load size of each TD carries.
361 PacketSize
= (UINT8
)DataLen
;
362 if (DataLen
> MaximumPacketLength
) {
363 PacketSize
= MaximumPacketLength
;
380 // Link two TDs in vertical depth
382 LinkTDToTD (PtrPreTD
, PtrTD
);
386 Data
= (VOID
*)((UINT8
*)Data
+ PacketSize
);
387 DataPhy
+= PacketSize
;
388 DataLen
-= PacketSize
;
392 // PtrPreTD points to the last TD before the Setup-Stage TD.
397 // Status Stage of Control Transfer
399 if (PktID
== OUTPUT_PACKET_ID
) {
400 PktID
= INPUT_PACKET_ID
;
402 PktID
= OUTPUT_PACKET_ID
;
406 // create Status Stage TD structure
417 LinkTDToTD (PtrPreTD
, PtrStatusTD
);
420 // Poll QH-TDs execution and get result.
421 // detail status is returned
423 Status
= ExecuteControlTransfer (
432 // TRUE means must search other framelistindex
434 SetQHVerticalValidorInvalid (PtrQH
, FALSE
);
435 DeleteQueuedTDs (UhcDev
, PtrSetupTD
);
438 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
440 if (!IsStatusOK (UhcDev
, StatusReg
)) {
441 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
442 Status
= EFI_DEVICE_ERROR
;
445 ClearStatusReg (UhcDev
, StatusReg
);
447 if (DataMap
!= NULL
) {
448 IoMmuUnmap (UhcDev
->IoMmu
, DataMap
);
451 if (RequestMap
!= NULL
) {
452 IoMmuUnmap (UhcDev
->IoMmu
, RequestMap
);
459 Submits bulk transfer to a bulk endpoint of a USB device.
461 @param PeiServices The pointer of EFI_PEI_SERVICES.
462 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
463 @param DeviceAddress Target device address.
464 @param EndPointAddress Endpoint number and its direction in bit 7.
465 @param MaximumPacketLength Maximum packet size the endpoint is capable of
466 sending or receiving.
467 @param Data Array of pointers to the buffers of data to transmit
468 from or receive into.
469 @param DataLength The lenght of the data buffer.
470 @param DataToggle On input, the initial data toggle for the transfer;
471 On output, it is updated to to next data toggle to use of
472 the subsequent bulk transfer.
473 @param TimeOut Indicates the maximum time, in millisecond, which the
474 transfer is allowed to complete.
475 If Timeout is 0, then the caller must wait for the function
476 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
477 @param TransferResult A pointer to the detailed result information of the
480 @retval EFI_SUCCESS The transfer was completed successfully.
481 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
482 @retval EFI_INVALID_PARAMETER Parameters are invalid.
483 @retval EFI_TIMEOUT The transfer failed due to timeout.
484 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
490 IN EFI_PEI_SERVICES
**PeiServices
,
491 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
492 IN UINT8 DeviceAddress
,
493 IN UINT8 EndPointAddress
,
494 IN UINT8 MaximumPacketLength
,
496 IN OUT UINTN
*DataLength
,
497 IN OUT UINT8
*DataToggle
,
499 OUT UINT32
*TransferResult
508 TD_STRUCT
*PtrFirstTD
;
518 EFI_USB_DATA_DIRECTION TransferDirection
;
520 BOOLEAN ShortPacketEnable
;
522 UINT16 CommandContent
;
527 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
530 // Enable the maximum packet size (64bytes)
531 // that can be used for full speed bandwidth reclamation
532 // at the end of a frame.
534 CommandContent
= USBReadPortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
);
535 if ((CommandContent
& USBCMD_MAXP
) != USBCMD_MAXP
) {
536 CommandContent
|= USBCMD_MAXP
;
537 USBWritePortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
, CommandContent
);
540 StatusReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBSTS
;
543 // these code lines are added here per complier's strict demand
545 PktID
= INPUT_PACKET_ID
;
551 ShortPacketEnable
= FALSE
;
553 if ((DataLength
== 0) || (Data
== NULL
) || (TransferResult
== NULL
)) {
554 return EFI_INVALID_PARAMETER
;
557 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
558 return EFI_INVALID_PARAMETER
;
561 if ( (MaximumPacketLength
!= 8) && (MaximumPacketLength
!= 16)
562 && (MaximumPacketLength
!= 32) && (MaximumPacketLength
!= 64))
564 return EFI_INVALID_PARAMETER
;
568 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
570 if (!IsStatusOK (UhcDev
, StatusReg
)) {
571 ClearStatusReg (UhcDev
, StatusReg
);
572 *TransferResult
= EFI_USB_ERR_SYSTEM
;
573 return EFI_DEVICE_ERROR
;
576 ClearStatusReg (UhcDev
, StatusReg
);
579 // Map the source data buffer for bus master access,
580 // then create a list of TDs
582 if ((EndPointAddress
& 0x80) != 0) {
583 TransferDirection
= EfiUsbDataIn
;
585 TransferDirection
= EfiUsbDataOut
;
588 Status
= UhciMapUserData (UhcDev
, TransferDirection
, Data
, DataLength
, &PktID
, &DataPhy
, &DataMap
);
590 if (EFI_ERROR (Status
)) {
594 DataLen
= (UINT32
)*DataLength
;
596 PtrQH
= UhcDev
->BulkQH
;
599 while (DataLen
> 0) {
601 // create TD structures and link together
605 PacketSize
= (UINT8
)DataLen
;
606 if (DataLen
> MaximumPacketLength
) {
607 PacketSize
= MaximumPacketLength
;
619 USB_FULL_SPEED_DEVICE
,
624 // Enable short packet detection.
625 // (default action is disabling short packet detection)
627 if (ShortPacketEnable
) {
628 EnableorDisableTDShortPacket (PtrTD
, TRUE
);
633 PtrFirstTD
->PtrNextTD
= NULL
;
637 // Link two TDs in vertical depth
639 LinkTDToTD (PtrPreTD
, PtrTD
);
645 Data
= (VOID
*)((UINT8
*)Data
+ PacketSize
);
646 DataPhy
+= PacketSize
;
647 DataLen
-= PacketSize
;
651 // link TD structures to QH structure
653 LinkTDToQH (PtrQH
, PtrFirstTD
);
656 // Execute QH-TD and get result
659 // detail status is put into the Result field in the pIRP
660 // the Data Toggle value is also re-updated to the value
661 // of the last successful TD
663 Status
= ExecBulkTransfer (
673 // Delete Bulk transfer TD structure
675 DeleteQueuedTDs (UhcDev
, PtrFirstTD
);
678 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
680 if (!IsStatusOK (UhcDev
, StatusReg
)) {
681 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
682 Status
= EFI_DEVICE_ERROR
;
685 ClearStatusReg (UhcDev
, StatusReg
);
687 if (DataMap
!= NULL
) {
688 IoMmuUnmap (UhcDev
->IoMmu
, DataMap
);
695 Retrieves the number of root hub ports.
697 @param[in] PeiServices The pointer to the PEI Services Table.
698 @param[in] This The pointer to this instance of the
699 PEI_USB_HOST_CONTROLLER_PPI.
700 @param[out] PortNumber The pointer to the number of the root hub ports.
702 @retval EFI_SUCCESS The port number was retrieved successfully.
703 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
708 UhcGetRootHubPortNumber (
709 IN EFI_PEI_SERVICES
**PeiServices
,
710 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
711 OUT UINT8
*PortNumber
716 UINT16 RHPortControl
;
719 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
721 if (PortNumber
== NULL
) {
722 return EFI_INVALID_PARAMETER
;
727 for (Index
= 0; Index
< 2; Index
++) {
728 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ Index
* 2;
729 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
731 // Port Register content is valid
733 if (RHPortControl
!= 0xff) {
742 Retrieves the current status of a USB root hub port.
744 @param PeiServices The pointer of EFI_PEI_SERVICES.
745 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
746 @param PortNumber The root hub port to retrieve the state from.
747 @param PortStatus Variable to receive the port state.
749 @retval EFI_SUCCESS The status of the USB root hub port specified.
750 by PortNumber was returned in PortStatus.
751 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
756 UhcGetRootHubPortStatus (
757 IN EFI_PEI_SERVICES
**PeiServices
,
758 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
760 OUT EFI_USB_PORT_STATUS
*PortStatus
766 UINT8 TotalPortNumber
;
768 if (PortStatus
== NULL
) {
769 return EFI_INVALID_PARAMETER
;
772 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
773 if (PortNumber
> TotalPortNumber
) {
774 return EFI_INVALID_PARAMETER
;
777 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
778 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
780 PortStatus
->PortStatus
= 0;
781 PortStatus
->PortChangeStatus
= 0;
783 RHPortStatus
= USBReadPortW (UhcDev
, PSAddr
);
786 // Current Connect Status
788 if ((RHPortStatus
& USBPORTSC_CCS
) != 0) {
789 PortStatus
->PortStatus
|= USB_PORT_STAT_CONNECTION
;
793 // Port Enabled/Disabled
795 if ((RHPortStatus
& USBPORTSC_PED
) != 0) {
796 PortStatus
->PortStatus
|= USB_PORT_STAT_ENABLE
;
802 if ((RHPortStatus
& USBPORTSC_SUSP
) != 0) {
803 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
809 if ((RHPortStatus
& USBPORTSC_PR
) != 0) {
810 PortStatus
->PortStatus
|= USB_PORT_STAT_RESET
;
814 // Low Speed Device Attached
816 if ((RHPortStatus
& USBPORTSC_LSDA
) != 0) {
817 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
821 // Fill Port Status Change bits
824 // Connect Status Change
826 if ((RHPortStatus
& USBPORTSC_CSC
) != 0) {
827 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_CONNECTION
;
831 // Port Enabled/Disabled Change
833 if ((RHPortStatus
& USBPORTSC_PEDC
) != 0) {
834 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_ENABLE
;
841 Sets a feature for the specified root hub port.
843 @param PeiServices The pointer of EFI_PEI_SERVICES
844 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI
845 @param PortNumber Root hub port to set.
846 @param PortFeature Feature to set.
848 @retval EFI_SUCCESS The feature specified by PortFeature was set.
849 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
850 @retval EFI_TIMEOUT The time out occurred.
855 UhcSetRootHubPortFeature (
856 IN EFI_PEI_SERVICES
**PeiServices
,
857 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
859 IN EFI_USB_PORT_FEATURE PortFeature
864 UINT32 CommandRegAddr
;
865 UINT16 RHPortControl
;
866 UINT8 TotalPortNumber
;
868 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
869 if (PortNumber
> TotalPortNumber
) {
870 return EFI_INVALID_PARAMETER
;
873 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
874 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
875 CommandRegAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
877 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
879 switch (PortFeature
) {
880 case EfiUsbPortSuspend
:
881 if ((USBReadPortW (UhcDev
, CommandRegAddr
) & USBCMD_EGSM
) == 0) {
883 // if global suspend is not active, can set port suspend
885 RHPortControl
&= 0xfff5;
886 RHPortControl
|= USBPORTSC_SUSP
;
891 case EfiUsbPortReset
:
892 RHPortControl
&= 0xfff5;
893 RHPortControl
|= USBPORTSC_PR
;
899 case EfiUsbPortPower
:
902 case EfiUsbPortEnable
:
903 RHPortControl
&= 0xfff5;
904 RHPortControl
|= USBPORTSC_PED
;
908 return EFI_INVALID_PARAMETER
;
911 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
917 Clears a feature for the specified root hub port.
919 @param PeiServices The pointer of EFI_PEI_SERVICES.
920 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
921 @param PortNumber Specifies the root hub port whose feature
922 is requested to be cleared.
923 @param PortFeature Indicates the feature selector associated with the
924 feature clear request.
926 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
927 for the USB root hub port specified by PortNumber.
928 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
933 UhcClearRootHubPortFeature (
934 IN EFI_PEI_SERVICES
**PeiServices
,
935 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
937 IN EFI_USB_PORT_FEATURE PortFeature
942 UINT16 RHPortControl
;
943 UINT8 TotalPortNumber
;
945 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
947 if (PortNumber
> TotalPortNumber
) {
948 return EFI_INVALID_PARAMETER
;
951 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
952 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
954 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
956 switch (PortFeature
) {
958 // clear PORT_ENABLE feature means disable port.
960 case EfiUsbPortEnable
:
961 RHPortControl
&= 0xfff5;
962 RHPortControl
&= ~USBPORTSC_PED
;
966 // clear PORT_SUSPEND feature means resume the port.
967 // (cause a resume on the specified port if in suspend mode)
969 case EfiUsbPortSuspend
:
970 RHPortControl
&= 0xfff5;
971 RHPortControl
&= ~USBPORTSC_SUSP
;
977 case EfiUsbPortPower
:
981 // clear PORT_RESET means clear the reset signal.
983 case EfiUsbPortReset
:
984 RHPortControl
&= 0xfff5;
985 RHPortControl
&= ~USBPORTSC_PR
;
989 // clear connect status change
991 case EfiUsbPortConnectChange
:
992 RHPortControl
&= 0xfff5;
993 RHPortControl
|= USBPORTSC_CSC
;
997 // clear enable/disable status change
999 case EfiUsbPortEnableChange
:
1000 RHPortControl
&= 0xfff5;
1001 RHPortControl
|= USBPORTSC_PEDC
;
1005 // root hub does not support this request
1007 case EfiUsbPortSuspendChange
:
1011 // root hub does not support this request
1013 case EfiUsbPortOverCurrentChange
:
1017 // root hub does not support this request
1019 case EfiUsbPortResetChange
:
1023 return EFI_INVALID_PARAMETER
;
1026 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
1034 @param UhcDev UHCI Device.
1036 @retval EFI_SUCCESS UHCI successfully initialized.
1037 @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.
1042 IN USB_UHC_DEV
*UhcDev
1046 UINT32 FrameListBaseAddrReg
;
1051 // Create and Initialize Frame List For the Host Controller.
1053 Status
= CreateFrameList (UhcDev
);
1054 if (EFI_ERROR (Status
)) {
1058 FrameListBaseAddrReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBFLBASEADD
;
1059 CommandReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
1062 // Set Frame List Base Address to the specific register to inform the hardware.
1064 SetFrameListBaseAddress (UhcDev
, FrameListBaseAddrReg
, (UINT32
)(UINTN
)(UhcDev
->FrameListEntry
));
1066 Command
= USBReadPortW (UhcDev
, CommandReg
);
1067 Command
|= USBCMD_GRESET
;
1068 USBWritePortW (UhcDev
, CommandReg
, Command
);
1070 MicroSecondDelay (50 * 1000);
1072 Command
&= ~USBCMD_GRESET
;
1074 USBWritePortW (UhcDev
, CommandReg
, Command
);
1077 // UHCI spec page120 reset recovery time
1079 MicroSecondDelay (20 * 1000);
1082 // Set Run/Stop bit to 1.
1084 Command
= USBReadPortW (UhcDev
, CommandReg
);
1085 Command
|= USBCMD_RS
| USBCMD_MAXP
;
1086 USBWritePortW (UhcDev
, CommandReg
, Command
);
1092 Create Frame List Structure.
1094 @param UhcDev UHCI device.
1096 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1097 @retval EFI_SUCCESS Success.
1106 EFI_PHYSICAL_ADDRESS FrameListBaseAddr
;
1107 FRAMELIST_ENTRY
*FrameListPtr
;
1111 // The Frame List ocupies 4K bytes,
1112 // and must be aligned on 4-Kbyte boundaries.
1114 Status
= PeiServicesAllocatePages (
1115 EfiBootServicesData
,
1120 if (Status
!= EFI_SUCCESS
) {
1121 return EFI_OUT_OF_RESOURCES
;
1125 // Create Control QH and Bulk QH and link them into Framelist Entry
1127 Status
= CreateQH (UhcDev
, &UhcDev
->ConfigQH
);
1128 if (Status
!= EFI_SUCCESS
) {
1129 return EFI_OUT_OF_RESOURCES
;
1132 ASSERT (UhcDev
->ConfigQH
!= NULL
);
1134 Status
= CreateQH (UhcDev
, &UhcDev
->BulkQH
);
1135 if (Status
!= EFI_SUCCESS
) {
1136 return EFI_OUT_OF_RESOURCES
;
1139 ASSERT (UhcDev
->BulkQH
!= NULL
);
1142 // Set the corresponding QH pointer
1144 SetQHHorizontalLinkPtr (UhcDev
->ConfigQH
, UhcDev
->BulkQH
);
1145 SetQHHorizontalQHorTDSelect (UhcDev
->ConfigQH
, TRUE
);
1146 SetQHHorizontalValidorInvalid (UhcDev
->ConfigQH
, TRUE
);
1148 UhcDev
->FrameListEntry
= (FRAMELIST_ENTRY
*)((UINTN
)FrameListBaseAddr
);
1150 FrameListPtr
= UhcDev
->FrameListEntry
;
1152 for (Index
= 0; Index
< 1024; Index
++) {
1153 FrameListPtr
->FrameListPtrTerminate
= 0;
1154 FrameListPtr
->FrameListPtr
= (UINT32
)(UINTN
)UhcDev
->ConfigQH
>> 4;
1155 FrameListPtr
->FrameListPtrQSelect
= 1;
1156 FrameListPtr
->FrameListRsvd
= 0;
1164 Read a 16bit width data from Uhc HC IO space register.
1166 @param UhcDev The UHCI device.
1167 @param Port The IO space address of the register.
1169 @retval the register content read.
1174 IN USB_UHC_DEV
*UhcDev
,
1178 return IoRead16 (Port
);
1182 Write a 16bit width data into Uhc HC IO space register.
1184 @param UhcDev The UHCI device.
1185 @param Port The IO space address of the register.
1186 @param Data The data written into the register.
1191 IN USB_UHC_DEV
*UhcDev
,
1196 IoWrite16 (Port
, Data
);
1200 Write a 32bit width data into Uhc HC IO space register.
1202 @param UhcDev The UHCI device.
1203 @param Port The IO space address of the register.
1204 @param Data The data written into the register.
1209 IN USB_UHC_DEV
*UhcDev
,
1214 IoWrite32 (Port
, Data
);
1218 Clear the content of UHCI's Status Register.
1220 @param UhcDev The UHCI device.
1221 @param StatusAddr The IO space address of the register.
1226 IN USB_UHC_DEV
*UhcDev
,
1227 IN UINT32 StatusAddr
1231 // Clear the content of UHCI's Status Register
1233 USBWritePortW (UhcDev
, StatusAddr
, 0x003F);
1237 Check whether the host controller operates well.
1239 @param UhcDev The UHCI device.
1240 @param StatusRegAddr The io address of status register.
1242 @retval TRUE Host controller is working.
1243 @retval FALSE Host controller is halted or system error.
1248 IN USB_UHC_DEV
*UhcDev
,
1249 IN UINT32 StatusRegAddr
1254 StatusValue
= USBReadPortW (UhcDev
, StatusRegAddr
);
1256 if ((StatusValue
& (USBSTS_HCPE
| USBSTS_HSE
| USBSTS_HCH
)) != 0) {
1264 Set Frame List Base Address.
1266 @param UhcDev The UHCI device.
1267 @param FrameListRegAddr The address of frame list register.
1268 @param Addr The address of frame list table.
1272 SetFrameListBaseAddress (
1273 IN USB_UHC_DEV
*UhcDev
,
1274 IN UINT32 FrameListRegAddr
,
1279 // Sets value in the USB Frame List Base Address register.
1281 USBWritePortDW (UhcDev
, FrameListRegAddr
, (UINT32
)(Addr
& 0xFFFFF000));
1285 Create QH and initialize.
1287 @param UhcDev The UHCI device.
1288 @param PtrQH Place to store QH_STRUCT pointer.
1290 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1291 @retval EFI_SUCCESS Success.
1296 IN USB_UHC_DEV
*UhcDev
,
1297 OUT QH_STRUCT
**PtrQH
1303 // allocate align memory for QH_STRUCT
1305 Status
= AllocateTDorQHStruct (UhcDev
, sizeof (QH_STRUCT
), (void **)PtrQH
);
1306 if (EFI_ERROR (Status
)) {
1307 return EFI_OUT_OF_RESOURCES
;
1311 // init each field of the QH_STRUCT
1313 SetQHHorizontalValidorInvalid (*PtrQH
, FALSE
);
1314 SetQHVerticalValidorInvalid (*PtrQH
, FALSE
);
1320 Set the horizontal link pointer in QH.
1322 @param PtrQH Place to store QH_STRUCT pointer.
1323 @param PtrNext Place to the next QH_STRUCT.
1327 SetQHHorizontalLinkPtr (
1328 IN QH_STRUCT
*PtrQH
,
1333 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1334 // Only the highest 28bit of the address is valid
1335 // (take 32bit address as an example).
1337 PtrQH
->QueueHead
.QHHorizontalPtr
= (UINT32
)(UINTN
)PtrNext
>> 4;
1341 Set a QH or TD horizontally to be connected with a specific QH.
1343 @param PtrQH Place to store QH_STRUCT pointer.
1344 @param IsQH Specify QH or TD is connected.
1348 SetQHHorizontalQHorTDSelect (
1349 IN QH_STRUCT
*PtrQH
,
1354 // if QH is connected, the specified bit is set,
1355 // if TD is connected, the specified bit is cleared.
1357 PtrQH
->QueueHead
.QHHorizontalQSelect
= IsQH
? 1 : 0;
1361 Set the horizontal validor bit in QH.
1363 @param PtrQH Place to store QH_STRUCT pointer.
1364 @param IsValid Specify the horizontal linker is valid or not.
1368 SetQHHorizontalValidorInvalid (
1369 IN QH_STRUCT
*PtrQH
,
1374 // Valid means the horizontal link pointer is valid,
1375 // else, it's invalid.
1377 PtrQH
->QueueHead
.QHHorizontalTerminate
= IsValid
? 0 : 1;
1381 Set the vertical link pointer in QH.
1383 @param PtrQH Place to store QH_STRUCT pointer.
1384 @param PtrNext Place to the next QH_STRUCT.
1388 SetQHVerticalLinkPtr (
1389 IN QH_STRUCT
*PtrQH
,
1394 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1395 // Only the highest 28bit of the address is valid
1396 // (take 32bit address as an example).
1398 PtrQH
->QueueHead
.QHVerticalPtr
= (UINT32
)(UINTN
)PtrNext
>> 4;
1402 Set a QH or TD vertically to be connected with a specific QH.
1404 @param PtrQH Place to store QH_STRUCT pointer.
1405 @param IsQH Specify QH or TD is connected.
1409 SetQHVerticalQHorTDSelect (
1410 IN QH_STRUCT
*PtrQH
,
1415 // Set the specified bit if the Vertical Link Pointer pointing to a QH,
1416 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
1418 PtrQH
->QueueHead
.QHVerticalQSelect
= IsQH
? 1 : 0;
1422 Set the vertical validor bit in QH.
1424 @param PtrQH Place to store QH_STRUCT pointer.
1425 @param IsValid Specify the vertical linker is valid or not.
1429 SetQHVerticalValidorInvalid (
1430 IN QH_STRUCT
*PtrQH
,
1435 // If TRUE, meaning the Vertical Link Pointer field is valid,
1436 // else, the field is invalid.
1438 PtrQH
->QueueHead
.QHVerticalTerminate
= IsValid
? 0 : 1;
1442 Allocate TD or QH Struct.
1444 @param UhcDev The UHCI device.
1445 @param Size The size of allocation.
1446 @param PtrStruct Place to store TD_STRUCT pointer.
1448 @return EFI_SUCCESS Allocate successfully.
1449 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1453 AllocateTDorQHStruct (
1454 IN USB_UHC_DEV
*UhcDev
,
1456 OUT VOID
**PtrStruct
1461 Status
= EFI_SUCCESS
;
1464 Status
= UhcAllocatePool (
1466 (UINT8
**)PtrStruct
,
1469 if (EFI_ERROR (Status
)) {
1473 ZeroMem (*PtrStruct
, Size
);
1481 @param UhcDev The UHCI device.
1482 @param PtrTD Place to store TD_STRUCT pointer.
1484 @return EFI_SUCCESS Allocate successfully.
1485 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1490 IN USB_UHC_DEV
*UhcDev
,
1491 OUT TD_STRUCT
**PtrTD
1497 // create memory for TD_STRUCT, and align the memory.
1499 Status
= AllocateTDorQHStruct (UhcDev
, sizeof (TD_STRUCT
), (void **)PtrTD
);
1500 if (EFI_ERROR (Status
)) {
1507 SetTDLinkPtrValidorInvalid (*PtrTD
, FALSE
);
1513 Generate Setup Stage TD.
1515 @param UhcDev The UHCI device.
1516 @param DevAddr Device address.
1517 @param Endpoint Endpoint number.
1518 @param DeviceSpeed Device Speed.
1519 @param DevRequest CPU memory address of request structure buffer to transfer.
1520 @param RequestPhy PCI memory address of request structure buffer to transfer.
1521 @param RequestLen Request length.
1522 @param PtrTD TD_STRUCT generated.
1524 @return EFI_SUCCESS Generate setup stage TD successfully.
1525 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1530 IN USB_UHC_DEV
*UhcDev
,
1533 IN UINT8 DeviceSpeed
,
1534 IN UINT8
*DevRequest
,
1535 IN UINT8
*RequestPhy
,
1536 IN UINT8 RequestLen
,
1537 OUT TD_STRUCT
**PtrTD
1540 TD_STRUCT
*TdStruct
;
1543 Status
= CreateTD (UhcDev
, &TdStruct
);
1544 if (EFI_ERROR (Status
)) {
1548 SetTDLinkPtr (TdStruct
, NULL
);
1551 // Depth first fashion
1553 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1556 // initialize as the last TD in the QH context,
1557 // this field will be updated in the TD linkage process.
1559 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1562 // Disable Short Packet Detection by default
1564 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1567 // Max error counter is 3, retry 3 times when error encountered.
1569 SetTDControlErrorCounter (TdStruct
, 3);
1572 // set device speed attribute
1573 // (TRUE - Slow Device; FALSE - Full Speed Device)
1575 switch (DeviceSpeed
) {
1576 case USB_SLOW_SPEED_DEVICE
:
1577 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1580 case USB_FULL_SPEED_DEVICE
:
1581 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1586 // Non isochronous transfer TD
1588 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1591 // Interrupt On Complete bit be set to zero,
1592 // Disable IOC interrupt.
1594 SetorClearTDControlIOC (TdStruct
, FALSE
);
1597 // Set TD Active bit
1599 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1601 SetTDTokenMaxLength (TdStruct
, RequestLen
);
1603 SetTDTokenDataToggle0 (TdStruct
);
1605 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1607 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1609 SetTDTokenPacketID (TdStruct
, SETUP_PACKET_ID
);
1611 TdStruct
->PtrTDBuffer
= (UINT8
*)DevRequest
;
1612 TdStruct
->TDBufferLength
= RequestLen
;
1614 // Set the beginning address of the buffer that will be used
1615 // during the transaction.
1617 TdStruct
->TDData
.TDBufferPtr
= (UINT32
)(UINTN
)RequestPhy
;
1625 Generate Data Stage TD.
1627 @param UhcDev The UHCI device.
1628 @param DevAddr Device address.
1629 @param Endpoint Endpoint number.
1630 @param PtrData CPU memory address of user data buffer to transfer.
1631 @param DataPhy PCI memory address of user data buffer to transfer.
1632 @param Len Data length.
1633 @param PktID PacketID.
1634 @param Toggle Data toggle value.
1635 @param DeviceSpeed Device Speed.
1636 @param PtrTD TD_STRUCT generated.
1638 @return EFI_SUCCESS Generate data stage TD successfully.
1639 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1644 IN USB_UHC_DEV
*UhcDev
,
1652 IN UINT8 DeviceSpeed
,
1653 OUT TD_STRUCT
**PtrTD
1656 TD_STRUCT
*TdStruct
;
1659 Status
= CreateTD (UhcDev
, &TdStruct
);
1660 if (EFI_ERROR (Status
)) {
1664 SetTDLinkPtr (TdStruct
, NULL
);
1667 // Depth first fashion
1669 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1672 // Link pointer pointing to TD struct
1674 SetTDLinkPtrQHorTDSelect (TdStruct
, FALSE
);
1677 // initialize as the last TD in the QH context,
1678 // this field will be updated in the TD linkage process.
1680 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1683 // Disable short packet detect
1685 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1687 // Max error counter is 3
1689 SetTDControlErrorCounter (TdStruct
, 3);
1692 // set device speed attribute
1693 // (TRUE - Slow Device; FALSE - Full Speed Device)
1695 switch (DeviceSpeed
) {
1696 case USB_SLOW_SPEED_DEVICE
:
1697 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1700 case USB_FULL_SPEED_DEVICE
:
1701 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1706 // Non isochronous transfer TD
1708 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1711 // Disable Interrupt On Complete
1712 // Disable IOC interrupt.
1714 SetorClearTDControlIOC (TdStruct
, FALSE
);
1719 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1721 SetTDTokenMaxLength (TdStruct
, Len
);
1724 SetTDTokenDataToggle1 (TdStruct
);
1726 SetTDTokenDataToggle0 (TdStruct
);
1729 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1731 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1733 SetTDTokenPacketID (TdStruct
, PktID
);
1735 TdStruct
->PtrTDBuffer
= (UINT8
*)PtrData
;
1736 TdStruct
->TDBufferLength
= Len
;
1738 // Set the beginning address of the buffer that will be used
1739 // during the transaction.
1741 TdStruct
->TDData
.TDBufferPtr
= (UINT32
)(UINTN
)DataPhy
;
1749 Generate Status Stage TD.
1751 @param UhcDev The UHCI device.
1752 @param DevAddr Device address.
1753 @param Endpoint Endpoint number.
1754 @param PktID PacketID.
1755 @param DeviceSpeed Device Speed.
1756 @param PtrTD TD_STRUCT generated.
1758 @return EFI_SUCCESS Generate status stage TD successfully.
1759 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1764 IN USB_UHC_DEV
*UhcDev
,
1768 IN UINT8 DeviceSpeed
,
1769 OUT TD_STRUCT
**PtrTD
1772 TD_STRUCT
*PtrTDStruct
;
1775 Status
= CreateTD (UhcDev
, &PtrTDStruct
);
1776 if (EFI_ERROR (Status
)) {
1780 SetTDLinkPtr (PtrTDStruct
, NULL
);
1783 // Depth first fashion
1785 SetTDLinkPtrDepthorBreadth (PtrTDStruct
, TRUE
);
1788 // initialize as the last TD in the QH context,
1789 // this field will be updated in the TD linkage process.
1791 SetTDLinkPtrValidorInvalid (PtrTDStruct
, FALSE
);
1794 // Disable short packet detect
1796 EnableorDisableTDShortPacket (PtrTDStruct
, FALSE
);
1799 // Max error counter is 3
1801 SetTDControlErrorCounter (PtrTDStruct
, 3);
1804 // set device speed attribute
1805 // (TRUE - Slow Device; FALSE - Full Speed Device)
1807 switch (DeviceSpeed
) {
1808 case USB_SLOW_SPEED_DEVICE
:
1809 SetTDLoworFullSpeedDevice (PtrTDStruct
, TRUE
);
1812 case USB_FULL_SPEED_DEVICE
:
1813 SetTDLoworFullSpeedDevice (PtrTDStruct
, FALSE
);
1818 // Non isochronous transfer TD
1820 SetTDControlIsochronousorNot (PtrTDStruct
, FALSE
);
1823 // Disable Interrupt On Complete
1824 // Disable IOC interrupt.
1826 SetorClearTDControlIOC (PtrTDStruct
, FALSE
);
1829 // Set TD Active bit
1831 SetTDStatusActiveorInactive (PtrTDStruct
, TRUE
);
1833 SetTDTokenMaxLength (PtrTDStruct
, 0);
1835 SetTDTokenDataToggle1 (PtrTDStruct
);
1837 SetTDTokenEndPoint (PtrTDStruct
, Endpoint
);
1839 SetTDTokenDeviceAddress (PtrTDStruct
, DevAddr
);
1841 SetTDTokenPacketID (PtrTDStruct
, PktID
);
1843 PtrTDStruct
->PtrTDBuffer
= NULL
;
1844 PtrTDStruct
->TDBufferLength
= 0;
1846 // Set the beginning address of the buffer that will be used
1847 // during the transaction.
1849 PtrTDStruct
->TDData
.TDBufferPtr
= 0;
1851 *PtrTD
= PtrTDStruct
;
1857 Set the link pointer validor bit in TD.
1859 @param PtrTDStruct Place to store TD_STRUCT pointer.
1860 @param IsValid Specify the linker pointer is valid or not.
1864 SetTDLinkPtrValidorInvalid (
1865 IN TD_STRUCT
*PtrTDStruct
,
1870 // Valid means the link pointer is valid,
1871 // else, it's invalid.
1873 PtrTDStruct
->TDData
.TDLinkPtrTerminate
= (IsValid
? 0 : 1);
1877 Set the Link Pointer pointing to a QH or TD.
1879 @param PtrTDStruct Place to store TD_STRUCT pointer.
1880 @param IsQH Specify QH or TD is connected.
1884 SetTDLinkPtrQHorTDSelect (
1885 IN TD_STRUCT
*PtrTDStruct
,
1890 // Indicate whether the Link Pointer pointing to a QH or TD
1892 PtrTDStruct
->TDData
.TDLinkPtrQSelect
= (IsQH
? 1 : 0);
1896 Set the traverse is depth-first or breadth-first.
1898 @param PtrTDStruct Place to store TD_STRUCT pointer.
1899 @param IsDepth Specify the traverse is depth-first or breadth-first.
1903 SetTDLinkPtrDepthorBreadth (
1904 IN TD_STRUCT
*PtrTDStruct
,
1909 // If TRUE, indicating the host controller should process in depth first fashion,
1910 // else, the host controller should process in breadth first fashion
1912 PtrTDStruct
->TDData
.TDLinkPtrDepthSelect
= (IsDepth
? 1 : 0);
1916 Set TD Link Pointer in TD.
1918 @param PtrTDStruct Place to store TD_STRUCT pointer.
1919 @param PtrNext Place to the next TD_STRUCT.
1924 IN TD_STRUCT
*PtrTDStruct
,
1929 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
1930 // only the highest 28 bits are valid. (if take 32bit address as an example)
1932 PtrTDStruct
->TDData
.TDLinkPtr
= (UINT32
)(UINTN
)PtrNext
>> 4;
1936 Get TD Link Pointer.
1938 @param PtrTDStruct Place to store TD_STRUCT pointer.
1940 @retval Get TD Link Pointer in TD.
1945 IN TD_STRUCT
*PtrTDStruct
1949 // Get TD Link Pointer. Restore it back to 32bit
1950 // (if take 32bit address as an example)
1952 return (VOID
*)(UINTN
)((PtrTDStruct
->TDData
.TDLinkPtr
) << 4);
1956 Enable/Disable short packet detection mechanism.
1958 @param PtrTDStruct Place to store TD_STRUCT pointer.
1959 @param IsEnable Enable or disable short packet detection mechanism.
1963 EnableorDisableTDShortPacket (
1964 IN TD_STRUCT
*PtrTDStruct
,
1969 // TRUE means enable short packet detection mechanism.
1971 PtrTDStruct
->TDData
.TDStatusSPD
= (IsEnable
? 1 : 0);
1975 Set the max error counter in TD.
1977 @param PtrTDStruct Place to store TD_STRUCT pointer.
1978 @param MaxErrors The number of allowable error.
1982 SetTDControlErrorCounter (
1983 IN TD_STRUCT
*PtrTDStruct
,
1988 // valid value of MaxErrors is 0,1,2,3
1990 if (MaxErrors
> 3) {
1994 PtrTDStruct
->TDData
.TDStatusErr
= MaxErrors
;
1998 Set the TD is targeting a low-speed device or not.
2000 @param PtrTDStruct Place to store TD_STRUCT pointer.
2001 @param IsLowSpeedDevice Whether The device is low-speed.
2005 SetTDLoworFullSpeedDevice (
2006 IN TD_STRUCT
*PtrTDStruct
,
2007 IN BOOLEAN IsLowSpeedDevice
2011 // TRUE means the TD is targeting at a Low-speed device
2013 PtrTDStruct
->TDData
.TDStatusLS
= (IsLowSpeedDevice
? 1 : 0);
2017 Set the TD is isochronous transfer type or not.
2019 @param PtrTDStruct Place to store TD_STRUCT pointer.
2020 @param IsIsochronous Whether the transaction isochronous transfer type.
2024 SetTDControlIsochronousorNot (
2025 IN TD_STRUCT
*PtrTDStruct
,
2026 IN BOOLEAN IsIsochronous
2030 // TRUE means the TD belongs to Isochronous transfer type.
2032 PtrTDStruct
->TDData
.TDStatusIOS
= (IsIsochronous
? 1 : 0);
2036 Set if UCHI should issue an interrupt on completion of the frame
2037 in which this TD is executed
2039 @param PtrTDStruct Place to store TD_STRUCT pointer.
2040 @param IsSet Whether HC should issue an interrupt on completion.
2044 SetorClearTDControlIOC (
2045 IN TD_STRUCT
*PtrTDStruct
,
2050 // If this bit is set, it indicates that the host controller should issue
2051 // an interrupt on completion of the frame in which this TD is executed.
2053 PtrTDStruct
->TDData
.TDStatusIOC
= IsSet
? 1 : 0;
2057 Set if the TD is active and can be executed.
2059 @param PtrTDStruct Place to store TD_STRUCT pointer.
2060 @param IsActive Whether the TD is active and can be executed.
2064 SetTDStatusActiveorInactive (
2065 IN TD_STRUCT
*PtrTDStruct
,
2070 // If this bit is set, it indicates that the TD is active and can be
2074 PtrTDStruct
->TDData
.TDStatus
|= 0x80;
2076 PtrTDStruct
->TDData
.TDStatus
&= 0x7F;
2081 Specifies the maximum number of data bytes allowed for the transfer.
2083 @param PtrTDStruct Place to store TD_STRUCT pointer.
2084 @param MaxLen The maximum number of data bytes allowed.
2086 @retval The allowed maximum number of data.
2089 SetTDTokenMaxLength (
2090 IN TD_STRUCT
*PtrTDStruct
,
2095 // Specifies the maximum number of data bytes allowed for the transfer.
2096 // the legal value extent is 0 ~ 0x500.
2098 if (MaxLen
> 0x500) {
2102 PtrTDStruct
->TDData
.TDTokenMaxLen
= MaxLen
- 1;
2108 Set the data toggle bit to DATA1.
2110 @param PtrTDStruct Place to store TD_STRUCT pointer.
2114 SetTDTokenDataToggle1 (
2115 IN TD_STRUCT
*PtrTDStruct
2119 // Set the data toggle bit to DATA1
2121 PtrTDStruct
->TDData
.TDTokenDataToggle
= 1;
2125 Set the data toggle bit to DATA0.
2127 @param PtrTDStruct Place to store TD_STRUCT pointer.
2131 SetTDTokenDataToggle0 (
2132 IN TD_STRUCT
*PtrTDStruct
2136 // Set the data toggle bit to DATA0
2138 PtrTDStruct
->TDData
.TDTokenDataToggle
= 0;
2142 Set EndPoint Number the TD is targeting at.
2144 @param PtrTDStruct Place to store TD_STRUCT pointer.
2145 @param EndPoint The Endport number of the target.
2149 SetTDTokenEndPoint (
2150 IN TD_STRUCT
*PtrTDStruct
,
2155 // Set EndPoint Number the TD is targeting at.
2157 PtrTDStruct
->TDData
.TDTokenEndPt
= (UINT8
)EndPoint
;
2161 Set Device Address the TD is targeting at.
2163 @param PtrTDStruct Place to store TD_STRUCT pointer.
2164 @param DevAddr The Device Address of the target.
2168 SetTDTokenDeviceAddress (
2169 IN TD_STRUCT
*PtrTDStruct
,
2174 // Set Device Address the TD is targeting at.
2176 PtrTDStruct
->TDData
.TDTokenDevAddr
= (UINT8
)DevAddr
;
2180 Set Packet Identification the TD is targeting at.
2182 @param PtrTDStruct Place to store TD_STRUCT pointer.
2183 @param PacketID The Packet Identification of the target.
2187 SetTDTokenPacketID (
2188 IN TD_STRUCT
*PtrTDStruct
,
2193 // Set the Packet Identification to be used for this transaction.
2195 PtrTDStruct
->TDData
.TDTokenPID
= PacketID
;
2199 Detect whether the TD is active.
2201 @param PtrTDStruct Place to store TD_STRUCT pointer.
2203 @retval The TD is active or not.
2208 IN TD_STRUCT
*PtrTDStruct
2214 // Detect whether the TD is active.
2216 TDStatus
= (UINT8
)(PtrTDStruct
->TDData
.TDStatus
);
2217 return (BOOLEAN
)(TDStatus
& 0x80);
2221 Detect whether the TD is stalled.
2223 @param PtrTDStruct Place to store TD_STRUCT pointer.
2225 @retval The TD is stalled or not.
2230 IN TD_STRUCT
*PtrTDStruct
2236 // Detect whether the device/endpoint addressed by this TD is stalled.
2238 TDStatus
= (UINT8
)(PtrTDStruct
->TDData
.TDStatus
);
2239 return (BOOLEAN
)(TDStatus
& 0x40);
2243 Detect whether Data Buffer Error is happened.
2245 @param PtrTDStruct Place to store TD_STRUCT pointer.
2247 @retval The Data Buffer Error is happened or not.
2251 IsTDStatusBufferError (
2252 IN TD_STRUCT
*PtrTDStruct
2258 // Detect whether Data Buffer Error is happened.
2260 TDStatus
= (UINT8
)(PtrTDStruct
->TDData
.TDStatus
);
2261 return (BOOLEAN
)(TDStatus
& 0x20);
2265 Detect whether Babble Error is happened.
2267 @param PtrTDStruct Place to store TD_STRUCT pointer.
2269 @retval The Babble Error is happened or not.
2273 IsTDStatusBabbleError (
2274 IN TD_STRUCT
*PtrTDStruct
2280 // Detect whether Babble Error is happened.
2282 TDStatus
= (UINT8
)(PtrTDStruct
->TDData
.TDStatus
);
2283 return (BOOLEAN
)(TDStatus
& 0x10);
2287 Detect whether NAK is received.
2289 @param PtrTDStruct Place to store TD_STRUCT pointer.
2291 @retval The NAK is received or not.
2295 IsTDStatusNAKReceived (
2296 IN TD_STRUCT
*PtrTDStruct
2302 // Detect whether NAK is received.
2304 TDStatus
= (UINT8
)(PtrTDStruct
->TDData
.TDStatus
);
2305 return (BOOLEAN
)(TDStatus
& 0x08);
2309 Detect whether CRC/Time Out Error is encountered.
2311 @param PtrTDStruct Place to store TD_STRUCT pointer.
2313 @retval The CRC/Time Out Error is encountered or not.
2317 IsTDStatusCRCTimeOutError (
2318 IN TD_STRUCT
*PtrTDStruct
2324 // Detect whether CRC/Time Out Error is encountered.
2326 TDStatus
= (UINT8
)(PtrTDStruct
->TDData
.TDStatus
);
2327 return (BOOLEAN
)(TDStatus
& 0x04);
2331 Detect whether Bitstuff Error is received.
2333 @param PtrTDStruct Place to store TD_STRUCT pointer.
2335 @retval The Bitstuff Error is received or not.
2339 IsTDStatusBitStuffError (
2340 IN TD_STRUCT
*PtrTDStruct
2346 // Detect whether Bitstuff Error is received.
2348 TDStatus
= (UINT8
)(PtrTDStruct
->TDData
.TDStatus
);
2349 return (BOOLEAN
)(TDStatus
& 0x02);
2353 Retrieve the actual number of bytes that were tansferred.
2355 @param PtrTDStruct Place to store TD_STRUCT pointer.
2357 @retval The actual number of bytes that were tansferred.
2361 GetTDStatusActualLength (
2362 IN TD_STRUCT
*PtrTDStruct
2366 // Retrieve the actual number of bytes that were tansferred.
2367 // the value is encoded as n-1. so return the decoded value.
2369 return (UINT16
)((PtrTDStruct
->TDData
.TDStatusActualLength
) + 1);
2373 Retrieve the information of whether the Link Pointer field is valid or not.
2375 @param PtrTDStruct Place to store TD_STRUCT pointer.
2377 @retval The linker pointer field is valid or not.
2381 GetTDLinkPtrValidorInvalid (
2382 IN TD_STRUCT
*PtrTDStruct
2386 // Retrieve the information of whether the Link Pointer field
2389 if ((PtrTDStruct
->TDData
.TDLinkPtrTerminate
& BIT0
) != 0) {
2397 Count TD Number from PtrFirstTD.
2399 @param PtrFirstTD Place to store TD_STRUCT pointer.
2401 @retval The queued TDs number.
2406 IN TD_STRUCT
*PtrFirstTD
2413 // Count the queued TDs number.
2418 Ptr
= (TD_STRUCT
*)Ptr
->PtrNextTD
;
2428 @param PtrQH Place to store QH_STRUCT pointer.
2429 @param PtrTD Place to store TD_STRUCT pointer.
2434 IN QH_STRUCT
*PtrQH
,
2438 if ((PtrQH
== NULL
) || (PtrTD
== NULL
)) {
2443 // Validate QH Vertical Ptr field
2445 SetQHVerticalValidorInvalid (PtrQH
, TRUE
);
2448 // Vertical Ptr pointing to TD structure
2450 SetQHVerticalQHorTDSelect (PtrQH
, FALSE
);
2452 SetQHVerticalLinkPtr (PtrQH
, (VOID
*)PtrTD
);
2454 PtrQH
->PtrDown
= (VOID
*)PtrTD
;
2460 @param PtrPreTD Place to store TD_STRUCT pointer.
2461 @param PtrTD Place to store TD_STRUCT pointer.
2466 IN TD_STRUCT
*PtrPreTD
,
2470 if ((PtrPreTD
== NULL
) || (PtrTD
== NULL
)) {
2475 // Depth first fashion
2477 SetTDLinkPtrDepthorBreadth (PtrPreTD
, TRUE
);
2480 // Link pointer pointing to TD struct
2482 SetTDLinkPtrQHorTDSelect (PtrPreTD
, FALSE
);
2485 // Validate the link pointer valid bit
2487 SetTDLinkPtrValidorInvalid (PtrPreTD
, TRUE
);
2489 SetTDLinkPtr (PtrPreTD
, PtrTD
);
2491 PtrPreTD
->PtrNextTD
= (VOID
*)PtrTD
;
2493 PtrTD
->PtrNextTD
= NULL
;
2497 Execute Control Transfer.
2499 @param UhcDev The UCHI device.
2500 @param PtrTD A pointer to TD_STRUCT data.
2501 @param ActualLen Actual transfer Length.
2502 @param TimeOut TimeOut value.
2503 @param TransferResult Transfer Result.
2505 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2506 @return EFI_TIMEOUT The transfer failed due to time out.
2507 @return EFI_SUCCESS The transfer finished OK.
2511 ExecuteControlTransfer (
2512 IN USB_UHC_DEV
*UhcDev
,
2513 IN TD_STRUCT
*PtrTD
,
2514 OUT UINTN
*ActualLen
,
2516 OUT UINT32
*TransferResult
2521 BOOLEAN InfiniteLoop
;
2524 *TransferResult
= EFI_USB_NOERROR
;
2526 InfiniteLoop
= FALSE
;
2528 Delay
= TimeOut
* STALL_1_MILLI_SECOND
;
2530 // If Timeout is 0, then the caller must wait for the function to be completed
2531 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2534 InfiniteLoop
= TRUE
;
2538 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2541 // TD is inactive, means the control transfer is end.
2543 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2547 MicroSecondDelay (STALL_1_MICRO_SECOND
);
2549 } while (InfiniteLoop
|| (Delay
!= 0));
2551 if (*TransferResult
!= EFI_USB_NOERROR
) {
2552 return EFI_DEVICE_ERROR
;
2559 Execute Bulk Transfer.
2561 @param UhcDev The UCHI device.
2562 @param PtrTD A pointer to TD_STRUCT data.
2563 @param ActualLen Actual transfer Length.
2564 @param DataToggle DataToggle value.
2565 @param TimeOut TimeOut value.
2566 @param TransferResult Transfer Result.
2568 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2569 @return EFI_TIMEOUT The transfer failed due to time out.
2570 @return EFI_SUCCESS The transfer finished OK.
2575 IN USB_UHC_DEV
*UhcDev
,
2576 IN TD_STRUCT
*PtrTD
,
2577 IN OUT UINTN
*ActualLen
,
2578 IN UINT8
*DataToggle
,
2580 OUT UINT32
*TransferResult
2586 BOOLEAN InfiniteLoop
;
2589 *TransferResult
= EFI_USB_NOERROR
;
2591 InfiniteLoop
= FALSE
;
2593 Delay
= TimeOut
* STALL_1_MILLI_SECOND
;
2595 // If Timeout is 0, then the caller must wait for the function to be completed
2596 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2599 InfiniteLoop
= TRUE
;
2603 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2605 // TD is inactive, thus meaning bulk transfer's end.
2607 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2611 MicroSecondDelay (STALL_1_MICRO_SECOND
);
2613 } while (InfiniteLoop
|| (Delay
!= 0));
2618 if (*TransferResult
!= EFI_USB_NOERROR
) {
2620 // scroll the Data Toggle back to the last success TD
2622 ScrollNum
= CountTDsNumber (PtrTD
) - ErrTDPos
;
2623 if ((ScrollNum
% 2) != 0) {
2628 // If error, wait 100ms to retry by upper layer
2630 MicroSecondDelay (100 * 1000);
2631 return EFI_DEVICE_ERROR
;
2640 @param UhcDev The UCHI device.
2641 @param PtrFirstTD Place to store TD_STRUCT pointer.
2646 IN USB_UHC_DEV
*UhcDev
,
2647 IN TD_STRUCT
*PtrFirstTD
2656 // Delete all the TDs in a queue.
2658 while (Tptr1
!= NULL
) {
2661 if (!GetTDLinkPtrValidorInvalid (Tptr2
)) {
2665 // has more than one TD in the queue.
2667 Tptr1
= GetTDLinkPtr (Tptr2
);
2670 UhcFreePool (UhcDev
, (UINT8
*)Tptr2
, sizeof (TD_STRUCT
));
2679 @param PtrTD A pointer to TD_STRUCT data.
2680 @param Result The result to return.
2681 @param ErrTDPos The Error TD position.
2682 @param ActualTransferSize Actual transfer size.
2684 @retval The TD is executed successfully or not.
2689 IN TD_STRUCT
*PtrTD
,
2691 OUT UINTN
*ErrTDPos
,
2692 OUT UINTN
*ActualTransferSize
2697 *Result
= EFI_USB_NOERROR
;
2703 *ActualTransferSize
= 0;
2705 while (PtrTD
!= NULL
) {
2706 if (IsTDStatusActive (PtrTD
)) {
2707 *Result
|= EFI_USB_ERR_NOTEXECUTE
;
2710 if (IsTDStatusStalled (PtrTD
)) {
2711 *Result
|= EFI_USB_ERR_STALL
;
2714 if (IsTDStatusBufferError (PtrTD
)) {
2715 *Result
|= EFI_USB_ERR_BUFFER
;
2718 if (IsTDStatusBabbleError (PtrTD
)) {
2719 *Result
|= EFI_USB_ERR_BABBLE
;
2722 if (IsTDStatusNAKReceived (PtrTD
)) {
2723 *Result
|= EFI_USB_ERR_NAK
;
2726 if (IsTDStatusCRCTimeOutError (PtrTD
)) {
2727 *Result
|= EFI_USB_ERR_TIMEOUT
;
2730 if (IsTDStatusBitStuffError (PtrTD
)) {
2731 *Result
|= EFI_USB_ERR_BITSTUFF
;
2735 // Accumulate actual transferred data length in each TD.
2737 Len
= GetTDStatusActualLength (PtrTD
) & 0x7FF;
2738 *ActualTransferSize
+= Len
;
2741 // if any error encountered, stop processing the left TDs.
2743 if ((*Result
) != 0) {
2747 PtrTD
= (TD_STRUCT
*)(PtrTD
->PtrNextTD
);
2749 // Record the first Error TD's position in the queue,
2750 // this value is zero-based.
2759 Create Memory Block.
2761 @param UhcDev The UCHI device.
2762 @param MemoryHeader The Pointer to allocated memory block.
2763 @param MemoryBlockSizeInPages The page size of memory block to be allocated.
2765 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2766 @retval EFI_SUCCESS Success.
2771 IN USB_UHC_DEV
*UhcDev
,
2772 OUT MEMORY_MANAGE_HEADER
**MemoryHeader
,
2773 IN UINTN MemoryBlockSizeInPages
2781 EFI_PHYSICAL_ADDRESS MappedAddr
;
2784 // Memory Block uses MemoryBlockSizeInPages pages,
2785 // memory management header and bit array use 1 page
2787 MemPages
= MemoryBlockSizeInPages
+ 1;
2788 Status
= IoMmuAllocateBuffer (
2795 if (EFI_ERROR (Status
) || (TempPtr
== NULL
)) {
2796 return EFI_OUT_OF_RESOURCES
;
2801 ZeroMem (Ptr
, MemPages
* EFI_PAGE_SIZE
);
2803 *MemoryHeader
= (MEMORY_MANAGE_HEADER
*)Ptr
;
2805 // adjust Ptr pointer to the next empty memory
2807 Ptr
+= sizeof (MEMORY_MANAGE_HEADER
);
2809 // Set Bit Array initial address
2811 (*MemoryHeader
)->BitArrayPtr
= Ptr
;
2813 (*MemoryHeader
)->Next
= NULL
;
2816 // Memory block initial address
2819 Ptr
+= EFI_PAGE_SIZE
;
2820 (*MemoryHeader
)->MemoryBlockPtr
= Ptr
;
2822 // set Memory block size
2824 (*MemoryHeader
)->MemoryBlockSizeInBytes
= MemoryBlockSizeInPages
* EFI_PAGE_SIZE
;
2826 // each bit in Bit Array will manage 32byte memory in memory block
2828 (*MemoryHeader
)->BitArraySizeInBytes
= ((*MemoryHeader
)->MemoryBlockSizeInBytes
/ 32) / 8;
2834 Initialize UHCI memory management.
2836 @param UhcDev The UCHI device.
2838 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2839 @retval EFI_SUCCESS Success.
2843 InitializeMemoryManagement (
2844 IN USB_UHC_DEV
*UhcDev
2847 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2851 MemPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2852 Status
= CreateMemoryBlock (UhcDev
, &MemoryHeader
, MemPages
);
2853 if (EFI_ERROR (Status
)) {
2857 UhcDev
->Header1
= MemoryHeader
;
2863 Initialize UHCI memory management.
2865 @param UhcDev The UCHI device.
2866 @param Pool Buffer pointer to store the buffer pointer.
2867 @param AllocSize The size of the pool to be allocated.
2869 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2870 @retval EFI_SUCCESS Success.
2875 IN USB_UHC_DEV
*UhcDev
,
2880 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2881 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
2882 MEMORY_MANAGE_HEADER
*NewMemoryHeader
;
2883 UINTN RealAllocSize
;
2884 UINTN MemoryBlockSizeInPages
;
2889 MemoryHeader
= UhcDev
->Header1
;
2892 // allocate unit is 32 byte (align on 32 byte)
2894 if ((AllocSize
& 0x1F) != 0) {
2895 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
2897 RealAllocSize
= AllocSize
;
2900 Status
= EFI_NOT_FOUND
;
2901 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
2902 Status
= AllocMemInMemoryBlock (
2907 if (!EFI_ERROR (Status
)) {
2913 // There is no enough memory,
2914 // Create a new Memory Block
2917 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
2918 // just allocate a large enough memory block.
2920 if (RealAllocSize
> (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
* EFI_PAGE_SIZE
)) {
2921 MemoryBlockSizeInPages
= RealAllocSize
/ EFI_PAGE_SIZE
+ 1;
2923 MemoryBlockSizeInPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2926 Status
= CreateMemoryBlock (UhcDev
, &NewMemoryHeader
, MemoryBlockSizeInPages
);
2927 if (EFI_ERROR (Status
)) {
2932 // Link the new Memory Block to the Memory Header list
2934 InsertMemoryHeaderToList (MemoryHeader
, NewMemoryHeader
);
2936 Status
= AllocMemInMemoryBlock (
2945 Alloc Memory In MemoryBlock.
2947 @param MemoryHeader The pointer to memory manage header.
2948 @param Pool Buffer pointer to store the buffer pointer.
2949 @param NumberOfMemoryUnit The size of the pool to be allocated.
2951 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2952 @retval EFI_SUCCESS Success.
2956 AllocMemInMemoryBlock (
2957 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
2959 IN UINTN NumberOfMemoryUnit
2968 UINTN NumberOfZeros
;
2974 ByteValue
= MemoryHeader
->BitArrayPtr
[0];
2977 for (TempBytePos
= 0; TempBytePos
< MemoryHeader
->BitArraySizeInBytes
;) {
2979 // Pop out BitValue from a byte in TempBytePos.
2981 BitValue
= (UINT8
)(ByteValue
& 0x1);
2983 if (BitValue
== 0) {
2985 // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
2989 // Found enough consecutive free space, break the loop
2991 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2996 // Encountering a '1', meant the bit is ocupied.
2998 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
3000 // Found enough consecutive free space,break the loop
3005 // the NumberOfZeros only record the number of those consecutive zeros,
3006 // so reset the NumberOfZeros to 0 when encountering '1' before finding
3007 // enough consecutive '0's
3011 // reset the (FoundBytePos,FoundBitPos) to the position of '1'
3013 FoundBytePos
= TempBytePos
;
3014 FoundBitPos
= Index
;
3019 // right shift the byte
3024 // step forward a bit
3029 // step forward a byte, getting the byte value,
3030 // and reset the bit pos.
3033 ByteValue
= MemoryHeader
->BitArrayPtr
[TempBytePos
];
3038 if (NumberOfZeros
< NumberOfMemoryUnit
) {
3039 return EFI_NOT_FOUND
;
3043 // Found enough free space.
3046 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
3047 // 1)(FoundBytePos,FoundBitPos) record the position
3048 // of the last '1' before the consecutive '0's, it must
3049 // be adjusted to the start position of the consecutive '0's.
3050 // 2)the start address of the consecutive '0's is just the start of
3051 // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
3053 if ((MemoryHeader
->BitArrayPtr
[0] & BIT0
) != 0) {
3058 // Have the (FoundBytePos,FoundBitPos) make sense.
3060 if (FoundBitPos
> 7) {
3066 // Set the memory as allocated
3068 for (TempBytePos
= FoundBytePos
, Index
= FoundBitPos
, Count
= 0; Count
< NumberOfMemoryUnit
; Count
++) {
3069 MemoryHeader
->BitArrayPtr
[TempBytePos
] = (UINT8
)(MemoryHeader
->BitArrayPtr
[TempBytePos
] | (1 << Index
));
3077 *Pool
= MemoryHeader
->MemoryBlockPtr
+ (FoundBytePos
* 8 + FoundBitPos
) * 32;
3085 @param UhcDev The UHCI device.
3086 @param Pool A pointer to store the buffer address.
3087 @param AllocSize The size of the pool to be freed.
3092 IN USB_UHC_DEV
*UhcDev
,
3097 MEMORY_MANAGE_HEADER
*MemoryHeader
;
3098 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3104 UINTN RealAllocSize
;
3106 MemoryHeader
= UhcDev
->Header1
;
3109 // allocate unit is 32 byte (align on 32 byte)
3111 if ((AllocSize
& 0x1F) != 0) {
3112 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
3114 RealAllocSize
= AllocSize
;
3117 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
;
3118 TempHeaderPtr
= TempHeaderPtr
->Next
)
3120 if ((Pool
>= TempHeaderPtr
->MemoryBlockPtr
) &&
3121 ((Pool
+ RealAllocSize
) <= (TempHeaderPtr
->MemoryBlockPtr
+
3122 TempHeaderPtr
->MemoryBlockSizeInBytes
)))
3125 // Pool is in the Memory Block area,
3126 // find the start byte and bit in the bit array
3128 StartBytePos
= ((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) / 8;
3129 StartBitPos
= (UINT8
)(((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) % 8);
3132 // reset associated bits in bit array
3134 for (Index
= StartBytePos
, Index2
= StartBitPos
, Count
= 0; Count
< (RealAllocSize
/ 32); Count
++) {
3135 TempHeaderPtr
->BitArrayPtr
[Index
] = (UINT8
)(TempHeaderPtr
->BitArrayPtr
[Index
] ^ (1 << Index2
));
3152 Insert a new memory header into list.
3154 @param MemoryHeader A pointer to the memory header list.
3155 @param NewMemoryHeader A new memory header to be inserted into the list.
3159 InsertMemoryHeaderToList (
3160 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
3161 IN MEMORY_MANAGE_HEADER
*NewMemoryHeader
3164 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3166 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
3167 if (TempHeaderPtr
->Next
== NULL
) {
3168 TempHeaderPtr
->Next
= NewMemoryHeader
;
3175 Map address of request structure buffer.
3177 @param Uhc The UHCI device.
3178 @param Request The user request buffer.
3179 @param MappedAddr Mapped address of request.
3180 @param Map Identificaion of this mapping to return.
3182 @return EFI_SUCCESS Success.
3183 @return EFI_DEVICE_ERROR Fail to map the user request.
3187 UhciMapUserRequest (
3188 IN USB_UHC_DEV
*Uhc
,
3189 IN OUT VOID
*Request
,
3190 OUT UINT8
**MappedAddr
,
3196 EFI_PHYSICAL_ADDRESS PhyAddr
;
3198 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
3201 EdkiiIoMmuOperationBusMasterRead
,
3208 if (!EFI_ERROR (Status
)) {
3209 *MappedAddr
= (UINT8
*)(UINTN
)PhyAddr
;
3216 Map address of user data buffer.
3218 @param Uhc The UHCI device.
3219 @param Direction Direction of the data transfer.
3220 @param Data The user data buffer.
3221 @param Len Length of the user data.
3222 @param PktId Packet identificaion.
3223 @param MappedAddr Mapped address to return.
3224 @param Map Identificaion of this mapping to return.
3226 @return EFI_SUCCESS Success.
3227 @return EFI_DEVICE_ERROR Fail to map the user data.
3232 IN USB_UHC_DEV
*Uhc
,
3233 IN EFI_USB_DATA_DIRECTION Direction
,
3237 OUT UINT8
**MappedAddr
,
3242 EFI_PHYSICAL_ADDRESS PhyAddr
;
3244 Status
= EFI_SUCCESS
;
3246 switch (Direction
) {
3249 // BusMasterWrite means cpu read
3251 *PktId
= INPUT_PACKET_ID
;
3254 EdkiiIoMmuOperationBusMasterWrite
,
3261 if (EFI_ERROR (Status
)) {
3265 *MappedAddr
= (UINT8
*)(UINTN
)PhyAddr
;
3269 *PktId
= OUTPUT_PACKET_ID
;
3272 EdkiiIoMmuOperationBusMasterRead
,
3279 if (EFI_ERROR (Status
)) {
3283 *MappedAddr
= (UINT8
*)(UINTN
)PhyAddr
;
3287 if ((Len
!= NULL
) && (*Len
!= 0)) {
3288 Status
= EFI_INVALID_PARAMETER
;
3292 *PktId
= OUTPUT_PACKET_ID
;
3298 Status
= EFI_INVALID_PARAMETER
;