2 PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
5 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved. <BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 Initializes Usb Host Controller.
23 @param FileHandle Handle of the file being invoked.
24 @param PeiServices Describes the list of possible PEI Services.
26 @retval EFI_SUCCESS PPI successfully installed.
27 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
33 IN EFI_PEI_FILE_HANDLE FileHandle
,
34 IN CONST EFI_PEI_SERVICES
**PeiServices
37 PEI_USB_CONTROLLER_PPI
*ChipSetUsbControllerPpi
;
44 EFI_PHYSICAL_ADDRESS TempPtr
;
47 // Shadow this PEIM to run from memory
49 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
53 Status
= PeiServicesLocatePpi (
54 &gPeiUsbControllerPpiGuid
,
57 (VOID
**) &ChipSetUsbControllerPpi
60 // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.
62 ASSERT_EFI_ERROR (Status
);
66 Status
= ChipSetUsbControllerPpi
->GetUsbController (
67 (EFI_PEI_SERVICES
**) PeiServices
,
68 ChipSetUsbControllerPpi
,
74 // When status is error, meant no controller is found
76 if (EFI_ERROR (Status
)) {
81 // This PEIM is for UHC type controller.
83 if (ControllerType
!= PEI_UHCI_CONTROLLER
) {
88 MemPages
= sizeof (USB_UHC_DEV
) / EFI_PAGE_SIZE
+ 1;
90 Status
= PeiServicesAllocatePages (
95 if (EFI_ERROR (Status
)) {
96 return EFI_OUT_OF_RESOURCES
;
99 UhcDev
= (USB_UHC_DEV
*) ((UINTN
) TempPtr
);
100 UhcDev
->Signature
= USB_UHC_DEV_SIGNATURE
;
101 UhcDev
->UsbHostControllerBaseAddress
= (UINT32
) BaseAddress
;
104 // Init local memory management service
106 Status
= InitializeMemoryManagement (UhcDev
);
107 if (EFI_ERROR (Status
)) {
112 // Initialize Uhc's hardware
114 Status
= InitializeUsbHC (UhcDev
);
115 if (EFI_ERROR (Status
)) {
119 UhcDev
->UsbHostControllerPpi
.ControlTransfer
= UhcControlTransfer
;
120 UhcDev
->UsbHostControllerPpi
.BulkTransfer
= UhcBulkTransfer
;
121 UhcDev
->UsbHostControllerPpi
.GetRootHubPortNumber
= UhcGetRootHubPortNumber
;
122 UhcDev
->UsbHostControllerPpi
.GetRootHubPortStatus
= UhcGetRootHubPortStatus
;
123 UhcDev
->UsbHostControllerPpi
.SetRootHubPortFeature
= UhcSetRootHubPortFeature
;
124 UhcDev
->UsbHostControllerPpi
.ClearRootHubPortFeature
= UhcClearRootHubPortFeature
;
126 UhcDev
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
127 UhcDev
->PpiDescriptor
.Guid
= &gPeiUsbHostControllerPpiGuid
;
128 UhcDev
->PpiDescriptor
.Ppi
= &UhcDev
->UsbHostControllerPpi
;
130 Status
= PeiServicesInstallPpi (&UhcDev
->PpiDescriptor
);
131 if (EFI_ERROR (Status
)) {
143 Submits control transfer to a target USB device.
145 @param PeiServices The pointer of EFI_PEI_SERVICES.
146 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
147 @param DeviceAddress The target device address.
148 @param DeviceSpeed Target device speed.
149 @param MaximumPacketLength Maximum packet size the default control transfer
150 endpoint is capable of sending or receiving.
151 @param Request USB device request to send.
152 @param TransferDirection Specifies the data direction for the data stage.
153 @param Data Data buffer to be transmitted or received from USB device.
154 @param DataLength The size (in bytes) of the data buffer.
155 @param TimeOut Indicates the maximum timeout, in millisecond.
156 @param TransferResult Return the result of this control transfer.
158 @retval EFI_SUCCESS Transfer was completed successfully.
159 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
160 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
161 @retval EFI_TIMEOUT Transfer failed due to timeout.
162 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
168 IN EFI_PEI_SERVICES
**PeiServices
,
169 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
170 IN UINT8 DeviceAddress
,
171 IN UINT8 DeviceSpeed
,
172 IN UINT8 MaximumPacketLength
,
173 IN EFI_USB_DEVICE_REQUEST
*Request
,
174 IN EFI_USB_DATA_DIRECTION TransferDirection
,
175 IN OUT VOID
*Data OPTIONAL
,
176 IN OUT UINTN
*DataLength OPTIONAL
,
178 OUT UINT32
*TransferResult
187 TD_STRUCT
*PtrSetupTD
;
188 TD_STRUCT
*PtrStatusTD
;
191 UINT8
*PtrDataSource
;
195 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
197 StatusReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBSTS
;
199 PktID
= INPUT_PACKET_ID
;
201 if (Request
== NULL
|| TransferResult
== NULL
) {
202 return EFI_INVALID_PARAMETER
;
205 // if errors exist that cause host controller halt,
206 // then return EFI_DEVICE_ERROR.
209 if (!IsStatusOK (UhcDev
, StatusReg
)) {
210 ClearStatusReg (UhcDev
, StatusReg
);
211 *TransferResult
= EFI_USB_ERR_SYSTEM
;
212 return EFI_DEVICE_ERROR
;
215 ClearStatusReg (UhcDev
, StatusReg
);
218 // generate Setup Stage TD
221 PtrQH
= UhcDev
->ConfigQH
;
229 (UINT8
) sizeof (EFI_USB_DEVICE_REQUEST
),
234 // link setup TD structures to QH structure
236 LinkTDToQH (PtrQH
, PtrSetupTD
);
238 PtrPreTD
= PtrSetupTD
;
241 // Data Stage of Control Transfer
243 switch (TransferDirection
) {
246 PktID
= INPUT_PACKET_ID
;
247 PtrDataSource
= Data
;
248 DataLen
= (UINT32
) *DataLength
;
253 PktID
= OUTPUT_PACKET_ID
;
254 PtrDataSource
= Data
;
255 DataLen
= (UINT32
) *DataLength
;
263 if (*DataLength
!= 0) {
264 return EFI_INVALID_PARAMETER
;
267 PktID
= OUTPUT_PACKET_ID
;
268 PtrDataSource
= NULL
;
274 return EFI_INVALID_PARAMETER
;
280 while (DataLen
> 0) {
282 // create TD structures and link together
287 // PacketSize is the data load size of each TD carries.
289 PacketSize
= (UINT8
) DataLen
;
290 if (DataLen
> MaximumPacketLength
) {
291 PacketSize
= MaximumPacketLength
;
307 // Link two TDs in vertical depth
309 LinkTDToTD (PtrPreTD
, PtrTD
);
314 DataLen
-= PacketSize
;
318 // PtrPreTD points to the last TD before the Setup-Stage TD.
323 // Status Stage of Control Transfer
325 if (PktID
== OUTPUT_PACKET_ID
) {
326 PktID
= INPUT_PACKET_ID
;
328 PktID
= OUTPUT_PACKET_ID
;
331 // create Status Stage TD structure
342 LinkTDToTD (PtrPreTD
, PtrStatusTD
);
345 // Poll QH-TDs execution and get result.
346 // detail status is returned
348 Status
= ExecuteControlTransfer (
357 // TRUE means must search other framelistindex
359 SetQHVerticalValidorInvalid(PtrQH
, FALSE
);
360 DeleteQueuedTDs (UhcDev
, PtrSetupTD
);
363 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
365 if (!IsStatusOK (UhcDev
, StatusReg
)) {
367 ClearStatusReg (UhcDev
, StatusReg
);
368 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
369 return EFI_DEVICE_ERROR
;
372 ClearStatusReg (UhcDev
, StatusReg
);
378 Submits bulk transfer to a bulk endpoint of a USB device.
380 @param PeiServices The pointer of EFI_PEI_SERVICES.
381 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
382 @param DeviceAddress Target device address.
383 @param EndPointAddress Endpoint number and its direction in bit 7.
384 @param MaximumPacketLength Maximum packet size the endpoint is capable of
385 sending or receiving.
386 @param Data Array of pointers to the buffers of data to transmit
387 from or receive into.
388 @param DataLength The lenght of the data buffer.
389 @param DataToggle On input, the initial data toggle for the transfer;
390 On output, it is updated to to next data toggle to use of
391 the subsequent bulk transfer.
392 @param TimeOut Indicates the maximum time, in millisecond, which the
393 transfer is allowed to complete.
394 @param TransferResult A pointer to the detailed result information of the
397 @retval EFI_SUCCESS The transfer was completed successfully.
398 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
399 @retval EFI_INVALID_PARAMETER Parameters are invalid.
400 @retval EFI_TIMEOUT The transfer failed due to timeout.
401 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
407 IN EFI_PEI_SERVICES
**PeiServices
,
408 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
409 IN UINT8 DeviceAddress
,
410 IN UINT8 EndPointAddress
,
411 IN UINT8 MaximumPacketLength
,
413 IN OUT UINTN
*DataLength
,
414 IN OUT UINT8
*DataToggle
,
416 OUT UINT32
*TransferResult
425 TD_STRUCT
*PtrFirstTD
;
430 UINT8
*PtrDataSource
;
437 EFI_USB_DATA_DIRECTION TransferDirection
;
439 BOOLEAN ShortPacketEnable
;
441 UINT16 CommandContent
;
443 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
446 // Enable the maximum packet size (64bytes)
447 // that can be used for full speed bandwidth reclamation
448 // at the end of a frame.
450 CommandContent
= USBReadPortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
);
451 if ((CommandContent
& USBCMD_MAXP
) != USBCMD_MAXP
) {
452 CommandContent
|= USBCMD_MAXP
;
453 USBWritePortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
, CommandContent
);
456 StatusReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBSTS
;
459 // these code lines are added here per complier's strict demand
461 PktID
= INPUT_PACKET_ID
;
468 ShortPacketEnable
= FALSE
;
470 if ((DataLength
== 0) || (Data
== NULL
) || (TransferResult
== NULL
)) {
471 return EFI_INVALID_PARAMETER
;
474 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
475 return EFI_INVALID_PARAMETER
;
478 if (MaximumPacketLength
!= 8 && MaximumPacketLength
!= 16
479 && MaximumPacketLength
!= 32 && MaximumPacketLength
!= 64) {
480 return EFI_INVALID_PARAMETER
;
483 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
485 if (!IsStatusOK (UhcDev
, StatusReg
)) {
487 ClearStatusReg (UhcDev
, StatusReg
);
488 *TransferResult
= EFI_USB_ERR_SYSTEM
;
489 return EFI_DEVICE_ERROR
;
492 ClearStatusReg (UhcDev
, StatusReg
);
494 if ((EndPointAddress
& 0x80) != 0) {
495 TransferDirection
= EfiUsbDataIn
;
497 TransferDirection
= EfiUsbDataOut
;
500 switch (TransferDirection
) {
503 ShortPacketEnable
= TRUE
;
504 PktID
= INPUT_PACKET_ID
;
505 PtrDataSource
= Data
;
506 DataLen
= (UINT32
) *DataLength
;
511 PktID
= OUTPUT_PACKET_ID
;
512 PtrDataSource
= Data
;
513 DataLen
= (UINT32
) *DataLength
;
521 PtrQH
= UhcDev
->BulkQH
;
524 while (DataLen
> 0) {
526 // create TD structures and link together
530 PacketSize
= (UINT8
) DataLen
;
531 if (DataLen
> MaximumPacketLength
) {
532 PacketSize
= MaximumPacketLength
;
543 USB_FULL_SPEED_DEVICE
,
548 // Enable short packet detection.
549 // (default action is disabling short packet detection)
551 if (ShortPacketEnable
) {
552 EnableorDisableTDShortPacket (PtrTD
, TRUE
);
557 PtrFirstTD
->PtrNextTD
= NULL
;
561 // Link two TDs in vertical depth
563 LinkTDToTD (PtrPreTD
, PtrTD
);
570 DataLen
-= PacketSize
;
573 // link TD structures to QH structure
575 LinkTDToQH (PtrQH
, PtrFirstTD
);
578 // Execute QH-TD and get result
581 // detail status is put into the Result field in the pIRP
582 // the Data Toggle value is also re-updated to the value
583 // of the last successful TD
585 Status
= ExecBulkTransfer (
595 // Delete Bulk transfer TD structure
597 DeleteQueuedTDs (UhcDev
, PtrFirstTD
);
600 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
602 if (!IsStatusOK (UhcDev
, StatusReg
)) {
604 ClearStatusReg (UhcDev
, StatusReg
);
605 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
606 return EFI_DEVICE_ERROR
;
609 ClearStatusReg (UhcDev
, StatusReg
);
615 Retrieves the number of root hub ports.
617 @param[in] PeiServices The pointer to the PEI Services Table.
618 @param[in] This The pointer to this instance of the
619 PEI_USB_HOST_CONTROLLER_PPI.
620 @param[out] PortNumber The pointer to the number of the root hub ports.
622 @retval EFI_SUCCESS The port number was retrieved successfully.
623 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
628 UhcGetRootHubPortNumber (
629 IN EFI_PEI_SERVICES
**PeiServices
,
630 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
631 OUT UINT8
*PortNumber
636 UINT16 RHPortControl
;
639 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
641 if (PortNumber
== NULL
) {
642 return EFI_INVALID_PARAMETER
;
647 for (Index
= 0; Index
< 2; Index
++) {
648 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ Index
* 2;
649 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
651 // Port Register content is valid
653 if (RHPortControl
!= 0xff) {
662 Retrieves the current status of a USB root hub port.
664 @param PeiServices The pointer of EFI_PEI_SERVICES.
665 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
666 @param PortNumber The root hub port to retrieve the state from.
667 @param PortStatus Variable to receive the port state.
669 @retval EFI_SUCCESS The status of the USB root hub port specified.
670 by PortNumber was returned in PortStatus.
671 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
676 UhcGetRootHubPortStatus (
677 IN EFI_PEI_SERVICES
**PeiServices
,
678 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
680 OUT EFI_USB_PORT_STATUS
*PortStatus
686 UINT8 TotalPortNumber
;
688 if (PortStatus
== NULL
) {
689 return EFI_INVALID_PARAMETER
;
692 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
693 if (PortNumber
> TotalPortNumber
) {
694 return EFI_INVALID_PARAMETER
;
697 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
698 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
700 PortStatus
->PortStatus
= 0;
701 PortStatus
->PortChangeStatus
= 0;
703 RHPortStatus
= USBReadPortW (UhcDev
, PSAddr
);
706 // Current Connect Status
708 if ((RHPortStatus
& USBPORTSC_CCS
) != 0) {
709 PortStatus
->PortStatus
|= USB_PORT_STAT_CONNECTION
;
712 // Port Enabled/Disabled
714 if ((RHPortStatus
& USBPORTSC_PED
) != 0) {
715 PortStatus
->PortStatus
|= USB_PORT_STAT_ENABLE
;
720 if ((RHPortStatus
& USBPORTSC_SUSP
) != 0) {
721 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
726 if ((RHPortStatus
& USBPORTSC_PR
) != 0) {
727 PortStatus
->PortStatus
|= USB_PORT_STAT_RESET
;
730 // Low Speed Device Attached
732 if ((RHPortStatus
& USBPORTSC_LSDA
) != 0) {
733 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
736 // Fill Port Status Change bits
739 // Connect Status Change
741 if ((RHPortStatus
& USBPORTSC_CSC
) != 0) {
742 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_CONNECTION
;
745 // Port Enabled/Disabled Change
747 if ((RHPortStatus
& USBPORTSC_PEDC
) != 0) {
748 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_ENABLE
;
755 Sets a feature for the specified root hub port.
757 @param PeiServices The pointer of EFI_PEI_SERVICES
758 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI
759 @param PortNumber Root hub port to set.
760 @param PortFeature Feature to set.
762 @retval EFI_SUCCESS The feature specified by PortFeature was set.
763 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
764 @retval EFI_TIMEOUT The time out occurred.
769 UhcSetRootHubPortFeature (
770 IN EFI_PEI_SERVICES
**PeiServices
,
771 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
773 IN EFI_USB_PORT_FEATURE PortFeature
778 UINT32 CommandRegAddr
;
779 UINT16 RHPortControl
;
780 UINT8 TotalPortNumber
;
782 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
783 if (PortNumber
> TotalPortNumber
) {
784 return EFI_INVALID_PARAMETER
;
787 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
788 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
789 CommandRegAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
791 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
793 switch (PortFeature
) {
795 case EfiUsbPortSuspend
:
796 if ((USBReadPortW (UhcDev
, CommandRegAddr
) & USBCMD_EGSM
) == 0) {
798 // if global suspend is not active, can set port suspend
800 RHPortControl
&= 0xfff5;
801 RHPortControl
|= USBPORTSC_SUSP
;
805 case EfiUsbPortReset
:
806 RHPortControl
&= 0xfff5;
807 RHPortControl
|= USBPORTSC_PR
;
813 case EfiUsbPortPower
:
816 case EfiUsbPortEnable
:
817 RHPortControl
&= 0xfff5;
818 RHPortControl
|= USBPORTSC_PED
;
822 return EFI_INVALID_PARAMETER
;
825 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
831 Clears a feature for the specified root hub port.
833 @param PeiServices The pointer of EFI_PEI_SERVICES.
834 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
835 @param PortNumber Specifies the root hub port whose feature
836 is requested to be cleared.
837 @param PortFeature Indicates the feature selector associated with the
838 feature clear request.
840 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
841 for the USB root hub port specified by PortNumber.
842 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
847 UhcClearRootHubPortFeature (
848 IN EFI_PEI_SERVICES
**PeiServices
,
849 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
851 IN EFI_USB_PORT_FEATURE PortFeature
856 UINT16 RHPortControl
;
857 UINT8 TotalPortNumber
;
859 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
861 if (PortNumber
> TotalPortNumber
) {
862 return EFI_INVALID_PARAMETER
;
865 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
866 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
868 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
870 switch (PortFeature
) {
872 // clear PORT_ENABLE feature means disable port.
874 case EfiUsbPortEnable
:
875 RHPortControl
&= 0xfff5;
876 RHPortControl
&= ~USBPORTSC_PED
;
880 // clear PORT_SUSPEND feature means resume the port.
881 // (cause a resume on the specified port if in suspend mode)
883 case EfiUsbPortSuspend
:
884 RHPortControl
&= 0xfff5;
885 RHPortControl
&= ~USBPORTSC_SUSP
;
891 case EfiUsbPortPower
:
895 // clear PORT_RESET means clear the reset signal.
897 case EfiUsbPortReset
:
898 RHPortControl
&= 0xfff5;
899 RHPortControl
&= ~USBPORTSC_PR
;
903 // clear connect status change
905 case EfiUsbPortConnectChange
:
906 RHPortControl
&= 0xfff5;
907 RHPortControl
|= USBPORTSC_CSC
;
911 // clear enable/disable status change
913 case EfiUsbPortEnableChange
:
914 RHPortControl
&= 0xfff5;
915 RHPortControl
|= USBPORTSC_PEDC
;
919 // root hub does not support this request
921 case EfiUsbPortSuspendChange
:
925 // root hub does not support this request
927 case EfiUsbPortOverCurrentChange
:
931 // root hub does not support this request
933 case EfiUsbPortResetChange
:
937 return EFI_INVALID_PARAMETER
;
940 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
948 @param UhcDev UHCI Device.
950 @retval EFI_SUCCESS UHCI successfully initialized.
951 @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.
956 IN USB_UHC_DEV
*UhcDev
960 UINT32 FrameListBaseAddrReg
;
965 // Create and Initialize Frame List For the Host Controller.
967 Status
= CreateFrameList (UhcDev
);
968 if (EFI_ERROR (Status
)) {
972 FrameListBaseAddrReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBFLBASEADD
;
973 CommandReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
976 // Set Frame List Base Address to the specific register to inform the hardware.
978 SetFrameListBaseAddress (UhcDev
, FrameListBaseAddrReg
, (UINT32
) (UINTN
) (UhcDev
->FrameListEntry
));
980 Command
= USBReadPortW (UhcDev
, CommandReg
);
981 Command
|= USBCMD_GRESET
;
982 USBWritePortW (UhcDev
, CommandReg
, Command
);
984 MicroSecondDelay (50 * 1000);
987 Command
&= ~USBCMD_GRESET
;
989 USBWritePortW (UhcDev
, CommandReg
, Command
);
992 //UHCI spec page120 reset recovery time
994 MicroSecondDelay (20 * 1000);
997 // Set Run/Stop bit to 1.
999 Command
= USBReadPortW (UhcDev
, CommandReg
);
1000 Command
|= USBCMD_RS
| USBCMD_MAXP
;
1001 USBWritePortW (UhcDev
, CommandReg
, Command
);
1007 Create Frame List Structure.
1009 @param UhcDev UHCI device.
1011 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1012 @retval EFI_SUCCESS Success.
1021 EFI_PHYSICAL_ADDRESS FrameListBaseAddr
;
1022 FRAMELIST_ENTRY
*FrameListPtr
;
1026 // The Frame List ocupies 4K bytes,
1027 // and must be aligned on 4-Kbyte boundaries.
1029 Status
= PeiServicesAllocatePages (
1030 EfiBootServicesData
,
1035 if (Status
!= EFI_SUCCESS
) {
1036 return EFI_OUT_OF_RESOURCES
;
1040 //Create Control QH and Bulk QH and link them into Framelist Entry
1042 Status
= CreateQH(UhcDev
, &UhcDev
->ConfigQH
);
1043 if (Status
!= EFI_SUCCESS
) {
1044 return EFI_OUT_OF_RESOURCES
;
1047 Status
= CreateQH(UhcDev
, &UhcDev
->BulkQH
);
1048 if (Status
!= EFI_SUCCESS
) {
1049 return EFI_OUT_OF_RESOURCES
;
1053 //Set the corresponding QH pointer
1055 SetQHHorizontalLinkPtr(UhcDev
->ConfigQH
, UhcDev
->BulkQH
);
1056 SetQHHorizontalQHorTDSelect (UhcDev
->ConfigQH
, TRUE
);
1057 SetQHHorizontalValidorInvalid (UhcDev
->ConfigQH
, TRUE
);
1059 UhcDev
->FrameListEntry
= (FRAMELIST_ENTRY
*) ((UINTN
) FrameListBaseAddr
);
1061 FrameListPtr
= UhcDev
->FrameListEntry
;
1063 for (Index
= 0; Index
< 1024; Index
++) {
1064 FrameListPtr
->FrameListPtrTerminate
= 0;
1065 FrameListPtr
->FrameListPtr
= (UINT32
)(UINTN
)UhcDev
->ConfigQH
>> 4;
1066 FrameListPtr
->FrameListPtrQSelect
= 1;
1067 FrameListPtr
->FrameListRsvd
= 0;
1075 Read a 16bit width data from Uhc HC IO space register.
1077 @param UhcDev The UHCI device.
1078 @param Port The IO space address of the register.
1080 @retval the register content read.
1085 IN USB_UHC_DEV
*UhcDev
,
1089 return IoRead16 (Port
);
1093 Write a 16bit width data into Uhc HC IO space register.
1095 @param UhcDev The UHCI device.
1096 @param Port The IO space address of the register.
1097 @param Data The data written into the register.
1102 IN USB_UHC_DEV
*UhcDev
,
1107 IoWrite16 (Port
, Data
);
1111 Write a 32bit width data into Uhc HC IO space register.
1113 @param UhcDev The UHCI device.
1114 @param Port The IO space address of the register.
1115 @param Data The data written into the register.
1120 IN USB_UHC_DEV
*UhcDev
,
1125 IoWrite32 (Port
, Data
);
1129 Clear the content of UHCI's Status Register.
1131 @param UhcDev The UHCI device.
1132 @param StatusAddr The IO space address of the register.
1137 IN USB_UHC_DEV
*UhcDev
,
1138 IN UINT32 StatusAddr
1142 // Clear the content of UHCI's Status Register
1144 USBWritePortW (UhcDev
, StatusAddr
, 0x003F);
1148 Check whether the host controller operates well.
1150 @param UhcDev The UHCI device.
1151 @param StatusRegAddr The io address of status register.
1153 @retval TRUE Host controller is working.
1154 @retval FALSE Host controller is halted or system error.
1159 IN USB_UHC_DEV
*UhcDev
,
1160 IN UINT32 StatusRegAddr
1165 StatusValue
= USBReadPortW (UhcDev
, StatusRegAddr
);
1167 if ((StatusValue
& (USBSTS_HCPE
| USBSTS_HSE
| USBSTS_HCH
)) != 0) {
1175 Get Current Frame Number.
1177 @param UhcDev The UHCI device.
1178 @param FrameNumberAddr The address of frame list register.
1180 @retval The content of the frame list register.
1184 GetCurrentFrameNumber (
1185 IN USB_UHC_DEV
*UhcDev
,
1186 IN UINT32 FrameNumberAddr
1190 // Gets value in the USB frame number register.
1192 return (UINT16
) (USBReadPortW (UhcDev
, FrameNumberAddr
) & 0x03FF);
1196 Set Frame List Base Address.
1198 @param UhcDev The UHCI device.
1199 @param FrameListRegAddr The address of frame list register.
1200 @param Addr The address of frame list table.
1204 SetFrameListBaseAddress (
1205 IN USB_UHC_DEV
*UhcDev
,
1206 IN UINT32 FrameListRegAddr
,
1211 // Sets value in the USB Frame List Base Address register.
1213 USBWritePortDW (UhcDev
, FrameListRegAddr
, (UINT32
) (Addr
& 0xFFFFF000));
1217 Create QH and initialize.
1219 @param UhcDev The UHCI device.
1220 @param PtrQH Place to store QH_STRUCT pointer.
1222 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1223 @retval EFI_SUCCESS Success.
1228 IN USB_UHC_DEV
*UhcDev
,
1229 OUT QH_STRUCT
**PtrQH
1235 // allocate align memory for QH_STRUCT
1237 Status
= AllocateTDorQHStruct (UhcDev
, sizeof(QH_STRUCT
), (void **)PtrQH
);
1238 if (EFI_ERROR (Status
)) {
1239 return EFI_OUT_OF_RESOURCES
;
1242 // init each field of the QH_STRUCT
1244 SetQHHorizontalValidorInvalid (*PtrQH
, FALSE
);
1245 SetQHVerticalValidorInvalid (*PtrQH
, FALSE
);
1251 Set the horizontal link pointer in QH.
1253 @param PtrQH Place to store QH_STRUCT pointer.
1254 @param PtrNext Place to the next QH_STRUCT.
1258 SetQHHorizontalLinkPtr (
1259 IN QH_STRUCT
*PtrQH
,
1264 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1265 // Only the highest 28bit of the address is valid
1266 // (take 32bit address as an example).
1268 PtrQH
->QueueHead
.QHHorizontalPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1272 Get the horizontal link pointer in QH.
1274 @param PtrQH Place to store QH_STRUCT pointer.
1276 @retval The horizontal link pointer in QH.
1280 GetQHHorizontalLinkPtr (
1285 // Restore the 28bit address to 32bit address
1286 // (take 32bit address as an example)
1288 return (VOID
*) (UINTN
) ((PtrQH
->QueueHead
.QHHorizontalPtr
) << 4);
1292 Set a QH or TD horizontally to be connected with a specific QH.
1294 @param PtrQH Place to store QH_STRUCT pointer.
1295 @param IsQH Specify QH or TD is connected.
1299 SetQHHorizontalQHorTDSelect (
1300 IN QH_STRUCT
*PtrQH
,
1305 // if QH is connected, the specified bit is set,
1306 // if TD is connected, the specified bit is cleared.
1308 PtrQH
->QueueHead
.QHHorizontalQSelect
= IsQH
? 1 : 0;
1312 Set the horizontal validor bit in QH.
1314 @param PtrQH Place to store QH_STRUCT pointer.
1315 @param IsValid Specify the horizontal linker is valid or not.
1319 SetQHHorizontalValidorInvalid (
1320 IN QH_STRUCT
*PtrQH
,
1325 // Valid means the horizontal link pointer is valid,
1326 // else, it's invalid.
1328 PtrQH
->QueueHead
.QHHorizontalTerminate
= IsValid
? 0 : 1;
1332 Set the vertical link pointer in QH.
1334 @param PtrQH Place to store QH_STRUCT pointer.
1335 @param PtrNext Place to the next QH_STRUCT.
1339 SetQHVerticalLinkPtr (
1340 IN QH_STRUCT
*PtrQH
,
1345 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1346 // Only the highest 28bit of the address is valid
1347 // (take 32bit address as an example).
1349 PtrQH
->QueueHead
.QHVerticalPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1353 Set a QH or TD vertically to be connected with a specific QH.
1355 @param PtrQH Place to store QH_STRUCT pointer.
1356 @param IsQH Specify QH or TD is connected.
1360 SetQHVerticalQHorTDSelect (
1361 IN QH_STRUCT
*PtrQH
,
1366 // Set the specified bit if the Vertical Link Pointer pointing to a QH,
1367 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
1369 PtrQH
->QueueHead
.QHVerticalQSelect
= IsQH
? 1 : 0;
1373 Set the vertical validor bit in QH.
1375 @param PtrQH Place to store QH_STRUCT pointer.
1376 @param IsValid Specify the vertical linker is valid or not.
1380 SetQHVerticalValidorInvalid (
1381 IN QH_STRUCT
*PtrQH
,
1386 // If TRUE, meaning the Vertical Link Pointer field is valid,
1387 // else, the field is invalid.
1389 PtrQH
->QueueHead
.QHVerticalTerminate
= IsValid
? 0 : 1;
1393 Get the vertical validor bit in QH.
1395 @param PtrQH Place to store QH_STRUCT pointer.
1397 @retval The vertical linker is valid or not.
1401 GetQHHorizontalValidorInvalid (
1406 // If TRUE, meaning the Horizontal Link Pointer field is valid,
1407 // else, the field is invalid.
1409 return (BOOLEAN
) (!(PtrQH
->QueueHead
.QHHorizontalTerminate
));
1413 Allocate TD or QH Struct.
1415 @param UhcDev The UHCI device.
1416 @param Size The size of allocation.
1417 @param PtrStruct Place to store TD_STRUCT pointer.
1419 @return EFI_SUCCESS Allocate successfully.
1420 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1424 AllocateTDorQHStruct (
1425 IN USB_UHC_DEV
*UhcDev
,
1427 OUT VOID
**PtrStruct
1432 Status
= EFI_SUCCESS
;
1435 Status
= UhcAllocatePool (
1437 (UINT8
**) PtrStruct
,
1440 if (EFI_ERROR (Status
)) {
1444 ZeroMem (*PtrStruct
, Size
);
1452 @param UhcDev The UHCI device.
1453 @param PtrTD Place to store TD_STRUCT pointer.
1455 @return EFI_SUCCESS Allocate successfully.
1456 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1461 IN USB_UHC_DEV
*UhcDev
,
1462 OUT TD_STRUCT
**PtrTD
1467 // create memory for TD_STRUCT, and align the memory.
1469 Status
= AllocateTDorQHStruct (UhcDev
, sizeof(TD_STRUCT
), (void **)PtrTD
);
1470 if (EFI_ERROR (Status
)) {
1477 SetTDLinkPtrValidorInvalid (*PtrTD
, FALSE
);
1483 Generate Setup Stage TD.
1485 @param UhcDev The UHCI device.
1486 @param DevAddr Device address.
1487 @param Endpoint Endpoint number.
1488 @param DeviceSpeed Device Speed.
1489 @param DevRequest Device reuquest.
1490 @param RequestLen Request length.
1491 @param PtrTD TD_STRUCT generated.
1493 @return EFI_SUCCESS Generate setup stage TD successfully.
1494 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1499 IN USB_UHC_DEV
*UhcDev
,
1502 IN UINT8 DeviceSpeed
,
1503 IN UINT8
*DevRequest
,
1504 IN UINT8 RequestLen
,
1505 OUT TD_STRUCT
**PtrTD
1508 TD_STRUCT
*TdStruct
;
1511 Status
= CreateTD (UhcDev
, &TdStruct
);
1512 if (EFI_ERROR (Status
)) {
1516 SetTDLinkPtr (TdStruct
, NULL
);
1519 // Depth first fashion
1521 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1524 // initialize as the last TD in the QH context,
1525 // this field will be updated in the TD linkage process.
1527 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1530 // Disable Short Packet Detection by default
1532 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1535 // Max error counter is 3, retry 3 times when error encountered.
1537 SetTDControlErrorCounter (TdStruct
, 3);
1540 // set device speed attribute
1541 // (TRUE - Slow Device; FALSE - Full Speed Device)
1543 switch (DeviceSpeed
) {
1544 case USB_SLOW_SPEED_DEVICE
:
1545 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1548 case USB_FULL_SPEED_DEVICE
:
1549 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1553 // Non isochronous transfer TD
1555 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1558 // Interrupt On Complete bit be set to zero,
1559 // Disable IOC interrupt.
1561 SetorClearTDControlIOC (TdStruct
, FALSE
);
1564 // Set TD Active bit
1566 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1568 SetTDTokenMaxLength (TdStruct
, RequestLen
);
1570 SetTDTokenDataToggle0 (TdStruct
);
1572 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1574 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1576 SetTDTokenPacketID (TdStruct
, SETUP_PACKET_ID
);
1578 TdStruct
->PtrTDBuffer
= (UINT8
*) DevRequest
;
1579 TdStruct
->TDBufferLength
= RequestLen
;
1580 SetTDDataBuffer (TdStruct
);
1588 Generate Data Stage TD.
1590 @param UhcDev The UHCI device.
1591 @param DevAddr Device address.
1592 @param Endpoint Endpoint number.
1593 @param PtrData Data buffer.
1594 @param Len Data length.
1595 @param PktID PacketID.
1596 @param Toggle Data toggle value.
1597 @param DeviceSpeed Device Speed.
1598 @param PtrTD TD_STRUCT generated.
1600 @return EFI_SUCCESS Generate data stage TD successfully.
1601 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1606 IN USB_UHC_DEV
*UhcDev
,
1613 IN UINT8 DeviceSpeed
,
1614 OUT TD_STRUCT
**PtrTD
1617 TD_STRUCT
*TdStruct
;
1620 Status
= CreateTD (UhcDev
, &TdStruct
);
1621 if (EFI_ERROR (Status
)) {
1625 SetTDLinkPtr (TdStruct
, NULL
);
1628 // Depth first fashion
1630 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1633 // Link pointer pointing to TD struct
1635 SetTDLinkPtrQHorTDSelect (TdStruct
, FALSE
);
1638 // initialize as the last TD in the QH context,
1639 // this field will be updated in the TD linkage process.
1641 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1644 // Disable short packet detect
1646 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1648 // Max error counter is 3
1650 SetTDControlErrorCounter (TdStruct
, 3);
1653 // set device speed attribute
1654 // (TRUE - Slow Device; FALSE - Full Speed Device)
1656 switch (DeviceSpeed
) {
1657 case USB_SLOW_SPEED_DEVICE
:
1658 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1661 case USB_FULL_SPEED_DEVICE
:
1662 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1666 // Non isochronous transfer TD
1668 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1671 // Disable Interrupt On Complete
1672 // Disable IOC interrupt.
1674 SetorClearTDControlIOC (TdStruct
, FALSE
);
1679 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1681 SetTDTokenMaxLength (TdStruct
, Len
);
1684 SetTDTokenDataToggle1 (TdStruct
);
1686 SetTDTokenDataToggle0 (TdStruct
);
1689 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1691 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1693 SetTDTokenPacketID (TdStruct
, PktID
);
1695 TdStruct
->PtrTDBuffer
= (UINT8
*) PtrData
;
1696 TdStruct
->TDBufferLength
= Len
;
1697 SetTDDataBuffer (TdStruct
);
1705 Generate Status Stage TD.
1707 @param UhcDev The UHCI device.
1708 @param DevAddr Device address.
1709 @param Endpoint Endpoint number.
1710 @param PktID PacketID.
1711 @param DeviceSpeed Device Speed.
1712 @param PtrTD TD_STRUCT generated.
1714 @return EFI_SUCCESS Generate status stage TD successfully.
1715 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1720 IN USB_UHC_DEV
*UhcDev
,
1724 IN UINT8 DeviceSpeed
,
1725 OUT TD_STRUCT
**PtrTD
1728 TD_STRUCT
*PtrTDStruct
;
1731 Status
= CreateTD (UhcDev
, &PtrTDStruct
);
1732 if (EFI_ERROR (Status
)) {
1736 SetTDLinkPtr (PtrTDStruct
, NULL
);
1739 // Depth first fashion
1741 SetTDLinkPtrDepthorBreadth (PtrTDStruct
, TRUE
);
1744 // initialize as the last TD in the QH context,
1745 // this field will be updated in the TD linkage process.
1747 SetTDLinkPtrValidorInvalid (PtrTDStruct
, FALSE
);
1750 // Disable short packet detect
1752 EnableorDisableTDShortPacket (PtrTDStruct
, FALSE
);
1755 // Max error counter is 3
1757 SetTDControlErrorCounter (PtrTDStruct
, 3);
1760 // set device speed attribute
1761 // (TRUE - Slow Device; FALSE - Full Speed Device)
1763 switch (DeviceSpeed
) {
1764 case USB_SLOW_SPEED_DEVICE
:
1765 SetTDLoworFullSpeedDevice (PtrTDStruct
, TRUE
);
1768 case USB_FULL_SPEED_DEVICE
:
1769 SetTDLoworFullSpeedDevice (PtrTDStruct
, FALSE
);
1773 // Non isochronous transfer TD
1775 SetTDControlIsochronousorNot (PtrTDStruct
, FALSE
);
1778 // Disable Interrupt On Complete
1779 // Disable IOC interrupt.
1781 SetorClearTDControlIOC (PtrTDStruct
, FALSE
);
1784 // Set TD Active bit
1786 SetTDStatusActiveorInactive (PtrTDStruct
, TRUE
);
1788 SetTDTokenMaxLength (PtrTDStruct
, 0);
1790 SetTDTokenDataToggle1 (PtrTDStruct
);
1792 SetTDTokenEndPoint (PtrTDStruct
, Endpoint
);
1794 SetTDTokenDeviceAddress (PtrTDStruct
, DevAddr
);
1796 SetTDTokenPacketID (PtrTDStruct
, PktID
);
1798 PtrTDStruct
->PtrTDBuffer
= NULL
;
1799 PtrTDStruct
->TDBufferLength
= 0;
1800 SetTDDataBuffer (PtrTDStruct
);
1802 *PtrTD
= PtrTDStruct
;
1808 Set the link pointer validor bit in TD.
1810 @param PtrTDStruct Place to store TD_STRUCT pointer.
1811 @param IsValid Specify the linker pointer is valid or not.
1815 SetTDLinkPtrValidorInvalid (
1816 IN TD_STRUCT
*PtrTDStruct
,
1821 // Valid means the link pointer is valid,
1822 // else, it's invalid.
1824 PtrTDStruct
->TDData
.TDLinkPtrTerminate
= (IsValid
? 0 : 1);
1828 Set the Link Pointer pointing to a QH or TD.
1830 @param PtrTDStruct Place to store TD_STRUCT pointer.
1831 @param IsQH Specify QH or TD is connected.
1835 SetTDLinkPtrQHorTDSelect (
1836 IN TD_STRUCT
*PtrTDStruct
,
1841 // Indicate whether the Link Pointer pointing to a QH or TD
1843 PtrTDStruct
->TDData
.TDLinkPtrQSelect
= (IsQH
? 1 : 0);
1847 Set the traverse is depth-first or breadth-first.
1849 @param PtrTDStruct Place to store TD_STRUCT pointer.
1850 @param IsDepth Specify the traverse is depth-first or breadth-first.
1854 SetTDLinkPtrDepthorBreadth (
1855 IN TD_STRUCT
*PtrTDStruct
,
1860 // If TRUE, indicating the host controller should process in depth first fashion,
1861 // else, the host controller should process in breadth first fashion
1863 PtrTDStruct
->TDData
.TDLinkPtrDepthSelect
= (IsDepth
? 1 : 0);
1867 Set TD Link Pointer in TD.
1869 @param PtrTDStruct Place to store TD_STRUCT pointer.
1870 @param PtrNext Place to the next TD_STRUCT.
1875 IN TD_STRUCT
*PtrTDStruct
,
1880 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
1881 // only the highest 28 bits are valid. (if take 32bit address as an example)
1883 PtrTDStruct
->TDData
.TDLinkPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1887 Get TD Link Pointer.
1889 @param PtrTDStruct Place to store TD_STRUCT pointer.
1891 @retval Get TD Link Pointer in TD.
1896 IN TD_STRUCT
*PtrTDStruct
1900 // Get TD Link Pointer. Restore it back to 32bit
1901 // (if take 32bit address as an example)
1903 return (VOID
*) (UINTN
) ((PtrTDStruct
->TDData
.TDLinkPtr
) << 4);
1907 Get the information about whether the Link Pointer field pointing to
1910 @param PtrTDStruct Place to store TD_STRUCT pointer.
1912 @retval whether the Link Pointer field pointing to a QH or a TD.
1917 IN TD_STRUCT
*PtrTDStruct
1921 // Get the information about whether the Link Pointer field pointing to
1924 return (BOOLEAN
) (PtrTDStruct
->TDData
.TDLinkPtrQSelect
);
1928 Enable/Disable short packet detection mechanism.
1930 @param PtrTDStruct Place to store TD_STRUCT pointer.
1931 @param IsEnable Enable or disable short packet detection mechanism.
1935 EnableorDisableTDShortPacket (
1936 IN TD_STRUCT
*PtrTDStruct
,
1941 // TRUE means enable short packet detection mechanism.
1943 PtrTDStruct
->TDData
.TDStatusSPD
= (IsEnable
? 1 : 0);
1947 Set the max error counter in TD.
1949 @param PtrTDStruct Place to store TD_STRUCT pointer.
1950 @param MaxErrors The number of allowable error.
1954 SetTDControlErrorCounter (
1955 IN TD_STRUCT
*PtrTDStruct
,
1960 // valid value of MaxErrors is 0,1,2,3
1962 if (MaxErrors
> 3) {
1966 PtrTDStruct
->TDData
.TDStatusErr
= MaxErrors
;
1970 Set the TD is targeting a low-speed device or not.
1972 @param PtrTDStruct Place to store TD_STRUCT pointer.
1973 @param IsLowSpeedDevice Whether The device is low-speed.
1977 SetTDLoworFullSpeedDevice (
1978 IN TD_STRUCT
*PtrTDStruct
,
1979 IN BOOLEAN IsLowSpeedDevice
1983 // TRUE means the TD is targeting at a Low-speed device
1985 PtrTDStruct
->TDData
.TDStatusLS
= (IsLowSpeedDevice
? 1 : 0);
1989 Set the TD is isochronous transfer type or not.
1991 @param PtrTDStruct Place to store TD_STRUCT pointer.
1992 @param IsIsochronous Whether the transaction isochronous transfer type.
1996 SetTDControlIsochronousorNot (
1997 IN TD_STRUCT
*PtrTDStruct
,
1998 IN BOOLEAN IsIsochronous
2002 // TRUE means the TD belongs to Isochronous transfer type.
2004 PtrTDStruct
->TDData
.TDStatusIOS
= (IsIsochronous
? 1 : 0);
2008 Set if UCHI should issue an interrupt on completion of the frame
2009 in which this TD is executed
2011 @param PtrTDStruct Place to store TD_STRUCT pointer.
2012 @param IsSet Whether HC should issue an interrupt on completion.
2016 SetorClearTDControlIOC (
2017 IN TD_STRUCT
*PtrTDStruct
,
2022 // If this bit is set, it indicates that the host controller should issue
2023 // an interrupt on completion of the frame in which this TD is executed.
2025 PtrTDStruct
->TDData
.TDStatusIOC
= IsSet
? 1 : 0;
2029 Set if the TD is active and can be executed.
2031 @param PtrTDStruct Place to store TD_STRUCT pointer.
2032 @param IsActive Whether the TD is active and can be executed.
2036 SetTDStatusActiveorInactive (
2037 IN TD_STRUCT
*PtrTDStruct
,
2042 // If this bit is set, it indicates that the TD is active and can be
2046 PtrTDStruct
->TDData
.TDStatus
|= 0x80;
2048 PtrTDStruct
->TDData
.TDStatus
&= 0x7F;
2053 Specifies the maximum number of data bytes allowed for the transfer.
2055 @param PtrTDStruct Place to store TD_STRUCT pointer.
2056 @param MaxLen The maximum number of data bytes allowed.
2058 @retval The allowed maximum number of data.
2061 SetTDTokenMaxLength (
2062 IN TD_STRUCT
*PtrTDStruct
,
2067 // Specifies the maximum number of data bytes allowed for the transfer.
2068 // the legal value extent is 0 ~ 0x500.
2070 if (MaxLen
> 0x500) {
2074 PtrTDStruct
->TDData
.TDTokenMaxLen
= MaxLen
- 1;
2080 Set the data toggle bit to DATA1.
2082 @param PtrTDStruct Place to store TD_STRUCT pointer.
2086 SetTDTokenDataToggle1 (
2087 IN TD_STRUCT
*PtrTDStruct
2091 // Set the data toggle bit to DATA1
2093 PtrTDStruct
->TDData
.TDTokenDataToggle
= 1;
2097 Set the data toggle bit to DATA0.
2099 @param PtrTDStruct Place to store TD_STRUCT pointer.
2103 SetTDTokenDataToggle0 (
2104 IN TD_STRUCT
*PtrTDStruct
2108 // Set the data toggle bit to DATA0
2110 PtrTDStruct
->TDData
.TDTokenDataToggle
= 0;
2114 Set EndPoint Number the TD is targeting at.
2116 @param PtrTDStruct Place to store TD_STRUCT pointer.
2117 @param EndPoint The Endport number of the target.
2121 SetTDTokenEndPoint (
2122 IN TD_STRUCT
*PtrTDStruct
,
2127 // Set EndPoint Number the TD is targeting at.
2129 PtrTDStruct
->TDData
.TDTokenEndPt
= (UINT8
) EndPoint
;
2133 Set Device Address the TD is targeting at.
2135 @param PtrTDStruct Place to store TD_STRUCT pointer.
2136 @param DevAddr The Device Address of the target.
2140 SetTDTokenDeviceAddress (
2141 IN TD_STRUCT
*PtrTDStruct
,
2146 // Set Device Address the TD is targeting at.
2148 PtrTDStruct
->TDData
.TDTokenDevAddr
= (UINT8
) DevAddr
;
2152 Set Packet Identification the TD is targeting at.
2154 @param PtrTDStruct Place to store TD_STRUCT pointer.
2155 @param PacketID The Packet Identification of the target.
2159 SetTDTokenPacketID (
2160 IN TD_STRUCT
*PtrTDStruct
,
2165 // Set the Packet Identification to be used for this transaction.
2167 PtrTDStruct
->TDData
.TDTokenPID
= PacketID
;
2171 Set the beginning address of the data buffer that will be used
2172 during the transaction.
2174 @param PtrTDStruct Place to store TD_STRUCT pointer.
2179 IN TD_STRUCT
*PtrTDStruct
2183 // Set the beginning address of the data buffer that will be used
2184 // during the transaction.
2186 PtrTDStruct
->TDData
.TDBufferPtr
= (UINT32
) (UINTN
) (PtrTDStruct
->PtrTDBuffer
);
2190 Detect whether the TD is active.
2192 @param PtrTDStruct Place to store TD_STRUCT pointer.
2194 @retval The TD is active or not.
2199 IN TD_STRUCT
*PtrTDStruct
2205 // Detect whether the TD is active.
2207 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2208 return (BOOLEAN
) (TDStatus
& 0x80);
2212 Detect whether the TD is stalled.
2214 @param PtrTDStruct Place to store TD_STRUCT pointer.
2216 @retval The TD is stalled or not.
2221 IN TD_STRUCT
*PtrTDStruct
2227 // Detect whether the device/endpoint addressed by this TD is stalled.
2229 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2230 return (BOOLEAN
) (TDStatus
& 0x40);
2234 Detect whether Data Buffer Error is happened.
2236 @param PtrTDStruct Place to store TD_STRUCT pointer.
2238 @retval The Data Buffer Error is happened or not.
2242 IsTDStatusBufferError (
2243 IN TD_STRUCT
*PtrTDStruct
2249 // Detect whether Data Buffer Error is happened.
2251 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2252 return (BOOLEAN
) (TDStatus
& 0x20);
2256 Detect whether Babble Error is happened.
2258 @param PtrTDStruct Place to store TD_STRUCT pointer.
2260 @retval The Babble Error is happened or not.
2264 IsTDStatusBabbleError (
2265 IN TD_STRUCT
*PtrTDStruct
2271 // Detect whether Babble Error is happened.
2273 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2274 return (BOOLEAN
) (TDStatus
& 0x10);
2278 Detect whether NAK is received.
2280 @param PtrTDStruct Place to store TD_STRUCT pointer.
2282 @retval The NAK is received or not.
2286 IsTDStatusNAKReceived (
2287 IN TD_STRUCT
*PtrTDStruct
2293 // Detect whether NAK is received.
2295 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2296 return (BOOLEAN
) (TDStatus
& 0x08);
2300 Detect whether CRC/Time Out Error is encountered.
2302 @param PtrTDStruct Place to store TD_STRUCT pointer.
2304 @retval The CRC/Time Out Error is encountered or not.
2308 IsTDStatusCRCTimeOutError (
2309 IN TD_STRUCT
*PtrTDStruct
2315 // Detect whether CRC/Time Out Error is encountered.
2317 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2318 return (BOOLEAN
) (TDStatus
& 0x04);
2322 Detect whether Bitstuff Error is received.
2324 @param PtrTDStruct Place to store TD_STRUCT pointer.
2326 @retval The Bitstuff Error is received or not.
2330 IsTDStatusBitStuffError (
2331 IN TD_STRUCT
*PtrTDStruct
2337 // Detect whether Bitstuff Error is received.
2339 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2340 return (BOOLEAN
) (TDStatus
& 0x02);
2344 Retrieve the actual number of bytes that were tansferred.
2346 @param PtrTDStruct Place to store TD_STRUCT pointer.
2348 @retval The actual number of bytes that were tansferred.
2352 GetTDStatusActualLength (
2353 IN TD_STRUCT
*PtrTDStruct
2357 // Retrieve the actual number of bytes that were tansferred.
2358 // the value is encoded as n-1. so return the decoded value.
2360 return (UINT16
) ((PtrTDStruct
->TDData
.TDStatusActualLength
) + 1);
2364 Retrieve the information of whether the Link Pointer field is valid or not.
2366 @param PtrTDStruct Place to store TD_STRUCT pointer.
2368 @retval The linker pointer field is valid or not.
2372 GetTDLinkPtrValidorInvalid (
2373 IN TD_STRUCT
*PtrTDStruct
2377 // Retrieve the information of whether the Link Pointer field
2380 if ((PtrTDStruct
->TDData
.TDLinkPtrTerminate
& BIT0
) != 0) {
2389 Count TD Number from PtrFirstTD.
2391 @param PtrFirstTD Place to store TD_STRUCT pointer.
2393 @retval The queued TDs number.
2398 IN TD_STRUCT
*PtrFirstTD
2405 // Count the queued TDs number.
2410 Ptr
= (TD_STRUCT
*) Ptr
->PtrNextTD
;
2420 @param PtrQH Place to store QH_STRUCT pointer.
2421 @param PtrTD Place to store TD_STRUCT pointer.
2426 IN QH_STRUCT
*PtrQH
,
2430 if (PtrQH
== NULL
|| PtrTD
== NULL
) {
2434 // Validate QH Vertical Ptr field
2436 SetQHVerticalValidorInvalid (PtrQH
, TRUE
);
2439 // Vertical Ptr pointing to TD structure
2441 SetQHVerticalQHorTDSelect (PtrQH
, FALSE
);
2443 SetQHVerticalLinkPtr (PtrQH
, (VOID
*) PtrTD
);
2445 PtrQH
->PtrDown
= (VOID
*) PtrTD
;
2451 @param PtrPreTD Place to store TD_STRUCT pointer.
2452 @param PtrTD Place to store TD_STRUCT pointer.
2457 IN TD_STRUCT
*PtrPreTD
,
2461 if (PtrPreTD
== NULL
|| PtrTD
== NULL
) {
2465 // Depth first fashion
2467 SetTDLinkPtrDepthorBreadth (PtrPreTD
, TRUE
);
2470 // Link pointer pointing to TD struct
2472 SetTDLinkPtrQHorTDSelect (PtrPreTD
, FALSE
);
2475 // Validate the link pointer valid bit
2477 SetTDLinkPtrValidorInvalid (PtrPreTD
, TRUE
);
2479 SetTDLinkPtr (PtrPreTD
, PtrTD
);
2481 PtrPreTD
->PtrNextTD
= (VOID
*) PtrTD
;
2483 PtrTD
->PtrNextTD
= NULL
;
2487 Execute Control Transfer.
2489 @param UhcDev The UCHI device.
2490 @param PtrTD A pointer to TD_STRUCT data.
2491 @param ActualLen Actual transfer Length.
2492 @param TimeOut TimeOut value.
2493 @param TransferResult Transfer Result.
2495 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2496 @return EFI_TIMEOUT The transfer failed due to time out.
2497 @return EFI_SUCCESS The transfer finished OK.
2501 ExecuteControlTransfer (
2502 IN USB_UHC_DEV
*UhcDev
,
2503 IN TD_STRUCT
*PtrTD
,
2504 OUT UINTN
*ActualLen
,
2506 OUT UINT32
*TransferResult
2513 *TransferResult
= EFI_USB_NOERROR
;
2516 Delay
= (TimeOut
* STALL_1_MILLI_SECOND
/ 200) + 1;
2520 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2523 // TD is inactive, means the control transfer is end.
2525 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2528 MicroSecondDelay (200);
2531 } while (Delay
!= 0);
2534 if (*TransferResult
!= EFI_USB_NOERROR
) {
2535 return EFI_DEVICE_ERROR
;
2542 Execute Bulk Transfer.
2544 @param UhcDev The UCHI device.
2545 @param PtrTD A pointer to TD_STRUCT data.
2546 @param ActualLen Actual transfer Length.
2547 @param DataToggle DataToggle value.
2548 @param TimeOut TimeOut value.
2549 @param TransferResult Transfer Result.
2551 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2552 @return EFI_TIMEOUT The transfer failed due to time out.
2553 @return EFI_SUCCESS The transfer finished OK.
2558 IN USB_UHC_DEV
*UhcDev
,
2559 IN TD_STRUCT
*PtrTD
,
2560 IN OUT UINTN
*ActualLen
,
2561 IN UINT8
*DataToggle
,
2563 OUT UINT32
*TransferResult
2571 *TransferResult
= EFI_USB_NOERROR
;
2574 Delay
= (TimeOut
* STALL_1_MILLI_SECOND
/ 200) + 1;
2578 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2580 // TD is inactive, thus meaning bulk transfer's end.
2582 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2585 MicroSecondDelay (200);
2588 } while (Delay
!= 0);
2593 if (*TransferResult
!= EFI_USB_NOERROR
) {
2595 // scroll the Data Toggle back to the last success TD
2597 ScrollNum
= CountTDsNumber (PtrTD
) - ErrTDPos
;
2598 if ((ScrollNum
% 2) != 0) {
2603 // If error, wait 100ms to retry by upper layer
2605 MicroSecondDelay (100 * 1000);
2606 return EFI_DEVICE_ERROR
;
2615 @param UhcDev The UCHI device.
2616 @param PtrFirstTD Place to store TD_STRUCT pointer.
2621 IN USB_UHC_DEV
*UhcDev
,
2622 IN TD_STRUCT
*PtrFirstTD
2631 // Delete all the TDs in a queue.
2633 while (Tptr1
!= NULL
) {
2637 if (!GetTDLinkPtrValidorInvalid (Tptr2
)) {
2641 // has more than one TD in the queue.
2643 Tptr1
= GetTDLinkPtr (Tptr2
);
2646 UhcFreePool (UhcDev
, (UINT8
*) Tptr2
, sizeof (TD_STRUCT
));
2655 @param PtrTD A pointer to TD_STRUCT data.
2656 @param Result The result to return.
2657 @param ErrTDPos The Error TD position.
2658 @param ActualTransferSize Actual transfer size.
2660 @retval The TD is executed successfully or not.
2665 IN TD_STRUCT
*PtrTD
,
2667 OUT UINTN
*ErrTDPos
,
2668 OUT UINTN
*ActualTransferSize
2673 *Result
= EFI_USB_NOERROR
;
2679 *ActualTransferSize
= 0;
2681 while (PtrTD
!= NULL
) {
2683 if (IsTDStatusActive (PtrTD
)) {
2684 *Result
|= EFI_USB_ERR_NOTEXECUTE
;
2687 if (IsTDStatusStalled (PtrTD
)) {
2688 *Result
|= EFI_USB_ERR_STALL
;
2691 if (IsTDStatusBufferError (PtrTD
)) {
2692 *Result
|= EFI_USB_ERR_BUFFER
;
2695 if (IsTDStatusBabbleError (PtrTD
)) {
2696 *Result
|= EFI_USB_ERR_BABBLE
;
2699 if (IsTDStatusNAKReceived (PtrTD
)) {
2700 *Result
|= EFI_USB_ERR_NAK
;
2703 if (IsTDStatusCRCTimeOutError (PtrTD
)) {
2704 *Result
|= EFI_USB_ERR_TIMEOUT
;
2707 if (IsTDStatusBitStuffError (PtrTD
)) {
2708 *Result
|= EFI_USB_ERR_BITSTUFF
;
2711 // Accumulate actual transferred data length in each TD.
2713 Len
= GetTDStatusActualLength (PtrTD
) & 0x7FF;
2714 *ActualTransferSize
+= Len
;
2717 // if any error encountered, stop processing the left TDs.
2719 if ((*Result
) != 0) {
2723 PtrTD
= (TD_STRUCT
*) (PtrTD
->PtrNextTD
);
2725 // Record the first Error TD's position in the queue,
2726 // this value is zero-based.
2735 Create Memory Block.
2737 @param UhcDev The UCHI device.
2738 @param MemoryHeader The Pointer to allocated memory block.
2739 @param MemoryBlockSizeInPages The page size of memory block to be allocated.
2741 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2742 @retval EFI_SUCCESS Success.
2747 IN USB_UHC_DEV
*UhcDev
,
2748 OUT MEMORY_MANAGE_HEADER
**MemoryHeader
,
2749 IN UINTN MemoryBlockSizeInPages
2753 EFI_PHYSICAL_ADDRESS TempPtr
;
2758 // Memory Block uses MemoryBlockSizeInPages pages,
2759 // memory management header and bit array use 1 page
2761 MemPages
= MemoryBlockSizeInPages
+ 1;
2762 Status
= PeiServicesAllocatePages (
2763 EfiBootServicesData
,
2767 if (EFI_ERROR (Status
)) {
2771 Ptr
= (UINT8
*) ((UINTN
) TempPtr
);
2773 ZeroMem (Ptr
, MemPages
* EFI_PAGE_SIZE
);
2775 *MemoryHeader
= (MEMORY_MANAGE_HEADER
*) Ptr
;
2777 // adjust Ptr pointer to the next empty memory
2779 Ptr
+= sizeof (MEMORY_MANAGE_HEADER
);
2781 // Set Bit Array initial address
2783 (*MemoryHeader
)->BitArrayPtr
= Ptr
;
2785 (*MemoryHeader
)->Next
= NULL
;
2788 // Memory block initial address
2790 Ptr
= (UINT8
*) ((UINTN
) TempPtr
);
2791 Ptr
+= EFI_PAGE_SIZE
;
2792 (*MemoryHeader
)->MemoryBlockPtr
= Ptr
;
2794 // set Memory block size
2796 (*MemoryHeader
)->MemoryBlockSizeInBytes
= MemoryBlockSizeInPages
* EFI_PAGE_SIZE
;
2798 // each bit in Bit Array will manage 32byte memory in memory block
2800 (*MemoryHeader
)->BitArraySizeInBytes
= ((*MemoryHeader
)->MemoryBlockSizeInBytes
/ 32) / 8;
2806 Initialize UHCI memory management.
2808 @param UhcDev The UCHI device.
2810 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2811 @retval EFI_SUCCESS Success.
2815 InitializeMemoryManagement (
2816 IN USB_UHC_DEV
*UhcDev
2819 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2823 MemPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2824 Status
= CreateMemoryBlock (UhcDev
, &MemoryHeader
, MemPages
);
2825 if (EFI_ERROR (Status
)) {
2829 UhcDev
->Header1
= MemoryHeader
;
2835 Initialize UHCI memory management.
2837 @param UhcDev The UCHI device.
2838 @param Pool Buffer pointer to store the buffer pointer.
2839 @param AllocSize The size of the pool to be allocated.
2841 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2842 @retval EFI_SUCCESS Success.
2847 IN USB_UHC_DEV
*UhcDev
,
2852 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2853 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
2854 MEMORY_MANAGE_HEADER
*NewMemoryHeader
;
2855 UINTN RealAllocSize
;
2856 UINTN MemoryBlockSizeInPages
;
2861 MemoryHeader
= UhcDev
->Header1
;
2864 // allocate unit is 32 byte (align on 32 byte)
2866 if ((AllocSize
& 0x1F) != 0) {
2867 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
2869 RealAllocSize
= AllocSize
;
2872 Status
= EFI_NOT_FOUND
;
2873 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
2875 Status
= AllocMemInMemoryBlock (
2880 if (!EFI_ERROR (Status
)) {
2885 // There is no enough memory,
2886 // Create a new Memory Block
2889 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
2890 // just allocate a large enough memory block.
2892 if (RealAllocSize
> (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
* EFI_PAGE_SIZE
)) {
2893 MemoryBlockSizeInPages
= RealAllocSize
/ EFI_PAGE_SIZE
+ 1;
2895 MemoryBlockSizeInPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2898 Status
= CreateMemoryBlock (UhcDev
, &NewMemoryHeader
, MemoryBlockSizeInPages
);
2899 if (EFI_ERROR (Status
)) {
2903 // Link the new Memory Block to the Memory Header list
2905 InsertMemoryHeaderToList (MemoryHeader
, NewMemoryHeader
);
2907 Status
= AllocMemInMemoryBlock (
2916 Alloc Memory In MemoryBlock.
2918 @param MemoryHeader The pointer to memory manage header.
2919 @param Pool Buffer pointer to store the buffer pointer.
2920 @param NumberOfMemoryUnit The size of the pool to be allocated.
2922 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2923 @retval EFI_SUCCESS Success.
2927 AllocMemInMemoryBlock (
2928 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
2930 IN UINTN NumberOfMemoryUnit
2939 UINTN NumberOfZeros
;
2945 ByteValue
= MemoryHeader
->BitArrayPtr
[0];
2948 for (TempBytePos
= 0; TempBytePos
< MemoryHeader
->BitArraySizeInBytes
;) {
2950 // Pop out BitValue from a byte in TempBytePos.
2952 BitValue
= (UINT8
)(ByteValue
& 0x1);
2954 if (BitValue
== 0) {
2956 // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
2960 // Found enough consecutive free space, break the loop
2962 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2967 // Encountering a '1', meant the bit is ocupied.
2969 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2971 // Found enough consecutive free space,break the loop
2976 // the NumberOfZeros only record the number of those consecutive zeros,
2977 // so reset the NumberOfZeros to 0 when encountering '1' before finding
2978 // enough consecutive '0's
2982 // reset the (FoundBytePos,FoundBitPos) to the position of '1'
2984 FoundBytePos
= TempBytePos
;
2985 FoundBitPos
= Index
;
2989 // right shift the byte
2994 // step forward a bit
2999 // step forward a byte, getting the byte value,
3000 // and reset the bit pos.
3003 ByteValue
= MemoryHeader
->BitArrayPtr
[TempBytePos
];
3008 if (NumberOfZeros
< NumberOfMemoryUnit
) {
3009 return EFI_NOT_FOUND
;
3012 // Found enough free space.
3015 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
3016 // 1)(FoundBytePos,FoundBitPos) record the position
3017 // of the last '1' before the consecutive '0's, it must
3018 // be adjusted to the start position of the consecutive '0's.
3019 // 2)the start address of the consecutive '0's is just the start of
3020 // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
3022 if ((MemoryHeader
->BitArrayPtr
[0] & BIT0
) != 0) {
3026 // Have the (FoundBytePos,FoundBitPos) make sense.
3028 if (FoundBitPos
> 7) {
3033 // Set the memory as allocated
3035 for (TempBytePos
= FoundBytePos
, Index
= FoundBitPos
, Count
= 0; Count
< NumberOfMemoryUnit
; Count
++) {
3037 MemoryHeader
->BitArrayPtr
[TempBytePos
] = (UINT8
) (MemoryHeader
->BitArrayPtr
[TempBytePos
] | (1 << Index
));
3045 *Pool
= MemoryHeader
->MemoryBlockPtr
+ (FoundBytePos
* 8 + FoundBitPos
) * 32;
3053 @param UhcDev The UHCI device.
3054 @param Pool A pointer to store the buffer address.
3055 @param AllocSize The size of the pool to be freed.
3060 IN USB_UHC_DEV
*UhcDev
,
3065 MEMORY_MANAGE_HEADER
*MemoryHeader
;
3066 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3072 UINTN RealAllocSize
;
3074 MemoryHeader
= UhcDev
->Header1
;
3077 // allocate unit is 32 byte (align on 32 byte)
3079 if ((AllocSize
& 0x1F) != 0) {
3080 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
3082 RealAllocSize
= AllocSize
;
3085 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
;
3086 TempHeaderPtr
= TempHeaderPtr
->Next
) {
3088 if ((Pool
>= TempHeaderPtr
->MemoryBlockPtr
) &&
3089 ((Pool
+ RealAllocSize
) <= (TempHeaderPtr
->MemoryBlockPtr
+
3090 TempHeaderPtr
->MemoryBlockSizeInBytes
))) {
3093 // Pool is in the Memory Block area,
3094 // find the start byte and bit in the bit array
3096 StartBytePos
= ((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) / 8;
3097 StartBitPos
= (UINT8
) (((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) % 8);
3100 // reset associated bits in bit arry
3102 for (Index
= StartBytePos
, Index2
= StartBitPos
, Count
= 0; Count
< (RealAllocSize
/ 32); Count
++) {
3104 TempHeaderPtr
->BitArrayPtr
[Index
] = (UINT8
) (TempHeaderPtr
->BitArrayPtr
[Index
] ^ (1 << Index2
));
3121 Insert a new memory header into list.
3123 @param MemoryHeader A pointer to the memory header list.
3124 @param NewMemoryHeader A new memory header to be inserted into the list.
3128 InsertMemoryHeaderToList (
3129 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
3130 IN MEMORY_MANAGE_HEADER
*NewMemoryHeader
3133 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3135 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
3136 if (TempHeaderPtr
->Next
== NULL
) {
3137 TempHeaderPtr
->Next
= NewMemoryHeader
;
3144 Judge the memory block in the memory header is empty or not.
3146 @param MemoryHeaderPtr A pointer to the memory header list.
3148 @retval Whether the memory block in the memory header is empty or not.
3152 IsMemoryBlockEmptied (
3153 IN MEMORY_MANAGE_HEADER
*MemoryHeaderPtr
3158 for (Index
= 0; Index
< MemoryHeaderPtr
->BitArraySizeInBytes
; Index
++) {
3159 if (MemoryHeaderPtr
->BitArrayPtr
[Index
] != 0) {
3168 remove a memory header from list.
3170 @param FirstMemoryHeader A pointer to the memory header list.
3171 @param FreeMemoryHeader A memory header to be removed into the list.
3176 IN MEMORY_MANAGE_HEADER
*FirstMemoryHeader
,
3177 IN MEMORY_MANAGE_HEADER
*FreeMemoryHeader
3180 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3182 if ((FirstMemoryHeader
== NULL
) || (FreeMemoryHeader
== NULL
)) {
3186 for (TempHeaderPtr
= FirstMemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
3188 if (TempHeaderPtr
->Next
== FreeMemoryHeader
) {
3190 // Link the before and after
3192 TempHeaderPtr
->Next
= FreeMemoryHeader
->Next
;