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
;
277 if (Request
== NULL
|| TransferResult
== NULL
) {
278 return EFI_INVALID_PARAMETER
;
281 // if errors exist that cause host controller halt,
282 // then return EFI_DEVICE_ERROR.
285 if (!IsStatusOK (UhcDev
, StatusReg
)) {
286 ClearStatusReg (UhcDev
, StatusReg
);
287 *TransferResult
= EFI_USB_ERR_SYSTEM
;
288 return EFI_DEVICE_ERROR
;
291 ClearStatusReg (UhcDev
, StatusReg
);
294 // Map the Request and data for bus master access,
295 // then create a list of TD for this transfer
297 Status
= UhciMapUserRequest (UhcDev
, Request
, &RequestPhy
, &RequestMap
);
298 if (EFI_ERROR (Status
)) {
302 Status
= UhciMapUserData (UhcDev
, TransferDirection
, Data
, DataLength
, &PktID
, &DataPhy
, &DataMap
);
304 if (EFI_ERROR (Status
)) {
305 if (RequestMap
!= NULL
) {
306 IoMmuUnmap (UhcDev
->IoMmu
, RequestMap
);
312 // generate Setup Stage TD
315 PtrQH
= UhcDev
->ConfigQH
;
324 (UINT8
) sizeof (EFI_USB_DEVICE_REQUEST
),
329 // link setup TD structures to QH structure
331 LinkTDToQH (PtrQH
, PtrSetupTD
);
333 PtrPreTD
= PtrSetupTD
;
336 // Data Stage of Control Transfer
339 if (TransferDirection
== EfiUsbNoData
) {
342 DataLen
= (UINT32
) *DataLength
;
348 while (DataLen
> 0) {
350 // create TD structures and link together
355 // PacketSize is the data load size of each TD carries.
357 PacketSize
= (UINT8
) DataLen
;
358 if (DataLen
> MaximumPacketLength
) {
359 PacketSize
= MaximumPacketLength
;
376 // Link two TDs in vertical depth
378 LinkTDToTD (PtrPreTD
, PtrTD
);
382 Data
= (VOID
*) ((UINT8
*) Data
+ PacketSize
);
383 DataPhy
+= PacketSize
;
384 DataLen
-= PacketSize
;
388 // PtrPreTD points to the last TD before the Setup-Stage TD.
393 // Status Stage of Control Transfer
395 if (PktID
== OUTPUT_PACKET_ID
) {
396 PktID
= INPUT_PACKET_ID
;
398 PktID
= OUTPUT_PACKET_ID
;
401 // create Status Stage TD structure
412 LinkTDToTD (PtrPreTD
, PtrStatusTD
);
415 // Poll QH-TDs execution and get result.
416 // detail status is returned
418 Status
= ExecuteControlTransfer (
427 // TRUE means must search other framelistindex
429 SetQHVerticalValidorInvalid(PtrQH
, FALSE
);
430 DeleteQueuedTDs (UhcDev
, PtrSetupTD
);
433 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
435 if (!IsStatusOK (UhcDev
, StatusReg
)) {
436 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
437 Status
= EFI_DEVICE_ERROR
;
440 ClearStatusReg (UhcDev
, StatusReg
);
442 if (DataMap
!= NULL
) {
443 IoMmuUnmap (UhcDev
->IoMmu
, DataMap
);
445 if (RequestMap
!= NULL
) {
446 IoMmuUnmap (UhcDev
->IoMmu
, RequestMap
);
453 Submits bulk transfer to a bulk endpoint of a USB device.
455 @param PeiServices The pointer of EFI_PEI_SERVICES.
456 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
457 @param DeviceAddress Target device address.
458 @param EndPointAddress Endpoint number and its direction in bit 7.
459 @param MaximumPacketLength Maximum packet size the endpoint is capable of
460 sending or receiving.
461 @param Data Array of pointers to the buffers of data to transmit
462 from or receive into.
463 @param DataLength The lenght of the data buffer.
464 @param DataToggle On input, the initial data toggle for the transfer;
465 On output, it is updated to to next data toggle to use of
466 the subsequent bulk transfer.
467 @param TimeOut Indicates the maximum time, in millisecond, which the
468 transfer is allowed to complete.
469 If Timeout is 0, then the caller must wait for the function
470 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
471 @param TransferResult A pointer to the detailed result information of the
474 @retval EFI_SUCCESS The transfer was completed successfully.
475 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
476 @retval EFI_INVALID_PARAMETER Parameters are invalid.
477 @retval EFI_TIMEOUT The transfer failed due to timeout.
478 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
484 IN EFI_PEI_SERVICES
**PeiServices
,
485 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
486 IN UINT8 DeviceAddress
,
487 IN UINT8 EndPointAddress
,
488 IN UINT8 MaximumPacketLength
,
490 IN OUT UINTN
*DataLength
,
491 IN OUT UINT8
*DataToggle
,
493 OUT UINT32
*TransferResult
502 TD_STRUCT
*PtrFirstTD
;
512 EFI_USB_DATA_DIRECTION TransferDirection
;
514 BOOLEAN ShortPacketEnable
;
516 UINT16 CommandContent
;
521 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
524 // Enable the maximum packet size (64bytes)
525 // that can be used for full speed bandwidth reclamation
526 // at the end of a frame.
528 CommandContent
= USBReadPortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
);
529 if ((CommandContent
& USBCMD_MAXP
) != USBCMD_MAXP
) {
530 CommandContent
|= USBCMD_MAXP
;
531 USBWritePortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
, CommandContent
);
534 StatusReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBSTS
;
537 // these code lines are added here per complier's strict demand
539 PktID
= INPUT_PACKET_ID
;
545 ShortPacketEnable
= FALSE
;
547 if ((DataLength
== 0) || (Data
== NULL
) || (TransferResult
== NULL
)) {
548 return EFI_INVALID_PARAMETER
;
551 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
552 return EFI_INVALID_PARAMETER
;
555 if (MaximumPacketLength
!= 8 && MaximumPacketLength
!= 16
556 && MaximumPacketLength
!= 32 && MaximumPacketLength
!= 64) {
557 return EFI_INVALID_PARAMETER
;
560 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
562 if (!IsStatusOK (UhcDev
, StatusReg
)) {
564 ClearStatusReg (UhcDev
, StatusReg
);
565 *TransferResult
= EFI_USB_ERR_SYSTEM
;
566 return EFI_DEVICE_ERROR
;
569 ClearStatusReg (UhcDev
, StatusReg
);
572 // Map the source data buffer for bus master access,
573 // then create a list of TDs
575 if ((EndPointAddress
& 0x80) != 0) {
576 TransferDirection
= EfiUsbDataIn
;
578 TransferDirection
= EfiUsbDataOut
;
581 Status
= UhciMapUserData (UhcDev
, TransferDirection
, Data
, DataLength
, &PktID
, &DataPhy
, &DataMap
);
583 if (EFI_ERROR (Status
)) {
587 DataLen
= (UINT32
) *DataLength
;
589 PtrQH
= UhcDev
->BulkQH
;
592 while (DataLen
> 0) {
594 // create TD structures and link together
598 PacketSize
= (UINT8
) DataLen
;
599 if (DataLen
> MaximumPacketLength
) {
600 PacketSize
= MaximumPacketLength
;
612 USB_FULL_SPEED_DEVICE
,
617 // Enable short packet detection.
618 // (default action is disabling short packet detection)
620 if (ShortPacketEnable
) {
621 EnableorDisableTDShortPacket (PtrTD
, TRUE
);
626 PtrFirstTD
->PtrNextTD
= NULL
;
630 // Link two TDs in vertical depth
632 LinkTDToTD (PtrPreTD
, PtrTD
);
638 Data
= (VOID
*) ((UINT8
*) Data
+ PacketSize
);
639 DataPhy
+= PacketSize
;
640 DataLen
-= PacketSize
;
643 // link TD structures to QH structure
645 LinkTDToQH (PtrQH
, PtrFirstTD
);
648 // Execute QH-TD and get result
651 // detail status is put into the Result field in the pIRP
652 // the Data Toggle value is also re-updated to the value
653 // of the last successful TD
655 Status
= ExecBulkTransfer (
665 // Delete Bulk transfer TD structure
667 DeleteQueuedTDs (UhcDev
, PtrFirstTD
);
670 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
672 if (!IsStatusOK (UhcDev
, StatusReg
)) {
673 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
674 Status
= EFI_DEVICE_ERROR
;
677 ClearStatusReg (UhcDev
, StatusReg
);
679 if (DataMap
!= NULL
) {
680 IoMmuUnmap (UhcDev
->IoMmu
, DataMap
);
687 Retrieves the number of root hub ports.
689 @param[in] PeiServices The pointer to the PEI Services Table.
690 @param[in] This The pointer to this instance of the
691 PEI_USB_HOST_CONTROLLER_PPI.
692 @param[out] PortNumber The pointer to the number of the root hub ports.
694 @retval EFI_SUCCESS The port number was retrieved successfully.
695 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
700 UhcGetRootHubPortNumber (
701 IN EFI_PEI_SERVICES
**PeiServices
,
702 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
703 OUT UINT8
*PortNumber
708 UINT16 RHPortControl
;
711 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
713 if (PortNumber
== NULL
) {
714 return EFI_INVALID_PARAMETER
;
719 for (Index
= 0; Index
< 2; Index
++) {
720 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ Index
* 2;
721 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
723 // Port Register content is valid
725 if (RHPortControl
!= 0xff) {
734 Retrieves the current status of a USB root hub port.
736 @param PeiServices The pointer of EFI_PEI_SERVICES.
737 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
738 @param PortNumber The root hub port to retrieve the state from.
739 @param PortStatus Variable to receive the port state.
741 @retval EFI_SUCCESS The status of the USB root hub port specified.
742 by PortNumber was returned in PortStatus.
743 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
748 UhcGetRootHubPortStatus (
749 IN EFI_PEI_SERVICES
**PeiServices
,
750 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
752 OUT EFI_USB_PORT_STATUS
*PortStatus
758 UINT8 TotalPortNumber
;
760 if (PortStatus
== NULL
) {
761 return EFI_INVALID_PARAMETER
;
764 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
765 if (PortNumber
> TotalPortNumber
) {
766 return EFI_INVALID_PARAMETER
;
769 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
770 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
772 PortStatus
->PortStatus
= 0;
773 PortStatus
->PortChangeStatus
= 0;
775 RHPortStatus
= USBReadPortW (UhcDev
, PSAddr
);
778 // Current Connect Status
780 if ((RHPortStatus
& USBPORTSC_CCS
) != 0) {
781 PortStatus
->PortStatus
|= USB_PORT_STAT_CONNECTION
;
784 // Port Enabled/Disabled
786 if ((RHPortStatus
& USBPORTSC_PED
) != 0) {
787 PortStatus
->PortStatus
|= USB_PORT_STAT_ENABLE
;
792 if ((RHPortStatus
& USBPORTSC_SUSP
) != 0) {
793 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
798 if ((RHPortStatus
& USBPORTSC_PR
) != 0) {
799 PortStatus
->PortStatus
|= USB_PORT_STAT_RESET
;
802 // Low Speed Device Attached
804 if ((RHPortStatus
& USBPORTSC_LSDA
) != 0) {
805 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
808 // Fill Port Status Change bits
811 // Connect Status Change
813 if ((RHPortStatus
& USBPORTSC_CSC
) != 0) {
814 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_CONNECTION
;
817 // Port Enabled/Disabled Change
819 if ((RHPortStatus
& USBPORTSC_PEDC
) != 0) {
820 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_ENABLE
;
827 Sets a feature for the specified root hub port.
829 @param PeiServices The pointer of EFI_PEI_SERVICES
830 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI
831 @param PortNumber Root hub port to set.
832 @param PortFeature Feature to set.
834 @retval EFI_SUCCESS The feature specified by PortFeature was set.
835 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
836 @retval EFI_TIMEOUT The time out occurred.
841 UhcSetRootHubPortFeature (
842 IN EFI_PEI_SERVICES
**PeiServices
,
843 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
845 IN EFI_USB_PORT_FEATURE PortFeature
850 UINT32 CommandRegAddr
;
851 UINT16 RHPortControl
;
852 UINT8 TotalPortNumber
;
854 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
855 if (PortNumber
> TotalPortNumber
) {
856 return EFI_INVALID_PARAMETER
;
859 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
860 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
861 CommandRegAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
863 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
865 switch (PortFeature
) {
867 case EfiUsbPortSuspend
:
868 if ((USBReadPortW (UhcDev
, CommandRegAddr
) & USBCMD_EGSM
) == 0) {
870 // if global suspend is not active, can set port suspend
872 RHPortControl
&= 0xfff5;
873 RHPortControl
|= USBPORTSC_SUSP
;
877 case EfiUsbPortReset
:
878 RHPortControl
&= 0xfff5;
879 RHPortControl
|= USBPORTSC_PR
;
885 case EfiUsbPortPower
:
888 case EfiUsbPortEnable
:
889 RHPortControl
&= 0xfff5;
890 RHPortControl
|= USBPORTSC_PED
;
894 return EFI_INVALID_PARAMETER
;
897 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
903 Clears a feature for the specified root hub port.
905 @param PeiServices The pointer of EFI_PEI_SERVICES.
906 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
907 @param PortNumber Specifies the root hub port whose feature
908 is requested to be cleared.
909 @param PortFeature Indicates the feature selector associated with the
910 feature clear request.
912 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
913 for the USB root hub port specified by PortNumber.
914 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
919 UhcClearRootHubPortFeature (
920 IN EFI_PEI_SERVICES
**PeiServices
,
921 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
923 IN EFI_USB_PORT_FEATURE PortFeature
928 UINT16 RHPortControl
;
929 UINT8 TotalPortNumber
;
931 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
933 if (PortNumber
> TotalPortNumber
) {
934 return EFI_INVALID_PARAMETER
;
937 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
938 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
940 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
942 switch (PortFeature
) {
944 // clear PORT_ENABLE feature means disable port.
946 case EfiUsbPortEnable
:
947 RHPortControl
&= 0xfff5;
948 RHPortControl
&= ~USBPORTSC_PED
;
952 // clear PORT_SUSPEND feature means resume the port.
953 // (cause a resume on the specified port if in suspend mode)
955 case EfiUsbPortSuspend
:
956 RHPortControl
&= 0xfff5;
957 RHPortControl
&= ~USBPORTSC_SUSP
;
963 case EfiUsbPortPower
:
967 // clear PORT_RESET means clear the reset signal.
969 case EfiUsbPortReset
:
970 RHPortControl
&= 0xfff5;
971 RHPortControl
&= ~USBPORTSC_PR
;
975 // clear connect status change
977 case EfiUsbPortConnectChange
:
978 RHPortControl
&= 0xfff5;
979 RHPortControl
|= USBPORTSC_CSC
;
983 // clear enable/disable status change
985 case EfiUsbPortEnableChange
:
986 RHPortControl
&= 0xfff5;
987 RHPortControl
|= USBPORTSC_PEDC
;
991 // root hub does not support this request
993 case EfiUsbPortSuspendChange
:
997 // root hub does not support this request
999 case EfiUsbPortOverCurrentChange
:
1003 // root hub does not support this request
1005 case EfiUsbPortResetChange
:
1009 return EFI_INVALID_PARAMETER
;
1012 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
1020 @param UhcDev UHCI Device.
1022 @retval EFI_SUCCESS UHCI successfully initialized.
1023 @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.
1028 IN USB_UHC_DEV
*UhcDev
1032 UINT32 FrameListBaseAddrReg
;
1037 // Create and Initialize Frame List For the Host Controller.
1039 Status
= CreateFrameList (UhcDev
);
1040 if (EFI_ERROR (Status
)) {
1044 FrameListBaseAddrReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBFLBASEADD
;
1045 CommandReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
1048 // Set Frame List Base Address to the specific register to inform the hardware.
1050 SetFrameListBaseAddress (UhcDev
, FrameListBaseAddrReg
, (UINT32
) (UINTN
) (UhcDev
->FrameListEntry
));
1052 Command
= USBReadPortW (UhcDev
, CommandReg
);
1053 Command
|= USBCMD_GRESET
;
1054 USBWritePortW (UhcDev
, CommandReg
, Command
);
1056 MicroSecondDelay (50 * 1000);
1059 Command
&= ~USBCMD_GRESET
;
1061 USBWritePortW (UhcDev
, CommandReg
, Command
);
1064 //UHCI spec page120 reset recovery time
1066 MicroSecondDelay (20 * 1000);
1069 // Set Run/Stop bit to 1.
1071 Command
= USBReadPortW (UhcDev
, CommandReg
);
1072 Command
|= USBCMD_RS
| USBCMD_MAXP
;
1073 USBWritePortW (UhcDev
, CommandReg
, Command
);
1079 Create Frame List Structure.
1081 @param UhcDev UHCI device.
1083 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1084 @retval EFI_SUCCESS Success.
1093 EFI_PHYSICAL_ADDRESS FrameListBaseAddr
;
1094 FRAMELIST_ENTRY
*FrameListPtr
;
1098 // The Frame List ocupies 4K bytes,
1099 // and must be aligned on 4-Kbyte boundaries.
1101 Status
= PeiServicesAllocatePages (
1102 EfiBootServicesData
,
1107 if (Status
!= EFI_SUCCESS
) {
1108 return EFI_OUT_OF_RESOURCES
;
1112 //Create Control QH and Bulk QH and link them into Framelist Entry
1114 Status
= CreateQH(UhcDev
, &UhcDev
->ConfigQH
);
1115 if (Status
!= EFI_SUCCESS
) {
1116 return EFI_OUT_OF_RESOURCES
;
1118 ASSERT (UhcDev
->ConfigQH
!= NULL
);
1120 Status
= CreateQH(UhcDev
, &UhcDev
->BulkQH
);
1121 if (Status
!= EFI_SUCCESS
) {
1122 return EFI_OUT_OF_RESOURCES
;
1124 ASSERT (UhcDev
->BulkQH
!= NULL
);
1127 //Set the corresponding QH pointer
1129 SetQHHorizontalLinkPtr(UhcDev
->ConfigQH
, UhcDev
->BulkQH
);
1130 SetQHHorizontalQHorTDSelect (UhcDev
->ConfigQH
, TRUE
);
1131 SetQHHorizontalValidorInvalid (UhcDev
->ConfigQH
, TRUE
);
1133 UhcDev
->FrameListEntry
= (FRAMELIST_ENTRY
*) ((UINTN
) FrameListBaseAddr
);
1135 FrameListPtr
= UhcDev
->FrameListEntry
;
1137 for (Index
= 0; Index
< 1024; Index
++) {
1138 FrameListPtr
->FrameListPtrTerminate
= 0;
1139 FrameListPtr
->FrameListPtr
= (UINT32
)(UINTN
)UhcDev
->ConfigQH
>> 4;
1140 FrameListPtr
->FrameListPtrQSelect
= 1;
1141 FrameListPtr
->FrameListRsvd
= 0;
1149 Read a 16bit width data from Uhc HC IO space register.
1151 @param UhcDev The UHCI device.
1152 @param Port The IO space address of the register.
1154 @retval the register content read.
1159 IN USB_UHC_DEV
*UhcDev
,
1163 return IoRead16 (Port
);
1167 Write a 16bit width data into Uhc HC IO space register.
1169 @param UhcDev The UHCI device.
1170 @param Port The IO space address of the register.
1171 @param Data The data written into the register.
1176 IN USB_UHC_DEV
*UhcDev
,
1181 IoWrite16 (Port
, Data
);
1185 Write a 32bit width data into Uhc HC IO space register.
1187 @param UhcDev The UHCI device.
1188 @param Port The IO space address of the register.
1189 @param Data The data written into the register.
1194 IN USB_UHC_DEV
*UhcDev
,
1199 IoWrite32 (Port
, Data
);
1203 Clear the content of UHCI's Status Register.
1205 @param UhcDev The UHCI device.
1206 @param StatusAddr The IO space address of the register.
1211 IN USB_UHC_DEV
*UhcDev
,
1212 IN UINT32 StatusAddr
1216 // Clear the content of UHCI's Status Register
1218 USBWritePortW (UhcDev
, StatusAddr
, 0x003F);
1222 Check whether the host controller operates well.
1224 @param UhcDev The UHCI device.
1225 @param StatusRegAddr The io address of status register.
1227 @retval TRUE Host controller is working.
1228 @retval FALSE Host controller is halted or system error.
1233 IN USB_UHC_DEV
*UhcDev
,
1234 IN UINT32 StatusRegAddr
1239 StatusValue
= USBReadPortW (UhcDev
, StatusRegAddr
);
1241 if ((StatusValue
& (USBSTS_HCPE
| USBSTS_HSE
| USBSTS_HCH
)) != 0) {
1251 Set Frame List Base Address.
1253 @param UhcDev The UHCI device.
1254 @param FrameListRegAddr The address of frame list register.
1255 @param Addr The address of frame list table.
1259 SetFrameListBaseAddress (
1260 IN USB_UHC_DEV
*UhcDev
,
1261 IN UINT32 FrameListRegAddr
,
1266 // Sets value in the USB Frame List Base Address register.
1268 USBWritePortDW (UhcDev
, FrameListRegAddr
, (UINT32
) (Addr
& 0xFFFFF000));
1272 Create QH and initialize.
1274 @param UhcDev The UHCI device.
1275 @param PtrQH Place to store QH_STRUCT pointer.
1277 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1278 @retval EFI_SUCCESS Success.
1283 IN USB_UHC_DEV
*UhcDev
,
1284 OUT QH_STRUCT
**PtrQH
1290 // allocate align memory for QH_STRUCT
1292 Status
= AllocateTDorQHStruct (UhcDev
, sizeof(QH_STRUCT
), (void **)PtrQH
);
1293 if (EFI_ERROR (Status
)) {
1294 return EFI_OUT_OF_RESOURCES
;
1297 // init each field of the QH_STRUCT
1299 SetQHHorizontalValidorInvalid (*PtrQH
, FALSE
);
1300 SetQHVerticalValidorInvalid (*PtrQH
, FALSE
);
1306 Set the horizontal link pointer in QH.
1308 @param PtrQH Place to store QH_STRUCT pointer.
1309 @param PtrNext Place to the next QH_STRUCT.
1313 SetQHHorizontalLinkPtr (
1314 IN QH_STRUCT
*PtrQH
,
1319 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1320 // Only the highest 28bit of the address is valid
1321 // (take 32bit address as an example).
1323 PtrQH
->QueueHead
.QHHorizontalPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1329 Set a QH or TD horizontally to be connected with a specific QH.
1331 @param PtrQH Place to store QH_STRUCT pointer.
1332 @param IsQH Specify QH or TD is connected.
1336 SetQHHorizontalQHorTDSelect (
1337 IN QH_STRUCT
*PtrQH
,
1342 // if QH is connected, the specified bit is set,
1343 // if TD is connected, the specified bit is cleared.
1345 PtrQH
->QueueHead
.QHHorizontalQSelect
= IsQH
? 1 : 0;
1349 Set the horizontal validor bit in QH.
1351 @param PtrQH Place to store QH_STRUCT pointer.
1352 @param IsValid Specify the horizontal linker is valid or not.
1356 SetQHHorizontalValidorInvalid (
1357 IN QH_STRUCT
*PtrQH
,
1362 // Valid means the horizontal link pointer is valid,
1363 // else, it's invalid.
1365 PtrQH
->QueueHead
.QHHorizontalTerminate
= IsValid
? 0 : 1;
1369 Set the vertical link pointer in QH.
1371 @param PtrQH Place to store QH_STRUCT pointer.
1372 @param PtrNext Place to the next QH_STRUCT.
1376 SetQHVerticalLinkPtr (
1377 IN QH_STRUCT
*PtrQH
,
1382 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1383 // Only the highest 28bit of the address is valid
1384 // (take 32bit address as an example).
1386 PtrQH
->QueueHead
.QHVerticalPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1390 Set a QH or TD vertically to be connected with a specific QH.
1392 @param PtrQH Place to store QH_STRUCT pointer.
1393 @param IsQH Specify QH or TD is connected.
1397 SetQHVerticalQHorTDSelect (
1398 IN QH_STRUCT
*PtrQH
,
1403 // Set the specified bit if the Vertical Link Pointer pointing to a QH,
1404 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
1406 PtrQH
->QueueHead
.QHVerticalQSelect
= IsQH
? 1 : 0;
1410 Set the vertical validor bit in QH.
1412 @param PtrQH Place to store QH_STRUCT pointer.
1413 @param IsValid Specify the vertical linker is valid or not.
1417 SetQHVerticalValidorInvalid (
1418 IN QH_STRUCT
*PtrQH
,
1423 // If TRUE, meaning the Vertical Link Pointer field is valid,
1424 // else, the field is invalid.
1426 PtrQH
->QueueHead
.QHVerticalTerminate
= IsValid
? 0 : 1;
1432 Allocate TD or QH Struct.
1434 @param UhcDev The UHCI device.
1435 @param Size The size of allocation.
1436 @param PtrStruct Place to store TD_STRUCT pointer.
1438 @return EFI_SUCCESS Allocate successfully.
1439 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1443 AllocateTDorQHStruct (
1444 IN USB_UHC_DEV
*UhcDev
,
1446 OUT VOID
**PtrStruct
1451 Status
= EFI_SUCCESS
;
1454 Status
= UhcAllocatePool (
1456 (UINT8
**) PtrStruct
,
1459 if (EFI_ERROR (Status
)) {
1463 ZeroMem (*PtrStruct
, Size
);
1471 @param UhcDev The UHCI device.
1472 @param PtrTD Place to store TD_STRUCT pointer.
1474 @return EFI_SUCCESS Allocate successfully.
1475 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1480 IN USB_UHC_DEV
*UhcDev
,
1481 OUT TD_STRUCT
**PtrTD
1486 // create memory for TD_STRUCT, and align the memory.
1488 Status
= AllocateTDorQHStruct (UhcDev
, sizeof(TD_STRUCT
), (void **)PtrTD
);
1489 if (EFI_ERROR (Status
)) {
1496 SetTDLinkPtrValidorInvalid (*PtrTD
, FALSE
);
1502 Generate Setup Stage TD.
1504 @param UhcDev The UHCI device.
1505 @param DevAddr Device address.
1506 @param Endpoint Endpoint number.
1507 @param DeviceSpeed Device Speed.
1508 @param DevRequest CPU memory address of request structure buffer to transfer.
1509 @param RequestPhy PCI memory address of request structure buffer to transfer.
1510 @param RequestLen Request length.
1511 @param PtrTD TD_STRUCT generated.
1513 @return EFI_SUCCESS Generate setup stage TD successfully.
1514 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1519 IN USB_UHC_DEV
*UhcDev
,
1522 IN UINT8 DeviceSpeed
,
1523 IN UINT8
*DevRequest
,
1524 IN UINT8
*RequestPhy
,
1525 IN UINT8 RequestLen
,
1526 OUT TD_STRUCT
**PtrTD
1529 TD_STRUCT
*TdStruct
;
1532 Status
= CreateTD (UhcDev
, &TdStruct
);
1533 if (EFI_ERROR (Status
)) {
1537 SetTDLinkPtr (TdStruct
, NULL
);
1540 // Depth first fashion
1542 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1545 // initialize as the last TD in the QH context,
1546 // this field will be updated in the TD linkage process.
1548 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1551 // Disable Short Packet Detection by default
1553 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1556 // Max error counter is 3, retry 3 times when error encountered.
1558 SetTDControlErrorCounter (TdStruct
, 3);
1561 // set device speed attribute
1562 // (TRUE - Slow Device; FALSE - Full Speed Device)
1564 switch (DeviceSpeed
) {
1565 case USB_SLOW_SPEED_DEVICE
:
1566 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1569 case USB_FULL_SPEED_DEVICE
:
1570 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1574 // Non isochronous transfer TD
1576 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1579 // Interrupt On Complete bit be set to zero,
1580 // Disable IOC interrupt.
1582 SetorClearTDControlIOC (TdStruct
, FALSE
);
1585 // Set TD Active bit
1587 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1589 SetTDTokenMaxLength (TdStruct
, RequestLen
);
1591 SetTDTokenDataToggle0 (TdStruct
);
1593 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1595 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1597 SetTDTokenPacketID (TdStruct
, SETUP_PACKET_ID
);
1599 TdStruct
->PtrTDBuffer
= (UINT8
*) DevRequest
;
1600 TdStruct
->TDBufferLength
= RequestLen
;
1602 // Set the beginning address of the buffer that will be used
1603 // during the transaction.
1605 TdStruct
->TDData
.TDBufferPtr
= (UINT32
) (UINTN
) RequestPhy
;
1613 Generate Data Stage TD.
1615 @param UhcDev The UHCI device.
1616 @param DevAddr Device address.
1617 @param Endpoint Endpoint number.
1618 @param PtrData CPU memory address of user data buffer to transfer.
1619 @param DataPhy PCI memory address of user data buffer to transfer.
1620 @param Len Data length.
1621 @param PktID PacketID.
1622 @param Toggle Data toggle value.
1623 @param DeviceSpeed Device Speed.
1624 @param PtrTD TD_STRUCT generated.
1626 @return EFI_SUCCESS Generate data stage TD successfully.
1627 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1632 IN USB_UHC_DEV
*UhcDev
,
1640 IN UINT8 DeviceSpeed
,
1641 OUT TD_STRUCT
**PtrTD
1644 TD_STRUCT
*TdStruct
;
1647 Status
= CreateTD (UhcDev
, &TdStruct
);
1648 if (EFI_ERROR (Status
)) {
1652 SetTDLinkPtr (TdStruct
, NULL
);
1655 // Depth first fashion
1657 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1660 // Link pointer pointing to TD struct
1662 SetTDLinkPtrQHorTDSelect (TdStruct
, FALSE
);
1665 // initialize as the last TD in the QH context,
1666 // this field will be updated in the TD linkage process.
1668 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1671 // Disable short packet detect
1673 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1675 // Max error counter is 3
1677 SetTDControlErrorCounter (TdStruct
, 3);
1680 // set device speed attribute
1681 // (TRUE - Slow Device; FALSE - Full Speed Device)
1683 switch (DeviceSpeed
) {
1684 case USB_SLOW_SPEED_DEVICE
:
1685 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1688 case USB_FULL_SPEED_DEVICE
:
1689 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1693 // Non isochronous transfer TD
1695 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1698 // Disable Interrupt On Complete
1699 // Disable IOC interrupt.
1701 SetorClearTDControlIOC (TdStruct
, FALSE
);
1706 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1708 SetTDTokenMaxLength (TdStruct
, Len
);
1711 SetTDTokenDataToggle1 (TdStruct
);
1713 SetTDTokenDataToggle0 (TdStruct
);
1716 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1718 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1720 SetTDTokenPacketID (TdStruct
, PktID
);
1722 TdStruct
->PtrTDBuffer
= (UINT8
*) PtrData
;
1723 TdStruct
->TDBufferLength
= Len
;
1725 // Set the beginning address of the buffer that will be used
1726 // during the transaction.
1728 TdStruct
->TDData
.TDBufferPtr
= (UINT32
) (UINTN
) DataPhy
;
1736 Generate Status Stage TD.
1738 @param UhcDev The UHCI device.
1739 @param DevAddr Device address.
1740 @param Endpoint Endpoint number.
1741 @param PktID PacketID.
1742 @param DeviceSpeed Device Speed.
1743 @param PtrTD TD_STRUCT generated.
1745 @return EFI_SUCCESS Generate status stage TD successfully.
1746 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1751 IN USB_UHC_DEV
*UhcDev
,
1755 IN UINT8 DeviceSpeed
,
1756 OUT TD_STRUCT
**PtrTD
1759 TD_STRUCT
*PtrTDStruct
;
1762 Status
= CreateTD (UhcDev
, &PtrTDStruct
);
1763 if (EFI_ERROR (Status
)) {
1767 SetTDLinkPtr (PtrTDStruct
, NULL
);
1770 // Depth first fashion
1772 SetTDLinkPtrDepthorBreadth (PtrTDStruct
, TRUE
);
1775 // initialize as the last TD in the QH context,
1776 // this field will be updated in the TD linkage process.
1778 SetTDLinkPtrValidorInvalid (PtrTDStruct
, FALSE
);
1781 // Disable short packet detect
1783 EnableorDisableTDShortPacket (PtrTDStruct
, FALSE
);
1786 // Max error counter is 3
1788 SetTDControlErrorCounter (PtrTDStruct
, 3);
1791 // set device speed attribute
1792 // (TRUE - Slow Device; FALSE - Full Speed Device)
1794 switch (DeviceSpeed
) {
1795 case USB_SLOW_SPEED_DEVICE
:
1796 SetTDLoworFullSpeedDevice (PtrTDStruct
, TRUE
);
1799 case USB_FULL_SPEED_DEVICE
:
1800 SetTDLoworFullSpeedDevice (PtrTDStruct
, FALSE
);
1804 // Non isochronous transfer TD
1806 SetTDControlIsochronousorNot (PtrTDStruct
, FALSE
);
1809 // Disable Interrupt On Complete
1810 // Disable IOC interrupt.
1812 SetorClearTDControlIOC (PtrTDStruct
, FALSE
);
1815 // Set TD Active bit
1817 SetTDStatusActiveorInactive (PtrTDStruct
, TRUE
);
1819 SetTDTokenMaxLength (PtrTDStruct
, 0);
1821 SetTDTokenDataToggle1 (PtrTDStruct
);
1823 SetTDTokenEndPoint (PtrTDStruct
, Endpoint
);
1825 SetTDTokenDeviceAddress (PtrTDStruct
, DevAddr
);
1827 SetTDTokenPacketID (PtrTDStruct
, PktID
);
1829 PtrTDStruct
->PtrTDBuffer
= NULL
;
1830 PtrTDStruct
->TDBufferLength
= 0;
1832 // Set the beginning address of the buffer that will be used
1833 // during the transaction.
1835 PtrTDStruct
->TDData
.TDBufferPtr
= 0;
1837 *PtrTD
= PtrTDStruct
;
1843 Set the link pointer validor bit in TD.
1845 @param PtrTDStruct Place to store TD_STRUCT pointer.
1846 @param IsValid Specify the linker pointer is valid or not.
1850 SetTDLinkPtrValidorInvalid (
1851 IN TD_STRUCT
*PtrTDStruct
,
1856 // Valid means the link pointer is valid,
1857 // else, it's invalid.
1859 PtrTDStruct
->TDData
.TDLinkPtrTerminate
= (IsValid
? 0 : 1);
1863 Set the Link Pointer pointing to a QH or TD.
1865 @param PtrTDStruct Place to store TD_STRUCT pointer.
1866 @param IsQH Specify QH or TD is connected.
1870 SetTDLinkPtrQHorTDSelect (
1871 IN TD_STRUCT
*PtrTDStruct
,
1876 // Indicate whether the Link Pointer pointing to a QH or TD
1878 PtrTDStruct
->TDData
.TDLinkPtrQSelect
= (IsQH
? 1 : 0);
1882 Set the traverse is depth-first or breadth-first.
1884 @param PtrTDStruct Place to store TD_STRUCT pointer.
1885 @param IsDepth Specify the traverse is depth-first or breadth-first.
1889 SetTDLinkPtrDepthorBreadth (
1890 IN TD_STRUCT
*PtrTDStruct
,
1895 // If TRUE, indicating the host controller should process in depth first fashion,
1896 // else, the host controller should process in breadth first fashion
1898 PtrTDStruct
->TDData
.TDLinkPtrDepthSelect
= (IsDepth
? 1 : 0);
1902 Set TD Link Pointer in TD.
1904 @param PtrTDStruct Place to store TD_STRUCT pointer.
1905 @param PtrNext Place to the next TD_STRUCT.
1910 IN TD_STRUCT
*PtrTDStruct
,
1915 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
1916 // only the highest 28 bits are valid. (if take 32bit address as an example)
1918 PtrTDStruct
->TDData
.TDLinkPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1922 Get TD Link Pointer.
1924 @param PtrTDStruct Place to store TD_STRUCT pointer.
1926 @retval Get TD Link Pointer in TD.
1931 IN TD_STRUCT
*PtrTDStruct
1935 // Get TD Link Pointer. Restore it back to 32bit
1936 // (if take 32bit address as an example)
1938 return (VOID
*) (UINTN
) ((PtrTDStruct
->TDData
.TDLinkPtr
) << 4);
1944 Enable/Disable short packet detection mechanism.
1946 @param PtrTDStruct Place to store TD_STRUCT pointer.
1947 @param IsEnable Enable or disable short packet detection mechanism.
1951 EnableorDisableTDShortPacket (
1952 IN TD_STRUCT
*PtrTDStruct
,
1957 // TRUE means enable short packet detection mechanism.
1959 PtrTDStruct
->TDData
.TDStatusSPD
= (IsEnable
? 1 : 0);
1963 Set the max error counter in TD.
1965 @param PtrTDStruct Place to store TD_STRUCT pointer.
1966 @param MaxErrors The number of allowable error.
1970 SetTDControlErrorCounter (
1971 IN TD_STRUCT
*PtrTDStruct
,
1976 // valid value of MaxErrors is 0,1,2,3
1978 if (MaxErrors
> 3) {
1982 PtrTDStruct
->TDData
.TDStatusErr
= MaxErrors
;
1986 Set the TD is targeting a low-speed device or not.
1988 @param PtrTDStruct Place to store TD_STRUCT pointer.
1989 @param IsLowSpeedDevice Whether The device is low-speed.
1993 SetTDLoworFullSpeedDevice (
1994 IN TD_STRUCT
*PtrTDStruct
,
1995 IN BOOLEAN IsLowSpeedDevice
1999 // TRUE means the TD is targeting at a Low-speed device
2001 PtrTDStruct
->TDData
.TDStatusLS
= (IsLowSpeedDevice
? 1 : 0);
2005 Set the TD is isochronous transfer type or not.
2007 @param PtrTDStruct Place to store TD_STRUCT pointer.
2008 @param IsIsochronous Whether the transaction isochronous transfer type.
2012 SetTDControlIsochronousorNot (
2013 IN TD_STRUCT
*PtrTDStruct
,
2014 IN BOOLEAN IsIsochronous
2018 // TRUE means the TD belongs to Isochronous transfer type.
2020 PtrTDStruct
->TDData
.TDStatusIOS
= (IsIsochronous
? 1 : 0);
2024 Set if UCHI should issue an interrupt on completion of the frame
2025 in which this TD is executed
2027 @param PtrTDStruct Place to store TD_STRUCT pointer.
2028 @param IsSet Whether HC should issue an interrupt on completion.
2032 SetorClearTDControlIOC (
2033 IN TD_STRUCT
*PtrTDStruct
,
2038 // If this bit is set, it indicates that the host controller should issue
2039 // an interrupt on completion of the frame in which this TD is executed.
2041 PtrTDStruct
->TDData
.TDStatusIOC
= IsSet
? 1 : 0;
2045 Set if the TD is active and can be executed.
2047 @param PtrTDStruct Place to store TD_STRUCT pointer.
2048 @param IsActive Whether the TD is active and can be executed.
2052 SetTDStatusActiveorInactive (
2053 IN TD_STRUCT
*PtrTDStruct
,
2058 // If this bit is set, it indicates that the TD is active and can be
2062 PtrTDStruct
->TDData
.TDStatus
|= 0x80;
2064 PtrTDStruct
->TDData
.TDStatus
&= 0x7F;
2069 Specifies the maximum number of data bytes allowed for the transfer.
2071 @param PtrTDStruct Place to store TD_STRUCT pointer.
2072 @param MaxLen The maximum number of data bytes allowed.
2074 @retval The allowed maximum number of data.
2077 SetTDTokenMaxLength (
2078 IN TD_STRUCT
*PtrTDStruct
,
2083 // Specifies the maximum number of data bytes allowed for the transfer.
2084 // the legal value extent is 0 ~ 0x500.
2086 if (MaxLen
> 0x500) {
2090 PtrTDStruct
->TDData
.TDTokenMaxLen
= MaxLen
- 1;
2096 Set the data toggle bit to DATA1.
2098 @param PtrTDStruct Place to store TD_STRUCT pointer.
2102 SetTDTokenDataToggle1 (
2103 IN TD_STRUCT
*PtrTDStruct
2107 // Set the data toggle bit to DATA1
2109 PtrTDStruct
->TDData
.TDTokenDataToggle
= 1;
2113 Set the data toggle bit to DATA0.
2115 @param PtrTDStruct Place to store TD_STRUCT pointer.
2119 SetTDTokenDataToggle0 (
2120 IN TD_STRUCT
*PtrTDStruct
2124 // Set the data toggle bit to DATA0
2126 PtrTDStruct
->TDData
.TDTokenDataToggle
= 0;
2130 Set EndPoint Number the TD is targeting at.
2132 @param PtrTDStruct Place to store TD_STRUCT pointer.
2133 @param EndPoint The Endport number of the target.
2137 SetTDTokenEndPoint (
2138 IN TD_STRUCT
*PtrTDStruct
,
2143 // Set EndPoint Number the TD is targeting at.
2145 PtrTDStruct
->TDData
.TDTokenEndPt
= (UINT8
) EndPoint
;
2149 Set Device Address the TD is targeting at.
2151 @param PtrTDStruct Place to store TD_STRUCT pointer.
2152 @param DevAddr The Device Address of the target.
2156 SetTDTokenDeviceAddress (
2157 IN TD_STRUCT
*PtrTDStruct
,
2162 // Set Device Address the TD is targeting at.
2164 PtrTDStruct
->TDData
.TDTokenDevAddr
= (UINT8
) DevAddr
;
2168 Set Packet Identification the TD is targeting at.
2170 @param PtrTDStruct Place to store TD_STRUCT pointer.
2171 @param PacketID The Packet Identification of the target.
2175 SetTDTokenPacketID (
2176 IN TD_STRUCT
*PtrTDStruct
,
2181 // Set the Packet Identification to be used for this transaction.
2183 PtrTDStruct
->TDData
.TDTokenPID
= PacketID
;
2187 Detect whether the TD is active.
2189 @param PtrTDStruct Place to store TD_STRUCT pointer.
2191 @retval The TD is active or not.
2196 IN TD_STRUCT
*PtrTDStruct
2202 // Detect whether the TD is active.
2204 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2205 return (BOOLEAN
) (TDStatus
& 0x80);
2209 Detect whether the TD is stalled.
2211 @param PtrTDStruct Place to store TD_STRUCT pointer.
2213 @retval The TD is stalled or not.
2218 IN TD_STRUCT
*PtrTDStruct
2224 // Detect whether the device/endpoint addressed by this TD is stalled.
2226 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2227 return (BOOLEAN
) (TDStatus
& 0x40);
2231 Detect whether Data Buffer Error is happened.
2233 @param PtrTDStruct Place to store TD_STRUCT pointer.
2235 @retval The Data Buffer Error is happened or not.
2239 IsTDStatusBufferError (
2240 IN TD_STRUCT
*PtrTDStruct
2246 // Detect whether Data Buffer Error is happened.
2248 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2249 return (BOOLEAN
) (TDStatus
& 0x20);
2253 Detect whether Babble Error is happened.
2255 @param PtrTDStruct Place to store TD_STRUCT pointer.
2257 @retval The Babble Error is happened or not.
2261 IsTDStatusBabbleError (
2262 IN TD_STRUCT
*PtrTDStruct
2268 // Detect whether Babble Error is happened.
2270 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2271 return (BOOLEAN
) (TDStatus
& 0x10);
2275 Detect whether NAK is received.
2277 @param PtrTDStruct Place to store TD_STRUCT pointer.
2279 @retval The NAK is received or not.
2283 IsTDStatusNAKReceived (
2284 IN TD_STRUCT
*PtrTDStruct
2290 // Detect whether NAK is received.
2292 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2293 return (BOOLEAN
) (TDStatus
& 0x08);
2297 Detect whether CRC/Time Out Error is encountered.
2299 @param PtrTDStruct Place to store TD_STRUCT pointer.
2301 @retval The CRC/Time Out Error is encountered or not.
2305 IsTDStatusCRCTimeOutError (
2306 IN TD_STRUCT
*PtrTDStruct
2312 // Detect whether CRC/Time Out Error is encountered.
2314 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2315 return (BOOLEAN
) (TDStatus
& 0x04);
2319 Detect whether Bitstuff Error is received.
2321 @param PtrTDStruct Place to store TD_STRUCT pointer.
2323 @retval The Bitstuff Error is received or not.
2327 IsTDStatusBitStuffError (
2328 IN TD_STRUCT
*PtrTDStruct
2334 // Detect whether Bitstuff Error is received.
2336 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2337 return (BOOLEAN
) (TDStatus
& 0x02);
2341 Retrieve the actual number of bytes that were tansferred.
2343 @param PtrTDStruct Place to store TD_STRUCT pointer.
2345 @retval The actual number of bytes that were tansferred.
2349 GetTDStatusActualLength (
2350 IN TD_STRUCT
*PtrTDStruct
2354 // Retrieve the actual number of bytes that were tansferred.
2355 // the value is encoded as n-1. so return the decoded value.
2357 return (UINT16
) ((PtrTDStruct
->TDData
.TDStatusActualLength
) + 1);
2361 Retrieve the information of whether the Link Pointer field is valid or not.
2363 @param PtrTDStruct Place to store TD_STRUCT pointer.
2365 @retval The linker pointer field is valid or not.
2369 GetTDLinkPtrValidorInvalid (
2370 IN TD_STRUCT
*PtrTDStruct
2374 // Retrieve the information of whether the Link Pointer field
2377 if ((PtrTDStruct
->TDData
.TDLinkPtrTerminate
& BIT0
) != 0) {
2386 Count TD Number from PtrFirstTD.
2388 @param PtrFirstTD Place to store TD_STRUCT pointer.
2390 @retval The queued TDs number.
2395 IN TD_STRUCT
*PtrFirstTD
2402 // Count the queued TDs number.
2407 Ptr
= (TD_STRUCT
*) Ptr
->PtrNextTD
;
2417 @param PtrQH Place to store QH_STRUCT pointer.
2418 @param PtrTD Place to store TD_STRUCT pointer.
2423 IN QH_STRUCT
*PtrQH
,
2427 if (PtrQH
== NULL
|| PtrTD
== NULL
) {
2431 // Validate QH Vertical Ptr field
2433 SetQHVerticalValidorInvalid (PtrQH
, TRUE
);
2436 // Vertical Ptr pointing to TD structure
2438 SetQHVerticalQHorTDSelect (PtrQH
, FALSE
);
2440 SetQHVerticalLinkPtr (PtrQH
, (VOID
*) PtrTD
);
2442 PtrQH
->PtrDown
= (VOID
*) PtrTD
;
2448 @param PtrPreTD Place to store TD_STRUCT pointer.
2449 @param PtrTD Place to store TD_STRUCT pointer.
2454 IN TD_STRUCT
*PtrPreTD
,
2458 if (PtrPreTD
== NULL
|| PtrTD
== NULL
) {
2462 // Depth first fashion
2464 SetTDLinkPtrDepthorBreadth (PtrPreTD
, TRUE
);
2467 // Link pointer pointing to TD struct
2469 SetTDLinkPtrQHorTDSelect (PtrPreTD
, FALSE
);
2472 // Validate the link pointer valid bit
2474 SetTDLinkPtrValidorInvalid (PtrPreTD
, TRUE
);
2476 SetTDLinkPtr (PtrPreTD
, PtrTD
);
2478 PtrPreTD
->PtrNextTD
= (VOID
*) PtrTD
;
2480 PtrTD
->PtrNextTD
= NULL
;
2484 Execute Control Transfer.
2486 @param UhcDev The UCHI device.
2487 @param PtrTD A pointer to TD_STRUCT data.
2488 @param ActualLen Actual transfer Length.
2489 @param TimeOut TimeOut value.
2490 @param TransferResult Transfer Result.
2492 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2493 @return EFI_TIMEOUT The transfer failed due to time out.
2494 @return EFI_SUCCESS The transfer finished OK.
2498 ExecuteControlTransfer (
2499 IN USB_UHC_DEV
*UhcDev
,
2500 IN TD_STRUCT
*PtrTD
,
2501 OUT UINTN
*ActualLen
,
2503 OUT UINT32
*TransferResult
2508 BOOLEAN InfiniteLoop
;
2511 *TransferResult
= EFI_USB_NOERROR
;
2513 InfiniteLoop
= FALSE
;
2515 Delay
= TimeOut
* STALL_1_MILLI_SECOND
;
2517 // If Timeout is 0, then the caller must wait for the function to be completed
2518 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2521 InfiniteLoop
= TRUE
;
2526 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2529 // TD is inactive, means the control transfer is end.
2531 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2534 MicroSecondDelay (STALL_1_MICRO_SECOND
);
2537 } while (InfiniteLoop
|| (Delay
!= 0));
2539 if (*TransferResult
!= EFI_USB_NOERROR
) {
2540 return EFI_DEVICE_ERROR
;
2547 Execute Bulk Transfer.
2549 @param UhcDev The UCHI device.
2550 @param PtrTD A pointer to TD_STRUCT data.
2551 @param ActualLen Actual transfer Length.
2552 @param DataToggle DataToggle value.
2553 @param TimeOut TimeOut value.
2554 @param TransferResult Transfer Result.
2556 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2557 @return EFI_TIMEOUT The transfer failed due to time out.
2558 @return EFI_SUCCESS The transfer finished OK.
2563 IN USB_UHC_DEV
*UhcDev
,
2564 IN TD_STRUCT
*PtrTD
,
2565 IN OUT UINTN
*ActualLen
,
2566 IN UINT8
*DataToggle
,
2568 OUT UINT32
*TransferResult
2574 BOOLEAN InfiniteLoop
;
2577 *TransferResult
= EFI_USB_NOERROR
;
2579 InfiniteLoop
= FALSE
;
2581 Delay
= TimeOut
* STALL_1_MILLI_SECOND
;
2583 // If Timeout is 0, then the caller must wait for the function to be completed
2584 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2587 InfiniteLoop
= TRUE
;
2592 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2594 // TD is inactive, thus meaning bulk transfer's end.
2596 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2599 MicroSecondDelay (STALL_1_MICRO_SECOND
);
2602 } while (InfiniteLoop
|| (Delay
!= 0));
2607 if (*TransferResult
!= EFI_USB_NOERROR
) {
2609 // scroll the Data Toggle back to the last success TD
2611 ScrollNum
= CountTDsNumber (PtrTD
) - ErrTDPos
;
2612 if ((ScrollNum
% 2) != 0) {
2617 // If error, wait 100ms to retry by upper layer
2619 MicroSecondDelay (100 * 1000);
2620 return EFI_DEVICE_ERROR
;
2629 @param UhcDev The UCHI device.
2630 @param PtrFirstTD Place to store TD_STRUCT pointer.
2635 IN USB_UHC_DEV
*UhcDev
,
2636 IN TD_STRUCT
*PtrFirstTD
2645 // Delete all the TDs in a queue.
2647 while (Tptr1
!= NULL
) {
2651 if (!GetTDLinkPtrValidorInvalid (Tptr2
)) {
2655 // has more than one TD in the queue.
2657 Tptr1
= GetTDLinkPtr (Tptr2
);
2660 UhcFreePool (UhcDev
, (UINT8
*) Tptr2
, sizeof (TD_STRUCT
));
2669 @param PtrTD A pointer to TD_STRUCT data.
2670 @param Result The result to return.
2671 @param ErrTDPos The Error TD position.
2672 @param ActualTransferSize Actual transfer size.
2674 @retval The TD is executed successfully or not.
2679 IN TD_STRUCT
*PtrTD
,
2681 OUT UINTN
*ErrTDPos
,
2682 OUT UINTN
*ActualTransferSize
2687 *Result
= EFI_USB_NOERROR
;
2693 *ActualTransferSize
= 0;
2695 while (PtrTD
!= NULL
) {
2697 if (IsTDStatusActive (PtrTD
)) {
2698 *Result
|= EFI_USB_ERR_NOTEXECUTE
;
2701 if (IsTDStatusStalled (PtrTD
)) {
2702 *Result
|= EFI_USB_ERR_STALL
;
2705 if (IsTDStatusBufferError (PtrTD
)) {
2706 *Result
|= EFI_USB_ERR_BUFFER
;
2709 if (IsTDStatusBabbleError (PtrTD
)) {
2710 *Result
|= EFI_USB_ERR_BABBLE
;
2713 if (IsTDStatusNAKReceived (PtrTD
)) {
2714 *Result
|= EFI_USB_ERR_NAK
;
2717 if (IsTDStatusCRCTimeOutError (PtrTD
)) {
2718 *Result
|= EFI_USB_ERR_TIMEOUT
;
2721 if (IsTDStatusBitStuffError (PtrTD
)) {
2722 *Result
|= EFI_USB_ERR_BITSTUFF
;
2725 // Accumulate actual transferred data length in each TD.
2727 Len
= GetTDStatusActualLength (PtrTD
) & 0x7FF;
2728 *ActualTransferSize
+= Len
;
2731 // if any error encountered, stop processing the left TDs.
2733 if ((*Result
) != 0) {
2737 PtrTD
= (TD_STRUCT
*) (PtrTD
->PtrNextTD
);
2739 // Record the first Error TD's position in the queue,
2740 // this value is zero-based.
2749 Create Memory Block.
2751 @param UhcDev The UCHI device.
2752 @param MemoryHeader The Pointer to allocated memory block.
2753 @param MemoryBlockSizeInPages The page size of memory block to be allocated.
2755 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2756 @retval EFI_SUCCESS Success.
2761 IN USB_UHC_DEV
*UhcDev
,
2762 OUT MEMORY_MANAGE_HEADER
**MemoryHeader
,
2763 IN UINTN MemoryBlockSizeInPages
2771 EFI_PHYSICAL_ADDRESS MappedAddr
;
2774 // Memory Block uses MemoryBlockSizeInPages pages,
2775 // memory management header and bit array use 1 page
2777 MemPages
= MemoryBlockSizeInPages
+ 1;
2778 Status
= IoMmuAllocateBuffer (
2785 if (EFI_ERROR (Status
) || (TempPtr
== NULL
)) {
2786 return EFI_OUT_OF_RESOURCES
;
2791 ZeroMem (Ptr
, MemPages
* EFI_PAGE_SIZE
);
2793 *MemoryHeader
= (MEMORY_MANAGE_HEADER
*) Ptr
;
2795 // adjust Ptr pointer to the next empty memory
2797 Ptr
+= sizeof (MEMORY_MANAGE_HEADER
);
2799 // Set Bit Array initial address
2801 (*MemoryHeader
)->BitArrayPtr
= Ptr
;
2803 (*MemoryHeader
)->Next
= NULL
;
2806 // Memory block initial address
2809 Ptr
+= EFI_PAGE_SIZE
;
2810 (*MemoryHeader
)->MemoryBlockPtr
= Ptr
;
2812 // set Memory block size
2814 (*MemoryHeader
)->MemoryBlockSizeInBytes
= MemoryBlockSizeInPages
* EFI_PAGE_SIZE
;
2816 // each bit in Bit Array will manage 32byte memory in memory block
2818 (*MemoryHeader
)->BitArraySizeInBytes
= ((*MemoryHeader
)->MemoryBlockSizeInBytes
/ 32) / 8;
2824 Initialize UHCI memory management.
2826 @param UhcDev The UCHI device.
2828 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2829 @retval EFI_SUCCESS Success.
2833 InitializeMemoryManagement (
2834 IN USB_UHC_DEV
*UhcDev
2837 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2841 MemPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2842 Status
= CreateMemoryBlock (UhcDev
, &MemoryHeader
, MemPages
);
2843 if (EFI_ERROR (Status
)) {
2847 UhcDev
->Header1
= MemoryHeader
;
2853 Initialize UHCI memory management.
2855 @param UhcDev The UCHI device.
2856 @param Pool Buffer pointer to store the buffer pointer.
2857 @param AllocSize The size of the pool to be allocated.
2859 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2860 @retval EFI_SUCCESS Success.
2865 IN USB_UHC_DEV
*UhcDev
,
2870 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2871 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
2872 MEMORY_MANAGE_HEADER
*NewMemoryHeader
;
2873 UINTN RealAllocSize
;
2874 UINTN MemoryBlockSizeInPages
;
2879 MemoryHeader
= UhcDev
->Header1
;
2882 // allocate unit is 32 byte (align on 32 byte)
2884 if ((AllocSize
& 0x1F) != 0) {
2885 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
2887 RealAllocSize
= AllocSize
;
2890 Status
= EFI_NOT_FOUND
;
2891 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
2893 Status
= AllocMemInMemoryBlock (
2898 if (!EFI_ERROR (Status
)) {
2903 // There is no enough memory,
2904 // Create a new Memory Block
2907 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
2908 // just allocate a large enough memory block.
2910 if (RealAllocSize
> (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
* EFI_PAGE_SIZE
)) {
2911 MemoryBlockSizeInPages
= RealAllocSize
/ EFI_PAGE_SIZE
+ 1;
2913 MemoryBlockSizeInPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2916 Status
= CreateMemoryBlock (UhcDev
, &NewMemoryHeader
, MemoryBlockSizeInPages
);
2917 if (EFI_ERROR (Status
)) {
2921 // Link the new Memory Block to the Memory Header list
2923 InsertMemoryHeaderToList (MemoryHeader
, NewMemoryHeader
);
2925 Status
= AllocMemInMemoryBlock (
2934 Alloc Memory In MemoryBlock.
2936 @param MemoryHeader The pointer to memory manage header.
2937 @param Pool Buffer pointer to store the buffer pointer.
2938 @param NumberOfMemoryUnit The size of the pool to be allocated.
2940 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2941 @retval EFI_SUCCESS Success.
2945 AllocMemInMemoryBlock (
2946 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
2948 IN UINTN NumberOfMemoryUnit
2957 UINTN NumberOfZeros
;
2963 ByteValue
= MemoryHeader
->BitArrayPtr
[0];
2966 for (TempBytePos
= 0; TempBytePos
< MemoryHeader
->BitArraySizeInBytes
;) {
2968 // Pop out BitValue from a byte in TempBytePos.
2970 BitValue
= (UINT8
)(ByteValue
& 0x1);
2972 if (BitValue
== 0) {
2974 // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
2978 // Found enough consecutive free space, break the loop
2980 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2985 // Encountering a '1', meant the bit is ocupied.
2987 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2989 // Found enough consecutive free space,break the loop
2994 // the NumberOfZeros only record the number of those consecutive zeros,
2995 // so reset the NumberOfZeros to 0 when encountering '1' before finding
2996 // enough consecutive '0's
3000 // reset the (FoundBytePos,FoundBitPos) to the position of '1'
3002 FoundBytePos
= TempBytePos
;
3003 FoundBitPos
= Index
;
3007 // right shift the byte
3012 // step forward a bit
3017 // step forward a byte, getting the byte value,
3018 // and reset the bit pos.
3021 ByteValue
= MemoryHeader
->BitArrayPtr
[TempBytePos
];
3026 if (NumberOfZeros
< NumberOfMemoryUnit
) {
3027 return EFI_NOT_FOUND
;
3030 // Found enough free space.
3033 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
3034 // 1)(FoundBytePos,FoundBitPos) record the position
3035 // of the last '1' before the consecutive '0's, it must
3036 // be adjusted to the start position of the consecutive '0's.
3037 // 2)the start address of the consecutive '0's is just the start of
3038 // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
3040 if ((MemoryHeader
->BitArrayPtr
[0] & BIT0
) != 0) {
3044 // Have the (FoundBytePos,FoundBitPos) make sense.
3046 if (FoundBitPos
> 7) {
3051 // Set the memory as allocated
3053 for (TempBytePos
= FoundBytePos
, Index
= FoundBitPos
, Count
= 0; Count
< NumberOfMemoryUnit
; Count
++) {
3055 MemoryHeader
->BitArrayPtr
[TempBytePos
] = (UINT8
) (MemoryHeader
->BitArrayPtr
[TempBytePos
] | (1 << Index
));
3063 *Pool
= MemoryHeader
->MemoryBlockPtr
+ (FoundBytePos
* 8 + FoundBitPos
) * 32;
3071 @param UhcDev The UHCI device.
3072 @param Pool A pointer to store the buffer address.
3073 @param AllocSize The size of the pool to be freed.
3078 IN USB_UHC_DEV
*UhcDev
,
3083 MEMORY_MANAGE_HEADER
*MemoryHeader
;
3084 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3090 UINTN RealAllocSize
;
3092 MemoryHeader
= UhcDev
->Header1
;
3095 // allocate unit is 32 byte (align on 32 byte)
3097 if ((AllocSize
& 0x1F) != 0) {
3098 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
3100 RealAllocSize
= AllocSize
;
3103 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
;
3104 TempHeaderPtr
= TempHeaderPtr
->Next
) {
3106 if ((Pool
>= TempHeaderPtr
->MemoryBlockPtr
) &&
3107 ((Pool
+ RealAllocSize
) <= (TempHeaderPtr
->MemoryBlockPtr
+
3108 TempHeaderPtr
->MemoryBlockSizeInBytes
))) {
3111 // Pool is in the Memory Block area,
3112 // find the start byte and bit in the bit array
3114 StartBytePos
= ((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) / 8;
3115 StartBitPos
= (UINT8
) (((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) % 8);
3118 // reset associated bits in bit array
3120 for (Index
= StartBytePos
, Index2
= StartBitPos
, Count
= 0; Count
< (RealAllocSize
/ 32); Count
++) {
3122 TempHeaderPtr
->BitArrayPtr
[Index
] = (UINT8
) (TempHeaderPtr
->BitArrayPtr
[Index
] ^ (1 << Index2
));
3139 Insert a new memory header into list.
3141 @param MemoryHeader A pointer to the memory header list.
3142 @param NewMemoryHeader A new memory header to be inserted into the list.
3146 InsertMemoryHeaderToList (
3147 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
3148 IN MEMORY_MANAGE_HEADER
*NewMemoryHeader
3151 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3153 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
3154 if (TempHeaderPtr
->Next
== NULL
) {
3155 TempHeaderPtr
->Next
= NewMemoryHeader
;
3166 Map address of request structure buffer.
3168 @param Uhc The UHCI device.
3169 @param Request The user request buffer.
3170 @param MappedAddr Mapped address of request.
3171 @param Map Identificaion of this mapping to return.
3173 @return EFI_SUCCESS Success.
3174 @return EFI_DEVICE_ERROR Fail to map the user request.
3178 UhciMapUserRequest (
3179 IN USB_UHC_DEV
*Uhc
,
3180 IN OUT VOID
*Request
,
3181 OUT UINT8
**MappedAddr
,
3187 EFI_PHYSICAL_ADDRESS PhyAddr
;
3189 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
3192 EdkiiIoMmuOperationBusMasterRead
,
3199 if (!EFI_ERROR (Status
)) {
3200 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3207 Map address of user data buffer.
3209 @param Uhc The UHCI device.
3210 @param Direction Direction of the data transfer.
3211 @param Data The user data buffer.
3212 @param Len Length of the user data.
3213 @param PktId Packet identificaion.
3214 @param MappedAddr Mapped address to return.
3215 @param Map Identificaion of this mapping to return.
3217 @return EFI_SUCCESS Success.
3218 @return EFI_DEVICE_ERROR Fail to map the user data.
3223 IN USB_UHC_DEV
*Uhc
,
3224 IN EFI_USB_DATA_DIRECTION Direction
,
3228 OUT UINT8
**MappedAddr
,
3233 EFI_PHYSICAL_ADDRESS PhyAddr
;
3235 Status
= EFI_SUCCESS
;
3237 switch (Direction
) {
3240 // BusMasterWrite means cpu read
3242 *PktId
= INPUT_PACKET_ID
;
3245 EdkiiIoMmuOperationBusMasterWrite
,
3252 if (EFI_ERROR (Status
)) {
3256 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3260 *PktId
= OUTPUT_PACKET_ID
;
3263 EdkiiIoMmuOperationBusMasterRead
,
3270 if (EFI_ERROR (Status
)) {
3274 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3278 if ((Len
!= NULL
) && (*Len
!= 0)) {
3279 Status
= EFI_INVALID_PARAMETER
;
3283 *PktId
= OUTPUT_PACKET_ID
;
3289 Status
= EFI_INVALID_PARAMETER
;