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 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 Stop the host controller.
23 @param Uhc The UHCI device.
24 @param Timeout Max time allowed.
26 @retval EFI_SUCCESS The host controller is stopped.
27 @retval EFI_TIMEOUT Failed to stop the host controller.
36 UINT16 CommandContent
;
40 CommandContent
= USBReadPortW (Uhc
, Uhc
->UsbHostControllerBaseAddress
+ USBCMD
);
41 CommandContent
&= USBCMD_RS
;
42 USBWritePortW (Uhc
, Uhc
->UsbHostControllerBaseAddress
+ USBCMD
, CommandContent
);
45 // ensure the HC is in halt status after send the stop command
46 // Timeout is in us unit.
48 for (Index
= 0; Index
< (Timeout
/ 50) + 1; Index
++) {
49 UsbSts
= USBReadPortW (Uhc
, Uhc
->UsbHostControllerBaseAddress
+ USBSTS
);
51 if ((UsbSts
& USBSTS_HCH
) == USBSTS_HCH
) {
55 MicroSecondDelay (50);
62 One notified function to stop the Host Controller at the end of PEI
64 @param[in] PeiServices Pointer to PEI Services Table.
65 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
66 caused this function to execute.
67 @param[in] Ppi Pointer to the PPI data associated with this function.
69 @retval EFI_SUCCESS The function completes successfully
75 IN EFI_PEI_SERVICES
**PeiServices
,
76 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
82 Uhc
= PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor
);
85 // Stop the Host Controller
87 UhciStopHc (Uhc
, 1000 * 1000);
93 Initializes Usb Host Controller.
95 @param FileHandle Handle of the file being invoked.
96 @param PeiServices Describes the list of possible PEI Services.
98 @retval EFI_SUCCESS PPI successfully installed.
99 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
105 IN EFI_PEI_FILE_HANDLE FileHandle
,
106 IN CONST EFI_PEI_SERVICES
**PeiServices
109 PEI_USB_CONTROLLER_PPI
*ChipSetUsbControllerPpi
;
112 UINTN ControllerType
;
116 EFI_PHYSICAL_ADDRESS TempPtr
;
119 // Shadow this PEIM to run from memory
121 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
125 Status
= PeiServicesLocatePpi (
126 &gPeiUsbControllerPpiGuid
,
129 (VOID
**) &ChipSetUsbControllerPpi
132 // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.
134 ASSERT_EFI_ERROR (Status
);
138 Status
= ChipSetUsbControllerPpi
->GetUsbController (
139 (EFI_PEI_SERVICES
**) PeiServices
,
140 ChipSetUsbControllerPpi
,
146 // When status is error, meant no controller is found
148 if (EFI_ERROR (Status
)) {
153 // This PEIM is for UHC type controller.
155 if (ControllerType
!= PEI_UHCI_CONTROLLER
) {
160 MemPages
= sizeof (USB_UHC_DEV
) / EFI_PAGE_SIZE
+ 1;
162 Status
= PeiServicesAllocatePages (
167 if (EFI_ERROR (Status
)) {
168 return EFI_OUT_OF_RESOURCES
;
171 UhcDev
= (USB_UHC_DEV
*) ((UINTN
) TempPtr
);
172 UhcDev
->Signature
= USB_UHC_DEV_SIGNATURE
;
173 IoMmuInit (&UhcDev
->IoMmu
);
174 UhcDev
->UsbHostControllerBaseAddress
= (UINT32
) BaseAddress
;
177 // Init local memory management service
179 Status
= InitializeMemoryManagement (UhcDev
);
180 if (EFI_ERROR (Status
)) {
185 // Initialize Uhc's hardware
187 Status
= InitializeUsbHC (UhcDev
);
188 if (EFI_ERROR (Status
)) {
192 UhcDev
->UsbHostControllerPpi
.ControlTransfer
= UhcControlTransfer
;
193 UhcDev
->UsbHostControllerPpi
.BulkTransfer
= UhcBulkTransfer
;
194 UhcDev
->UsbHostControllerPpi
.GetRootHubPortNumber
= UhcGetRootHubPortNumber
;
195 UhcDev
->UsbHostControllerPpi
.GetRootHubPortStatus
= UhcGetRootHubPortStatus
;
196 UhcDev
->UsbHostControllerPpi
.SetRootHubPortFeature
= UhcSetRootHubPortFeature
;
197 UhcDev
->UsbHostControllerPpi
.ClearRootHubPortFeature
= UhcClearRootHubPortFeature
;
199 UhcDev
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
200 UhcDev
->PpiDescriptor
.Guid
= &gPeiUsbHostControllerPpiGuid
;
201 UhcDev
->PpiDescriptor
.Ppi
= &UhcDev
->UsbHostControllerPpi
;
203 Status
= PeiServicesInstallPpi (&UhcDev
->PpiDescriptor
);
204 if (EFI_ERROR (Status
)) {
209 UhcDev
->EndOfPeiNotifyList
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
210 UhcDev
->EndOfPeiNotifyList
.Guid
= &gEfiEndOfPeiSignalPpiGuid
;
211 UhcDev
->EndOfPeiNotifyList
.Notify
= UhcEndOfPei
;
213 PeiServicesNotifyPpi (&UhcDev
->EndOfPeiNotifyList
);
222 Submits control transfer to a target USB device.
224 @param PeiServices The pointer of EFI_PEI_SERVICES.
225 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
226 @param DeviceAddress The target device address.
227 @param DeviceSpeed Target device speed.
228 @param MaximumPacketLength Maximum packet size the default control transfer
229 endpoint is capable of sending or receiving.
230 @param Request USB device request to send.
231 @param TransferDirection Specifies the data direction for the data stage.
232 @param Data Data buffer to be transmitted or received from USB device.
233 @param DataLength The size (in bytes) of the data buffer.
234 @param TimeOut Indicates the maximum timeout, in millisecond.
235 If Timeout is 0, then the caller must wait for the function
236 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
237 @param TransferResult Return the result of this control transfer.
239 @retval EFI_SUCCESS Transfer was completed successfully.
240 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
241 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
242 @retval EFI_TIMEOUT Transfer failed due to timeout.
243 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
249 IN EFI_PEI_SERVICES
**PeiServices
,
250 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
251 IN UINT8 DeviceAddress
,
252 IN UINT8 DeviceSpeed
,
253 IN UINT8 MaximumPacketLength
,
254 IN EFI_USB_DEVICE_REQUEST
*Request
,
255 IN EFI_USB_DATA_DIRECTION TransferDirection
,
256 IN OUT VOID
*Data OPTIONAL
,
257 IN OUT UINTN
*DataLength OPTIONAL
,
259 OUT UINT32
*TransferResult
268 TD_STRUCT
*PtrSetupTD
;
269 TD_STRUCT
*PtrStatusTD
;
278 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
280 StatusReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBSTS
;
282 PktID
= INPUT_PACKET_ID
;
284 if (Request
== NULL
|| TransferResult
== NULL
) {
285 return EFI_INVALID_PARAMETER
;
288 // if errors exist that cause host controller halt,
289 // then return EFI_DEVICE_ERROR.
292 if (!IsStatusOK (UhcDev
, StatusReg
)) {
293 ClearStatusReg (UhcDev
, StatusReg
);
294 *TransferResult
= EFI_USB_ERR_SYSTEM
;
295 return EFI_DEVICE_ERROR
;
298 ClearStatusReg (UhcDev
, StatusReg
);
301 // Map the Request and data for bus master access,
302 // then create a list of TD for this transfer
304 Status
= UhciMapUserRequest (UhcDev
, Request
, &RequestPhy
, &RequestMap
);
305 if (EFI_ERROR (Status
)) {
309 Status
= UhciMapUserData (UhcDev
, TransferDirection
, Data
, DataLength
, &PktID
, &DataPhy
, &DataMap
);
311 if (EFI_ERROR (Status
)) {
312 if (RequestMap
!= NULL
) {
313 IoMmuUnmap (UhcDev
->IoMmu
, RequestMap
);
319 // generate Setup Stage TD
322 PtrQH
= UhcDev
->ConfigQH
;
331 (UINT8
) sizeof (EFI_USB_DEVICE_REQUEST
),
336 // link setup TD structures to QH structure
338 LinkTDToQH (PtrQH
, PtrSetupTD
);
340 PtrPreTD
= PtrSetupTD
;
343 // Data Stage of Control Transfer
346 if (TransferDirection
== EfiUsbNoData
) {
349 DataLen
= (UINT32
) *DataLength
;
355 while (DataLen
> 0) {
357 // create TD structures and link together
362 // PacketSize is the data load size of each TD carries.
364 PacketSize
= (UINT8
) DataLen
;
365 if (DataLen
> MaximumPacketLength
) {
366 PacketSize
= MaximumPacketLength
;
383 // Link two TDs in vertical depth
385 LinkTDToTD (PtrPreTD
, PtrTD
);
389 Data
= (VOID
*) ((UINT8
*) Data
+ PacketSize
);
390 DataPhy
+= PacketSize
;
391 DataLen
-= PacketSize
;
395 // PtrPreTD points to the last TD before the Setup-Stage TD.
400 // Status Stage of Control Transfer
402 if (PktID
== OUTPUT_PACKET_ID
) {
403 PktID
= INPUT_PACKET_ID
;
405 PktID
= OUTPUT_PACKET_ID
;
408 // create Status Stage TD structure
419 LinkTDToTD (PtrPreTD
, PtrStatusTD
);
422 // Poll QH-TDs execution and get result.
423 // detail status is returned
425 Status
= ExecuteControlTransfer (
434 // TRUE means must search other framelistindex
436 SetQHVerticalValidorInvalid(PtrQH
, FALSE
);
437 DeleteQueuedTDs (UhcDev
, PtrSetupTD
);
440 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
442 if (!IsStatusOK (UhcDev
, StatusReg
)) {
443 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
444 Status
= EFI_DEVICE_ERROR
;
447 ClearStatusReg (UhcDev
, StatusReg
);
449 if (DataMap
!= NULL
) {
450 IoMmuUnmap (UhcDev
->IoMmu
, DataMap
);
452 if (RequestMap
!= NULL
) {
453 IoMmuUnmap (UhcDev
->IoMmu
, RequestMap
);
460 Submits bulk transfer to a bulk endpoint of a USB device.
462 @param PeiServices The pointer of EFI_PEI_SERVICES.
463 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
464 @param DeviceAddress Target device address.
465 @param EndPointAddress Endpoint number and its direction in bit 7.
466 @param MaximumPacketLength Maximum packet size the endpoint is capable of
467 sending or receiving.
468 @param Data Array of pointers to the buffers of data to transmit
469 from or receive into.
470 @param DataLength The lenght of the data buffer.
471 @param DataToggle On input, the initial data toggle for the transfer;
472 On output, it is updated to to next data toggle to use of
473 the subsequent bulk transfer.
474 @param TimeOut Indicates the maximum time, in millisecond, which the
475 transfer is allowed to complete.
476 If Timeout is 0, then the caller must wait for the function
477 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
478 @param TransferResult A pointer to the detailed result information of the
481 @retval EFI_SUCCESS The transfer was completed successfully.
482 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
483 @retval EFI_INVALID_PARAMETER Parameters are invalid.
484 @retval EFI_TIMEOUT The transfer failed due to timeout.
485 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
491 IN EFI_PEI_SERVICES
**PeiServices
,
492 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
493 IN UINT8 DeviceAddress
,
494 IN UINT8 EndPointAddress
,
495 IN UINT8 MaximumPacketLength
,
497 IN OUT UINTN
*DataLength
,
498 IN OUT UINT8
*DataToggle
,
500 OUT UINT32
*TransferResult
509 TD_STRUCT
*PtrFirstTD
;
519 EFI_USB_DATA_DIRECTION TransferDirection
;
521 BOOLEAN ShortPacketEnable
;
523 UINT16 CommandContent
;
528 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
531 // Enable the maximum packet size (64bytes)
532 // that can be used for full speed bandwidth reclamation
533 // at the end of a frame.
535 CommandContent
= USBReadPortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
);
536 if ((CommandContent
& USBCMD_MAXP
) != USBCMD_MAXP
) {
537 CommandContent
|= USBCMD_MAXP
;
538 USBWritePortW (UhcDev
, UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
, CommandContent
);
541 StatusReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBSTS
;
544 // these code lines are added here per complier's strict demand
546 PktID
= INPUT_PACKET_ID
;
552 ShortPacketEnable
= FALSE
;
554 if ((DataLength
== 0) || (Data
== NULL
) || (TransferResult
== NULL
)) {
555 return EFI_INVALID_PARAMETER
;
558 if ((*DataToggle
!= 1) && (*DataToggle
!= 0)) {
559 return EFI_INVALID_PARAMETER
;
562 if (MaximumPacketLength
!= 8 && MaximumPacketLength
!= 16
563 && MaximumPacketLength
!= 32 && MaximumPacketLength
!= 64) {
564 return EFI_INVALID_PARAMETER
;
567 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
569 if (!IsStatusOK (UhcDev
, StatusReg
)) {
571 ClearStatusReg (UhcDev
, StatusReg
);
572 *TransferResult
= EFI_USB_ERR_SYSTEM
;
573 return EFI_DEVICE_ERROR
;
576 ClearStatusReg (UhcDev
, StatusReg
);
579 // Map the source data buffer for bus master access,
580 // then create a list of TDs
582 if ((EndPointAddress
& 0x80) != 0) {
583 TransferDirection
= EfiUsbDataIn
;
585 TransferDirection
= EfiUsbDataOut
;
588 Status
= UhciMapUserData (UhcDev
, TransferDirection
, Data
, DataLength
, &PktID
, &DataPhy
, &DataMap
);
590 if (EFI_ERROR (Status
)) {
594 DataLen
= (UINT32
) *DataLength
;
596 PtrQH
= UhcDev
->BulkQH
;
599 while (DataLen
> 0) {
601 // create TD structures and link together
605 PacketSize
= (UINT8
) DataLen
;
606 if (DataLen
> MaximumPacketLength
) {
607 PacketSize
= MaximumPacketLength
;
619 USB_FULL_SPEED_DEVICE
,
624 // Enable short packet detection.
625 // (default action is disabling short packet detection)
627 if (ShortPacketEnable
) {
628 EnableorDisableTDShortPacket (PtrTD
, TRUE
);
633 PtrFirstTD
->PtrNextTD
= NULL
;
637 // Link two TDs in vertical depth
639 LinkTDToTD (PtrPreTD
, PtrTD
);
645 Data
= (VOID
*) ((UINT8
*) Data
+ PacketSize
);
646 DataPhy
+= PacketSize
;
647 DataLen
-= PacketSize
;
650 // link TD structures to QH structure
652 LinkTDToQH (PtrQH
, PtrFirstTD
);
655 // Execute QH-TD and get result
658 // detail status is put into the Result field in the pIRP
659 // the Data Toggle value is also re-updated to the value
660 // of the last successful TD
662 Status
= ExecBulkTransfer (
672 // Delete Bulk transfer TD structure
674 DeleteQueuedTDs (UhcDev
, PtrFirstTD
);
677 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
679 if (!IsStatusOK (UhcDev
, StatusReg
)) {
680 *TransferResult
|= EFI_USB_ERR_SYSTEM
;
681 Status
= EFI_DEVICE_ERROR
;
684 ClearStatusReg (UhcDev
, StatusReg
);
686 if (DataMap
!= NULL
) {
687 IoMmuUnmap (UhcDev
->IoMmu
, DataMap
);
694 Retrieves the number of root hub ports.
696 @param[in] PeiServices The pointer to the PEI Services Table.
697 @param[in] This The pointer to this instance of the
698 PEI_USB_HOST_CONTROLLER_PPI.
699 @param[out] PortNumber The pointer to the number of the root hub ports.
701 @retval EFI_SUCCESS The port number was retrieved successfully.
702 @retval EFI_INVALID_PARAMETER PortNumber is NULL.
707 UhcGetRootHubPortNumber (
708 IN EFI_PEI_SERVICES
**PeiServices
,
709 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
710 OUT UINT8
*PortNumber
715 UINT16 RHPortControl
;
718 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
720 if (PortNumber
== NULL
) {
721 return EFI_INVALID_PARAMETER
;
726 for (Index
= 0; Index
< 2; Index
++) {
727 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ Index
* 2;
728 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
730 // Port Register content is valid
732 if (RHPortControl
!= 0xff) {
741 Retrieves the current status of a USB root hub port.
743 @param PeiServices The pointer of EFI_PEI_SERVICES.
744 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
745 @param PortNumber The root hub port to retrieve the state from.
746 @param PortStatus Variable to receive the port state.
748 @retval EFI_SUCCESS The status of the USB root hub port specified.
749 by PortNumber was returned in PortStatus.
750 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
755 UhcGetRootHubPortStatus (
756 IN EFI_PEI_SERVICES
**PeiServices
,
757 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
759 OUT EFI_USB_PORT_STATUS
*PortStatus
765 UINT8 TotalPortNumber
;
767 if (PortStatus
== NULL
) {
768 return EFI_INVALID_PARAMETER
;
771 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
772 if (PortNumber
> TotalPortNumber
) {
773 return EFI_INVALID_PARAMETER
;
776 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
777 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
779 PortStatus
->PortStatus
= 0;
780 PortStatus
->PortChangeStatus
= 0;
782 RHPortStatus
= USBReadPortW (UhcDev
, PSAddr
);
785 // Current Connect Status
787 if ((RHPortStatus
& USBPORTSC_CCS
) != 0) {
788 PortStatus
->PortStatus
|= USB_PORT_STAT_CONNECTION
;
791 // Port Enabled/Disabled
793 if ((RHPortStatus
& USBPORTSC_PED
) != 0) {
794 PortStatus
->PortStatus
|= USB_PORT_STAT_ENABLE
;
799 if ((RHPortStatus
& USBPORTSC_SUSP
) != 0) {
800 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
805 if ((RHPortStatus
& USBPORTSC_PR
) != 0) {
806 PortStatus
->PortStatus
|= USB_PORT_STAT_RESET
;
809 // Low Speed Device Attached
811 if ((RHPortStatus
& USBPORTSC_LSDA
) != 0) {
812 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
815 // Fill Port Status Change bits
818 // Connect Status Change
820 if ((RHPortStatus
& USBPORTSC_CSC
) != 0) {
821 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_CONNECTION
;
824 // Port Enabled/Disabled Change
826 if ((RHPortStatus
& USBPORTSC_PEDC
) != 0) {
827 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_ENABLE
;
834 Sets a feature for the specified root hub port.
836 @param PeiServices The pointer of EFI_PEI_SERVICES
837 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI
838 @param PortNumber Root hub port to set.
839 @param PortFeature Feature to set.
841 @retval EFI_SUCCESS The feature specified by PortFeature was set.
842 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
843 @retval EFI_TIMEOUT The time out occurred.
848 UhcSetRootHubPortFeature (
849 IN EFI_PEI_SERVICES
**PeiServices
,
850 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
852 IN EFI_USB_PORT_FEATURE PortFeature
857 UINT32 CommandRegAddr
;
858 UINT16 RHPortControl
;
859 UINT8 TotalPortNumber
;
861 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
862 if (PortNumber
> TotalPortNumber
) {
863 return EFI_INVALID_PARAMETER
;
866 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
867 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
868 CommandRegAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
870 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
872 switch (PortFeature
) {
874 case EfiUsbPortSuspend
:
875 if ((USBReadPortW (UhcDev
, CommandRegAddr
) & USBCMD_EGSM
) == 0) {
877 // if global suspend is not active, can set port suspend
879 RHPortControl
&= 0xfff5;
880 RHPortControl
|= USBPORTSC_SUSP
;
884 case EfiUsbPortReset
:
885 RHPortControl
&= 0xfff5;
886 RHPortControl
|= USBPORTSC_PR
;
892 case EfiUsbPortPower
:
895 case EfiUsbPortEnable
:
896 RHPortControl
&= 0xfff5;
897 RHPortControl
|= USBPORTSC_PED
;
901 return EFI_INVALID_PARAMETER
;
904 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
910 Clears a feature for the specified root hub port.
912 @param PeiServices The pointer of EFI_PEI_SERVICES.
913 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.
914 @param PortNumber Specifies the root hub port whose feature
915 is requested to be cleared.
916 @param PortFeature Indicates the feature selector associated with the
917 feature clear request.
919 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
920 for the USB root hub port specified by PortNumber.
921 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
926 UhcClearRootHubPortFeature (
927 IN EFI_PEI_SERVICES
**PeiServices
,
928 IN PEI_USB_HOST_CONTROLLER_PPI
*This
,
930 IN EFI_USB_PORT_FEATURE PortFeature
935 UINT16 RHPortControl
;
936 UINT8 TotalPortNumber
;
938 UhcGetRootHubPortNumber (PeiServices
, This
, &TotalPortNumber
);
940 if (PortNumber
> TotalPortNumber
) {
941 return EFI_INVALID_PARAMETER
;
944 UhcDev
= PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This
);
945 PSAddr
= UhcDev
->UsbHostControllerBaseAddress
+ USBPORTSC1
+ PortNumber
* 2;
947 RHPortControl
= USBReadPortW (UhcDev
, PSAddr
);
949 switch (PortFeature
) {
951 // clear PORT_ENABLE feature means disable port.
953 case EfiUsbPortEnable
:
954 RHPortControl
&= 0xfff5;
955 RHPortControl
&= ~USBPORTSC_PED
;
959 // clear PORT_SUSPEND feature means resume the port.
960 // (cause a resume on the specified port if in suspend mode)
962 case EfiUsbPortSuspend
:
963 RHPortControl
&= 0xfff5;
964 RHPortControl
&= ~USBPORTSC_SUSP
;
970 case EfiUsbPortPower
:
974 // clear PORT_RESET means clear the reset signal.
976 case EfiUsbPortReset
:
977 RHPortControl
&= 0xfff5;
978 RHPortControl
&= ~USBPORTSC_PR
;
982 // clear connect status change
984 case EfiUsbPortConnectChange
:
985 RHPortControl
&= 0xfff5;
986 RHPortControl
|= USBPORTSC_CSC
;
990 // clear enable/disable status change
992 case EfiUsbPortEnableChange
:
993 RHPortControl
&= 0xfff5;
994 RHPortControl
|= USBPORTSC_PEDC
;
998 // root hub does not support this request
1000 case EfiUsbPortSuspendChange
:
1004 // root hub does not support this request
1006 case EfiUsbPortOverCurrentChange
:
1010 // root hub does not support this request
1012 case EfiUsbPortResetChange
:
1016 return EFI_INVALID_PARAMETER
;
1019 USBWritePortW (UhcDev
, PSAddr
, RHPortControl
);
1027 @param UhcDev UHCI Device.
1029 @retval EFI_SUCCESS UHCI successfully initialized.
1030 @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.
1035 IN USB_UHC_DEV
*UhcDev
1039 UINT32 FrameListBaseAddrReg
;
1044 // Create and Initialize Frame List For the Host Controller.
1046 Status
= CreateFrameList (UhcDev
);
1047 if (EFI_ERROR (Status
)) {
1051 FrameListBaseAddrReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBFLBASEADD
;
1052 CommandReg
= UhcDev
->UsbHostControllerBaseAddress
+ USBCMD
;
1055 // Set Frame List Base Address to the specific register to inform the hardware.
1057 SetFrameListBaseAddress (UhcDev
, FrameListBaseAddrReg
, (UINT32
) (UINTN
) (UhcDev
->FrameListEntry
));
1059 Command
= USBReadPortW (UhcDev
, CommandReg
);
1060 Command
|= USBCMD_GRESET
;
1061 USBWritePortW (UhcDev
, CommandReg
, Command
);
1063 MicroSecondDelay (50 * 1000);
1066 Command
&= ~USBCMD_GRESET
;
1068 USBWritePortW (UhcDev
, CommandReg
, Command
);
1071 //UHCI spec page120 reset recovery time
1073 MicroSecondDelay (20 * 1000);
1076 // Set Run/Stop bit to 1.
1078 Command
= USBReadPortW (UhcDev
, CommandReg
);
1079 Command
|= USBCMD_RS
| USBCMD_MAXP
;
1080 USBWritePortW (UhcDev
, CommandReg
, Command
);
1086 Create Frame List Structure.
1088 @param UhcDev UHCI device.
1090 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1091 @retval EFI_SUCCESS Success.
1100 EFI_PHYSICAL_ADDRESS FrameListBaseAddr
;
1101 FRAMELIST_ENTRY
*FrameListPtr
;
1105 // The Frame List ocupies 4K bytes,
1106 // and must be aligned on 4-Kbyte boundaries.
1108 Status
= PeiServicesAllocatePages (
1109 EfiBootServicesData
,
1114 if (Status
!= EFI_SUCCESS
) {
1115 return EFI_OUT_OF_RESOURCES
;
1119 //Create Control QH and Bulk QH and link them into Framelist Entry
1121 Status
= CreateQH(UhcDev
, &UhcDev
->ConfigQH
);
1122 if (Status
!= EFI_SUCCESS
) {
1123 return EFI_OUT_OF_RESOURCES
;
1125 ASSERT (UhcDev
->ConfigQH
!= NULL
);
1127 Status
= CreateQH(UhcDev
, &UhcDev
->BulkQH
);
1128 if (Status
!= EFI_SUCCESS
) {
1129 return EFI_OUT_OF_RESOURCES
;
1131 ASSERT (UhcDev
->BulkQH
!= NULL
);
1134 //Set the corresponding QH pointer
1136 SetQHHorizontalLinkPtr(UhcDev
->ConfigQH
, UhcDev
->BulkQH
);
1137 SetQHHorizontalQHorTDSelect (UhcDev
->ConfigQH
, TRUE
);
1138 SetQHHorizontalValidorInvalid (UhcDev
->ConfigQH
, TRUE
);
1140 UhcDev
->FrameListEntry
= (FRAMELIST_ENTRY
*) ((UINTN
) FrameListBaseAddr
);
1142 FrameListPtr
= UhcDev
->FrameListEntry
;
1144 for (Index
= 0; Index
< 1024; Index
++) {
1145 FrameListPtr
->FrameListPtrTerminate
= 0;
1146 FrameListPtr
->FrameListPtr
= (UINT32
)(UINTN
)UhcDev
->ConfigQH
>> 4;
1147 FrameListPtr
->FrameListPtrQSelect
= 1;
1148 FrameListPtr
->FrameListRsvd
= 0;
1156 Read a 16bit width data from Uhc HC IO space register.
1158 @param UhcDev The UHCI device.
1159 @param Port The IO space address of the register.
1161 @retval the register content read.
1166 IN USB_UHC_DEV
*UhcDev
,
1170 return IoRead16 (Port
);
1174 Write a 16bit width data into Uhc HC IO space register.
1176 @param UhcDev The UHCI device.
1177 @param Port The IO space address of the register.
1178 @param Data The data written into the register.
1183 IN USB_UHC_DEV
*UhcDev
,
1188 IoWrite16 (Port
, Data
);
1192 Write a 32bit width data into Uhc HC IO space register.
1194 @param UhcDev The UHCI device.
1195 @param Port The IO space address of the register.
1196 @param Data The data written into the register.
1201 IN USB_UHC_DEV
*UhcDev
,
1206 IoWrite32 (Port
, Data
);
1210 Clear the content of UHCI's Status Register.
1212 @param UhcDev The UHCI device.
1213 @param StatusAddr The IO space address of the register.
1218 IN USB_UHC_DEV
*UhcDev
,
1219 IN UINT32 StatusAddr
1223 // Clear the content of UHCI's Status Register
1225 USBWritePortW (UhcDev
, StatusAddr
, 0x003F);
1229 Check whether the host controller operates well.
1231 @param UhcDev The UHCI device.
1232 @param StatusRegAddr The io address of status register.
1234 @retval TRUE Host controller is working.
1235 @retval FALSE Host controller is halted or system error.
1240 IN USB_UHC_DEV
*UhcDev
,
1241 IN UINT32 StatusRegAddr
1246 StatusValue
= USBReadPortW (UhcDev
, StatusRegAddr
);
1248 if ((StatusValue
& (USBSTS_HCPE
| USBSTS_HSE
| USBSTS_HCH
)) != 0) {
1258 Set Frame List Base Address.
1260 @param UhcDev The UHCI device.
1261 @param FrameListRegAddr The address of frame list register.
1262 @param Addr The address of frame list table.
1266 SetFrameListBaseAddress (
1267 IN USB_UHC_DEV
*UhcDev
,
1268 IN UINT32 FrameListRegAddr
,
1273 // Sets value in the USB Frame List Base Address register.
1275 USBWritePortDW (UhcDev
, FrameListRegAddr
, (UINT32
) (Addr
& 0xFFFFF000));
1279 Create QH and initialize.
1281 @param UhcDev The UHCI device.
1282 @param PtrQH Place to store QH_STRUCT pointer.
1284 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1285 @retval EFI_SUCCESS Success.
1290 IN USB_UHC_DEV
*UhcDev
,
1291 OUT QH_STRUCT
**PtrQH
1297 // allocate align memory for QH_STRUCT
1299 Status
= AllocateTDorQHStruct (UhcDev
, sizeof(QH_STRUCT
), (void **)PtrQH
);
1300 if (EFI_ERROR (Status
)) {
1301 return EFI_OUT_OF_RESOURCES
;
1304 // init each field of the QH_STRUCT
1306 SetQHHorizontalValidorInvalid (*PtrQH
, FALSE
);
1307 SetQHVerticalValidorInvalid (*PtrQH
, FALSE
);
1313 Set the horizontal link pointer in QH.
1315 @param PtrQH Place to store QH_STRUCT pointer.
1316 @param PtrNext Place to the next QH_STRUCT.
1320 SetQHHorizontalLinkPtr (
1321 IN QH_STRUCT
*PtrQH
,
1326 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1327 // Only the highest 28bit of the address is valid
1328 // (take 32bit address as an example).
1330 PtrQH
->QueueHead
.QHHorizontalPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1336 Set a QH or TD horizontally to be connected with a specific QH.
1338 @param PtrQH Place to store QH_STRUCT pointer.
1339 @param IsQH Specify QH or TD is connected.
1343 SetQHHorizontalQHorTDSelect (
1344 IN QH_STRUCT
*PtrQH
,
1349 // if QH is connected, the specified bit is set,
1350 // if TD is connected, the specified bit is cleared.
1352 PtrQH
->QueueHead
.QHHorizontalQSelect
= IsQH
? 1 : 0;
1356 Set the horizontal validor bit in QH.
1358 @param PtrQH Place to store QH_STRUCT pointer.
1359 @param IsValid Specify the horizontal linker is valid or not.
1363 SetQHHorizontalValidorInvalid (
1364 IN QH_STRUCT
*PtrQH
,
1369 // Valid means the horizontal link pointer is valid,
1370 // else, it's invalid.
1372 PtrQH
->QueueHead
.QHHorizontalTerminate
= IsValid
? 0 : 1;
1376 Set the vertical link pointer in QH.
1378 @param PtrQH Place to store QH_STRUCT pointer.
1379 @param PtrNext Place to the next QH_STRUCT.
1383 SetQHVerticalLinkPtr (
1384 IN QH_STRUCT
*PtrQH
,
1389 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1390 // Only the highest 28bit of the address is valid
1391 // (take 32bit address as an example).
1393 PtrQH
->QueueHead
.QHVerticalPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1397 Set a QH or TD vertically to be connected with a specific QH.
1399 @param PtrQH Place to store QH_STRUCT pointer.
1400 @param IsQH Specify QH or TD is connected.
1404 SetQHVerticalQHorTDSelect (
1405 IN QH_STRUCT
*PtrQH
,
1410 // Set the specified bit if the Vertical Link Pointer pointing to a QH,
1411 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
1413 PtrQH
->QueueHead
.QHVerticalQSelect
= IsQH
? 1 : 0;
1417 Set the vertical validor bit in QH.
1419 @param PtrQH Place to store QH_STRUCT pointer.
1420 @param IsValid Specify the vertical linker is valid or not.
1424 SetQHVerticalValidorInvalid (
1425 IN QH_STRUCT
*PtrQH
,
1430 // If TRUE, meaning the Vertical Link Pointer field is valid,
1431 // else, the field is invalid.
1433 PtrQH
->QueueHead
.QHVerticalTerminate
= IsValid
? 0 : 1;
1439 Allocate TD or QH Struct.
1441 @param UhcDev The UHCI device.
1442 @param Size The size of allocation.
1443 @param PtrStruct Place to store TD_STRUCT pointer.
1445 @return EFI_SUCCESS Allocate successfully.
1446 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1450 AllocateTDorQHStruct (
1451 IN USB_UHC_DEV
*UhcDev
,
1453 OUT VOID
**PtrStruct
1458 Status
= EFI_SUCCESS
;
1461 Status
= UhcAllocatePool (
1463 (UINT8
**) PtrStruct
,
1466 if (EFI_ERROR (Status
)) {
1470 ZeroMem (*PtrStruct
, Size
);
1478 @param UhcDev The UHCI device.
1479 @param PtrTD Place to store TD_STRUCT pointer.
1481 @return EFI_SUCCESS Allocate successfully.
1482 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1487 IN USB_UHC_DEV
*UhcDev
,
1488 OUT TD_STRUCT
**PtrTD
1493 // create memory for TD_STRUCT, and align the memory.
1495 Status
= AllocateTDorQHStruct (UhcDev
, sizeof(TD_STRUCT
), (void **)PtrTD
);
1496 if (EFI_ERROR (Status
)) {
1503 SetTDLinkPtrValidorInvalid (*PtrTD
, FALSE
);
1509 Generate Setup Stage TD.
1511 @param UhcDev The UHCI device.
1512 @param DevAddr Device address.
1513 @param Endpoint Endpoint number.
1514 @param DeviceSpeed Device Speed.
1515 @param DevRequest CPU memory address of request structure buffer to transfer.
1516 @param RequestPhy PCI memory address of request structure buffer to transfer.
1517 @param RequestLen Request length.
1518 @param PtrTD TD_STRUCT generated.
1520 @return EFI_SUCCESS Generate setup stage TD successfully.
1521 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1526 IN USB_UHC_DEV
*UhcDev
,
1529 IN UINT8 DeviceSpeed
,
1530 IN UINT8
*DevRequest
,
1531 IN UINT8
*RequestPhy
,
1532 IN UINT8 RequestLen
,
1533 OUT TD_STRUCT
**PtrTD
1536 TD_STRUCT
*TdStruct
;
1539 Status
= CreateTD (UhcDev
, &TdStruct
);
1540 if (EFI_ERROR (Status
)) {
1544 SetTDLinkPtr (TdStruct
, NULL
);
1547 // Depth first fashion
1549 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1552 // initialize as the last TD in the QH context,
1553 // this field will be updated in the TD linkage process.
1555 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1558 // Disable Short Packet Detection by default
1560 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1563 // Max error counter is 3, retry 3 times when error encountered.
1565 SetTDControlErrorCounter (TdStruct
, 3);
1568 // set device speed attribute
1569 // (TRUE - Slow Device; FALSE - Full Speed Device)
1571 switch (DeviceSpeed
) {
1572 case USB_SLOW_SPEED_DEVICE
:
1573 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1576 case USB_FULL_SPEED_DEVICE
:
1577 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1581 // Non isochronous transfer TD
1583 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1586 // Interrupt On Complete bit be set to zero,
1587 // Disable IOC interrupt.
1589 SetorClearTDControlIOC (TdStruct
, FALSE
);
1592 // Set TD Active bit
1594 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1596 SetTDTokenMaxLength (TdStruct
, RequestLen
);
1598 SetTDTokenDataToggle0 (TdStruct
);
1600 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1602 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1604 SetTDTokenPacketID (TdStruct
, SETUP_PACKET_ID
);
1606 TdStruct
->PtrTDBuffer
= (UINT8
*) DevRequest
;
1607 TdStruct
->TDBufferLength
= RequestLen
;
1609 // Set the beginning address of the buffer that will be used
1610 // during the transaction.
1612 TdStruct
->TDData
.TDBufferPtr
= (UINT32
) (UINTN
) RequestPhy
;
1620 Generate Data Stage TD.
1622 @param UhcDev The UHCI device.
1623 @param DevAddr Device address.
1624 @param Endpoint Endpoint number.
1625 @param PtrData CPU memory address of user data buffer to transfer.
1626 @param DataPhy PCI memory address of user data buffer to transfer.
1627 @param Len Data length.
1628 @param PktID PacketID.
1629 @param Toggle Data toggle value.
1630 @param DeviceSpeed Device Speed.
1631 @param PtrTD TD_STRUCT generated.
1633 @return EFI_SUCCESS Generate data stage TD successfully.
1634 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1639 IN USB_UHC_DEV
*UhcDev
,
1647 IN UINT8 DeviceSpeed
,
1648 OUT TD_STRUCT
**PtrTD
1651 TD_STRUCT
*TdStruct
;
1654 Status
= CreateTD (UhcDev
, &TdStruct
);
1655 if (EFI_ERROR (Status
)) {
1659 SetTDLinkPtr (TdStruct
, NULL
);
1662 // Depth first fashion
1664 SetTDLinkPtrDepthorBreadth (TdStruct
, TRUE
);
1667 // Link pointer pointing to TD struct
1669 SetTDLinkPtrQHorTDSelect (TdStruct
, FALSE
);
1672 // initialize as the last TD in the QH context,
1673 // this field will be updated in the TD linkage process.
1675 SetTDLinkPtrValidorInvalid (TdStruct
, FALSE
);
1678 // Disable short packet detect
1680 EnableorDisableTDShortPacket (TdStruct
, FALSE
);
1682 // Max error counter is 3
1684 SetTDControlErrorCounter (TdStruct
, 3);
1687 // set device speed attribute
1688 // (TRUE - Slow Device; FALSE - Full Speed Device)
1690 switch (DeviceSpeed
) {
1691 case USB_SLOW_SPEED_DEVICE
:
1692 SetTDLoworFullSpeedDevice (TdStruct
, TRUE
);
1695 case USB_FULL_SPEED_DEVICE
:
1696 SetTDLoworFullSpeedDevice (TdStruct
, FALSE
);
1700 // Non isochronous transfer TD
1702 SetTDControlIsochronousorNot (TdStruct
, FALSE
);
1705 // Disable Interrupt On Complete
1706 // Disable IOC interrupt.
1708 SetorClearTDControlIOC (TdStruct
, FALSE
);
1713 SetTDStatusActiveorInactive (TdStruct
, TRUE
);
1715 SetTDTokenMaxLength (TdStruct
, Len
);
1718 SetTDTokenDataToggle1 (TdStruct
);
1720 SetTDTokenDataToggle0 (TdStruct
);
1723 SetTDTokenEndPoint (TdStruct
, Endpoint
);
1725 SetTDTokenDeviceAddress (TdStruct
, DevAddr
);
1727 SetTDTokenPacketID (TdStruct
, PktID
);
1729 TdStruct
->PtrTDBuffer
= (UINT8
*) PtrData
;
1730 TdStruct
->TDBufferLength
= Len
;
1732 // Set the beginning address of the buffer that will be used
1733 // during the transaction.
1735 TdStruct
->TDData
.TDBufferPtr
= (UINT32
) (UINTN
) DataPhy
;
1743 Generate Status Stage TD.
1745 @param UhcDev The UHCI device.
1746 @param DevAddr Device address.
1747 @param Endpoint Endpoint number.
1748 @param PktID PacketID.
1749 @param DeviceSpeed Device Speed.
1750 @param PtrTD TD_STRUCT generated.
1752 @return EFI_SUCCESS Generate status stage TD successfully.
1753 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1758 IN USB_UHC_DEV
*UhcDev
,
1762 IN UINT8 DeviceSpeed
,
1763 OUT TD_STRUCT
**PtrTD
1766 TD_STRUCT
*PtrTDStruct
;
1769 Status
= CreateTD (UhcDev
, &PtrTDStruct
);
1770 if (EFI_ERROR (Status
)) {
1774 SetTDLinkPtr (PtrTDStruct
, NULL
);
1777 // Depth first fashion
1779 SetTDLinkPtrDepthorBreadth (PtrTDStruct
, TRUE
);
1782 // initialize as the last TD in the QH context,
1783 // this field will be updated in the TD linkage process.
1785 SetTDLinkPtrValidorInvalid (PtrTDStruct
, FALSE
);
1788 // Disable short packet detect
1790 EnableorDisableTDShortPacket (PtrTDStruct
, FALSE
);
1793 // Max error counter is 3
1795 SetTDControlErrorCounter (PtrTDStruct
, 3);
1798 // set device speed attribute
1799 // (TRUE - Slow Device; FALSE - Full Speed Device)
1801 switch (DeviceSpeed
) {
1802 case USB_SLOW_SPEED_DEVICE
:
1803 SetTDLoworFullSpeedDevice (PtrTDStruct
, TRUE
);
1806 case USB_FULL_SPEED_DEVICE
:
1807 SetTDLoworFullSpeedDevice (PtrTDStruct
, FALSE
);
1811 // Non isochronous transfer TD
1813 SetTDControlIsochronousorNot (PtrTDStruct
, FALSE
);
1816 // Disable Interrupt On Complete
1817 // Disable IOC interrupt.
1819 SetorClearTDControlIOC (PtrTDStruct
, FALSE
);
1822 // Set TD Active bit
1824 SetTDStatusActiveorInactive (PtrTDStruct
, TRUE
);
1826 SetTDTokenMaxLength (PtrTDStruct
, 0);
1828 SetTDTokenDataToggle1 (PtrTDStruct
);
1830 SetTDTokenEndPoint (PtrTDStruct
, Endpoint
);
1832 SetTDTokenDeviceAddress (PtrTDStruct
, DevAddr
);
1834 SetTDTokenPacketID (PtrTDStruct
, PktID
);
1836 PtrTDStruct
->PtrTDBuffer
= NULL
;
1837 PtrTDStruct
->TDBufferLength
= 0;
1839 // Set the beginning address of the buffer that will be used
1840 // during the transaction.
1842 PtrTDStruct
->TDData
.TDBufferPtr
= 0;
1844 *PtrTD
= PtrTDStruct
;
1850 Set the link pointer validor bit in TD.
1852 @param PtrTDStruct Place to store TD_STRUCT pointer.
1853 @param IsValid Specify the linker pointer is valid or not.
1857 SetTDLinkPtrValidorInvalid (
1858 IN TD_STRUCT
*PtrTDStruct
,
1863 // Valid means the link pointer is valid,
1864 // else, it's invalid.
1866 PtrTDStruct
->TDData
.TDLinkPtrTerminate
= (IsValid
? 0 : 1);
1870 Set the Link Pointer pointing to a QH or TD.
1872 @param PtrTDStruct Place to store TD_STRUCT pointer.
1873 @param IsQH Specify QH or TD is connected.
1877 SetTDLinkPtrQHorTDSelect (
1878 IN TD_STRUCT
*PtrTDStruct
,
1883 // Indicate whether the Link Pointer pointing to a QH or TD
1885 PtrTDStruct
->TDData
.TDLinkPtrQSelect
= (IsQH
? 1 : 0);
1889 Set the traverse is depth-first or breadth-first.
1891 @param PtrTDStruct Place to store TD_STRUCT pointer.
1892 @param IsDepth Specify the traverse is depth-first or breadth-first.
1896 SetTDLinkPtrDepthorBreadth (
1897 IN TD_STRUCT
*PtrTDStruct
,
1902 // If TRUE, indicating the host controller should process in depth first fashion,
1903 // else, the host controller should process in breadth first fashion
1905 PtrTDStruct
->TDData
.TDLinkPtrDepthSelect
= (IsDepth
? 1 : 0);
1909 Set TD Link Pointer in TD.
1911 @param PtrTDStruct Place to store TD_STRUCT pointer.
1912 @param PtrNext Place to the next TD_STRUCT.
1917 IN TD_STRUCT
*PtrTDStruct
,
1922 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
1923 // only the highest 28 bits are valid. (if take 32bit address as an example)
1925 PtrTDStruct
->TDData
.TDLinkPtr
= (UINT32
) (UINTN
) PtrNext
>> 4;
1929 Get TD Link Pointer.
1931 @param PtrTDStruct Place to store TD_STRUCT pointer.
1933 @retval Get TD Link Pointer in TD.
1938 IN TD_STRUCT
*PtrTDStruct
1942 // Get TD Link Pointer. Restore it back to 32bit
1943 // (if take 32bit address as an example)
1945 return (VOID
*) (UINTN
) ((PtrTDStruct
->TDData
.TDLinkPtr
) << 4);
1951 Enable/Disable short packet detection mechanism.
1953 @param PtrTDStruct Place to store TD_STRUCT pointer.
1954 @param IsEnable Enable or disable short packet detection mechanism.
1958 EnableorDisableTDShortPacket (
1959 IN TD_STRUCT
*PtrTDStruct
,
1964 // TRUE means enable short packet detection mechanism.
1966 PtrTDStruct
->TDData
.TDStatusSPD
= (IsEnable
? 1 : 0);
1970 Set the max error counter in TD.
1972 @param PtrTDStruct Place to store TD_STRUCT pointer.
1973 @param MaxErrors The number of allowable error.
1977 SetTDControlErrorCounter (
1978 IN TD_STRUCT
*PtrTDStruct
,
1983 // valid value of MaxErrors is 0,1,2,3
1985 if (MaxErrors
> 3) {
1989 PtrTDStruct
->TDData
.TDStatusErr
= MaxErrors
;
1993 Set the TD is targeting a low-speed device or not.
1995 @param PtrTDStruct Place to store TD_STRUCT pointer.
1996 @param IsLowSpeedDevice Whether The device is low-speed.
2000 SetTDLoworFullSpeedDevice (
2001 IN TD_STRUCT
*PtrTDStruct
,
2002 IN BOOLEAN IsLowSpeedDevice
2006 // TRUE means the TD is targeting at a Low-speed device
2008 PtrTDStruct
->TDData
.TDStatusLS
= (IsLowSpeedDevice
? 1 : 0);
2012 Set the TD is isochronous transfer type or not.
2014 @param PtrTDStruct Place to store TD_STRUCT pointer.
2015 @param IsIsochronous Whether the transaction isochronous transfer type.
2019 SetTDControlIsochronousorNot (
2020 IN TD_STRUCT
*PtrTDStruct
,
2021 IN BOOLEAN IsIsochronous
2025 // TRUE means the TD belongs to Isochronous transfer type.
2027 PtrTDStruct
->TDData
.TDStatusIOS
= (IsIsochronous
? 1 : 0);
2031 Set if UCHI should issue an interrupt on completion of the frame
2032 in which this TD is executed
2034 @param PtrTDStruct Place to store TD_STRUCT pointer.
2035 @param IsSet Whether HC should issue an interrupt on completion.
2039 SetorClearTDControlIOC (
2040 IN TD_STRUCT
*PtrTDStruct
,
2045 // If this bit is set, it indicates that the host controller should issue
2046 // an interrupt on completion of the frame in which this TD is executed.
2048 PtrTDStruct
->TDData
.TDStatusIOC
= IsSet
? 1 : 0;
2052 Set if the TD is active and can be executed.
2054 @param PtrTDStruct Place to store TD_STRUCT pointer.
2055 @param IsActive Whether the TD is active and can be executed.
2059 SetTDStatusActiveorInactive (
2060 IN TD_STRUCT
*PtrTDStruct
,
2065 // If this bit is set, it indicates that the TD is active and can be
2069 PtrTDStruct
->TDData
.TDStatus
|= 0x80;
2071 PtrTDStruct
->TDData
.TDStatus
&= 0x7F;
2076 Specifies the maximum number of data bytes allowed for the transfer.
2078 @param PtrTDStruct Place to store TD_STRUCT pointer.
2079 @param MaxLen The maximum number of data bytes allowed.
2081 @retval The allowed maximum number of data.
2084 SetTDTokenMaxLength (
2085 IN TD_STRUCT
*PtrTDStruct
,
2090 // Specifies the maximum number of data bytes allowed for the transfer.
2091 // the legal value extent is 0 ~ 0x500.
2093 if (MaxLen
> 0x500) {
2097 PtrTDStruct
->TDData
.TDTokenMaxLen
= MaxLen
- 1;
2103 Set the data toggle bit to DATA1.
2105 @param PtrTDStruct Place to store TD_STRUCT pointer.
2109 SetTDTokenDataToggle1 (
2110 IN TD_STRUCT
*PtrTDStruct
2114 // Set the data toggle bit to DATA1
2116 PtrTDStruct
->TDData
.TDTokenDataToggle
= 1;
2120 Set the data toggle bit to DATA0.
2122 @param PtrTDStruct Place to store TD_STRUCT pointer.
2126 SetTDTokenDataToggle0 (
2127 IN TD_STRUCT
*PtrTDStruct
2131 // Set the data toggle bit to DATA0
2133 PtrTDStruct
->TDData
.TDTokenDataToggle
= 0;
2137 Set EndPoint Number the TD is targeting at.
2139 @param PtrTDStruct Place to store TD_STRUCT pointer.
2140 @param EndPoint The Endport number of the target.
2144 SetTDTokenEndPoint (
2145 IN TD_STRUCT
*PtrTDStruct
,
2150 // Set EndPoint Number the TD is targeting at.
2152 PtrTDStruct
->TDData
.TDTokenEndPt
= (UINT8
) EndPoint
;
2156 Set Device Address the TD is targeting at.
2158 @param PtrTDStruct Place to store TD_STRUCT pointer.
2159 @param DevAddr The Device Address of the target.
2163 SetTDTokenDeviceAddress (
2164 IN TD_STRUCT
*PtrTDStruct
,
2169 // Set Device Address the TD is targeting at.
2171 PtrTDStruct
->TDData
.TDTokenDevAddr
= (UINT8
) DevAddr
;
2175 Set Packet Identification the TD is targeting at.
2177 @param PtrTDStruct Place to store TD_STRUCT pointer.
2178 @param PacketID The Packet Identification of the target.
2182 SetTDTokenPacketID (
2183 IN TD_STRUCT
*PtrTDStruct
,
2188 // Set the Packet Identification to be used for this transaction.
2190 PtrTDStruct
->TDData
.TDTokenPID
= PacketID
;
2194 Detect whether the TD is active.
2196 @param PtrTDStruct Place to store TD_STRUCT pointer.
2198 @retval The TD is active or not.
2203 IN TD_STRUCT
*PtrTDStruct
2209 // Detect whether the TD is active.
2211 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2212 return (BOOLEAN
) (TDStatus
& 0x80);
2216 Detect whether the TD is stalled.
2218 @param PtrTDStruct Place to store TD_STRUCT pointer.
2220 @retval The TD is stalled or not.
2225 IN TD_STRUCT
*PtrTDStruct
2231 // Detect whether the device/endpoint addressed by this TD is stalled.
2233 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2234 return (BOOLEAN
) (TDStatus
& 0x40);
2238 Detect whether Data Buffer Error is happened.
2240 @param PtrTDStruct Place to store TD_STRUCT pointer.
2242 @retval The Data Buffer Error is happened or not.
2246 IsTDStatusBufferError (
2247 IN TD_STRUCT
*PtrTDStruct
2253 // Detect whether Data Buffer Error is happened.
2255 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2256 return (BOOLEAN
) (TDStatus
& 0x20);
2260 Detect whether Babble Error is happened.
2262 @param PtrTDStruct Place to store TD_STRUCT pointer.
2264 @retval The Babble Error is happened or not.
2268 IsTDStatusBabbleError (
2269 IN TD_STRUCT
*PtrTDStruct
2275 // Detect whether Babble Error is happened.
2277 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2278 return (BOOLEAN
) (TDStatus
& 0x10);
2282 Detect whether NAK is received.
2284 @param PtrTDStruct Place to store TD_STRUCT pointer.
2286 @retval The NAK is received or not.
2290 IsTDStatusNAKReceived (
2291 IN TD_STRUCT
*PtrTDStruct
2297 // Detect whether NAK is received.
2299 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2300 return (BOOLEAN
) (TDStatus
& 0x08);
2304 Detect whether CRC/Time Out Error is encountered.
2306 @param PtrTDStruct Place to store TD_STRUCT pointer.
2308 @retval The CRC/Time Out Error is encountered or not.
2312 IsTDStatusCRCTimeOutError (
2313 IN TD_STRUCT
*PtrTDStruct
2319 // Detect whether CRC/Time Out Error is encountered.
2321 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2322 return (BOOLEAN
) (TDStatus
& 0x04);
2326 Detect whether Bitstuff Error is received.
2328 @param PtrTDStruct Place to store TD_STRUCT pointer.
2330 @retval The Bitstuff Error is received or not.
2334 IsTDStatusBitStuffError (
2335 IN TD_STRUCT
*PtrTDStruct
2341 // Detect whether Bitstuff Error is received.
2343 TDStatus
= (UINT8
) (PtrTDStruct
->TDData
.TDStatus
);
2344 return (BOOLEAN
) (TDStatus
& 0x02);
2348 Retrieve the actual number of bytes that were tansferred.
2350 @param PtrTDStruct Place to store TD_STRUCT pointer.
2352 @retval The actual number of bytes that were tansferred.
2356 GetTDStatusActualLength (
2357 IN TD_STRUCT
*PtrTDStruct
2361 // Retrieve the actual number of bytes that were tansferred.
2362 // the value is encoded as n-1. so return the decoded value.
2364 return (UINT16
) ((PtrTDStruct
->TDData
.TDStatusActualLength
) + 1);
2368 Retrieve the information of whether the Link Pointer field is valid or not.
2370 @param PtrTDStruct Place to store TD_STRUCT pointer.
2372 @retval The linker pointer field is valid or not.
2376 GetTDLinkPtrValidorInvalid (
2377 IN TD_STRUCT
*PtrTDStruct
2381 // Retrieve the information of whether the Link Pointer field
2384 if ((PtrTDStruct
->TDData
.TDLinkPtrTerminate
& BIT0
) != 0) {
2393 Count TD Number from PtrFirstTD.
2395 @param PtrFirstTD Place to store TD_STRUCT pointer.
2397 @retval The queued TDs number.
2402 IN TD_STRUCT
*PtrFirstTD
2409 // Count the queued TDs number.
2414 Ptr
= (TD_STRUCT
*) Ptr
->PtrNextTD
;
2424 @param PtrQH Place to store QH_STRUCT pointer.
2425 @param PtrTD Place to store TD_STRUCT pointer.
2430 IN QH_STRUCT
*PtrQH
,
2434 if (PtrQH
== NULL
|| PtrTD
== NULL
) {
2438 // Validate QH Vertical Ptr field
2440 SetQHVerticalValidorInvalid (PtrQH
, TRUE
);
2443 // Vertical Ptr pointing to TD structure
2445 SetQHVerticalQHorTDSelect (PtrQH
, FALSE
);
2447 SetQHVerticalLinkPtr (PtrQH
, (VOID
*) PtrTD
);
2449 PtrQH
->PtrDown
= (VOID
*) PtrTD
;
2455 @param PtrPreTD Place to store TD_STRUCT pointer.
2456 @param PtrTD Place to store TD_STRUCT pointer.
2461 IN TD_STRUCT
*PtrPreTD
,
2465 if (PtrPreTD
== NULL
|| PtrTD
== NULL
) {
2469 // Depth first fashion
2471 SetTDLinkPtrDepthorBreadth (PtrPreTD
, TRUE
);
2474 // Link pointer pointing to TD struct
2476 SetTDLinkPtrQHorTDSelect (PtrPreTD
, FALSE
);
2479 // Validate the link pointer valid bit
2481 SetTDLinkPtrValidorInvalid (PtrPreTD
, TRUE
);
2483 SetTDLinkPtr (PtrPreTD
, PtrTD
);
2485 PtrPreTD
->PtrNextTD
= (VOID
*) PtrTD
;
2487 PtrTD
->PtrNextTD
= NULL
;
2491 Execute Control Transfer.
2493 @param UhcDev The UCHI device.
2494 @param PtrTD A pointer to TD_STRUCT data.
2495 @param ActualLen Actual transfer Length.
2496 @param TimeOut TimeOut value.
2497 @param TransferResult Transfer Result.
2499 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2500 @return EFI_TIMEOUT The transfer failed due to time out.
2501 @return EFI_SUCCESS The transfer finished OK.
2505 ExecuteControlTransfer (
2506 IN USB_UHC_DEV
*UhcDev
,
2507 IN TD_STRUCT
*PtrTD
,
2508 OUT UINTN
*ActualLen
,
2510 OUT UINT32
*TransferResult
2515 BOOLEAN InfiniteLoop
;
2518 *TransferResult
= EFI_USB_NOERROR
;
2520 InfiniteLoop
= FALSE
;
2522 Delay
= TimeOut
* STALL_1_MILLI_SECOND
;
2524 // If Timeout is 0, then the caller must wait for the function to be completed
2525 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2528 InfiniteLoop
= TRUE
;
2533 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2536 // TD is inactive, means the control transfer is end.
2538 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2541 MicroSecondDelay (STALL_1_MICRO_SECOND
);
2544 } while (InfiniteLoop
|| (Delay
!= 0));
2546 if (*TransferResult
!= EFI_USB_NOERROR
) {
2547 return EFI_DEVICE_ERROR
;
2554 Execute Bulk Transfer.
2556 @param UhcDev The UCHI device.
2557 @param PtrTD A pointer to TD_STRUCT data.
2558 @param ActualLen Actual transfer Length.
2559 @param DataToggle DataToggle value.
2560 @param TimeOut TimeOut value.
2561 @param TransferResult Transfer Result.
2563 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2564 @return EFI_TIMEOUT The transfer failed due to time out.
2565 @return EFI_SUCCESS The transfer finished OK.
2570 IN USB_UHC_DEV
*UhcDev
,
2571 IN TD_STRUCT
*PtrTD
,
2572 IN OUT UINTN
*ActualLen
,
2573 IN UINT8
*DataToggle
,
2575 OUT UINT32
*TransferResult
2581 BOOLEAN InfiniteLoop
;
2584 *TransferResult
= EFI_USB_NOERROR
;
2586 InfiniteLoop
= FALSE
;
2588 Delay
= TimeOut
* STALL_1_MILLI_SECOND
;
2590 // If Timeout is 0, then the caller must wait for the function to be completed
2591 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2594 InfiniteLoop
= TRUE
;
2599 CheckTDsResults (PtrTD
, TransferResult
, &ErrTDPos
, ActualLen
);
2601 // TD is inactive, thus meaning bulk transfer's end.
2603 if ((*TransferResult
& EFI_USB_ERR_NOTEXECUTE
) != EFI_USB_ERR_NOTEXECUTE
) {
2606 MicroSecondDelay (STALL_1_MICRO_SECOND
);
2609 } while (InfiniteLoop
|| (Delay
!= 0));
2614 if (*TransferResult
!= EFI_USB_NOERROR
) {
2616 // scroll the Data Toggle back to the last success TD
2618 ScrollNum
= CountTDsNumber (PtrTD
) - ErrTDPos
;
2619 if ((ScrollNum
% 2) != 0) {
2624 // If error, wait 100ms to retry by upper layer
2626 MicroSecondDelay (100 * 1000);
2627 return EFI_DEVICE_ERROR
;
2636 @param UhcDev The UCHI device.
2637 @param PtrFirstTD Place to store TD_STRUCT pointer.
2642 IN USB_UHC_DEV
*UhcDev
,
2643 IN TD_STRUCT
*PtrFirstTD
2652 // Delete all the TDs in a queue.
2654 while (Tptr1
!= NULL
) {
2658 if (!GetTDLinkPtrValidorInvalid (Tptr2
)) {
2662 // has more than one TD in the queue.
2664 Tptr1
= GetTDLinkPtr (Tptr2
);
2667 UhcFreePool (UhcDev
, (UINT8
*) Tptr2
, sizeof (TD_STRUCT
));
2676 @param PtrTD A pointer to TD_STRUCT data.
2677 @param Result The result to return.
2678 @param ErrTDPos The Error TD position.
2679 @param ActualTransferSize Actual transfer size.
2681 @retval The TD is executed successfully or not.
2686 IN TD_STRUCT
*PtrTD
,
2688 OUT UINTN
*ErrTDPos
,
2689 OUT UINTN
*ActualTransferSize
2694 *Result
= EFI_USB_NOERROR
;
2700 *ActualTransferSize
= 0;
2702 while (PtrTD
!= NULL
) {
2704 if (IsTDStatusActive (PtrTD
)) {
2705 *Result
|= EFI_USB_ERR_NOTEXECUTE
;
2708 if (IsTDStatusStalled (PtrTD
)) {
2709 *Result
|= EFI_USB_ERR_STALL
;
2712 if (IsTDStatusBufferError (PtrTD
)) {
2713 *Result
|= EFI_USB_ERR_BUFFER
;
2716 if (IsTDStatusBabbleError (PtrTD
)) {
2717 *Result
|= EFI_USB_ERR_BABBLE
;
2720 if (IsTDStatusNAKReceived (PtrTD
)) {
2721 *Result
|= EFI_USB_ERR_NAK
;
2724 if (IsTDStatusCRCTimeOutError (PtrTD
)) {
2725 *Result
|= EFI_USB_ERR_TIMEOUT
;
2728 if (IsTDStatusBitStuffError (PtrTD
)) {
2729 *Result
|= EFI_USB_ERR_BITSTUFF
;
2732 // Accumulate actual transferred data length in each TD.
2734 Len
= GetTDStatusActualLength (PtrTD
) & 0x7FF;
2735 *ActualTransferSize
+= Len
;
2738 // if any error encountered, stop processing the left TDs.
2740 if ((*Result
) != 0) {
2744 PtrTD
= (TD_STRUCT
*) (PtrTD
->PtrNextTD
);
2746 // Record the first Error TD's position in the queue,
2747 // this value is zero-based.
2756 Create Memory Block.
2758 @param UhcDev The UCHI device.
2759 @param MemoryHeader The Pointer to allocated memory block.
2760 @param MemoryBlockSizeInPages The page size of memory block to be allocated.
2762 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2763 @retval EFI_SUCCESS Success.
2768 IN USB_UHC_DEV
*UhcDev
,
2769 OUT MEMORY_MANAGE_HEADER
**MemoryHeader
,
2770 IN UINTN MemoryBlockSizeInPages
2778 EFI_PHYSICAL_ADDRESS MappedAddr
;
2781 // Memory Block uses MemoryBlockSizeInPages pages,
2782 // memory management header and bit array use 1 page
2784 MemPages
= MemoryBlockSizeInPages
+ 1;
2785 Status
= IoMmuAllocateBuffer (
2792 if (EFI_ERROR (Status
) || (TempPtr
== NULL
)) {
2793 return EFI_OUT_OF_RESOURCES
;
2798 ZeroMem (Ptr
, MemPages
* EFI_PAGE_SIZE
);
2800 *MemoryHeader
= (MEMORY_MANAGE_HEADER
*) Ptr
;
2802 // adjust Ptr pointer to the next empty memory
2804 Ptr
+= sizeof (MEMORY_MANAGE_HEADER
);
2806 // Set Bit Array initial address
2808 (*MemoryHeader
)->BitArrayPtr
= Ptr
;
2810 (*MemoryHeader
)->Next
= NULL
;
2813 // Memory block initial address
2816 Ptr
+= EFI_PAGE_SIZE
;
2817 (*MemoryHeader
)->MemoryBlockPtr
= Ptr
;
2819 // set Memory block size
2821 (*MemoryHeader
)->MemoryBlockSizeInBytes
= MemoryBlockSizeInPages
* EFI_PAGE_SIZE
;
2823 // each bit in Bit Array will manage 32byte memory in memory block
2825 (*MemoryHeader
)->BitArraySizeInBytes
= ((*MemoryHeader
)->MemoryBlockSizeInBytes
/ 32) / 8;
2831 Initialize UHCI memory management.
2833 @param UhcDev The UCHI device.
2835 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2836 @retval EFI_SUCCESS Success.
2840 InitializeMemoryManagement (
2841 IN USB_UHC_DEV
*UhcDev
2844 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2848 MemPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2849 Status
= CreateMemoryBlock (UhcDev
, &MemoryHeader
, MemPages
);
2850 if (EFI_ERROR (Status
)) {
2854 UhcDev
->Header1
= MemoryHeader
;
2860 Initialize UHCI memory management.
2862 @param UhcDev The UCHI device.
2863 @param Pool Buffer pointer to store the buffer pointer.
2864 @param AllocSize The size of the pool to be allocated.
2866 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2867 @retval EFI_SUCCESS Success.
2872 IN USB_UHC_DEV
*UhcDev
,
2877 MEMORY_MANAGE_HEADER
*MemoryHeader
;
2878 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
2879 MEMORY_MANAGE_HEADER
*NewMemoryHeader
;
2880 UINTN RealAllocSize
;
2881 UINTN MemoryBlockSizeInPages
;
2886 MemoryHeader
= UhcDev
->Header1
;
2889 // allocate unit is 32 byte (align on 32 byte)
2891 if ((AllocSize
& 0x1F) != 0) {
2892 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
2894 RealAllocSize
= AllocSize
;
2897 Status
= EFI_NOT_FOUND
;
2898 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
2900 Status
= AllocMemInMemoryBlock (
2905 if (!EFI_ERROR (Status
)) {
2910 // There is no enough memory,
2911 // Create a new Memory Block
2914 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
2915 // just allocate a large enough memory block.
2917 if (RealAllocSize
> (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
* EFI_PAGE_SIZE
)) {
2918 MemoryBlockSizeInPages
= RealAllocSize
/ EFI_PAGE_SIZE
+ 1;
2920 MemoryBlockSizeInPages
= NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES
;
2923 Status
= CreateMemoryBlock (UhcDev
, &NewMemoryHeader
, MemoryBlockSizeInPages
);
2924 if (EFI_ERROR (Status
)) {
2928 // Link the new Memory Block to the Memory Header list
2930 InsertMemoryHeaderToList (MemoryHeader
, NewMemoryHeader
);
2932 Status
= AllocMemInMemoryBlock (
2941 Alloc Memory In MemoryBlock.
2943 @param MemoryHeader The pointer to memory manage header.
2944 @param Pool Buffer pointer to store the buffer pointer.
2945 @param NumberOfMemoryUnit The size of the pool to be allocated.
2947 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2948 @retval EFI_SUCCESS Success.
2952 AllocMemInMemoryBlock (
2953 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
2955 IN UINTN NumberOfMemoryUnit
2964 UINTN NumberOfZeros
;
2970 ByteValue
= MemoryHeader
->BitArrayPtr
[0];
2973 for (TempBytePos
= 0; TempBytePos
< MemoryHeader
->BitArraySizeInBytes
;) {
2975 // Pop out BitValue from a byte in TempBytePos.
2977 BitValue
= (UINT8
)(ByteValue
& 0x1);
2979 if (BitValue
== 0) {
2981 // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
2985 // Found enough consecutive free space, break the loop
2987 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2992 // Encountering a '1', meant the bit is ocupied.
2994 if (NumberOfZeros
>= NumberOfMemoryUnit
) {
2996 // Found enough consecutive free space,break the loop
3001 // the NumberOfZeros only record the number of those consecutive zeros,
3002 // so reset the NumberOfZeros to 0 when encountering '1' before finding
3003 // enough consecutive '0's
3007 // reset the (FoundBytePos,FoundBitPos) to the position of '1'
3009 FoundBytePos
= TempBytePos
;
3010 FoundBitPos
= Index
;
3014 // right shift the byte
3019 // step forward a bit
3024 // step forward a byte, getting the byte value,
3025 // and reset the bit pos.
3028 ByteValue
= MemoryHeader
->BitArrayPtr
[TempBytePos
];
3033 if (NumberOfZeros
< NumberOfMemoryUnit
) {
3034 return EFI_NOT_FOUND
;
3037 // Found enough free space.
3040 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
3041 // 1)(FoundBytePos,FoundBitPos) record the position
3042 // of the last '1' before the consecutive '0's, it must
3043 // be adjusted to the start position of the consecutive '0's.
3044 // 2)the start address of the consecutive '0's is just the start of
3045 // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
3047 if ((MemoryHeader
->BitArrayPtr
[0] & BIT0
) != 0) {
3051 // Have the (FoundBytePos,FoundBitPos) make sense.
3053 if (FoundBitPos
> 7) {
3058 // Set the memory as allocated
3060 for (TempBytePos
= FoundBytePos
, Index
= FoundBitPos
, Count
= 0; Count
< NumberOfMemoryUnit
; Count
++) {
3062 MemoryHeader
->BitArrayPtr
[TempBytePos
] = (UINT8
) (MemoryHeader
->BitArrayPtr
[TempBytePos
] | (1 << Index
));
3070 *Pool
= MemoryHeader
->MemoryBlockPtr
+ (FoundBytePos
* 8 + FoundBitPos
) * 32;
3078 @param UhcDev The UHCI device.
3079 @param Pool A pointer to store the buffer address.
3080 @param AllocSize The size of the pool to be freed.
3085 IN USB_UHC_DEV
*UhcDev
,
3090 MEMORY_MANAGE_HEADER
*MemoryHeader
;
3091 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3097 UINTN RealAllocSize
;
3099 MemoryHeader
= UhcDev
->Header1
;
3102 // allocate unit is 32 byte (align on 32 byte)
3104 if ((AllocSize
& 0x1F) != 0) {
3105 RealAllocSize
= (AllocSize
/ 32 + 1) * 32;
3107 RealAllocSize
= AllocSize
;
3110 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
;
3111 TempHeaderPtr
= TempHeaderPtr
->Next
) {
3113 if ((Pool
>= TempHeaderPtr
->MemoryBlockPtr
) &&
3114 ((Pool
+ RealAllocSize
) <= (TempHeaderPtr
->MemoryBlockPtr
+
3115 TempHeaderPtr
->MemoryBlockSizeInBytes
))) {
3118 // Pool is in the Memory Block area,
3119 // find the start byte and bit in the bit array
3121 StartBytePos
= ((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) / 8;
3122 StartBitPos
= (UINT8
) (((Pool
- TempHeaderPtr
->MemoryBlockPtr
) / 32) % 8);
3125 // reset associated bits in bit array
3127 for (Index
= StartBytePos
, Index2
= StartBitPos
, Count
= 0; Count
< (RealAllocSize
/ 32); Count
++) {
3129 TempHeaderPtr
->BitArrayPtr
[Index
] = (UINT8
) (TempHeaderPtr
->BitArrayPtr
[Index
] ^ (1 << Index2
));
3146 Insert a new memory header into list.
3148 @param MemoryHeader A pointer to the memory header list.
3149 @param NewMemoryHeader A new memory header to be inserted into the list.
3153 InsertMemoryHeaderToList (
3154 IN MEMORY_MANAGE_HEADER
*MemoryHeader
,
3155 IN MEMORY_MANAGE_HEADER
*NewMemoryHeader
3158 MEMORY_MANAGE_HEADER
*TempHeaderPtr
;
3160 for (TempHeaderPtr
= MemoryHeader
; TempHeaderPtr
!= NULL
; TempHeaderPtr
= TempHeaderPtr
->Next
) {
3161 if (TempHeaderPtr
->Next
== NULL
) {
3162 TempHeaderPtr
->Next
= NewMemoryHeader
;
3173 Map address of request structure buffer.
3175 @param Uhc The UHCI device.
3176 @param Request The user request buffer.
3177 @param MappedAddr Mapped address of request.
3178 @param Map Identificaion of this mapping to return.
3180 @return EFI_SUCCESS Success.
3181 @return EFI_DEVICE_ERROR Fail to map the user request.
3185 UhciMapUserRequest (
3186 IN USB_UHC_DEV
*Uhc
,
3187 IN OUT VOID
*Request
,
3188 OUT UINT8
**MappedAddr
,
3194 EFI_PHYSICAL_ADDRESS PhyAddr
;
3196 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
3199 EdkiiIoMmuOperationBusMasterRead
,
3206 if (!EFI_ERROR (Status
)) {
3207 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3214 Map address of user data buffer.
3216 @param Uhc The UHCI device.
3217 @param Direction Direction of the data transfer.
3218 @param Data The user data buffer.
3219 @param Len Length of the user data.
3220 @param PktId Packet identificaion.
3221 @param MappedAddr Mapped address to return.
3222 @param Map Identificaion of this mapping to return.
3224 @return EFI_SUCCESS Success.
3225 @return EFI_DEVICE_ERROR Fail to map the user data.
3230 IN USB_UHC_DEV
*Uhc
,
3231 IN EFI_USB_DATA_DIRECTION Direction
,
3235 OUT UINT8
**MappedAddr
,
3240 EFI_PHYSICAL_ADDRESS PhyAddr
;
3242 Status
= EFI_SUCCESS
;
3244 switch (Direction
) {
3247 // BusMasterWrite means cpu read
3249 *PktId
= INPUT_PACKET_ID
;
3252 EdkiiIoMmuOperationBusMasterWrite
,
3259 if (EFI_ERROR (Status
)) {
3263 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3267 *PktId
= OUTPUT_PACKET_ID
;
3270 EdkiiIoMmuOperationBusMasterRead
,
3277 if (EFI_ERROR (Status
)) {
3281 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
3285 if ((Len
!= NULL
) && (*Len
!= 0)) {
3286 Status
= EFI_INVALID_PARAMETER
;
3290 *PktId
= OUTPUT_PACKET_ID
;
3296 Status
= EFI_INVALID_PARAMETER
;