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
;
283 // if errors exist that cause host controller halt,
284 // then return EFI_DEVICE_ERROR.
287 if (!IsStatusOK (UhcDev
, StatusReg
)) {
288 ClearStatusReg (UhcDev
, StatusReg
);
289 *TransferResult
= EFI_USB_ERR_SYSTEM
;
290 return EFI_DEVICE_ERROR
;
293 ClearStatusReg (UhcDev
, StatusReg
);
296 // Map the Request and data for bus master access,
297 // then create a list of TD for this transfer
299 Status
= UhciMapUserRequest (UhcDev
, Request
, &RequestPhy
, &RequestMap
);
300 if (EFI_ERROR (Status
)) {
304 Status
= UhciMapUserData (UhcDev
, TransferDirection
, Data
, DataLength
, &PktID
, &DataPhy
, &DataMap
);
306 if (EFI_ERROR (Status
)) {
307 if (RequestMap
!= NULL
) {
308 IoMmuUnmap (UhcDev
->IoMmu
, RequestMap
);
314 // generate Setup Stage TD
317 PtrQH
= UhcDev
->ConfigQH
;
326 (UINT8
) sizeof (EFI_USB_DEVICE_REQUEST
),
331 // link setup TD structures to QH structure
333 LinkTDToQH (PtrQH
, PtrSetupTD
);
335 PtrPreTD
= PtrSetupTD
;
338 // Data Stage of Control Transfer
341 if (TransferDirection
== EfiUsbNoData
) {
344 DataLen
= (UINT32
) *DataLength
;
350 while (DataLen
> 0) {
352 // create TD structures and link together
357 // PacketSize is the data load size of each TD carries.
359 PacketSize
= (UINT8
) DataLen
;
360 if (DataLen
> MaximumPacketLength
) {
361 PacketSize
= MaximumPacketLength
;
378 // Link two TDs in vertical depth
380 LinkTDToTD (PtrPreTD
, PtrTD
);
384 Data
= (VOID
*) ((UINT8
*) Data
+ PacketSize
);
385 DataPhy
+= PacketSize
;
386 DataLen
-= PacketSize
;
390 // PtrPreTD points to the last TD before the Setup-Stage TD.
395 // Status Stage of Control Transfer
397 if (PktID
== OUTPUT_PACKET_ID
) {
398 PktID
= INPUT_PACKET_ID
;
400 PktID
= OUTPUT_PACKET_ID
;
403 // create Status Stage TD structure
414 LinkTDToTD (PtrPreTD
, PtrStatusTD
);
417 // Poll QH-TDs execution and get result.
418 // detail status is returned
420 Status
= ExecuteControlTransfer (
429 // TRUE means must search other framelistindex
431 SetQHVerticalValidorInvalid(PtrQH
, FALSE
);
432 DeleteQueuedTDs (UhcDev
, PtrSetupTD
);
435 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
437 if (!IsStatusOK (UhcDev
, StatusReg
)) {
438 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
439 Status
= EFI_DEVICE_ERROR
;
442 ClearStatusReg (UhcDev
, StatusReg
);
444 if (DataMap
!= NULL
) {
445 IoMmuUnmap (UhcDev
->IoMmu
, DataMap
);
447 if (RequestMap
!= NULL
) {
448 IoMmuUnmap (UhcDev
->IoMmu
, RequestMap
);
455 Submits bulk transfer to a bulk endpoint of a USB device.
457 @param PeiServices The pointer of EFI_PEI_SERVICES.
458 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
459 @param DeviceAddress Target device address.
460 @param EndPointAddress Endpoint number and its direction in bit 7.
461 @param MaximumPacketLength Maximum packet size the endpoint is capable of
462 sending or receiving.
463 @param Data Array of pointers to the buffers of data to transmit
464 from or receive into.
465 @param DataLength The lenght of the data buffer.
466 @param DataToggle On input, the initial data toggle for the transfer;
467 On output, it is updated to to next data toggle to use of
468 the subsequent bulk transfer.
469 @param TimeOut Indicates the maximum time, in millisecond, which the
470 transfer is allowed to complete.
471 If Timeout is 0, then the caller must wait for the function
472 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
473 @param TransferResult A pointer to the detailed result information of the
476 @retval EFI_SUCCESS The transfer was completed successfully.
477 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
478 @retval EFI_INVALID_PARAMETER Parameters are invalid.
479 @retval EFI_TIMEOUT The transfer failed due to timeout.
480 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
486 IN EFI_PEI_SERVICES
**PeiServices
,
487 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
488 IN UINT8 DeviceAddress
,
489 IN UINT8 EndPointAddress
,
490 IN UINT8 MaximumPacketLength
,
492 IN OUT UINTN
*DataLength
,
493 IN OUT UINT8
*DataToggle
,
495 OUT UINT32
*TransferResult
504 TD_STRUCT
*PtrFirstTD
;
514 EFI_USB_DATA_DIRECTION TransferDirection
;
516 BOOLEAN ShortPacketEnable
;
518 UINT16 CommandContent
;
523 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
526 // Enable the maximum packet size (64bytes)
527 // that can be used for full speed bandwidth reclamation
528 // at the end of a frame.
530 CommandContent
= USBReadPortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
);
531 if ((CommandContent
& USBCMD_MAXP
) != USBCMD_MAXP
) {
532 CommandContent
|= USBCMD_MAXP
;
533 USBWritePortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
, CommandContent
);
536 StatusReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBSTS
;
539 // these code lines are added here per complier's strict demand
541 PktID
= INPUT_PACKET_ID
;
547 ShortPacketEnable
= FALSE
;
549 if ((DataLength
== 0) || (Data
== NULL
) || (TransferResult
== NULL
)) {
550 return EFI_INVALID_PARAMETER
;
553 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
554 return EFI_INVALID_PARAMETER
;
557 if (MaximumPacketLength
!= 8 && MaximumPacketLength
!= 16
558 && MaximumPacketLength
!= 32 && MaximumPacketLength
!= 64) {
559 return EFI_INVALID_PARAMETER
;
562 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
564 if (!IsStatusOK (UhcDev
, StatusReg
)) {
566 ClearStatusReg (UhcDev
, StatusReg
);
567 *TransferResult
= EFI_USB_ERR_SYSTEM
;
568 return EFI_DEVICE_ERROR
;
571 ClearStatusReg (UhcDev
, StatusReg
);
574 // Map the source data buffer for bus master access,
575 // then create a list of TDs
577 if ((EndPointAddress
& 0x80) != 0) {
578 TransferDirection
= EfiUsbDataIn
;
580 TransferDirection
= EfiUsbDataOut
;
583 Status
= UhciMapUserData (UhcDev
, TransferDirection
, Data
, DataLength
, &PktID
, &DataPhy
, &DataMap
);
585 if (EFI_ERROR (Status
)) {
589 DataLen
= (UINT32
) *DataLength
;
591 PtrQH
= UhcDev
->BulkQH
;
594 while (DataLen
> 0) {
596 // create TD structures and link together
600 PacketSize
= (UINT8
) DataLen
;
601 if (DataLen
> MaximumPacketLength
) {
602 PacketSize
= MaximumPacketLength
;
614 USB_FULL_SPEED_DEVICE
,
619 // Enable short packet detection.
620 // (default action is disabling short packet detection)
622 if (ShortPacketEnable
) {
623 EnableorDisableTDShortPacket (PtrTD
, TRUE
);
628 PtrFirstTD
->PtrNextTD
= NULL
;
632 // Link two TDs in vertical depth
634 LinkTDToTD (PtrPreTD
, PtrTD
);
640 Data
= (VOID
*) ((UINT8
*) Data
+ PacketSize
);
641 DataPhy
+= PacketSize
;
642 DataLen
-= PacketSize
;
645 // link TD structures to QH structure
647 LinkTDToQH (PtrQH
, PtrFirstTD
);
650 // Execute QH-TD and get result
653 // detail status is put into the Result field in the pIRP
654 // the Data Toggle value is also re-updated to the value
655 // of the last successful TD
657 Status
= ExecBulkTransfer (
667 // Delete Bulk transfer TD structure
669 DeleteQueuedTDs (UhcDev
, PtrFirstTD
);
672 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
674 if (!IsStatusOK (UhcDev
, StatusReg
)) {
675 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
676 Status
= EFI_DEVICE_ERROR
;
679 ClearStatusReg (UhcDev
, StatusReg
);
681 if (DataMap
!= NULL
) {
682 IoMmuUnmap (UhcDev
->IoMmu
, DataMap
);
689 Retrieves the number of root hub ports.
691 @param[in] PeiServices The pointer to the PEI Services Table.
692 @param[in] This The pointer to this instance of the
693 PEI_USB_HOST_CONTROLLER_PPI.
694 @param[out] PortNumber The pointer to the number of the root hub ports.
696 @retval EFI_SUCCESS The port number was retrieved successfully.
697 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
702 UhcGetRootHubPortNumber (
703 IN EFI_PEI_SERVICES
**PeiServices
,
704 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
705 OUT UINT8
*PortNumber
710 UINT16 RHPortControl
;
713 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
715 if (PortNumber
== NULL
) {
716 return EFI_INVALID_PARAMETER
;
721 for (Index
= 0; Index
< 2; Index
++) {
722 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ Index
* 2;
723 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
725 // Port Register content is valid
727 if (RHPortControl
!= 0xff) {
736 Retrieves the current status of a USB root hub port.
738 @param PeiServices The pointer of EFI_PEI_SERVICES.
739 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
740 @param PortNumber The root hub port to retrieve the state from.
741 @param PortStatus Variable to receive the port state.
743 @retval EFI_SUCCESS The status of the USB root hub port specified.
744 by PortNumber was returned in PortStatus.
745 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
750 UhcGetRootHubPortStatus (
751 IN EFI_PEI_SERVICES
**PeiServices
,
752 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
754 OUT EFI_USB_PORT_STATUS
*PortStatus
760 UINT8 TotalPortNumber
;
762 if (PortStatus
== NULL
) {
763 return EFI_INVALID_PARAMETER
;
766 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
767 if (PortNumber
> TotalPortNumber
) {
768 return EFI_INVALID_PARAMETER
;
771 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
772 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
774 PortStatus
->PortStatus
= 0;
775 PortStatus
->PortChangeStatus
= 0;
777 RHPortStatus
= USBReadPortW (UhcDev
, PSAddr
);
780 // Current Connect Status
782 if ((RHPortStatus
& USBPORTSC_CCS
) != 0) {
783 PortStatus
->PortStatus
|= USB_PORT_STAT_CONNECTION
;
786 // Port Enabled/Disabled
788 if ((RHPortStatus
& USBPORTSC_PED
) != 0) {
789 PortStatus
->PortStatus
|= USB_PORT_STAT_ENABLE
;
794 if ((RHPortStatus
& USBPORTSC_SUSP
) != 0) {
795 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
800 if ((RHPortStatus
& USBPORTSC_PR
) != 0) {
801 PortStatus
->PortStatus
|= USB_PORT_STAT_RESET
;
804 // Low Speed Device Attached
806 if ((RHPortStatus
& USBPORTSC_LSDA
) != 0) {
807 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
810 // Fill Port Status Change bits
813 // Connect Status Change
815 if ((RHPortStatus
& USBPORTSC_CSC
) != 0) {
816 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_CONNECTION
;
819 // Port Enabled/Disabled Change
821 if ((RHPortStatus
& USBPORTSC_PEDC
) != 0) {
822 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_ENABLE
;
829 Sets a feature for the specified root hub port.
831 @param PeiServices The pointer of EFI_PEI_SERVICES
832 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI
833 @param PortNumber Root hub port to set.
834 @param PortFeature Feature to set.
836 @retval EFI_SUCCESS The feature specified by PortFeature was set.
837 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
838 @retval EFI_TIMEOUT The time out occurred.
843 UhcSetRootHubPortFeature (
844 IN EFI_PEI_SERVICES
**PeiServices
,
845 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
847 IN EFI_USB_PORT_FEATURE PortFeature
852 UINT32 CommandRegAddr
;
853 UINT16 RHPortControl
;
854 UINT8 TotalPortNumber
;
856 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
857 if (PortNumber
> TotalPortNumber
) {
858 return EFI_INVALID_PARAMETER
;
861 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
862 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
863 CommandRegAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
865 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
867 switch (PortFeature
) {
869 case EfiUsbPortSuspend
:
870 if ((USBReadPortW (UhcDev
, CommandRegAddr
) & USBCMD_EGSM
) == 0) {
872 // if global suspend is not active, can set port suspend
874 RHPortControl
&= 0xfff5;
875 RHPortControl
|= USBPORTSC_SUSP
;
879 case EfiUsbPortReset
:
880 RHPortControl
&= 0xfff5;
881 RHPortControl
|= USBPORTSC_PR
;
887 case EfiUsbPortPower
:
890 case EfiUsbPortEnable
:
891 RHPortControl
&= 0xfff5;
892 RHPortControl
|= USBPORTSC_PED
;
896 return EFI_INVALID_PARAMETER
;
899 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
905 Clears a feature for the specified root hub port.
907 @param PeiServices The pointer of EFI_PEI_SERVICES.
908 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
909 @param PortNumber Specifies the root hub port whose feature
910 is requested to be cleared.
911 @param PortFeature Indicates the feature selector associated with the
912 feature clear request.
914 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
915 for the USB root hub port specified by PortNumber.
916 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
921 UhcClearRootHubPortFeature (
922 IN EFI_PEI_SERVICES
**PeiServices
,
923 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
925 IN EFI_USB_PORT_FEATURE PortFeature
930 UINT16 RHPortControl
;
931 UINT8 TotalPortNumber
;
933 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
935 if (PortNumber
> TotalPortNumber
) {
936 return EFI_INVALID_PARAMETER
;
939 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
940 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
942 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
944 switch (PortFeature
) {
946 // clear PORT_ENABLE feature means disable port.
948 case EfiUsbPortEnable
:
949 RHPortControl
&= 0xfff5;
950 RHPortControl
&= ~USBPORTSC_PED
;
954 // clear PORT_SUSPEND feature means resume the port.
955 // (cause a resume on the specified port if in suspend mode)
957 case EfiUsbPortSuspend
:
958 RHPortControl
&= 0xfff5;
959 RHPortControl
&= ~USBPORTSC_SUSP
;
965 case EfiUsbPortPower
:
969 // clear PORT_RESET means clear the reset signal.
971 case EfiUsbPortReset
:
972 RHPortControl
&= 0xfff5;
973 RHPortControl
&= ~USBPORTSC_PR
;
977 // clear connect status change
979 case EfiUsbPortConnectChange
:
980 RHPortControl
&= 0xfff5;
981 RHPortControl
|= USBPORTSC_CSC
;
985 // clear enable/disable status change
987 case EfiUsbPortEnableChange
:
988 RHPortControl
&= 0xfff5;
989 RHPortControl
|= USBPORTSC_PEDC
;
993 // root hub does not support this request
995 case EfiUsbPortSuspendChange
:
999 // root hub does not support this request
1001 case EfiUsbPortOverCurrentChange
:
1005 // root hub does not support this request
1007 case EfiUsbPortResetChange
:
1011 return EFI_INVALID_PARAMETER
;
1014 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
1022 @param UhcDev UHCI Device.
1024 @retval EFI_SUCCESS UHCI successfully initialized.
1025 @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.
1030 IN USB_UHC_DEV
*UhcDev
1034 UINT32 FrameListBaseAddrReg
;
1039 // Create and Initialize Frame List For the Host Controller.
1041 Status
= CreateFrameList (UhcDev
);
1042 if (EFI_ERROR (Status
)) {
1046 FrameListBaseAddrReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBFLBASEADD
;
1047 CommandReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
1050 // Set Frame List Base Address to the specific register to inform the hardware.
1052 SetFrameListBaseAddress (UhcDev
, FrameListBaseAddrReg
, (UINT32
) (UINTN
) (UhcDev
->FrameListEntry
));
1054 Command
= USBReadPortW (UhcDev
, CommandReg
);
1055 Command
|= USBCMD_GRESET
;
1056 USBWritePortW (UhcDev
, CommandReg
, Command
);
1058 MicroSecondDelay (50 * 1000);
1061 Command
&= ~USBCMD_GRESET
;
1063 USBWritePortW (UhcDev
, CommandReg
, Command
);
1066 //UHCI spec page120 reset recovery time
1068 MicroSecondDelay (20 * 1000);
1071 // Set Run/Stop bit to 1.
1073 Command
= USBReadPortW (UhcDev
, CommandReg
);
1074 Command
|= USBCMD_RS
| USBCMD_MAXP
;
1075 USBWritePortW (UhcDev
, CommandReg
, Command
);
1081 Create Frame List Structure.
1083 @param UhcDev UHCI device.
1085 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1086 @retval EFI_SUCCESS Success.
1095 EFI_PHYSICAL_ADDRESS FrameListBaseAddr
;
1096 FRAMELIST_ENTRY
*FrameListPtr
;
1100 // The Frame List ocupies 4K bytes,
1101 // and must be aligned on 4-Kbyte boundaries.
1103 Status
= PeiServicesAllocatePages (
1104 EfiBootServicesData
,
1109 if (Status
!= EFI_SUCCESS
) {
1110 return EFI_OUT_OF_RESOURCES
;
1114 //Create Control QH and Bulk QH and link them into Framelist Entry
1116 Status
= CreateQH(UhcDev
, &UhcDev
->ConfigQH
);
1117 if (Status
!= EFI_SUCCESS
) {
1118 return EFI_OUT_OF_RESOURCES
;
1120 ASSERT (UhcDev
->ConfigQH
!= NULL
);
1122 Status
= CreateQH(UhcDev
, &UhcDev
->BulkQH
);
1123 if (Status
!= EFI_SUCCESS
) {
1124 return EFI_OUT_OF_RESOURCES
;
1126 ASSERT (UhcDev
->BulkQH
!= NULL
);
1129 //Set the corresponding QH pointer
1131 SetQHHorizontalLinkPtr(UhcDev
->ConfigQH
, UhcDev
->BulkQH
);
1132 SetQHHorizontalQHorTDSelect (UhcDev
->ConfigQH
, TRUE
);
1133 SetQHHorizontalValidorInvalid (UhcDev
->ConfigQH
, TRUE
);
1135 UhcDev
->FrameListEntry
= (FRAMELIST_ENTRY
*) ((UINTN
) FrameListBaseAddr
);
1137 FrameListPtr
= UhcDev
->FrameListEntry
;
1139 for (Index
= 0; Index
< 1024; Index
++) {
1140 FrameListPtr
->FrameListPtrTerminate
= 0;
1141 FrameListPtr
->FrameListPtr
= (UINT32
)(UINTN
)UhcDev
->ConfigQH
>> 4;
1142 FrameListPtr
->FrameListPtrQSelect
= 1;
1143 FrameListPtr
->FrameListRsvd
= 0;
1151 Read a 16bit width data from Uhc HC IO space register.
1153 @param UhcDev The UHCI device.
1154 @param Port The IO space address of the register.
1156 @retval the register content read.
1161 IN USB_UHC_DEV
*UhcDev
,
1165 return IoRead16 (Port
);
1169 Write a 16bit width data into Uhc HC IO space register.
1171 @param UhcDev The UHCI device.
1172 @param Port The IO space address of the register.
1173 @param Data The data written into the register.
1178 IN USB_UHC_DEV
*UhcDev
,
1183 IoWrite16 (Port
, Data
);
1187 Write a 32bit width data into Uhc HC IO space register.
1189 @param UhcDev The UHCI device.
1190 @param Port The IO space address of the register.
1191 @param Data The data written into the register.
1196 IN USB_UHC_DEV
*UhcDev
,
1201 IoWrite32 (Port
, Data
);
1205 Clear the content of UHCI's Status Register.
1207 @param UhcDev The UHCI device.
1208 @param StatusAddr The IO space address of the register.
1213 IN USB_UHC_DEV
*UhcDev
,
1214 IN UINT32 StatusAddr
1218 // Clear the content of UHCI's Status Register
1220 USBWritePortW (UhcDev
, StatusAddr
, 0x003F);
1224 Check whether the host controller operates well.
1226 @param UhcDev The UHCI device.
1227 @param StatusRegAddr The io address of status register.
1229 @retval TRUE Host controller is working.
1230 @retval FALSE Host controller is halted or system error.
1235 IN USB_UHC_DEV
*UhcDev
,
1236 IN UINT32 StatusRegAddr
1241 StatusValue
= USBReadPortW (UhcDev
, StatusRegAddr
);
1243 if ((StatusValue
& (USBSTS_HCPE
| USBSTS_HSE
| USBSTS_HCH
)) != 0) {
1253 Set Frame List Base Address.
1255 @param UhcDev The UHCI device.
1256 @param FrameListRegAddr The address of frame list register.
1257 @param Addr The address of frame list table.
1261 SetFrameListBaseAddress (
1262 IN USB_UHC_DEV
*UhcDev
,
1263 IN UINT32 FrameListRegAddr
,
1268 // Sets value in the USB Frame List Base Address register.
1270 USBWritePortDW (UhcDev
, FrameListRegAddr
, (UINT32
) (Addr
& 0xFFFFF000));
1274 Create QH and initialize.
1276 @param UhcDev The UHCI device.
1277 @param PtrQH Place to store QH_STRUCT pointer.
1279 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1280 @retval EFI_SUCCESS Success.
1285 IN USB_UHC_DEV
*UhcDev
,
1286 OUT QH_STRUCT
**PtrQH
1292 // allocate align memory for QH_STRUCT
1294 Status
= AllocateTDorQHStruct (UhcDev
, sizeof(QH_STRUCT
), (void **)PtrQH
);
1295 if (EFI_ERROR (Status
)) {
1296 return EFI_OUT_OF_RESOURCES
;
1299 // init each field of the QH_STRUCT
1301 SetQHHorizontalValidorInvalid (*PtrQH
, FALSE
);
1302 SetQHVerticalValidorInvalid (*PtrQH
, FALSE
);
1308 Set the horizontal link pointer in QH.
1310 @param PtrQH Place to store QH_STRUCT pointer.
1311 @param PtrNext Place to the next QH_STRUCT.
1315 SetQHHorizontalLinkPtr (
1316 IN QH_STRUCT
*PtrQH
,
1321 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1322 // Only the highest 28bit of the address is valid
1323 // (take 32bit address as an example).
1325 PtrQH
->QueueHead
.QHHorizontalPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1331 Set a QH or TD horizontally to be connected with a specific QH.
1333 @param PtrQH Place to store QH_STRUCT pointer.
1334 @param IsQH Specify QH or TD is connected.
1338 SetQHHorizontalQHorTDSelect (
1339 IN QH_STRUCT
*PtrQH
,
1344 // if QH is connected, the specified bit is set,
1345 // if TD is connected, the specified bit is cleared.
1347 PtrQH
->QueueHead
.QHHorizontalQSelect
= IsQH
? 1 : 0;
1351 Set the horizontal validor bit in QH.
1353 @param PtrQH Place to store QH_STRUCT pointer.
1354 @param IsValid Specify the horizontal linker is valid or not.
1358 SetQHHorizontalValidorInvalid (
1359 IN QH_STRUCT
*PtrQH
,
1364 // Valid means the horizontal link pointer is valid,
1365 // else, it's invalid.
1367 PtrQH
->QueueHead
.QHHorizontalTerminate
= IsValid
? 0 : 1;
1371 Set the vertical link pointer in QH.
1373 @param PtrQH Place to store QH_STRUCT pointer.
1374 @param PtrNext Place to the next QH_STRUCT.
1378 SetQHVerticalLinkPtr (
1379 IN QH_STRUCT
*PtrQH
,
1384 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1385 // Only the highest 28bit of the address is valid
1386 // (take 32bit address as an example).
1388 PtrQH
->QueueHead
.QHVerticalPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1392 Set a QH or TD vertically to be connected with a specific QH.
1394 @param PtrQH Place to store QH_STRUCT pointer.
1395 @param IsQH Specify QH or TD is connected.
1399 SetQHVerticalQHorTDSelect (
1400 IN QH_STRUCT
*PtrQH
,
1405 // Set the specified bit if the Vertical Link Pointer pointing to a QH,
1406 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
1408 PtrQH
->QueueHead
.QHVerticalQSelect
= IsQH
? 1 : 0;
1412 Set the vertical validor bit in QH.
1414 @param PtrQH Place to store QH_STRUCT pointer.
1415 @param IsValid Specify the vertical linker is valid or not.
1419 SetQHVerticalValidorInvalid (
1420 IN QH_STRUCT
*PtrQH
,
1425 // If TRUE, meaning the Vertical Link Pointer field is valid,
1426 // else, the field is invalid.
1428 PtrQH
->QueueHead
.QHVerticalTerminate
= IsValid
? 0 : 1;
1434 Allocate TD or QH Struct.
1436 @param UhcDev The UHCI device.
1437 @param Size The size of allocation.
1438 @param PtrStruct Place to store TD_STRUCT pointer.
1440 @return EFI_SUCCESS Allocate successfully.
1441 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1445 AllocateTDorQHStruct (
1446 IN USB_UHC_DEV
*UhcDev
,
1448 OUT VOID
**PtrStruct
1453 Status
= EFI_SUCCESS
;
1456 Status
= UhcAllocatePool (
1458 (UINT8
**) PtrStruct
,
1461 if (EFI_ERROR (Status
)) {
1465 ZeroMem (*PtrStruct
, Size
);
1473 @param UhcDev The UHCI device.
1474 @param PtrTD Place to store TD_STRUCT pointer.
1476 @return EFI_SUCCESS Allocate successfully.
1477 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1482 IN USB_UHC_DEV
*UhcDev
,
1483 OUT TD_STRUCT
**PtrTD
1488 // create memory for TD_STRUCT, and align the memory.
1490 Status
= AllocateTDorQHStruct (UhcDev
, sizeof(TD_STRUCT
), (void **)PtrTD
);
1491 if (EFI_ERROR (Status
)) {
1498 SetTDLinkPtrValidorInvalid (*PtrTD
, FALSE
);
1504 Generate Setup Stage TD.
1506 @param UhcDev The UHCI device.
1507 @param DevAddr Device address.
1508 @param Endpoint Endpoint number.
1509 @param DeviceSpeed Device Speed.
1510 @param DevRequest CPU memory address of request structure buffer to transfer.
1511 @param RequestPhy PCI memory address of request structure buffer to transfer.
1512 @param RequestLen Request length.
1513 @param PtrTD TD_STRUCT generated.
1515 @return EFI_SUCCESS Generate setup stage TD successfully.
1516 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1521 IN USB_UHC_DEV
*UhcDev
,
1524 IN UINT8 DeviceSpeed
,
1525 IN UINT8
*DevRequest
,
1526 IN UINT8
*RequestPhy
,
1527 IN UINT8 RequestLen
,
1528 OUT TD_STRUCT
**PtrTD
1531 TD_STRUCT
*TdStruct
;
1534 Status
= CreateTD (UhcDev
, &TdStruct
);
1535 if (EFI_ERROR (Status
)) {
1539 SetTDLinkPtr (TdStruct
, NULL
);
1542 // Depth first fashion
1544 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1547 // initialize as the last TD in the QH context,
1548 // this field will be updated in the TD linkage process.
1550 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1553 // Disable Short Packet Detection by default
1555 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1558 // Max error counter is 3, retry 3 times when error encountered.
1560 SetTDControlErrorCounter (TdStruct
, 3);
1563 // set device speed attribute
1564 // (TRUE - Slow Device; FALSE - Full Speed Device)
1566 switch (DeviceSpeed
) {
1567 case USB_SLOW_SPEED_DEVICE
:
1568 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1571 case USB_FULL_SPEED_DEVICE
:
1572 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1576 // Non isochronous transfer TD
1578 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1581 // Interrupt On Complete bit be set to zero,
1582 // Disable IOC interrupt.
1584 SetorClearTDControlIOC (TdStruct
, FALSE
);
1587 // Set TD Active bit
1589 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1591 SetTDTokenMaxLength (TdStruct
, RequestLen
);
1593 SetTDTokenDataToggle0 (TdStruct
);
1595 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1597 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1599 SetTDTokenPacketID (TdStruct
, SETUP_PACKET_ID
);
1601 TdStruct
->PtrTDBuffer
= (UINT8
*) DevRequest
;
1602 TdStruct
->TDBufferLength
= RequestLen
;
1604 // Set the beginning address of the buffer that will be used
1605 // during the transaction.
1607 TdStruct
->TDData
.TDBufferPtr
= (UINT32
) (UINTN
) RequestPhy
;
1615 Generate Data Stage TD.
1617 @param UhcDev The UHCI device.
1618 @param DevAddr Device address.
1619 @param Endpoint Endpoint number.
1620 @param PtrData CPU memory address of user data buffer to transfer.
1621 @param DataPhy PCI memory address of user data buffer to transfer.
1622 @param Len Data length.
1623 @param PktID PacketID.
1624 @param Toggle Data toggle value.
1625 @param DeviceSpeed Device Speed.
1626 @param PtrTD TD_STRUCT generated.
1628 @return EFI_SUCCESS Generate data stage TD successfully.
1629 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1634 IN USB_UHC_DEV
*UhcDev
,
1642 IN UINT8 DeviceSpeed
,
1643 OUT TD_STRUCT
**PtrTD
1646 TD_STRUCT
*TdStruct
;
1649 Status
= CreateTD (UhcDev
, &TdStruct
);
1650 if (EFI_ERROR (Status
)) {
1654 SetTDLinkPtr (TdStruct
, NULL
);
1657 // Depth first fashion
1659 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1662 // Link pointer pointing to TD struct
1664 SetTDLinkPtrQHorTDSelect (TdStruct
, FALSE
);
1667 // initialize as the last TD in the QH context,
1668 // this field will be updated in the TD linkage process.
1670 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1673 // Disable short packet detect
1675 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1677 // Max error counter is 3
1679 SetTDControlErrorCounter (TdStruct
, 3);
1682 // set device speed attribute
1683 // (TRUE - Slow Device; FALSE - Full Speed Device)
1685 switch (DeviceSpeed
) {
1686 case USB_SLOW_SPEED_DEVICE
:
1687 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1690 case USB_FULL_SPEED_DEVICE
:
1691 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1695 // Non isochronous transfer TD
1697 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1700 // Disable Interrupt On Complete
1701 // Disable IOC interrupt.
1703 SetorClearTDControlIOC (TdStruct
, FALSE
);
1708 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1710 SetTDTokenMaxLength (TdStruct
, Len
);
1713 SetTDTokenDataToggle1 (TdStruct
);
1715 SetTDTokenDataToggle0 (TdStruct
);
1718 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1720 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1722 SetTDTokenPacketID (TdStruct
, PktID
);
1724 TdStruct
->PtrTDBuffer
= (UINT8
*) PtrData
;
1725 TdStruct
->TDBufferLength
= Len
;
1727 // Set the beginning address of the buffer that will be used
1728 // during the transaction.
1730 TdStruct
->TDData
.TDBufferPtr
= (UINT32
) (UINTN
) DataPhy
;
1738 Generate Status Stage TD.
1740 @param UhcDev The UHCI device.
1741 @param DevAddr Device address.
1742 @param Endpoint Endpoint number.
1743 @param PktID PacketID.
1744 @param DeviceSpeed Device Speed.
1745 @param PtrTD TD_STRUCT generated.
1747 @return EFI_SUCCESS Generate status stage TD successfully.
1748 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1753 IN USB_UHC_DEV
*UhcDev
,
1757 IN UINT8 DeviceSpeed
,
1758 OUT TD_STRUCT
**PtrTD
1761 TD_STRUCT
*PtrTDStruct
;
1764 Status
= CreateTD (UhcDev
, &PtrTDStruct
);
1765 if (EFI_ERROR (Status
)) {
1769 SetTDLinkPtr (PtrTDStruct
, NULL
);
1772 // Depth first fashion
1774 SetTDLinkPtrDepthorBreadth (PtrTDStruct
, TRUE
);
1777 // initialize as the last TD in the QH context,
1778 // this field will be updated in the TD linkage process.
1780 SetTDLinkPtrValidorInvalid (PtrTDStruct
, FALSE
);
1783 // Disable short packet detect
1785 EnableorDisableTDShortPacket (PtrTDStruct
, FALSE
);
1788 // Max error counter is 3
1790 SetTDControlErrorCounter (PtrTDStruct
, 3);
1793 // set device speed attribute
1794 // (TRUE - Slow Device; FALSE - Full Speed Device)
1796 switch (DeviceSpeed
) {
1797 case USB_SLOW_SPEED_DEVICE
:
1798 SetTDLoworFullSpeedDevice (PtrTDStruct
, TRUE
);
1801 case USB_FULL_SPEED_DEVICE
:
1802 SetTDLoworFullSpeedDevice (PtrTDStruct
, FALSE
);
1806 // Non isochronous transfer TD
1808 SetTDControlIsochronousorNot (PtrTDStruct
, FALSE
);
1811 // Disable Interrupt On Complete
1812 // Disable IOC interrupt.
1814 SetorClearTDControlIOC (PtrTDStruct
, FALSE
);
1817 // Set TD Active bit
1819 SetTDStatusActiveorInactive (PtrTDStruct
, TRUE
);
1821 SetTDTokenMaxLength (PtrTDStruct
, 0);
1823 SetTDTokenDataToggle1 (PtrTDStruct
);
1825 SetTDTokenEndPoint (PtrTDStruct
, Endpoint
);
1827 SetTDTokenDeviceAddress (PtrTDStruct
, DevAddr
);
1829 SetTDTokenPacketID (PtrTDStruct
, PktID
);
1831 PtrTDStruct
->PtrTDBuffer
= NULL
;
1832 PtrTDStruct
->TDBufferLength
= 0;
1834 // Set the beginning address of the buffer that will be used
1835 // during the transaction.
1837 PtrTDStruct
->TDData
.TDBufferPtr
= 0;
1839 *PtrTD
= PtrTDStruct
;
1845 Set the link pointer validor bit in TD.
1847 @param PtrTDStruct Place to store TD_STRUCT pointer.
1848 @param IsValid Specify the linker pointer is valid or not.
1852 SetTDLinkPtrValidorInvalid (
1853 IN TD_STRUCT
*PtrTDStruct
,
1858 // Valid means the link pointer is valid,
1859 // else, it's invalid.
1861 PtrTDStruct
->TDData
.TDLinkPtrTerminate
= (IsValid
? 0 : 1);
1865 Set the Link Pointer pointing to a QH or TD.
1867 @param PtrTDStruct Place to store TD_STRUCT pointer.
1868 @param IsQH Specify QH or TD is connected.
1872 SetTDLinkPtrQHorTDSelect (
1873 IN TD_STRUCT
*PtrTDStruct
,
1878 // Indicate whether the Link Pointer pointing to a QH or TD
1880 PtrTDStruct
->TDData
.TDLinkPtrQSelect
= (IsQH
? 1 : 0);
1884 Set the traverse is depth-first or breadth-first.
1886 @param PtrTDStruct Place to store TD_STRUCT pointer.
1887 @param IsDepth Specify the traverse is depth-first or breadth-first.
1891 SetTDLinkPtrDepthorBreadth (
1892 IN TD_STRUCT
*PtrTDStruct
,
1897 // If TRUE, indicating the host controller should process in depth first fashion,
1898 // else, the host controller should process in breadth first fashion
1900 PtrTDStruct
->TDData
.TDLinkPtrDepthSelect
= (IsDepth
? 1 : 0);
1904 Set TD Link Pointer in TD.
1906 @param PtrTDStruct Place to store TD_STRUCT pointer.
1907 @param PtrNext Place to the next TD_STRUCT.
1912 IN TD_STRUCT
*PtrTDStruct
,
1917 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
1918 // only the highest 28 bits are valid. (if take 32bit address as an example)
1920 PtrTDStruct
->TDData
.TDLinkPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1924 Get TD Link Pointer.
1926 @param PtrTDStruct Place to store TD_STRUCT pointer.
1928 @retval Get TD Link Pointer in TD.
1933 IN TD_STRUCT
*PtrTDStruct
1937 // Get TD Link Pointer. Restore it back to 32bit
1938 // (if take 32bit address as an example)
1940 return (VOID
*) (UINTN
) ((PtrTDStruct
->TDData
.TDLinkPtr
) << 4);
1946 Enable/Disable short packet detection mechanism.
1948 @param PtrTDStruct Place to store TD_STRUCT pointer.
1949 @param IsEnable Enable or disable short packet detection mechanism.
1953 EnableorDisableTDShortPacket (
1954 IN TD_STRUCT
*PtrTDStruct
,
1959 // TRUE means enable short packet detection mechanism.
1961 PtrTDStruct
->TDData
.TDStatusSPD
= (IsEnable
? 1 : 0);
1965 Set the max error counter in TD.
1967 @param PtrTDStruct Place to store TD_STRUCT pointer.
1968 @param MaxErrors The number of allowable error.
1972 SetTDControlErrorCounter (
1973 IN TD_STRUCT
*PtrTDStruct
,
1978 // valid value of MaxErrors is 0,1,2,3
1980 if (MaxErrors
> 3) {
1984 PtrTDStruct
->TDData
.TDStatusErr
= MaxErrors
;
1988 Set the TD is targeting a low-speed device or not.
1990 @param PtrTDStruct Place to store TD_STRUCT pointer.
1991 @param IsLowSpeedDevice Whether The device is low-speed.
1995 SetTDLoworFullSpeedDevice (
1996 IN TD_STRUCT
*PtrTDStruct
,
1997 IN BOOLEAN IsLowSpeedDevice
2001 // TRUE means the TD is targeting at a Low-speed device
2003 PtrTDStruct
->TDData
.TDStatusLS
= (IsLowSpeedDevice
? 1 : 0);
2007 Set the TD is isochronous transfer type or not.
2009 @param PtrTDStruct Place to store TD_STRUCT pointer.
2010 @param IsIsochronous Whether the transaction isochronous transfer type.
2014 SetTDControlIsochronousorNot (
2015 IN TD_STRUCT
*PtrTDStruct
,
2016 IN BOOLEAN IsIsochronous
2020 // TRUE means the TD belongs to Isochronous transfer type.
2022 PtrTDStruct
->TDData
.TDStatusIOS
= (IsIsochronous
? 1 : 0);
2026 Set if UCHI should issue an interrupt on completion of the frame
2027 in which this TD is executed
2029 @param PtrTDStruct Place to store TD_STRUCT pointer.
2030 @param IsSet Whether HC should issue an interrupt on completion.
2034 SetorClearTDControlIOC (
2035 IN TD_STRUCT
*PtrTDStruct
,
2040 // If this bit is set, it indicates that the host controller should issue
2041 // an interrupt on completion of the frame in which this TD is executed.
2043 PtrTDStruct
->TDData
.TDStatusIOC
= IsSet
? 1 : 0;
2047 Set if the TD is active and can be executed.
2049 @param PtrTDStruct Place to store TD_STRUCT pointer.
2050 @param IsActive Whether the TD is active and can be executed.
2054 SetTDStatusActiveorInactive (
2055 IN TD_STRUCT
*PtrTDStruct
,
2060 // If this bit is set, it indicates that the TD is active and can be
2064 PtrTDStruct
->TDData
.TDStatus
|= 0x80;
2066 PtrTDStruct
->TDData
.TDStatus
&= 0x7F;
2071 Specifies the maximum number of data bytes allowed for the transfer.
2073 @param PtrTDStruct Place to store TD_STRUCT pointer.
2074 @param MaxLen The maximum number of data bytes allowed.
2076 @retval The allowed maximum number of data.
2079 SetTDTokenMaxLength (
2080 IN TD_STRUCT
*PtrTDStruct
,
2085 // Specifies the maximum number of data bytes allowed for the transfer.
2086 // the legal value extent is 0 ~ 0x500.
2088 if (MaxLen
> 0x500) {
2092 PtrTDStruct
->TDData
.TDTokenMaxLen
= MaxLen
- 1;
2098 Set the data toggle bit to DATA1.
2100 @param PtrTDStruct Place to store TD_STRUCT pointer.
2104 SetTDTokenDataToggle1 (
2105 IN TD_STRUCT
*PtrTDStruct
2109 // Set the data toggle bit to DATA1
2111 PtrTDStruct
->TDData
.TDTokenDataToggle
= 1;
2115 Set the data toggle bit to DATA0.
2117 @param PtrTDStruct Place to store TD_STRUCT pointer.
2121 SetTDTokenDataToggle0 (
2122 IN TD_STRUCT
*PtrTDStruct
2126 // Set the data toggle bit to DATA0
2128 PtrTDStruct
->TDData
.TDTokenDataToggle
= 0;
2132 Set EndPoint Number the TD is targeting at.
2134 @param PtrTDStruct Place to store TD_STRUCT pointer.
2135 @param EndPoint The Endport number of the target.
2139 SetTDTokenEndPoint (
2140 IN TD_STRUCT
*PtrTDStruct
,
2145 // Set EndPoint Number the TD is targeting at.
2147 PtrTDStruct
->TDData
.TDTokenEndPt
= (UINT8
) EndPoint
;
2151 Set Device Address the TD is targeting at.
2153 @param PtrTDStruct Place to store TD_STRUCT pointer.
2154 @param DevAddr The Device Address of the target.
2158 SetTDTokenDeviceAddress (
2159 IN TD_STRUCT
*PtrTDStruct
,
2164 // Set Device Address the TD is targeting at.
2166 PtrTDStruct
->TDData
.TDTokenDevAddr
= (UINT8
) DevAddr
;
2170 Set Packet Identification the TD is targeting at.
2172 @param PtrTDStruct Place to store TD_STRUCT pointer.
2173 @param PacketID The Packet Identification of the target.
2177 SetTDTokenPacketID (
2178 IN TD_STRUCT
*PtrTDStruct
,
2183 // Set the Packet Identification to be used for this transaction.
2185 PtrTDStruct
->TDData
.TDTokenPID
= PacketID
;
2189 Detect whether the TD is active.
2191 @param PtrTDStruct Place to store TD_STRUCT pointer.
2193 @retval The TD is active or not.
2198 IN TD_STRUCT
*PtrTDStruct
2204 // Detect whether the TD is active.
2206 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2207 return (BOOLEAN
) (TDStatus
& 0x80);
2211 Detect whether the TD is stalled.
2213 @param PtrTDStruct Place to store TD_STRUCT pointer.
2215 @retval The TD is stalled or not.
2220 IN TD_STRUCT
*PtrTDStruct
2226 // Detect whether the device/endpoint addressed by this TD is stalled.
2228 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2229 return (BOOLEAN
) (TDStatus
& 0x40);
2233 Detect whether Data Buffer Error is happened.
2235 @param PtrTDStruct Place to store TD_STRUCT pointer.
2237 @retval The Data Buffer Error is happened or not.
2241 IsTDStatusBufferError (
2242 IN TD_STRUCT
*PtrTDStruct
2248 // Detect whether Data Buffer Error is happened.
2250 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2251 return (BOOLEAN
) (TDStatus
& 0x20);
2255 Detect whether Babble Error is happened.
2257 @param PtrTDStruct Place to store TD_STRUCT pointer.
2259 @retval The Babble Error is happened or not.
2263 IsTDStatusBabbleError (
2264 IN TD_STRUCT
*PtrTDStruct
2270 // Detect whether Babble Error is happened.
2272 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2273 return (BOOLEAN
) (TDStatus
& 0x10);
2277 Detect whether NAK is received.
2279 @param PtrTDStruct Place to store TD_STRUCT pointer.
2281 @retval The NAK is received or not.
2285 IsTDStatusNAKReceived (
2286 IN TD_STRUCT
*PtrTDStruct
2292 // Detect whether NAK is received.
2294 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2295 return (BOOLEAN
) (TDStatus
& 0x08);
2299 Detect whether CRC/Time Out Error is encountered.
2301 @param PtrTDStruct Place to store TD_STRUCT pointer.
2303 @retval The CRC/Time Out Error is encountered or not.
2307 IsTDStatusCRCTimeOutError (
2308 IN TD_STRUCT
*PtrTDStruct
2314 // Detect whether CRC/Time Out Error is encountered.
2316 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2317 return (BOOLEAN
) (TDStatus
& 0x04);
2321 Detect whether Bitstuff Error is received.
2323 @param PtrTDStruct Place to store TD_STRUCT pointer.
2325 @retval The Bitstuff Error is received or not.
2329 IsTDStatusBitStuffError (
2330 IN TD_STRUCT
*PtrTDStruct
2336 // Detect whether Bitstuff Error is received.
2338 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2339 return (BOOLEAN
) (TDStatus
& 0x02);
2343 Retrieve the actual number of bytes that were tansferred.
2345 @param PtrTDStruct Place to store TD_STRUCT pointer.
2347 @retval The actual number of bytes that were tansferred.
2351 GetTDStatusActualLength (
2352 IN TD_STRUCT
*PtrTDStruct
2356 // Retrieve the actual number of bytes that were tansferred.
2357 // the value is encoded as n-1. so return the decoded value.
2359 return (UINT16
) ((PtrTDStruct
->TDData
.TDStatusActualLength
) + 1);
2363 Retrieve the information of whether the Link Pointer field is valid or not.
2365 @param PtrTDStruct Place to store TD_STRUCT pointer.
2367 @retval The linker pointer field is valid or not.
2371 GetTDLinkPtrValidorInvalid (
2372 IN TD_STRUCT
*PtrTDStruct
2376 // Retrieve the information of whether the Link Pointer field
2379 if ((PtrTDStruct
->TDData
.TDLinkPtrTerminate
& BIT0
) != 0) {
2388 Count TD Number from PtrFirstTD.
2390 @param PtrFirstTD Place to store TD_STRUCT pointer.
2392 @retval The queued TDs number.
2397 IN TD_STRUCT
*PtrFirstTD
2404 // Count the queued TDs number.
2409 Ptr
= (TD_STRUCT
*) Ptr
->PtrNextTD
;
2419 @param PtrQH Place to store QH_STRUCT pointer.
2420 @param PtrTD Place to store TD_STRUCT pointer.
2425 IN QH_STRUCT
*PtrQH
,
2429 if (PtrQH
== NULL
|| PtrTD
== NULL
) {
2433 // Validate QH Vertical Ptr field
2435 SetQHVerticalValidorInvalid (PtrQH
, TRUE
);
2438 // Vertical Ptr pointing to TD structure
2440 SetQHVerticalQHorTDSelect (PtrQH
, FALSE
);
2442 SetQHVerticalLinkPtr (PtrQH
, (VOID
*) PtrTD
);
2444 PtrQH
->PtrDown
= (VOID
*) PtrTD
;
2450 @param PtrPreTD Place to store TD_STRUCT pointer.
2451 @param PtrTD Place to store TD_STRUCT pointer.
2456 IN TD_STRUCT
*PtrPreTD
,
2460 if (PtrPreTD
== NULL
|| PtrTD
== NULL
) {
2464 // Depth first fashion
2466 SetTDLinkPtrDepthorBreadth (PtrPreTD
, TRUE
);
2469 // Link pointer pointing to TD struct
2471 SetTDLinkPtrQHorTDSelect (PtrPreTD
, FALSE
);
2474 // Validate the link pointer valid bit
2476 SetTDLinkPtrValidorInvalid (PtrPreTD
, TRUE
);
2478 SetTDLinkPtr (PtrPreTD
, PtrTD
);
2480 PtrPreTD
->PtrNextTD
= (VOID
*) PtrTD
;
2482 PtrTD
->PtrNextTD
= NULL
;
2486 Execute Control Transfer.
2488 @param UhcDev The UCHI device.
2489 @param PtrTD A pointer to TD_STRUCT data.
2490 @param ActualLen Actual transfer Length.
2491 @param TimeOut TimeOut value.
2492 @param TransferResult Transfer Result.
2494 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2495 @return EFI_TIMEOUT The transfer failed due to time out.
2496 @return EFI_SUCCESS The transfer finished OK.
2500 ExecuteControlTransfer (
2501 IN USB_UHC_DEV
*UhcDev
,
2502 IN TD_STRUCT
*PtrTD
,
2503 OUT UINTN
*ActualLen
,
2505 OUT UINT32
*TransferResult
2510 BOOLEAN InfiniteLoop
;
2513 *TransferResult
= EFI_USB_NOERROR
;
2515 InfiniteLoop
= FALSE
;
2517 Delay
= TimeOut
* STALL_1_MILLI_SECOND
;
2519 // If Timeout is 0, then the caller must wait for the function to be completed
2520 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2523 InfiniteLoop
= TRUE
;
2528 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2531 // TD is inactive, means the control transfer is end.
2533 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2536 MicroSecondDelay (STALL_1_MICRO_SECOND
);
2539 } while (InfiniteLoop
|| (Delay
!= 0));
2541 if (*TransferResult
!= EFI_USB_NOERROR
) {
2542 return EFI_DEVICE_ERROR
;
2549 Execute Bulk Transfer.
2551 @param UhcDev The UCHI device.
2552 @param PtrTD A pointer to TD_STRUCT data.
2553 @param ActualLen Actual transfer Length.
2554 @param DataToggle DataToggle value.
2555 @param TimeOut TimeOut value.
2556 @param TransferResult Transfer Result.
2558 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2559 @return EFI_TIMEOUT The transfer failed due to time out.
2560 @return EFI_SUCCESS The transfer finished OK.
2565 IN USB_UHC_DEV
*UhcDev
,
2566 IN TD_STRUCT
*PtrTD
,
2567 IN OUT UINTN
*ActualLen
,
2568 IN UINT8
*DataToggle
,
2570 OUT UINT32
*TransferResult
2576 BOOLEAN InfiniteLoop
;
2579 *TransferResult
= EFI_USB_NOERROR
;
2581 InfiniteLoop
= FALSE
;
2583 Delay
= TimeOut
* STALL_1_MILLI_SECOND
;
2585 // If Timeout is 0, then the caller must wait for the function to be completed
2586 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2589 InfiniteLoop
= TRUE
;
2594 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2596 // TD is inactive, thus meaning bulk transfer's end.
2598 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2601 MicroSecondDelay (STALL_1_MICRO_SECOND
);
2604 } while (InfiniteLoop
|| (Delay
!= 0));
2609 if (*TransferResult
!= EFI_USB_NOERROR
) {
2611 // scroll the Data Toggle back to the last success TD
2613 ScrollNum
= CountTDsNumber (PtrTD
) - ErrTDPos
;
2614 if ((ScrollNum
% 2) != 0) {
2619 // If error, wait 100ms to retry by upper layer
2621 MicroSecondDelay (100 * 1000);
2622 return EFI_DEVICE_ERROR
;
2631 @param UhcDev The UCHI device.
2632 @param PtrFirstTD Place to store TD_STRUCT pointer.
2637 IN USB_UHC_DEV
*UhcDev
,
2638 IN TD_STRUCT
*PtrFirstTD
2647 // Delete all the TDs in a queue.
2649 while (Tptr1
!= NULL
) {
2653 if (!GetTDLinkPtrValidorInvalid (Tptr2
)) {
2657 // has more than one TD in the queue.
2659 Tptr1
= GetTDLinkPtr (Tptr2
);
2662 UhcFreePool (UhcDev
, (UINT8
*) Tptr2
, sizeof (TD_STRUCT
));
2671 @param PtrTD A pointer to TD_STRUCT data.
2672 @param Result The result to return.
2673 @param ErrTDPos The Error TD position.
2674 @param ActualTransferSize Actual transfer size.
2676 @retval The TD is executed successfully or not.
2681 IN TD_STRUCT
*PtrTD
,
2683 OUT UINTN
*ErrTDPos
,
2684 OUT UINTN
*ActualTransferSize
2689 *Result
= EFI_USB_NOERROR
;
2695 *ActualTransferSize
= 0;
2697 while (PtrTD
!= NULL
) {
2699 if (IsTDStatusActive (PtrTD
)) {
2700 *Result
|= EFI_USB_ERR_NOTEXECUTE
;
2703 if (IsTDStatusStalled (PtrTD
)) {
2704 *Result
|= EFI_USB_ERR_STALL
;
2707 if (IsTDStatusBufferError (PtrTD
)) {
2708 *Result
|= EFI_USB_ERR_BUFFER
;
2711 if (IsTDStatusBabbleError (PtrTD
)) {
2712 *Result
|= EFI_USB_ERR_BABBLE
;
2715 if (IsTDStatusNAKReceived (PtrTD
)) {
2716 *Result
|= EFI_USB_ERR_NAK
;
2719 if (IsTDStatusCRCTimeOutError (PtrTD
)) {
2720 *Result
|= EFI_USB_ERR_TIMEOUT
;
2723 if (IsTDStatusBitStuffError (PtrTD
)) {
2724 *Result
|= EFI_USB_ERR_BITSTUFF
;
2727 // Accumulate actual transferred data length in each TD.
2729 Len
= GetTDStatusActualLength (PtrTD
) & 0x7FF;
2730 *ActualTransferSize
+= Len
;
2733 // if any error encountered, stop processing the left TDs.
2735 if ((*Result
) != 0) {
2739 PtrTD
= (TD_STRUCT
*) (PtrTD
->PtrNextTD
);
2741 // Record the first Error TD's position in the queue,
2742 // this value is zero-based.
2751 Create Memory Block.
2753 @param UhcDev The UCHI device.
2754 @param MemoryHeader The Pointer to allocated memory block.
2755 @param MemoryBlockSizeInPages The page size of memory block to be allocated.
2757 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2758 @retval EFI_SUCCESS Success.
2763 IN USB_UHC_DEV
*UhcDev
,
2764 OUT MEMORY_MANAGE_HEADER
**MemoryHeader
,
2765 IN UINTN MemoryBlockSizeInPages
2773 EFI_PHYSICAL_ADDRESS MappedAddr
;
2776 // Memory Block uses MemoryBlockSizeInPages pages,
2777 // memory management header and bit array use 1 page
2779 MemPages
= MemoryBlockSizeInPages
+ 1;
2780 Status
= IoMmuAllocateBuffer (
2787 if (EFI_ERROR (Status
) || (TempPtr
== NULL
)) {
2788 return EFI_OUT_OF_RESOURCES
;
2793 ZeroMem (Ptr
, MemPages
* EFI_PAGE_SIZE
);
2795 *MemoryHeader
= (MEMORY_MANAGE_HEADER
*) Ptr
;
2797 // adjust Ptr pointer to the next empty memory
2799 Ptr
+= sizeof (MEMORY_MANAGE_HEADER
);
2801 // Set Bit Array initial address
2803 (*MemoryHeader
)->BitArrayPtr
= Ptr
;
2805 (*MemoryHeader
)->Next
= NULL
;
2808 // Memory block initial address
2811 Ptr
+= EFI_PAGE_SIZE
;
2812 (*MemoryHeader
)->MemoryBlockPtr
= Ptr
;
2814 // set Memory block size
2816 (*MemoryHeader
)->MemoryBlockSizeInBytes
= MemoryBlockSizeInPages
* EFI_PAGE_SIZE
;
2818 // each bit in Bit Array will manage 32byte memory in memory block
2820 (*MemoryHeader
)->BitArraySizeInBytes
= ((*MemoryHeader
)->MemoryBlockSizeInBytes
/ 32) / 8;
2826 Initialize UHCI memory management.
2828 @param UhcDev The UCHI device.
2830 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2831 @retval EFI_SUCCESS Success.
2835 InitializeMemoryManagement (
2836 IN USB_UHC_DEV
*UhcDev
2839 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2843 MemPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2844 Status
= CreateMemoryBlock (UhcDev
, &MemoryHeader
, MemPages
);
2845 if (EFI_ERROR (Status
)) {
2849 UhcDev
->Header1
= MemoryHeader
;
2855 Initialize UHCI memory management.
2857 @param UhcDev The UCHI device.
2858 @param Pool Buffer pointer to store the buffer pointer.
2859 @param AllocSize The size of the pool to be allocated.
2861 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2862 @retval EFI_SUCCESS Success.
2867 IN USB_UHC_DEV
*UhcDev
,
2872 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2873 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
2874 MEMORY_MANAGE_HEADER
*NewMemoryHeader
;
2875 UINTN RealAllocSize
;
2876 UINTN MemoryBlockSizeInPages
;
2881 MemoryHeader
= UhcDev
->Header1
;
2884 // allocate unit is 32 byte (align on 32 byte)
2886 if ((AllocSize
& 0x1F) != 0) {
2887 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
2889 RealAllocSize
= AllocSize
;
2892 Status
= EFI_NOT_FOUND
;
2893 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
2895 Status
= AllocMemInMemoryBlock (
2900 if (!EFI_ERROR (Status
)) {
2905 // There is no enough memory,
2906 // Create a new Memory Block
2909 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
2910 // just allocate a large enough memory block.
2912 if (RealAllocSize
> (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
* EFI_PAGE_SIZE
)) {
2913 MemoryBlockSizeInPages
= RealAllocSize
/ EFI_PAGE_SIZE
+ 1;
2915 MemoryBlockSizeInPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2918 Status
= CreateMemoryBlock (UhcDev
, &NewMemoryHeader
, MemoryBlockSizeInPages
);
2919 if (EFI_ERROR (Status
)) {
2923 // Link the new Memory Block to the Memory Header list
2925 InsertMemoryHeaderToList (MemoryHeader
, NewMemoryHeader
);
2927 Status
= AllocMemInMemoryBlock (
2936 Alloc Memory In MemoryBlock.
2938 @param MemoryHeader The pointer to memory manage header.
2939 @param Pool Buffer pointer to store the buffer pointer.
2940 @param NumberOfMemoryUnit The size of the pool to be allocated.
2942 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2943 @retval EFI_SUCCESS Success.
2947 AllocMemInMemoryBlock (
2948 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
2950 IN UINTN NumberOfMemoryUnit
2959 UINTN NumberOfZeros
;
2965 ByteValue
= MemoryHeader
->BitArrayPtr
[0];
2968 for (TempBytePos
= 0; TempBytePos
< MemoryHeader
->BitArraySizeInBytes
;) {
2970 // Pop out BitValue from a byte in TempBytePos.
2972 BitValue
= (UINT8
)(ByteValue
& 0x1);
2974 if (BitValue
== 0) {
2976 // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
2980 // Found enough consecutive free space, break the loop
2982 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2987 // Encountering a '1', meant the bit is ocupied.
2989 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2991 // Found enough consecutive free space,break the loop
2996 // the NumberOfZeros only record the number of those consecutive zeros,
2997 // so reset the NumberOfZeros to 0 when encountering '1' before finding
2998 // enough consecutive '0's
3002 // reset the (FoundBytePos,FoundBitPos) to the position of '1'
3004 FoundBytePos
= TempBytePos
;
3005 FoundBitPos
= Index
;
3009 // right shift the byte
3014 // step forward a bit
3019 // step forward a byte, getting the byte value,
3020 // and reset the bit pos.
3023 ByteValue
= MemoryHeader
->BitArrayPtr
[TempBytePos
];
3028 if (NumberOfZeros
< NumberOfMemoryUnit
) {
3029 return EFI_NOT_FOUND
;
3032 // Found enough free space.
3035 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
3036 // 1)(FoundBytePos,FoundBitPos) record the position
3037 // of the last '1' before the consecutive '0's, it must
3038 // be adjusted to the start position of the consecutive '0's.
3039 // 2)the start address of the consecutive '0's is just the start of
3040 // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
3042 if ((MemoryHeader
->BitArrayPtr
[0] & BIT0
) != 0) {
3046 // Have the (FoundBytePos,FoundBitPos) make sense.
3048 if (FoundBitPos
> 7) {
3053 // Set the memory as allocated
3055 for (TempBytePos
= FoundBytePos
, Index
= FoundBitPos
, Count
= 0; Count
< NumberOfMemoryUnit
; Count
++) {
3057 MemoryHeader
->BitArrayPtr
[TempBytePos
] = (UINT8
) (MemoryHeader
->BitArrayPtr
[TempBytePos
] | (1 << Index
));
3065 *Pool
= MemoryHeader
->MemoryBlockPtr
+ (FoundBytePos
* 8 + FoundBitPos
) * 32;
3073 @param UhcDev The UHCI device.
3074 @param Pool A pointer to store the buffer address.
3075 @param AllocSize The size of the pool to be freed.
3080 IN USB_UHC_DEV
*UhcDev
,
3085 MEMORY_MANAGE_HEADER
*MemoryHeader
;
3086 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3092 UINTN RealAllocSize
;
3094 MemoryHeader
= UhcDev
->Header1
;
3097 // allocate unit is 32 byte (align on 32 byte)
3099 if ((AllocSize
& 0x1F) != 0) {
3100 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
3102 RealAllocSize
= AllocSize
;
3105 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
;
3106 TempHeaderPtr
= TempHeaderPtr
->Next
) {
3108 if ((Pool
>= TempHeaderPtr
->MemoryBlockPtr
) &&
3109 ((Pool
+ RealAllocSize
) <= (TempHeaderPtr
->MemoryBlockPtr
+
3110 TempHeaderPtr
->MemoryBlockSizeInBytes
))) {
3113 // Pool is in the Memory Block area,
3114 // find the start byte and bit in the bit array
3116 StartBytePos
= ((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) / 8;
3117 StartBitPos
= (UINT8
) (((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) % 8);
3120 // reset associated bits in bit array
3122 for (Index
= StartBytePos
, Index2
= StartBitPos
, Count
= 0; Count
< (RealAllocSize
/ 32); Count
++) {
3124 TempHeaderPtr
->BitArrayPtr
[Index
] = (UINT8
) (TempHeaderPtr
->BitArrayPtr
[Index
] ^ (1 << Index2
));
3141 Insert a new memory header into list.
3143 @param MemoryHeader A pointer to the memory header list.
3144 @param NewMemoryHeader A new memory header to be inserted into the list.
3148 InsertMemoryHeaderToList (
3149 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
3150 IN MEMORY_MANAGE_HEADER
*NewMemoryHeader
3153 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3155 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
3156 if (TempHeaderPtr
->Next
== NULL
) {
3157 TempHeaderPtr
->Next
= NewMemoryHeader
;
3168 Map address of request structure buffer.
3170 @param Uhc The UHCI device.
3171 @param Request The user request buffer.
3172 @param MappedAddr Mapped address of request.
3173 @param Map Identificaion of this mapping to return.
3175 @return EFI_SUCCESS Success.
3176 @return EFI_DEVICE_ERROR Fail to map the user request.
3180 UhciMapUserRequest (
3181 IN USB_UHC_DEV
*Uhc
,
3182 IN OUT VOID
*Request
,
3183 OUT UINT8
**MappedAddr
,
3189 EFI_PHYSICAL_ADDRESS PhyAddr
;
3191 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
3194 EdkiiIoMmuOperationBusMasterRead
,
3201 if (!EFI_ERROR (Status
)) {
3202 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3209 Map address of user data buffer.
3211 @param Uhc The UHCI device.
3212 @param Direction Direction of the data transfer.
3213 @param Data The user data buffer.
3214 @param Len Length of the user data.
3215 @param PktId Packet identificaion.
3216 @param MappedAddr Mapped address to return.
3217 @param Map Identificaion of this mapping to return.
3219 @return EFI_SUCCESS Success.
3220 @return EFI_DEVICE_ERROR Fail to map the user data.
3225 IN USB_UHC_DEV
*Uhc
,
3226 IN EFI_USB_DATA_DIRECTION Direction
,
3230 OUT UINT8
**MappedAddr
,
3235 EFI_PHYSICAL_ADDRESS PhyAddr
;
3237 Status
= EFI_SUCCESS
;
3239 switch (Direction
) {
3242 // BusMasterWrite means cpu read
3244 *PktId
= INPUT_PACKET_ID
;
3247 EdkiiIoMmuOperationBusMasterWrite
,
3254 if (EFI_ERROR (Status
)) {
3258 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3262 *PktId
= OUTPUT_PACKET_ID
;
3265 EdkiiIoMmuOperationBusMasterRead
,
3272 if (EFI_ERROR (Status
)) {
3276 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3280 if ((Len
!= NULL
) && (*Len
!= 0)) {
3281 Status
= EFI_INVALID_PARAMETER
;
3285 *PktId
= OUTPUT_PACKET_ID
;
3291 Status
= EFI_INVALID_PARAMETER
;