diff options
Diffstat (limited to 'Core/EM/UsbRecovery/UhcPeimSrc/UhcPeim.c')
-rw-r--r-- | Core/EM/UsbRecovery/UhcPeimSrc/UhcPeim.c | 3575 |
1 files changed, 3575 insertions, 0 deletions
diff --git a/Core/EM/UsbRecovery/UhcPeimSrc/UhcPeim.c b/Core/EM/UsbRecovery/UhcPeimSrc/UhcPeim.c new file mode 100644 index 0000000..ee535dd --- /dev/null +++ b/Core/EM/UsbRecovery/UhcPeimSrc/UhcPeim.c @@ -0,0 +1,3575 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2006, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// +// $Header: /Alaska/SOURCE/Modules/USBRecovery/UhcPeimSrc/UhcPeim.c 17 11/24/12 5:45a Ryanchou $ +// +// $Revision: 17 $ +// +// $Date: 11/24/12 5:45a $ +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USBRecovery/UhcPeimSrc/UhcPeim.c $ +// +// 17 11/24/12 5:45a Ryanchou +// [TAG] EIP103990 +// [Category] Improvement +// [Description] Synchronized with USB PEI module 4.6.3_USB_08.10.24. +// [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c, +// BotPeim.c, BotPeim.h, PeiAtapi.c, UsbBotPeim.c, UsbBotPeim.h, +// HubPeim.c, UsbPeim.c, XhciPei.c, XhciPei.h, HubPeim.h, PeiUsbLib.c, +// PeiUsbLib.h, UsbPeim.h +// +// 16 8/23/12 10:00p Wilsonlee +// [TAG] EIP97069 +// [Category] Improvement +// [Description] Reset root port algorythm update. +// [Files] EhciPei.c, EhciPei.h, OhciPei.c, OhciPei.h, UhcPeim.c, +// UhcPeim.h, UsbPeim.c, usb.h +// +// 15 1/18/11 1:01a Ryanchou +// [TAG] EIP47931 +// [Category] Improvement +// [Description] Added USB 3.0 hub support. +// [Files] EhciPei.c, EhciPei.h, HubPeim.c, HubPeim.h, OhciPei.c, +// OhciPei.h, UhcPeim.c, UhcPeim.h, usb.h, UsbHostController.h, +// UsbIoPeim.c, UsbPeim.c, UsbPeim.h, XhciPei.c, XhciPei.h +// +// 14 10/22/10 2:53a Rameshr +// [TAG]- EIP 43687 +// [Category]-IMPROVEMENT +// [Description]- Build warning from UsbRecovery driver - +// UsbHostController.obj : warning LNK4221: no public symbols found; +// archive member will be inaccessible. +// [Files]- uhcpeim.c, usbpeim.c, UsbHostcontroller.h +// +// 13 10/12/10 11:19a Olegi +// XHCI support added. +// +// 12 4/06/10 3:32p Fasihm +// EIP#31987 - Added the generic USBRecovery Fix in the module. +// +// 11 4/29/09 2:13p Olegi +// Added TreansactionTranslator to UHCI Bulk transfer. +// +// 10 3/17/09 5:06p Olegi +// Added TransactionTranslator for slow/full speed devices behind USB2 +// hub. +// +// 9 3/03/09 7:20p Olegi +// Changed the type of MaxPktSize from UINT8 to UINT16. +// +// 8 11/19/08 12:03p Rameshraju +// Continue to initilize other UCHI controllers on the system when Uchi +// controller initilization is failed. +// +// 7 10/23/08 2:00p Michaela +// Removed UsbDebug.h include +// +// 6 10/21/08 5:57p Michaela +// Added EHCI-related fixes for issues +// that may occur if EHCI is used before +// USB Recovery is invoked: +// Added SDL Tokens: +// PEI_EHCI_PCI_BDFS and +// PEI_EHCI_MEM_BASE_ADDRESSES. +// +// Removed/modified some debugging +// development code: +// Removed SDL Tokens: +// USBR_DEBUG_SUPPORT and +// USBR_SERIAL_PORT_AVAILABLE +// Removed Elinks: +// UsbRecoveryDebug_DIR and +// $(BUILD_DIR)\UsbRecoveryDebugDxe.ffs +// Modified SDL Token: +// FORCE_RECOVERY to default value of 0. +// +// (See this module's Help documentation +// for more information.) +// +// 5 7/18/08 5:05p Michaela +// 1 File-level debugging is now available +// 2 AMI_USB_DEBUG_INTERFACE.WaitConsoleKey() now returns +// the keypress so that conditional debugging can +// be dynamic (alphanumeric keys only) +// 3 Added more function headers. +// 4 Removed code that will never be used (I.e., Bala?). +// 5 Moved typedef, contants and extern declarations +// into header files. +// 6 Now all controller blocks are enabled for SB700 +// (EHCI controllers route to companion controller +// by default) +// 7 Removed unused constants and typedefs n OhciPei.h +// (also reorganized the file to make it more +// readable.) +// 8 Renamed many functions/variables according to +// coding standard. +// 9 Removed code initializing data structures for +// periodic lists, as this is not needed. +// 10 Removed the CONTROLLER_TYPE SDL token to +// allow UHCI and OHCI controllers to supported +// simultaneously. (modified MAKE files +// accordingly) +// +// 4 7/10/08 6:37p Michaela +// Updated to support OHCI controllers +// +// 3 10/23/07 5:40p Ambikas +// +// 2 8/17/07 4:06p Ambikas +// +// 1 9/22/06 12:21p Sivagarn +// - Initial Check-in +// - Included Recovery code in Source +// +//***************************************************************************** + +//<AMI_FHDR_START> +//---------------------------------------------------------------------------- +// +// Name: UhcPeim.C +// +// Description: This file belongs to "Framework". +// This file is modified by AMI to include copyright message, +// appropriate header and integration code. +// This file contains generic routines needed for USB recovery +// PEIM +// +//---------------------------------------------------------------------------- +//<AMI_FHDR_END> + +/*++ + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + --*/ + +/*++ + + Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + + Module Name: + + UhcPeim.c + + Abstract: + + Usb Host Controller PEIM + + --*/ + +#include "UhcPeim.h" + +#include EFI_PPI_DEFINITION( LoadFile ) +//#include "PeiUsbLib.h" + +EFI_GUID guidGetUhciController = EFI_PEI_GET_UHCI_CTRLER_GUID; +static EFI_GUID gPeiStallPpiGuid = EFI_PEI_STALL_PPI_GUID; +EFI_GUID gPeiCpuIoPpiInServiceTableGuid = + EFI_PEI_CPU_IO_PPI_INSTALLED_GUID; + +#define PAGESIZE 4096 +#include EFI_PPI_DEFINITION( LoadFile ) + + +// +// PEIM Entry Ppint +// +EFI_STATUS +UhcPeimEntry ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices ); + + +UINT32 +USBReadPortDW ( + IN USB_UHC_DEV *UhcDev, + IN UINT32 Port ); +void +PrintTD ( + TD_STRUCT *ptrTD, + USB_UHC_DEV *UhcDev ); +void +PrintQH ( + QH_STRUCT *ptrQH, + USB_UHC_DEV *UhcDev ); + +extern VOID ZeroMem ( + IN VOID *Buffer, + IN UINTN Size ); + + +EFI_STATUS UhcPeimEntry ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices ) +{ + PEI_CPU_IO_PPI *CpuIoPpi; + PEI_STALL_PPI *StallPpi; + EFI_PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi; + EFI_STATUS Status; + UINT8 Index; + UINTN ControllerType; + UINTN BaseAddress; + USB_UHC_DEV *UhcDev; + + // Locate the PEI_CPU_IO_PPI interface + if ( EFI_ERROR( (**PeiServices).LocatePpi( + PeiServices, &gPeiCpuIoPpiInServiceTableGuid, 0, NULL, + &CpuIoPpi ) ) ) { + return EFI_UNSUPPORTED; + } + + // Locate the PEI_STALL_PPI interface + if ( EFI_ERROR( (**PeiServices).LocatePpi( + PeiServices, &gPeiStallPpiGuid, 0, NULL, &StallPpi ) ) ) { + return EFI_UNSUPPORTED; + } + + // Locate the EFI_PEI_USB_CONTROLLER_PPI interface + if ( EFI_ERROR( (**PeiServices).LocatePpi( + PeiServices, &guidGetUhciController, 0, NULL, + &ChipSetUsbControllerPpi ) ) ) { + return EFI_UNSUPPORTED; + } + + //-------------------------------------------------- + // For each UHCI controller found: + // + // 1) Verify it is a UHCI controller + // 2) Allocate and initialize a USB_UHC_DEV structure + // to manage the controller. + // 3) Initialize the controller. + // 4) Install the PEI_USB_HOST_CONTROLLER_PPI interface. + // + //-------------------------------------------------- + Index = 0; + while (TRUE) { + + // GetUhciControllerPpi() returns error if no more controllers + if ( EFI_ERROR( ChipSetUsbControllerPpi->GetUhciControllerPpi( + PeiServices, ChipSetUsbControllerPpi, Index, + &ControllerType, + &BaseAddress ) ) ) { + break; + } + + // This PEIM is for UHC type controller. + if (ControllerType != PEI_UHCI_CONTROLLER) { + Index++; + continue; + } + + // Allocate and initialize USB_UHC_DEV members + if ( EFI_ERROR( (**PeiServices).AllocatePages( + PeiServices, EfiConventionalMemory, + sizeof(USB_UHC_DEV) / PAGESIZE + 1, + (EFI_PHYSICAL_ADDRESS *) &UhcDev ) ) ) { + return EFI_OUT_OF_RESOURCES; + } + UhcDev->Signature = USB_UHC_DEV_SIGNATURE; + UhcDev->PeiServices = PeiServices; + UhcDev->CpuIoPpi = (*PeiServices)->CpuIo; + UhcDev->StallPpi = StallPpi; + UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress; + + // Initialize Uhc's hardware + Status = InitializeUsbHC( UhcDev ); + if ( EFI_ERROR( Status ) ) { + PEI_TRACE( (EFI_D_ERROR, PeiServices, + "UHCPEIM: BaseAddress %x\n", BaseAddress) ); + PEI_TRACE( (EFI_D_ERROR, PeiServices, + "UHCPEIM: InitializeUSbHC Status %r\n", Status) ); + // error in initilizing the controller , so try for next controller + Index++; + continue; + } + + // Init local memory management service + Status = InitializeMemoryManagement( UhcDev ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + // Update PEI_USB_HOST_CONTROLLER_PPI members + UhcDev->UsbHostControllerPpi.ControlTransfer = UhcControlTransfer; + UhcDev->UsbHostControllerPpi.BulkTransfer = UhcBulkTransfer; + UhcDev->UsbHostControllerPpi.GetRootHubPortNumber = + UhcGetRootHubPortNumber; + UhcDev->UsbHostControllerPpi.GetRootHubPortStatus = + UhcGetRootHubPortStatus; + UhcDev->UsbHostControllerPpi.SetRootHubPortFeature = + UhcSetRootHubPortFeature; + UhcDev->UsbHostControllerPpi.ClearRootHubPortFeature = + UhcClearRootHubPortFeature; + UhcDev->UsbHostControllerPpi.PreConfigureDevice = NULL; + UhcDev->UsbHostControllerPpi.EnableEndpoints = NULL; + + // Install the PEI_USB_HOST_CONTROLLER_PPI interface + // for this controller + UhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI + | + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + UhcDev->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid; + UhcDev->PpiDescriptor.Ppi = &UhcDev->UsbHostControllerPpi; + if ( EFI_ERROR( (**PeiServices).InstallPpi( + PeiServices, &UhcDev->PpiDescriptor ) ) ) { + return EFI_UNSUPPORTED; + } + + Index++; + } + + PEI_TRACE( (EFI_D_ERROR, PeiServices, "UHCPEIM: Exit() \n") ); + + return EFI_SUCCESS; +} + + +EFI_STATUS UhcControlTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 DeviceSpeed, + IN UINT8 MaximumPacketLength, + IN UINT16 TransactionTranslator OPTIONAL, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data OPTIONAL, + IN OUT UINTN *DataLength OPTIONAL, + IN UINTN TimeOut, + OUT UINT32 *TransferResult ) +{ + USB_UHC_DEV *UhcDev; + UINT32 StatusReg; + UINT32 FrameNumReg; + UINT8 PktID; + QH_STRUCT *ptrQH; + TD_STRUCT *ptrTD; + TD_STRUCT *ptrPreTD; + TD_STRUCT *ptrSetupTD; + TD_STRUCT *ptrStatusTD; + EFI_STATUS Status; + UINTN i; + UINT32 DataLen; + UINT8 *ptrDataSource; + UINT8 *ptr; + UINT8 DataToggle; + UINT16 LoadFrameListIndex; + + UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS( This ); + + StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS; + FrameNumReg = UhcDev->UsbHostControllerBaseAddress + USBFRNUM; + + PktID = INPUT_PACKET_ID; + // PEI_TRACE ((EFI_D_ERROR, PeiServices, "Enter UhcControlTransfer\n")); + + if (Request == NULL || TransferResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // if errors exist that cause host controller halt, + // then return EFI_DEVICE_ERROR. + // + if ( IsHCHalted( UhcDev, StatusReg ) || + IsHCProcessErr( UhcDev, StatusReg ) || + IsHostSysErr( UhcDev, StatusReg ) ) { + + ClearStatusReg( UhcDev, StatusReg ); + *TransferResult = EFI_USB_ERR_SYSTEM; + PEI_TRACE( (EFI_D_ERROR, PeiServices, "UHCIPEIM: Ctrler halted\n") ); + return EFI_DEVICE_ERROR; + } + + ClearStatusReg( UhcDev, StatusReg ); + + // + // Setup Stage of Control Transfer + // + + // + // create QH structure and init + // + Status = CreateQH( UhcDev, &ptrQH ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + // + // generate Setup Stage TD + // + + GenSetupStageTD( UhcDev, DeviceAddress, 0, + DeviceSpeed, (UINT8 *) Request, + sizeof(EFI_USB_DEVICE_REQUEST), &ptrSetupTD ); + + // + // link setup TD structures to QH structure + // + LinkTDToQH( ptrQH, ptrSetupTD ); + + ptrPreTD = ptrSetupTD; + + // + // Data Stage of Control Transfer + // + switch (TransferDirection) + { + + case EfiUsbDataIn: + PktID = INPUT_PACKET_ID; + ptrDataSource = Data; + DataLen = (UINT32) *DataLength; + ptr = ptrDataSource; + break; + + case EfiUsbDataOut: + PktID = OUTPUT_PACKET_ID; + ptrDataSource = Data; + DataLen = (UINT32) *DataLength; + ptr = ptrDataSource; + break; + + // + // no data stage + // + case EfiUsbNoData: + if (*DataLength != 0) { + return EFI_INVALID_PARAMETER; + } + PktID = OUTPUT_PACKET_ID; + ptrDataSource = NULL; + DataLen = 0; + ptr = NULL; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + DataToggle = 1; + + ptrTD = ptrSetupTD; + while (DataLen > 0) { + + // + // create TD structures and link together + // + + UINT8 pktsize; + + // + // pktsize is the data load size of each TD carries. + // + pktsize = (UINT8) DataLen; + if (DataLen > MaximumPacketLength) { + pktsize = MaximumPacketLength; + } + GenDataTD( UhcDev, DeviceAddress, 0, ptr, pktsize, PktID, DataToggle, + DeviceSpeed, &ptrTD ); + + // + // Link two TDs in vertical depth + // + LinkTDToTD( ptrPreTD, ptrTD ); + ptrPreTD = ptrTD; + + DataToggle ^= 1; + ptr += pktsize; + DataLen -= pktsize; + } + + // + // ptrPreTD points to the last TD before the Setup-Stage TD. + // + ptrPreTD = ptrTD; + + // + // Status Stage of Control Transfer + // + if (PktID == OUTPUT_PACKET_ID) { + PktID = INPUT_PACKET_ID; + } + else { + PktID = OUTPUT_PACKET_ID; + } + // + // create Status Stage TD structure + // + CreateStatusTD( UhcDev, + DeviceAddress, + 0, + PktID, + DeviceSpeed, + &ptrStatusTD ); + + LinkTDToTD( ptrPreTD, ptrStatusTD ); + + // + // get the frame list index that the QH-TDs will be linked to. + // + LoadFrameListIndex = (UINT16) ( ( GetCurrentFrameNumber + ( UhcDev, FrameNumReg ) ) % 1024 ); + + // + // link QH-TDs to total 500 frame list entry to speed up the execution. + // + for (i = 0; i < 500; i++) { + + // + // put the QH-TDs directly or indirectly into the proper place in + // the Frame List + // + LinkQHToFrameList( UhcDev->FrameListEntry, + (UINT16) ( (LoadFrameListIndex + i) % 1024 ), ptrQH ); + } + + // + // Poll QH-TDs execution and get result. + // detail status is returned + // + //TimeOut = 1000; //bala + + Status = ExecuteControlTransfer( UhcDev, ptrSetupTD, + LoadFrameListIndex, DataLength, + TimeOut, TransferResult ); + // + // TRUE means must search other framelistindex + // + DeleteSingleQH( UhcDev, ptrQH, LoadFrameListIndex, TRUE ); + DeleteQueuedTDs( UhcDev, ptrSetupTD ); + + // + // if has errors that cause host controller halt, then return + // EFI_DEVICE_ERROR directly. + // + if ( IsHCHalted( UhcDev, StatusReg ) || + IsHCProcessErr( UhcDev, StatusReg ) || + IsHostSysErr( UhcDev, StatusReg ) ) { + + ClearStatusReg( UhcDev, StatusReg ); + *TransferResult |= EFI_USB_ERR_SYSTEM; + PEI_TRACE( (EFI_D_ERROR, PeiServices, + "UHCIPEIM: Ctrl transfer failed\n") ); + return EFI_DEVICE_ERROR; + } + + ClearStatusReg( UhcDev, StatusReg ); + + // PEI_TRACE ((EFI_D_ERROR, PeiServices, "Exit UhcControlTransfer\n")); + return Status; +} + + +void PrintTD ( + TD_STRUCT *ptrTD, + USB_UHC_DEV *UhcDev ) +{ + EFI_PEI_SERVICES **PeiServices; + UINT8 i; + UINT32 *Tmp; + + PeiServices = UhcDev->PeiServices; + PEI_TRACE( (EFI_D_ERROR, PeiServices, "UHCPIM: TD ... \n") ); + + Tmp = (UINT32 *) ptrTD; + for (i = 0; i < 4; i++) + { + PEI_TRACE( (EFI_D_ERROR, PeiServices, " %x", Tmp[i]) ); + + } + PEI_TRACE( (EFI_D_ERROR, PeiServices, "\n") ); + +} + + +void PrintQH ( + QH_STRUCT *ptrQH, + USB_UHC_DEV *UhcDev ) +{ + EFI_PEI_SERVICES **PeiServices; + UINT8 i; + UINT32 *Tmp; + + PeiServices = UhcDev->PeiServices; + PEI_TRACE( (EFI_D_ERROR, PeiServices, "UHCPIM: QH ... \n") ); + + Tmp = (UINT32 *) ptrQH; + for (i = 0; i < 2; i++) + { + PEI_TRACE( (EFI_D_ERROR, PeiServices, " %x", Tmp[i]) ); + + } + PEI_TRACE( (EFI_D_ERROR, PeiServices, "\n") ); + +} + + +EFI_STATUS UhcBulkTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINT16 MaximumPacketLength, + IN UINT16 TransactionTranslator OPTIONAL, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult ) +{ + USB_UHC_DEV *UhcDev; + UINT32 StatusReg; + UINT32 FrameNumReg; + + UINT32 DataLen; + + QH_STRUCT *ptrQH; + TD_STRUCT *ptrFirstTD; + TD_STRUCT *ptrTD; + TD_STRUCT *ptrPreTD; + + UINT16 LoadFrameListIndex; + UINT16 SavedFrameListIndex; + + UINT8 PktID; + UINT8 *ptrDataSource; + UINT8 *ptr; + + BOOLEAN IsFirstTD; + + EFI_STATUS Status; + UINT32 i; + + EFI_USB_DATA_DIRECTION TransferDirection; + // + // Used to calculate how many entries are linked to the specified bulk + // transfer QH-TDs + // + UINT32 LinkTimes; + + BOOLEAN ShortPacketEnable; + + UINT16 CommandContent; + + UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS( This ); + + // + // Enable the maximum packet size (64bytes) + // that can be used for full speed bandwidth reclamation + // at the end of a frame. + // + CommandContent = USBReadPortW( UhcDev, + UhcDev->UsbHostControllerBaseAddress + USBCMD ); + + if ( (CommandContent & USBCMD_MAXP) != USBCMD_MAXP ) { + CommandContent |= USBCMD_MAXP; + USBWritePortW( UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD, + CommandContent ); + + } + + StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS; + FrameNumReg = UhcDev->UsbHostControllerBaseAddress + USBFRNUM; + + // + // these code lines are added here per complier's strict demand + // + PktID = INPUT_PACKET_ID; + ptrTD = NULL; + ptrFirstTD = NULL; + ptrPreTD = NULL; + LinkTimes = 1; + DataLen = 0; + ptr = NULL; + + ShortPacketEnable = FALSE; + + if ( (DataLength == 0) || (Data == NULL) + || (TransferResult == NULL) ) { + return EFI_INVALID_PARAMETER; + } + + if ( (*DataToggle != 1) && (*DataToggle != 0) ) { + return EFI_INVALID_PARAMETER; + } + + if (MaximumPacketLength != 8 && MaximumPacketLength != 16 + && MaximumPacketLength != 32 && MaximumPacketLength != 64) { + return EFI_INVALID_PARAMETER; + } + + // + // if has errors that cause host controller halt, then return + // EFI_DEVICE_ERROR directly. + // + if ( IsHCHalted( UhcDev, StatusReg ) || + IsHCProcessErr( UhcDev, StatusReg ) || + IsHostSysErr( UhcDev, StatusReg ) ) { + + ClearStatusReg( UhcDev, StatusReg ); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + + ClearStatusReg( UhcDev, StatusReg ); + + // + // construct QH and TD data structures, + // and link them together + // + if (EndPointAddress & 0x80) { + TransferDirection = EfiUsbDataIn; + } + else { + TransferDirection = EfiUsbDataOut; + } + + switch (TransferDirection) + { + + case EfiUsbDataIn: + ShortPacketEnable = TRUE; + PktID = INPUT_PACKET_ID; + ptrDataSource = Data; + DataLen = (UINT32) *DataLength; + ptr = ptrDataSource; + break; + + case EfiUsbDataOut: + PktID = OUTPUT_PACKET_ID; + ptrDataSource = Data; + DataLen = (UINT32) *DataLength; + ptr = ptrDataSource; + break; + } + + // + // create QH structure and init + // + Status = CreateQH( UhcDev, &ptrQH ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + // + // Self link the QH, to make NAK TD retried in one frame. + // + //SelfLinkBulkTransferQH (ptrQH); + + // + // i is used to calculate the total number of TDs. + // + i = 0; + + IsFirstTD = TRUE; + while (DataLen > 0) { + + // + // create TD structures and link together + // + UINT16 pktsize; + + pktsize = (UINT16) DataLen; + if (DataLen > MaximumPacketLength) { + pktsize = MaximumPacketLength; + } + GenDataTD( UhcDev, DeviceAddress, EndPointAddress, ptr, + pktsize, PktID, *DataToggle, USB_FULL_SPEED_DEVICE, &ptrTD ); + + // + // Enable short packet detection. + // (default action is disabling short packet detection) + // + if (ShortPacketEnable) { + EnableorDisableTDShortPacket( ptrTD, TRUE ); + } + + if (IsFirstTD) { + ptrFirstTD = ptrTD; + ptrFirstTD->ptrNextTD = NULL; + IsFirstTD = FALSE; + } + else { + // + // Link two TDs in vertical depth + // + LinkTDToTD( ptrPreTD, ptrTD ); + } + + i++; + + ptrPreTD = ptrTD; + + *DataToggle ^= 1; + ptr += pktsize; + DataLen -= pktsize; + } + + // + // link TD structures to QH structure + // + LinkTDToQH( ptrQH, ptrFirstTD ); + + // + // calculate how many entries are linked to the specified bulk + // transfer QH-TDs the below values are referred to the USB spec + // revision1.1. + // + switch (MaximumPacketLength) + { + case 8: + LinkTimes = i / 71 + 1; + break; + + case 16: + LinkTimes = i / 51 + 1; + break; + + case 32: + LinkTimes = i / 33 + 1; + break; + + case 64: + LinkTimes = i / 19 + 1; + break; + } + LinkTimes += 200; // redundant + + // + // put QH-TDs into Frame list + // + + LoadFrameListIndex = (UINT16) + ( ( GetCurrentFrameNumber( UhcDev, + FrameNumReg ) ) % 1024 ); + SavedFrameListIndex = LoadFrameListIndex; + + for (i = 0; i <= LinkTimes; i++) { + + // + // put the QH-TD directly or indirectly into the proper + // place in the Frame List + // + LinkQHToFrameList( UhcDev->FrameListEntry, LoadFrameListIndex, ptrQH ); + + LoadFrameListIndex += 1; + LoadFrameListIndex %= 1024; + } + + LoadFrameListIndex = SavedFrameListIndex; + + // + // Execute QH-TD and get result + // + // + // detail status is put into the Result field in the pIRP + // the Data Toggle value is also re-updated to the value + // of the last successful TD + // + Status = ExecBulkTransfer( UhcDev, ptrFirstTD, + LoadFrameListIndex, DataLength, + DataToggle, TimeOut, TransferResult ); + + // + // Delete Bulk transfer QH-TD structure + // and maitain the pointers in the Frame List + // and other pointers in related QH structure + // + + + // TRUE means must search other framelistindex + DeleteSingleQH( UhcDev, ptrQH, LoadFrameListIndex, TRUE ); + DeleteQueuedTDs( UhcDev, ptrFirstTD ); + + // + // if has errors that cause host controller halt, then + // return EFI_DEVICE_ERROR directly. + // + if ( IsHCHalted( UhcDev, StatusReg ) || + IsHCProcessErr( UhcDev, StatusReg ) || + IsHostSysErr( UhcDev, StatusReg ) ) { + + ClearStatusReg( UhcDev, StatusReg ); + *TransferResult |= EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + + ClearStatusReg( UhcDev, StatusReg ); + + return Status; +} + + +EFI_STATUS UhcGetRootHubPortNumber ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + OUT UINT8 *PortNumber ) +{ + USB_UHC_DEV *UhcDev; + UINT32 PSAddr; + UINT16 RHPortControl; + UINT32 i; + + UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS( This ); + + if (PortNumber == NULL) { + return EFI_INVALID_PARAMETER; + } + + *PortNumber = 0; + + for (i = 0; i < 2; i++) { + PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + i * 2; + //RHPortControl = ReadRootPortReg(UhcDev->CpuIoPpi,PSAddr); + RHPortControl = USBReadPortW( UhcDev, PSAddr ); + // + // Port Register content is valid + // + if (RHPortControl != 0xff) { + (*PortNumber)++; + } + } + + return EFI_SUCCESS; +} + + +EFI_STATUS UhcGetRootHubPortStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus ) +{ + USB_UHC_DEV *UhcDev; + UINT32 PSAddr; + UINT16 RHPortStatus; // root hub port status + UINT8 TotalPortNumber; + + if (PortStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + + UhcGetRootHubPortNumber( PeiServices, This, &TotalPortNumber ); + if (PortNumber > TotalPortNumber) { + return EFI_INVALID_PARAMETER; + } + + UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS( This ); + PSAddr = UhcDev->UsbHostControllerBaseAddress + + USBPORTSC1 + (PortNumber - 1) * 2; + + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + //RHPortStatus = ReadRootPortReg (UhcDev->CpuIoPpi,PSAddr) ; + RHPortStatus = USBReadPortW( UhcDev, PSAddr ); + + // + // Fill Port Status bits + // + + // + // Current Connect Status + // + if (RHPortStatus & USBPORTSC_CCS) { + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + } + + // + // Port Enabled/Disabled + // + if (RHPortStatus & USBPORTSC_PED) { + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + } + + // + // Port Suspend + // + if (RHPortStatus & USBPORTSC_SUSP) { + PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; + } + + // + // Port Reset + // + if (RHPortStatus & USBPORTSC_PR) { + PortStatus->PortStatus |= USB_PORT_STAT_RESET; + } + + // + // Low Speed Device Attached + // + if (RHPortStatus & USBPORTSC_LSDA) { + PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; + } + + // + // Fill Port Status Change bits + // + + // + // Connect Status Change + // + if (RHPortStatus & USBPORTSC_CSC) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; + } + + // + // Port Enabled/Disabled Change + // + if (RHPortStatus & USBPORTSC_PEDC) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; + } + if (UhcDev->PortResetStatusChangeMap & (1 << (PortNumber - 1))) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET; + } + return EFI_SUCCESS; +} + + +EFI_STATUS UhcSetRootHubPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature ) +{ + USB_UHC_DEV *UhcDev; + UINT32 PSAddr; + UINT32 CommandRegAddr; + UINT16 RHPortControl; // root hub port status + UINT8 TotalPortNumber; + + UhcGetRootHubPortNumber( PeiServices, This, &TotalPortNumber ); + if (PortNumber > TotalPortNumber) { + return EFI_INVALID_PARAMETER; + } + + UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS( This ); + PSAddr = UhcDev->UsbHostControllerBaseAddress + + USBPORTSC1 + (PortNumber - 1) * 2; + CommandRegAddr = UhcDev->UsbHostControllerBaseAddress + USBCMD; + + RHPortControl = USBReadPortW( UhcDev, PSAddr ); + + switch (PortFeature) + { + + case EfiUsbPortSuspend: + if ( !(USBReadPortW( UhcDev, CommandRegAddr ) & USBCMD_EGSM) ) { + // + // if global suspend is not active, can set port suspend + // + RHPortControl &= 0xfff5; + RHPortControl |= USBPORTSC_SUSP; + } + break; + + case EfiUsbPortReset: + RHPortControl &= 0xfff5; + RHPortControl |= USBPORTSC_PR; // Set the reset bit + USBWritePortW( UhcDev, PSAddr, RHPortControl ); + UhcDev->StallPpi->Stall (UhcDev->PeiServices,UhcDev->StallPpi,10 * 1000); + RHPortControl = USBReadPortW( UhcDev, PSAddr ); + RHPortControl &= 0xfff5; + RHPortControl &= ~USBPORTSC_PR; + USBWritePortW( UhcDev, PSAddr, RHPortControl ); + UhcDev->PortResetStatusChangeMap |= (1 << (PortNumber - 1)); + return EFI_SUCCESS; + + case EfiUsbPortPower: + break; + + case EfiUsbPortEnable: + RHPortControl &= 0xfff5; + RHPortControl |= USBPORTSC_PED; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + //WriteRootPortReg(UhcDev->CpuIoPpi,PSAddr,RHPortControl) ; + USBWritePortW( UhcDev, PSAddr, RHPortControl ); + + return EFI_SUCCESS; +} + + +EFI_STATUS UhcClearRootHubPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature ) +{ + USB_UHC_DEV *UhcDev; + UINT32 PSAddr; + UINT16 RHPortControl; + UINT8 TotalPortNumber; + + UhcGetRootHubPortNumber( PeiServices, This, &TotalPortNumber ); + + if (PortNumber > TotalPortNumber) { + return EFI_INVALID_PARAMETER; + } + + UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS( This ); + PSAddr = UhcDev->UsbHostControllerBaseAddress + + USBPORTSC1 + (PortNumber - 1) * 2; + + //RHPortControl = ReadRootPortReg (UhcDev->CpuIoPpi,PSAddr) ; + RHPortControl = USBReadPortW( UhcDev, PSAddr ); + + switch (PortFeature) + { + + // + // clear PORT_ENABLE feature means disable port. + // + case EfiUsbPortEnable: + RHPortControl &= 0xfff5; + RHPortControl &= ~USBPORTSC_PED; + break; + + // + // clear PORT_SUSPEND feature means resume the port. + // (cause a resume on the specified port if in suspend mode) + // + case EfiUsbPortSuspend: + RHPortControl &= 0xfff5; + RHPortControl &= ~USBPORTSC_SUSP; + break; + + // + // no operation + // + case EfiUsbPortPower: + break; + + // + // clear PORT_RESET means clear the reset signal. + // + case EfiUsbPortReset: + RHPortControl &= 0xfff5; + RHPortControl &= ~USBPORTSC_PR; + break; + + // + // clear connect status change + // + case EfiUsbPortConnectChange: + RHPortControl &= 0xfff5; + RHPortControl |= USBPORTSC_CSC; + break; + + // + // clear enable/disable status change + // + case EfiUsbPortEnableChange: + RHPortControl &= 0xfff5; + RHPortControl |= USBPORTSC_PEDC; + break; + + // + // root hub does not support this request + // + case EfiUsbPortSuspendChange: + break; + + // + // root hub does not support this request + // + case EfiUsbPortOverCurrentChange: + break; + + // + // root hub does not support this request + // + case EfiUsbPortResetChange: + UhcDev->PortResetStatusChangeMap &= ~(1 << (PortNumber - 1)); + return EFI_SUCCESS; + + default: + return EFI_INVALID_PARAMETER; + } + + //WriteRootPortReg(UhcDev->CpuIoPpi,PSAddr,RHPortControl) ; + USBWritePortW( UhcDev, PSAddr, RHPortControl ); + + return EFI_SUCCESS; +} + + +EFI_STATUS InitializeUsbHC ( + USB_UHC_DEV *UhcDev ) +{ + EFI_STATUS Status; + UINT32 FrameListBaseAddrReg; + UINT32 StatusReg; + UINT32 CommandReg; + UINT16 Command; + UINTN Delay; + + // Create and Initialize Frame List For the Host Controller. + Status = CreateFrameList( UhcDev ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + FrameListBaseAddrReg = UhcDev->UsbHostControllerBaseAddress + + USBFLBASEADD; + StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS; + CommandReg = UhcDev->UsbHostControllerBaseAddress + USBCMD; + + //Issue a Global reset + Command = USBReadPortW (UhcDev,CommandReg); + Command |= USBCMD_GRESET ; + USBWritePortW (UhcDev,CommandReg,Command); + + Delay = (100 * STALL_1_MILLI_SECOND / 50) + 1; + + do { + UhcDev->StallPpi->Stall (UhcDev->PeiServices,UhcDev->StallPpi,50); + } while(Delay--); + + Command = USBReadPortW (UhcDev,CommandReg); + Command &= !USBCMD_GRESET ; + USBWritePortW (UhcDev,CommandReg,Command); + + Delay = (100 * STALL_1_MILLI_SECOND / 50) + 1; + + do { + UhcDev->StallPpi->Stall (UhcDev->PeiServices,UhcDev->StallPpi,50); + } while(Delay--); + + // Set Frame List Base Address to the specific register to + // inform the hardware. + SetFrameListBaseAddress( UhcDev, FrameListBaseAddrReg, + (UINT32) (UINTN) (UhcDev->FrameListEntry) ); + + // Make the Host Controller in Run state. + if ( IsHostSysErr( UhcDev, StatusReg ) + || IsHCProcessErr( UhcDev, StatusReg ) ) { + return EFI_DEVICE_ERROR; + } + + Command = USBReadPortW( UhcDev, CommandReg ); + Command |= USBCMD_RS; + + USBWritePortW( UhcDev, CommandReg, Command ); + return EFI_SUCCESS; +} + + +EFI_STATUS CreateFrameList ( + USB_UHC_DEV *UhcDev ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS FrameListBaseAddr; + + // + // The Frame List ocupies 4K bytes, + // and must be aligned on 4-Kbyte boundaries. + // + Status = ( **(UhcDev->PeiServices) ).AllocatePages( + UhcDev->PeiServices, + EfiConventionalMemory, + 1, + &FrameListBaseAddr ); + + if (Status != EFI_SUCCESS) { + return EFI_OUT_OF_RESOURCES; + } + + UhcDev->FrameListEntry = (FRAMELIST_ENTRY *) ( (UINTN) FrameListBaseAddr ); + + InitFrameList( UhcDev ); + + return EFI_SUCCESS; +} + + +VOID InitFrameList ( + USB_UHC_DEV *UhcDev ) +{ + FRAMELIST_ENTRY *FrameListPtr; + UINTN i; + + // + // Validate each Frame List Entry + // + FrameListPtr = UhcDev->FrameListEntry; + for (i = 0; i < 1024; i++) { + FrameListPtr->FrameListPtrTerminate = 1; + FrameListPtr->FrameListPtr = 0; + FrameListPtr->FrameListPtrQSelect = 0; + FrameListPtr->FrameListRsvd = 0; + FrameListPtr++; + } +} + + +UINT16 USBReadPortW ( + IN USB_UHC_DEV *UhcDev, + IN UINT32 Port ) +{ + UINT16 Data; + + // + // Perform 16bit Read + // + UhcDev->CpuIoPpi->Io.Read( + UhcDev->PeiServices, + UhcDev->CpuIoPpi, + EfiPeiCpuIoWidthUint16, + (UINT64) Port, + 1, + &Data + ); + + return Data; +} + + +VOID USBWritePortW ( + IN USB_UHC_DEV *UhcDev, + IN UINT32 Port, + IN UINT16 Data ) +{ + // + // Perform 16bit Write + // + UhcDev->CpuIoPpi->Io.Write( + UhcDev->PeiServices, + UhcDev->CpuIoPpi, + EfiPeiCpuIoWidthUint16, + (UINT64) Port, + 1, + &Data + ); +} + + +VOID USBWritePortDW ( + IN USB_UHC_DEV *UhcDev, + IN UINT32 Port, + IN UINT32 Data ) +{ + // + // Perform 32bit Write + // + + UhcDev->CpuIoPpi->Io.Write( + UhcDev->PeiServices, + UhcDev->CpuIoPpi, + EfiPeiCpuIoWidthUint32, + (UINT64) Port, + 1, + &Data + ); +} + + +UINT32 USBReadPortDW ( + IN USB_UHC_DEV *UhcDev, + IN UINT32 Port ) +{ + UINT32 Data; + + // + // Perform 16bit Read + // + UhcDev->CpuIoPpi->Io.Read( + UhcDev->PeiServices, + UhcDev->CpuIoPpi, + EfiPeiCpuIoWidthUint32, + (UINT64) Port, + 1, + &Data + ); + return Data; +} + + +// +// USB register-base helper functions +// + +VOID ClearStatusReg ( + IN USB_UHC_DEV *UhcDev, + IN UINT32 STSAddr ) +{ + UINT16 UsbSts; + + // + // Clear the content of UHC's Status Register + // + UsbSts = 0x003f; + USBWritePortW( UhcDev, STSAddr, UsbSts ); + //WriteUHCStatusReg (PciIo,STSAddr,UsbSts); +} + + +BOOLEAN IsHostSysErr ( + USB_UHC_DEV *UhcDev, + UINT32 StatusRegAddr ) +{ + UINT16 StatusValue; + + // + // Detect whether the interrupt is caused by serious error. + // see "UHCI Design Guid". + // + StatusValue = USBReadPortW( UhcDev, StatusRegAddr ); + + if (StatusValue & USBSTS_HSE) { + return TRUE; + } + else { + return FALSE; + } +} + + +BOOLEAN IsHCProcessErr ( + USB_UHC_DEV *UhcDev, + UINT32 StatusRegAddr ) +{ + UINT16 StatusValue; + + // + // Detect whether the interrupt is caused by fatal error. + // see "UHCI Design Guid". + // + StatusValue = USBReadPortW( UhcDev, StatusRegAddr ); + + if (StatusValue & USBSTS_HCPE) { + return TRUE; + } + else { + return FALSE; + } +} + + +BOOLEAN IsHCHalted ( + USB_UHC_DEV *UhcDev, + UINT32 StatusRegAddr ) +{ + UINT16 StatusValue; + + // + // Detect whether the the Host Controller is halted. + // + StatusValue = USBReadPortW( UhcDev, StatusRegAddr ); + + if (StatusValue & USBSTS_HCH) { + return TRUE; + } + else { + return FALSE; + } +} + + +UINT16 GetCurrentFrameNumber ( + USB_UHC_DEV *UhcDev, + UINT32 FRNUMAddr ) +{ + // + // Gets value in the USB frame number register. + // + + return (UINT16) (USBReadPortW( UhcDev, FRNUMAddr ) & 0x03ff); +} + + +VOID SetFrameListBaseAddress ( + USB_UHC_DEV *UhcDev, + UINT32 FLBASEADDRReg, + UINT32 Addr ) +{ + // + // Sets value in the USB Frame List Base Address register. + // + USBWritePortDW( UhcDev, FLBASEADDRReg, (UINT32) (Addr & 0xfffff000) ); +} + + +//////////////////////////////////////////////////////////////// +// +// QH TD related Helper Functions +// +//////////////////////////////////////////////////////////////// + +// +// functions for QH +// +EFI_STATUS AllocateQHStruct ( + USB_UHC_DEV *UhcDev, + QH_STRUCT **ppQHStruct ) +{ + EFI_STATUS Status; + + *ppQHStruct = NULL; + + Status = UhcAllocatePool( UhcDev, MEM_QH_TD_TYPE, + (UINT8 **) ppQHStruct, sizeof(QH_STRUCT) ); + + if ( EFI_ERROR( Status ) ) { + return Status; + } + + ZeroMem( *ppQHStruct, sizeof(QH_STRUCT) ); + + return EFI_SUCCESS; +} + + +VOID InitQH ( + IN QH_STRUCT *ptrQH ) +{ + // + // Make QH ready + // + SetQHHorizontalValidorInvalid( ptrQH, FALSE ); + SetQHVerticalValidorInvalid( ptrQH, FALSE ); +} + + +EFI_STATUS CreateQH ( + USB_UHC_DEV *UhcDev, + QH_STRUCT **pptrQH ) +{ + EFI_STATUS Status; + + // + // allocate align memory for QH_STRUCT + // + Status = AllocateQHStruct( UhcDev, pptrQH ); + if ( EFI_ERROR( Status ) ) { + return EFI_OUT_OF_RESOURCES; + } + + // + // init each field of the QH_STRUCT + // + InitQH( *pptrQH ); + + return EFI_SUCCESS; +} + + +VOID SetQHHorizontalLinkPtr ( + IN QH_STRUCT *ptrQH, + IN VOID *ptrNext ) +{ + // + // Since the QH_STRUCT is aligned on 16-byte boundaries, + // Only the highest 28bit of the address is valid + // (take 32bit address as an example). + // + ptrQH->QH.QHHorizontalPtr = (UINT32) (UINTN) ptrNext >> 4; +} + + +VOID *GetQHHorizontalLinkPtr ( + IN QH_STRUCT *ptrQH ) +{ + // + // Restore the 28bit address to 32bit address + //(take 32bit address as an example) + // + return ( (VOID *) (UINTN) ( (ptrQH->QH.QHHorizontalPtr) << 4 ) ); +} + + +VOID SetQHHorizontalQHorTDSelect ( + IN QH_STRUCT *ptrQH, + IN BOOLEAN bQH ) +{ + // + // if QH is connected, the specified bit is set, + // if TD is connected, the specified bit is cleared. + // + ptrQH->QH.QHHorizontalQSelect = bQH ? 1 : 0; +} + + +VOID SetQHHorizontalValidorInvalid ( + IN QH_STRUCT *ptrQH, + IN BOOLEAN bValid ) +{ + // + // Valid means the horizontal link pointer is valid, + // else, it's invalid. + // + ptrQH->QH.QHHorizontalTerminate = bValid ? 0 : 1; +} + + +VOID SetQHVerticalLinkPtr ( + IN QH_STRUCT *ptrQH, + IN VOID *ptrNext ) +{ + // + // Since the QH_STRUCT is aligned on 16-byte boundaries, + // Only the highest 28bit of the address is valid + // (take 32bit address as an example). + // + ptrQH->QH.QHVerticalPtr = (UINT32) (UINTN) ptrNext >> 4; +} + + +VOID SetQHVerticalQHorTDSelect ( + IN QH_STRUCT *ptrQH, + IN BOOLEAN bQH ) +{ + // + // Set the specified bit if the Vertical Link Pointer pointing to a QH, + // Clear the specified bit if the Vertical Link Pointer pointing to a TD. + // + ptrQH->QH.QHVerticalQSelect = bQH ? 1 : 0; +} + + +VOID SetQHVerticalValidorInvalid ( + IN QH_STRUCT *ptrQH, + IN BOOLEAN bValid ) +{ + // + // If TRUE, meaning the Vertical Link Pointer field is valid, + // else, the field is invalid. + // + ptrQH->QH.QHVerticalTerminate = bValid ? 0 : 1; +} + + +BOOLEAN GetQHHorizontalValidorInvalid ( + IN QH_STRUCT *ptrQH ) +{ + // + // If TRUE, meaning the Horizontal Link Pointer field is valid, + // else, the field is invalid. + // + return (BOOLEAN) ( !(ptrQH->QH.QHHorizontalTerminate) ); +} + + +// +// functions for TD +// + +EFI_STATUS AllocateTDStruct ( + USB_UHC_DEV *UhcDev, + TD_STRUCT **ppTDStruct ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + *ppTDStruct = NULL; + + Status = UhcAllocatePool( UhcDev, MEM_QH_TD_TYPE, + (UINT8 **) ppTDStruct, sizeof(TD_STRUCT) ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + ZeroMem( *ppTDStruct, sizeof (TD_STRUCT) ); + + return Status; +} + + +VOID InitTD ( + IN TD_STRUCT *ptrTD ) +{ + // + // Make TD ready. + // + SetTDLinkPtrValidorInvalid( ptrTD, FALSE ); +} + + +EFI_STATUS CreateTD ( + USB_UHC_DEV *UhcDev, + TD_STRUCT **pptrTD ) +{ + EFI_STATUS Status; + + // + // create memory for TD_STRUCT, and align the memory. + // + Status = AllocateTDStruct( UhcDev, pptrTD ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + InitTD( *pptrTD ); + + return EFI_SUCCESS; +} + + +EFI_STATUS GenSetupStageTD ( + USB_UHC_DEV *UhcDev, + UINT8 DevAddr, + UINT8 Endpoint, + UINT8 DeviceSpeed, + UINT8 *pDevReq, + UINT8 RequestLen, + TD_STRUCT **ppTD ) +{ + TD_STRUCT *pTDStruct; + EFI_STATUS Status; + + Status = CreateTD( UhcDev, &pTDStruct ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + SetTDLinkPtr( pTDStruct, NULL ); + + // + // Depth first fashion + // + SetTDLinkPtrDepthorBreadth( pTDStruct, TRUE ); + + //SetTDLinkPtrQHorTDSelect(pTDStruct,FALSE) ; + + // + // initialize as the last TD in the QH context, + // this field will be updated in the TD linkage process. + // + SetTDLinkPtrValidorInvalid( pTDStruct, FALSE ); + + // + // Disable Short Packet Detection by default + // + EnableorDisableTDShortPacket( pTDStruct, FALSE ); + + // + // Max error counter is 3, retry 3 times when error encountered. + // + SetTDControlErrorCounter( pTDStruct, 3 ); + + // + // set device speed attribute + // (TRUE - Slow Device; FALSE - Full Speed Device) + // + switch (DeviceSpeed) + { + case USB_SLOW_SPEED_DEVICE: + SetTDLoworFullSpeedDevice( pTDStruct, TRUE ); + break; + + case USB_FULL_SPEED_DEVICE: + SetTDLoworFullSpeedDevice( pTDStruct, FALSE ); + break; + } + + // + // Non isochronous transfer TD + // + SetTDControlIsochronousorNot( pTDStruct, FALSE ); + + // + // Interrupt On Complete bit be set to zero, + // Disable IOC interrupt. + // + SetorClearTDControlIOC( pTDStruct, FALSE ); + + // + // Set TD Active bit + // + SetTDStatusActiveorInactive( pTDStruct, TRUE ); + + SetTDTokenMaxLength( pTDStruct, RequestLen ); + + SetTDTokenDataToggle0( pTDStruct ); + + SetTDTokenEndPoint( pTDStruct, Endpoint ); + + SetTDTokenDeviceAddress( pTDStruct, DevAddr ); + + SetTDTokenPacketID( pTDStruct, SETUP_PACKET_ID ); + + pTDStruct->pTDBuffer = (UINT8 *) pDevReq; + pTDStruct->TDBufferLength = RequestLen; + SetTDDataBuffer( pTDStruct ); + + *ppTD = pTDStruct; + + return EFI_SUCCESS; +} + + +EFI_STATUS GenDataTD ( + USB_UHC_DEV *UhcDev, + UINT8 DevAddr, + UINT8 Endpoint, + UINT8 *pData, + UINT16 Len, + UINT8 PktID, + UINT8 Toggle, + UINT8 DeviceSpeed, + TD_STRUCT **ppTD ) +{ + TD_STRUCT *pTDStruct; + EFI_STATUS Status; + + Status = CreateTD( UhcDev, &pTDStruct ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + SetTDLinkPtr( pTDStruct, NULL ); + + // + // Depth first fashion + // + SetTDLinkPtrDepthorBreadth( pTDStruct, TRUE ); + + // + // Link pointer pointing to TD struct + // + SetTDLinkPtrQHorTDSelect( pTDStruct, FALSE ); + + // + // initialize as the last TD in the QH context, + // this field will be updated in the TD linkage process. + // + SetTDLinkPtrValidorInvalid( pTDStruct, FALSE ); + + // + // Disable short packet detect + // + EnableorDisableTDShortPacket( pTDStruct, FALSE ); + // + // Max error counter is 3 + // + SetTDControlErrorCounter( pTDStruct, 3 ); + + // + // set device speed attribute + // (TRUE - Slow Device; FALSE - Full Speed Device) + // + switch (DeviceSpeed) + { + case USB_SLOW_SPEED_DEVICE: + SetTDLoworFullSpeedDevice( pTDStruct, TRUE ); + break; + + case USB_FULL_SPEED_DEVICE: + SetTDLoworFullSpeedDevice( pTDStruct, FALSE ); + break; + } + // + // Non isochronous transfer TD + // + SetTDControlIsochronousorNot( pTDStruct, FALSE ); + + // + // Disable Interrupt On Complete + // Disable IOC interrupt. + // + SetorClearTDControlIOC( pTDStruct, FALSE ); + + // + // Set Active bit + // + SetTDStatusActiveorInactive( pTDStruct, TRUE ); + + SetTDTokenMaxLength( pTDStruct, Len ); + + if (Toggle) { + SetTDTokenDataToggle1( pTDStruct ); + } + else { + SetTDTokenDataToggle0( pTDStruct ); + } + + SetTDTokenEndPoint( pTDStruct, Endpoint ); + + SetTDTokenDeviceAddress( pTDStruct, DevAddr ); + + SetTDTokenPacketID( pTDStruct, PktID ); + + pTDStruct->pTDBuffer = (UINT8 *) pData; + pTDStruct->TDBufferLength = Len; + SetTDDataBuffer( pTDStruct ); + + *ppTD = pTDStruct; + + return EFI_SUCCESS; +} + + +EFI_STATUS CreateStatusTD ( + USB_UHC_DEV *UhcDev, + UINT8 DevAddr, + UINT8 Endpoint, + UINT8 PktID, + UINT8 DeviceSpeed, + TD_STRUCT **ppTD ) +{ + TD_STRUCT *ptrTDStruct; + EFI_STATUS Status; + + Status = CreateTD( UhcDev, &ptrTDStruct ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + SetTDLinkPtr( ptrTDStruct, NULL ); + + // Depth first fashion + SetTDLinkPtrDepthorBreadth( ptrTDStruct, TRUE ); + + //SetTDLinkPtrQHorTDSelect(pTDStruct,FALSE) ; + + // + // initialize as the last TD in the QH context, + // this field will be updated in the TD linkage process. + // + SetTDLinkPtrValidorInvalid( ptrTDStruct, FALSE ); + + // + // Disable short packet detect + // + EnableorDisableTDShortPacket( ptrTDStruct, FALSE ); + + // + // Max error counter is 3 + // + SetTDControlErrorCounter( ptrTDStruct, 3 ); + + // + // set device speed attribute + // (TRUE - Slow Device; FALSE - Full Speed Device) + // + switch (DeviceSpeed) + { + case USB_SLOW_SPEED_DEVICE: + SetTDLoworFullSpeedDevice( ptrTDStruct, TRUE ); + break; + + case USB_FULL_SPEED_DEVICE: + SetTDLoworFullSpeedDevice( ptrTDStruct, FALSE ); + break; + } + + // + // Non isochronous transfer TD + // + SetTDControlIsochronousorNot( ptrTDStruct, FALSE ); + + // + // Disable Interrupt On Complete + // Disable IOC interrupt. + // + SetorClearTDControlIOC( ptrTDStruct, FALSE ); + + // + // Set TD Active bit + // + SetTDStatusActiveorInactive( ptrTDStruct, TRUE ); + + SetTDTokenMaxLength( ptrTDStruct, 0 ); + + SetTDTokenDataToggle1( ptrTDStruct ); + + SetTDTokenEndPoint( ptrTDStruct, Endpoint ); + + SetTDTokenDeviceAddress( ptrTDStruct, DevAddr ); + + SetTDTokenPacketID( ptrTDStruct, PktID ); + + ptrTDStruct->pTDBuffer = NULL; + ptrTDStruct->TDBufferLength = 0; + SetTDDataBuffer( ptrTDStruct ); + + *ppTD = ptrTDStruct; + + return EFI_SUCCESS; +} + + +VOID SetTDLinkPtrValidorInvalid ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bValid ) +{ + // + // Valid means the link pointer is valid, + // else, it's invalid. + // + ptrTDStruct->TDData.TDLinkPtrTerminate = (bValid ? 0 : 1); +} + + +VOID SetTDLinkPtrQHorTDSelect ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bQH ) +{ + // + // Indicate whether the Link Pointer pointing to a QH or TD + // + ptrTDStruct->TDData.TDLinkPtrQSelect = (bQH ? 1 : 0); +} + + +VOID SetTDLinkPtrDepthorBreadth ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bDepth ) +{ + // + // If TRUE, indicating the host controller should process in + // depth first fashion, else, the host controller should process + // in breadth first fashion + // + ptrTDStruct->TDData.TDLinkPtrDepthSelect = (bDepth ? 1 : 0); +} + + +VOID SetTDLinkPtr ( + IN TD_STRUCT *ptrTDStruct, + IN VOID *ptrNext ) +{ + // + // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries, + // only the highest 28 bits are valid. (if take 32bit address as an example) + // + ptrTDStruct->TDData.TDLinkPtr = (UINT32) (UINTN) ptrNext >> 4; +} + + +VOID *GetTDLinkPtr ( + IN TD_STRUCT *ptrTDStruct ) +{ + // + // Get TD Link Pointer. Restore it back to 32bit + // (if take 32bit address as an example) + // + return ( (VOID *) (UINTN) ( (ptrTDStruct->TDData.TDLinkPtr) << 4 ) ); +} + + +BOOLEAN IsTDLinkPtrQHOrTD ( + IN TD_STRUCT *ptrTDStruct ) +{ + // + // Get the information about whether the Link Pointer field pointing to + // a QH or a TD. + // + return (BOOLEAN) (ptrTDStruct->TDData.TDLinkPtrQSelect); +} + + +VOID EnableorDisableTDShortPacket ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bEnable ) +{ + // + // TRUE means enable short packet detection mechanism. + // + ptrTDStruct->TDData.TDStatusSPD = (bEnable ? 1 : 0); +} + + +VOID SetTDControlErrorCounter ( + IN TD_STRUCT *ptrTDStruct, + IN UINT8 nMaxErrors ) +{ + // + // valid value of nMaxErrors is 0,1,2,3 + // + if (nMaxErrors > 3) { + nMaxErrors = 3; + } + ptrTDStruct->TDData.TDStatusErr = nMaxErrors; +} + + +VOID SetTDLoworFullSpeedDevice ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bLowSpeedDevice ) +{ + // + // TRUE means the TD is targeting at a Low-speed device + // + ptrTDStruct->TDData.TDStatusLS = (bLowSpeedDevice ? 1 : 0); +} + + +VOID SetTDControlIsochronousorNot ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bIsochronous ) +{ + // + // TRUE means the TD belongs to Isochronous transfer type. + // + ptrTDStruct->TDData.TDStatusIOS = (bIsochronous ? 1 : 0); +} + + +VOID SetorClearTDControlIOC ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bSet ) +{ + // + // If this bit is set, it indicates that the host controller should issue + // an interrupt on completion of the frame in which this TD is executed. + // + ptrTDStruct->TDData.TDStatusIOC = bSet ? 1 : 0; +} + + +VOID SetTDStatusActiveorInactive ( + IN TD_STRUCT *ptrTDStruct, + IN BOOLEAN bActive ) +{ + // + // If this bit is set, it indicates that the TD is active and can be + // executed. + // + if (bActive) { + ptrTDStruct->TDData.TDStatus |= 0x80; + } + else { + ptrTDStruct->TDData.TDStatus &= 0x7f; + } +} + + +UINT16 SetTDTokenMaxLength ( + IN TD_STRUCT *ptrTDStruct, + IN UINT16 nMaxLen ) +{ + // + // Specifies the maximum number of data bytes allowed for the transfer. + // the legal value extent is 0 ~ 0x500. + // + if (nMaxLen > 0x500) { + nMaxLen = 0x500; + } + ptrTDStruct->TDData.TDTokenMaxLen = nMaxLen - 1; + + return nMaxLen; +} + + +VOID SetTDTokenDataToggle1 ( + IN TD_STRUCT *ptrTDStruct ) +{ + // + // Set the data toggle bit to DATA1 + // + ptrTDStruct->TDData.TDTokenDataToggle = 1; +} + + +VOID SetTDTokenDataToggle0 ( + IN TD_STRUCT *ptrTDStruct ) +{ + // + // Set the data toggle bit to DATA0 + // + ptrTDStruct->TDData.TDTokenDataToggle = 0; +} + + +VOID SetTDTokenEndPoint ( + IN TD_STRUCT *ptrTDStruct, + IN UINTN nEndPoint ) +{ + // + // Set EndPoint Number the TD is targeting at. + // + ptrTDStruct->TDData.TDTokenEndPt = (UINT8) nEndPoint; +} + + +VOID SetTDTokenDeviceAddress ( + IN TD_STRUCT *ptrTDStruct, + IN UINTN nDevAddr ) +{ + // + // Set Device Address the TD is targeting at. + // + ptrTDStruct->TDData.TDTokenDevAddr = (UINT8) nDevAddr; +} + + +VOID SetTDTokenPacketID ( + IN TD_STRUCT *ptrTDStruct, + IN UINT8 nPID ) +{ + // + // Set the Packet Identification to be used for this transaction. + // + ptrTDStruct->TDData.TDTokenPID = nPID; +} + + +VOID SetTDDataBuffer ( + IN TD_STRUCT *ptrTDStruct ) +{ + // + // Set the beginning address of the data buffer that will be used + // during the transaction. + // + ptrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (ptrTDStruct-> + pTDBuffer); +} + + +BOOLEAN IsTDStatusActive ( + IN TD_STRUCT *ptrTDStruct ) +{ + UINT8 TDStatus; + + // + // Detect whether the TD is active. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x80); +} + + +BOOLEAN IsTDStatusStalled ( + IN TD_STRUCT *ptrTDStruct ) +{ + UINT8 TDStatus; + + // + // Detect whether the device/endpoint addressed by this TD is stalled. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x40); +} + + +BOOLEAN IsTDStatusBufferError ( + IN TD_STRUCT *ptrTDStruct ) +{ + UINT8 TDStatus; + + // + // Detect whether Data Buffer Error is happened. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x20); +} + + +BOOLEAN IsTDStatusBabbleError ( + IN TD_STRUCT *ptrTDStruct ) +{ + UINT8 TDStatus; + + // + // Detect whether Babble Error is happened. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x10); +} + + +BOOLEAN IsTDStatusNAKReceived ( + IN TD_STRUCT *ptrTDStruct ) +{ + UINT8 TDStatus; + + // + // Detect whether NAK is received. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x08); +} + + +BOOLEAN IsTDStatusCRCTimeOutError ( + IN TD_STRUCT *ptrTDStruct ) +{ + UINT8 TDStatus; + + // + // Detect whether CRC/Time Out Error is encountered. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x04); +} + + +BOOLEAN IsTDStatusBitStuffError ( + IN TD_STRUCT *ptrTDStruct ) +{ + UINT8 TDStatus; + + // + // Detect whether Bitstuff Error is received. + // + TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus); + return (BOOLEAN) (TDStatus & 0x02); +} + + +UINT16 GetTDStatusActualLength ( + IN TD_STRUCT *ptrTDStruct ) +{ + // + // Retrieve the actual number of bytes that were tansferred. + // the value is encoded as n-1. so return the decoded value. + // + return (UINT16) ( (ptrTDStruct->TDData.TDStatusActualLength) + 1 ); +} + + +BOOLEAN GetTDLinkPtrValidorInvalid ( + IN TD_STRUCT *ptrTDStruct ) +{ + // + // Retrieve the information of whether the Link Pointer field + // is valid or not. + // + if (ptrTDStruct->TDData.TDLinkPtrTerminate) { + return FALSE; + } + else { + return TRUE; + } + +} + + +UINTN CountTDsNumber ( + IN TD_STRUCT *ptrFirstTD ) +{ + UINTN Number; + TD_STRUCT *ptr; + + // + // Count the queued TDs number. + // + Number = 0; + ptr = ptrFirstTD; + while (ptr) { + ptr = (TD_STRUCT *) ptr->ptrNextTD; + Number++; + } + + return Number; +} + + +VOID LinkTDToQH ( + IN QH_STRUCT *ptrQH, + IN TD_STRUCT *ptrTD ) +{ + if (ptrQH == NULL || ptrTD == NULL) { + return; + } + // + // Validate QH Vertical Ptr field + // + SetQHVerticalValidorInvalid( ptrQH, TRUE ); + + // + // Vertical Ptr pointing to TD structure + // + SetQHVerticalQHorTDSelect( ptrQH, FALSE ); + + SetQHVerticalLinkPtr( ptrQH, (VOID *) ptrTD ); + + ptrQH->ptrDown = (VOID *) ptrTD; +} + + +VOID LinkTDToTD ( + IN TD_STRUCT *ptrPreTD, + IN TD_STRUCT *ptrTD ) +{ + if (ptrPreTD == NULL || ptrTD == NULL) { + return; + } + // + // Depth first fashion + // + SetTDLinkPtrDepthorBreadth( ptrPreTD, TRUE ); + + // + // Link pointer pointing to TD struct + // + SetTDLinkPtrQHorTDSelect( ptrPreTD, FALSE ); + + // + // Validate the link pointer valid bit + // + SetTDLinkPtrValidorInvalid( ptrPreTD, TRUE ); + + SetTDLinkPtr( ptrPreTD, ptrTD ); + + ptrPreTD->ptrNextTD = (VOID *) ptrTD; + + ptrTD->ptrNextTD = NULL; +} + + +// +// Transfer Schedule related Helper Functions +// +VOID SetorClearCurFrameListTerminate ( + IN FRAMELIST_ENTRY *pCurEntry, + IN BOOLEAN bSet ) +{ + // + // If TRUE, empty the frame. If FALSE, indicate the Pointer field is valid. + // + pCurEntry->FrameListPtrTerminate = (bSet ? 1 : 0); +} + + +VOID SetCurFrameListQHorTD ( + IN FRAMELIST_ENTRY *pCurEntry, + IN BOOLEAN bQH ) +{ + // + // This bit indicates to the hardware whether the item referenced by the + // link pointer is a TD or a QH. + // + pCurEntry->FrameListPtrQSelect = (bQH ? 1 : 0); +} + + +BOOLEAN IsCurFrameListQHorTD ( + IN FRAMELIST_ENTRY *pCurEntry ) +{ + // + //TRUE is QH + //FALSE is TD + // + return (BOOLEAN) (pCurEntry->FrameListPtrQSelect); +} + + +BOOLEAN GetCurFrameListTerminate ( + IN FRAMELIST_ENTRY *pCurEntry ) +{ + // + // TRUE means the frame is empty, + // FALSE means the link pointer field is valid. + // + return (BOOLEAN) (pCurEntry->FrameListPtrTerminate); +} + + +VOID SetCurFrameListPointer ( + IN FRAMELIST_ENTRY *pCurEntry, + IN UINT8 *ptr ) +{ + // + // Set the pointer field of the frame. + // + pCurEntry->FrameListPtr = (UINT32) (UINTN) ptr >> 4; +} + + +VOID *GetCurFrameListPointer ( + IN FRAMELIST_ENTRY *pCurEntry ) +{ + VOID *ptr; + + // + // Get the link pointer of the frame. + // + ptr = (VOID *) (UINTN) ( (pCurEntry->FrameListPtr) << 4 ); + return ptr; +} + + +VOID LinkQHToFrameList ( + IN FRAMELIST_ENTRY *pEntry, + IN UINT16 FrameListIndex, + IN QH_STRUCT *ptrQH ) +{ + FRAMELIST_ENTRY *pCurFrame; + QH_STRUCT *TempQH, *NextTempQH; + TD_STRUCT *TempTD; + BOOLEAN LINK; + + // + // Get frame list entry that the link process will begin from. + // + pCurFrame = pEntry + FrameListIndex; + + // + // if current frame is empty + // then link the specified QH directly to the Frame List. + // + if ( GetCurFrameListTerminate( pCurFrame ) ) { + + // + // Link new QH to the frame list entry. + // + SetCurFrameListQHorTD( pCurFrame, TRUE ); + + SetCurFrameListPointer( pCurFrame, (UINT8 *) ptrQH ); + + // + // clear T bit in the Frame List, means that the frame list + // entry is no longer empty. + // + SetorClearCurFrameListTerminate( pCurFrame, FALSE ); + + return; + + } + else { + // + // current frame list has link pointer + // + if ( !IsCurFrameListQHorTD( pCurFrame ) ) { + // + // a TD is linked to the framelist entry + // + TempTD = (TD_STRUCT *) GetCurFrameListPointer( pCurFrame ); + + while ( GetTDLinkPtrValidorInvalid( TempTD ) ) { + + if ( IsTDLinkPtrQHOrTD( TempTD ) ) { // QH linked next to the TD + break; + } + + TempTD = (TD_STRUCT *) GetTDLinkPtr( TempTD ); + } + + // + // either no ptr linked next to the TD or QH is linked next to the TD + // + if ( !GetTDLinkPtrValidorInvalid( TempTD ) ) { + + // + // no ptr linked next to the TD + // + TempTD->ptrNextQH = ptrQH; + SetTDLinkPtrQHorTDSelect( TempTD, TRUE ); + SetTDLinkPtr( TempTD, ptrQH ); + SetTDLinkPtrValidorInvalid( TempTD, TRUE ); + //ptrQH->ptrNext = NULL; + + return; + + } + else { + // + // QH is linked next to the TD + // + TempQH = (QH_STRUCT *) GetTDLinkPtr( TempTD ); + } + + } + else { + // + // a QH is linked to the framelist entry + // + TempQH = (QH_STRUCT *) GetCurFrameListPointer( pCurFrame ); + } + + // + // Set up Flag + // + LINK = TRUE; + + // + // aVOID the same qh repeated linking in one frame entry + // + if (TempQH == ptrQH) { + LINK = FALSE; + } + // + // if current QH has next QH connected + // + while ( GetQHHorizontalValidorInvalid( TempQH ) ) { + + // + // Get next QH pointer + // + NextTempQH = (QH_STRUCT *) GetQHHorizontalLinkPtr( TempQH ); + + // + // Bulk transfer qh may be self-linked, + // so, the code below is to aVOID dead-loop when meeting self-linked qh + // + if (NextTempQH == TempQH) { + LINK = FALSE; + break; + } + + TempQH = NextTempQH; + + // + // aVOID the same qh repeated linking in one frame entry + // + if (TempQH == ptrQH) { + LINK = FALSE; + } + } + + if (LINK) { + // Link + TempQH->ptrNext = ptrQH; + SetQHHorizontalQHorTDSelect( TempQH, TRUE ); + SetQHHorizontalLinkPtr( TempQH, ptrQH ); + SetQHHorizontalValidorInvalid( TempQH, TRUE ); + //ptrQH->ptrNext = NULL; + } + + return; + + } + +} + + +EFI_STATUS ExecuteControlTransfer ( + USB_UHC_DEV *UhcDev, + TD_STRUCT *ptrTD, + UINT32 wIndex, + UINTN *ActualLen, + UINTN TimeOut, + UINT32 *TransferResult ) +{ + UINT32 StatusAddr; + UINT32 FrameListBaseReg; + UINTN ErrTDPos; + UINTN Delay; + CHAR8 *ErrorStr; + + // + // Retrieve the Registers' address + // + StatusAddr = UhcDev->UsbHostControllerBaseAddress + USBSTS; + FrameListBaseReg = UhcDev->UsbHostControllerBaseAddress + USBFLBASEADD; + + ErrTDPos = 0; + *TransferResult = EFI_USB_NOERROR; + *ActualLen = 0; + Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1; + + do { + + CheckTDsResults( ptrTD, TransferResult, &ErrTDPos, ActualLen ); + + // + // TD is inactive, means the control transfer is end. + // + if ( (*TransferResult & EFI_USB_ERR_NOTEXECUTE) != + EFI_USB_ERR_NOTEXECUTE ) { + break; + } + UhcDev->StallPpi->Stall( UhcDev->PeiServices, UhcDev->StallPpi, 50 ); + + } while (Delay--); + + + if (*TransferResult != EFI_USB_NOERROR) { + switch (*TransferResult) + { + case EFI_USB_ERR_NOTEXECUTE: ErrorStr = gUsbErrorStrings[0]; + break; + + case EFI_USB_ERR_STALL: ErrorStr = gUsbErrorStrings[1]; + break; + + case EFI_USB_ERR_BUFFER: ErrorStr = gUsbErrorStrings[2]; + break; + + case EFI_USB_ERR_BABBLE: ErrorStr = gUsbErrorStrings[3]; + break; + + case EFI_USB_ERR_NAK: ErrorStr = gUsbErrorStrings[4]; + break; + + case EFI_USB_ERR_CRC: ErrorStr = gUsbErrorStrings[5]; + break; + + case EFI_USB_ERR_TIMEOUT: ErrorStr = gUsbErrorStrings[6]; + break; + + case EFI_USB_ERR_BITSTUFF: ErrorStr = gUsbErrorStrings[7]; + break; + + case EFI_USB_ERR_SYSTEM: ErrorStr = gUsbErrorStrings[8]; + break; + } + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS ExecBulkTransfer ( + USB_UHC_DEV *UhcDev, + TD_STRUCT *ptrTD, + UINT32 wIndex, + UINTN *ActualLen, + UINT8 *DataToggle, + UINTN TimeOut, + UINT32 *TransferResult ) +{ + UINT32 StatusAddr; + UINT32 FrameListBaseReg; + UINTN ErrTDPos; + UINTN ScrollNum; + UINTN Delay; + + StatusAddr = UhcDev->UsbHostControllerBaseAddress + USBSTS; + FrameListBaseReg = UhcDev->UsbHostControllerBaseAddress + USBFLBASEADD; + + ErrTDPos = 0; + *TransferResult = EFI_USB_NOERROR; + *ActualLen = 0; + + Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1; + + do { + + CheckTDsResults( ptrTD, TransferResult, &ErrTDPos, ActualLen ); + // + // TD is inactive, thus meaning bulk transfer's end. + // + if ( (*TransferResult & EFI_USB_ERR_NOTEXECUTE) != + EFI_USB_ERR_NOTEXECUTE ) { + break; + } + UhcDev->StallPpi->Stall( UhcDev->PeiServices, UhcDev->StallPpi, 50 ); + + } while (Delay--); + + // + // has error + // + if (*TransferResult != EFI_USB_NOERROR) { + + // + // scroll the Data Toggle back to the last success TD + // + ScrollNum = CountTDsNumber( ptrTD ) - ErrTDPos; + if (ScrollNum % 2) { + *DataToggle ^= 1; + } + + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +VOID DeleteSingleQH ( + USB_UHC_DEV *UhcDev, + QH_STRUCT *ptrQH, + UINT16 FrameListIndex, + BOOLEAN SearchOther ) +{ + FRAMELIST_ENTRY *pCurFrame; + UINTN i; + UINTN BeginFrame; + UINTN EndFrame; + QH_STRUCT *TempQH; + TD_STRUCT *TempTD; + VOID *PtrPreQH = NULL; + BOOLEAN Found = FALSE; + + if (ptrQH == NULL) { + return; + } + + if (SearchOther) { + BeginFrame = 0; + EndFrame = 1024; + } + else { + BeginFrame = FrameListIndex % 1024; + EndFrame = (FrameListIndex + 1) % 1024; + } + + for (i = BeginFrame; i < EndFrame; i++) { + + pCurFrame = UhcDev->FrameListEntry + i; + + if ( GetCurFrameListTerminate( pCurFrame ) ) { + // + // current frame list is empty,search next frame list entry + // + continue; + } + + if ( !IsCurFrameListQHorTD( pCurFrame ) ) { + // + // TD linked to current framelist + // + TempTD = (TD_STRUCT *) GetCurFrameListPointer( pCurFrame ); + + while ( GetTDLinkPtrValidorInvalid( TempTD ) ) { + + if ( IsTDLinkPtrQHOrTD( TempTD ) ) { + // + // QH linked next to the TD,break while() + // + break; + } + + TempTD = (TD_STRUCT *) GetTDLinkPtr( TempTD ); + } + + if ( !GetTDLinkPtrValidorInvalid( TempTD ) ) { + // + // no QH linked next to the last TD, + // search next frame list + // + continue; + } + + // + // a QH linked next to the last TD + // + TempQH = (QH_STRUCT *) GetTDLinkPtr( TempTD ); + + PtrPreQH = TempTD; + + } + else { + // + // a QH linked to current framelist + // + TempQH = (QH_STRUCT *) GetCurFrameListPointer( pCurFrame ); + + PtrPreQH = NULL; + } + + if (TempQH == ptrQH) { + + if (PtrPreQH) { // QH linked to a TD struct + + TempTD = (TD_STRUCT *) PtrPreQH; + SetTDLinkPtrValidorInvalid( TempTD, FALSE ); + SetTDLinkPtr( TempTD, NULL ); + TempTD->ptrNextQH = NULL; + + } + else { // QH linked directly to current framelist entry + + SetorClearCurFrameListTerminate( pCurFrame, TRUE ); + SetCurFrameListPointer( pCurFrame, NULL ); + } + + Found = TRUE; + // + // search next framelist entry + // + continue; + } + + while (TempQH != ptrQH) { + + PtrPreQH = TempQH; + + // + // Get next horizontal linked QH + // + TempQH = (QH_STRUCT *) GetQHHorizontalLinkPtr( TempQH ); + + // + // if has no valid QH linked,break the while() + // + if (TempQH == NULL) { + break; + } + + // + // detect self-linked QH, then break the loop + // + if (TempQH == PtrPreQH) { + break; + } + } + + if (TempQH != ptrQH) { + // + // search next frame list entry + // + continue; + } + + // + // TempQH == ptrQH, + // Update the related QHs + // + if ( GetQHHorizontalValidorInvalid( ptrQH ) ) { + // + // if has QH connected after the deleted QH + // + // + // get next QH of the deleted QH + // + TempQH = GetQHHorizontalLinkPtr( ptrQH ); + + //---------------------------------------------- + // + // Bulk transfer qh may be self link to itself to enhance performance + // so, only if the qh is not self linked, can we link the next qh to + // the previous qh + // + if (TempQH != ptrQH) { + // + // link the next QH to the previous QH + // + SetQHHorizontalLinkPtr( (QH_STRUCT *) PtrPreQH, TempQH ); + + ( (QH_STRUCT *) PtrPreQH )->ptrNext = TempQH; + } + //---------------------------------------------- + + // + // if the qh is self linked, also need to update the previous qh, + // the situation just the same as that there is no qh connected after + // the deleted qh + // + } + // + // has no QH connected after the deleted QH, + // or the deleted QH is self-linked, + // + // + // NULL the previous QH's link ptr and set Terminate field. + // + SetQHHorizontalValidorInvalid( (QH_STRUCT *) PtrPreQH, FALSE ); + SetQHHorizontalLinkPtr( (QH_STRUCT *) PtrPreQH, NULL ); + ( (QH_STRUCT *) PtrPreQH )->ptrNext = NULL; + + Found = TRUE; + } + + if (Found) { + // + // free memory once used by deleted QH + // + UhcFreePool( UhcDev, MEM_QH_TD_TYPE, (UINT8 *) ptrQH, + sizeof(QH_STRUCT) ); + } + + return; +} + + +VOID DeleteQueuedTDs ( + USB_UHC_DEV *UhcDev, + TD_STRUCT *ptrFirstTD ) +{ + TD_STRUCT *Tptr1, *Tptr2; + + Tptr1 = ptrFirstTD; + // + // Delete all the TDs in a queue. + // + while (Tptr1) { + + Tptr2 = Tptr1; + + if ( !GetTDLinkPtrValidorInvalid( Tptr2 ) ) { + Tptr1 = NULL; + } + else { + // + // has more than one TD in the queue. + // + Tptr1 = GetTDLinkPtr( Tptr2 ); + } + + UhcFreePool( UhcDev, MEM_QH_TD_TYPE, (UINT8 *) Tptr2, + sizeof(TD_STRUCT) ); + } + + return; +} + + +BOOLEAN CheckTDsResults ( + IN TD_STRUCT *ptrTD, + OUT UINT32 *Result, + OUT UINTN *ErrTDPos, + OUT UINTN *ActualTransferSize ) +{ + UINTN Len; + + *Result = EFI_USB_NOERROR; + *ErrTDPos = 0; + + // + // Init to zero. + // + *ActualTransferSize = 0; + + while (ptrTD) { + + if ( IsTDStatusActive( ptrTD ) ) { + *Result |= EFI_USB_ERR_NOTEXECUTE; + } + + if ( IsTDStatusStalled( ptrTD ) ) { + *Result |= EFI_USB_ERR_STALL; + } + + + if ( IsTDStatusBufferError( ptrTD ) ) { + *Result |= EFI_USB_ERR_BUFFER; + } + + if ( IsTDStatusBabbleError( ptrTD ) ) { + *Result |= EFI_USB_ERR_BABBLE; + } + + if ( IsTDStatusNAKReceived( ptrTD ) ) { + *Result |= EFI_USB_ERR_NAK; + } + + if ( IsTDStatusCRCTimeOutError( ptrTD ) ) { + *Result |= EFI_USB_ERR_TIMEOUT; + } + + if ( IsTDStatusBitStuffError( ptrTD ) ) { + *Result |= EFI_USB_ERR_BITSTUFF; + } + + // + // Accumulate actual transferred data length in each TD. + // + Len = GetTDStatusActualLength( ptrTD ) % 0x800; + *ActualTransferSize += Len; + + // + // if any error encountered, stop processing the left TDs. + // + if (*Result) { + return FALSE; + } + + ptrTD = (TD_STRUCT *) (ptrTD->ptrNextTD); + // + // Record the first Error TD's position in the queue, + // this value is zero-based. + // + (*ErrTDPos)++; + } + + return TRUE; +} + + +/* + VOID + SelfLinkBulkTransferQH ( + IN QH_STRUCT *ptrQH + ) + { + if (ptrQH == NULL) { + return; + } + + // + // Make the QH's horizontal link pointer pointing to itself. + // + ptrQH->ptrNext = ptrQH; + SetQHHorizontalQHorTDSelect(ptrQH,TRUE); + SetQHHorizontalLinkPtr(ptrQH,ptrQH); + SetQHHorizontalValidorInvalid(ptrQH,TRUE); + } + */ + +EFI_STATUS CreateMemoryBlock ( + USB_UHC_DEV *UhcDev, + MEMORY_MANAGE_HEADER **MemoryHeader, + UINTN MemoryBlockSizeInPages ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS TempPtr; + UINTN MemPages; + UINT8 *Ptr; + + // + // Memory Block uses MemoryBlockSizeInPages pages, + // memory management header and bit array use 1 page + // + MemPages = MemoryBlockSizeInPages + 1; + Status = ( **(UhcDev->PeiServices) ).AllocatePages( + UhcDev->PeiServices, + EfiConventionalMemory, + MemPages, + &TempPtr + ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + Ptr = (UINT8 *) ( (UINTN) TempPtr ); + + ZeroMem( Ptr, MemPages * PAGESIZE ); + + *MemoryHeader = (MEMORY_MANAGE_HEADER *) Ptr; + // + // adjust Ptr pointer to the next empty memory + // + Ptr += sizeof(MEMORY_MANAGE_HEADER); + // + // Set Bit Array initial address + // + (*MemoryHeader)->BitArrayPtr = Ptr; + + (*MemoryHeader)->Next = NULL; + + // + // Memory block initial address + // + Ptr = (UINT8 *) ( (UINTN) TempPtr ); + Ptr += PAGESIZE; + (*MemoryHeader)->MemoryBlockPtr = Ptr; + // + // set Memory block size + // + (*MemoryHeader)->MemoryBlockSizeInBytes = MemoryBlockSizeInPages * + PAGESIZE; + // + // each bit in Bit Array will manage 32byte memory in memory block + // + (*MemoryHeader)->BitArraySizeInBytes = + ( (*MemoryHeader)->MemoryBlockSizeInBytes / 32 ) / 8; + + return EFI_SUCCESS; +} + + +EFI_STATUS InitializeMemoryManagement ( + USB_UHC_DEV *UhcDev ) +{ + MEMORY_MANAGE_HEADER *MemoryHeader; + EFI_STATUS Status; + UINTN MemPages; + + MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES; + Status = CreateMemoryBlock( UhcDev, &MemoryHeader, MemPages ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + UhcDev->Header1 = MemoryHeader; + + Status = CreateMemoryBlock( UhcDev, &MemoryHeader, MemPages ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + + UhcDev->Header2 = MemoryHeader; + + return EFI_SUCCESS; +} + + +EFI_STATUS UhcAllocatePool ( + USB_UHC_DEV *UhcDev, + UINT8 Type, + UINT8 **Pool, + UINTN AllocSize ) +{ + MEMORY_MANAGE_HEADER *MemoryHeader; + MEMORY_MANAGE_HEADER *TempHeaderPtr; + MEMORY_MANAGE_HEADER *NewMemoryHeader; + UINTN RealAllocSize; + UINTN MemoryBlockSizeInPages; + EFI_STATUS Status; + + *Pool = NULL; + + switch (Type) + { + case MEM_QH_TD_TYPE: + MemoryHeader = UhcDev->Header1; + break; + + case MEM_DATA_BUFFER_TYPE: + MemoryHeader = UhcDev->Header2; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + // + // allocate unit is 32 byte (align on 32 byte) + // + if (AllocSize % 32) { + RealAllocSize = (AllocSize / 32 + 1) * 32; + } + else { + RealAllocSize = AllocSize; + } + //RealAllocSize = (AllocSize / 32 + 1) * 32; + + Status = EFI_NOT_FOUND; + for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; + TempHeaderPtr = TempHeaderPtr->Next) { + + Status = AllocMemInMemoryBlock( + TempHeaderPtr, + Pool, + RealAllocSize / 32 + ); + if ( !EFI_ERROR( Status ) ) { + return EFI_SUCCESS; + } + } + + // + // There is no enough memory, + // Create a new Memory Block + // + + // + // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES, + // just allocate a large enough memory block. + // + if ( RealAllocSize > (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES * PAGESIZE) ) { + MemoryBlockSizeInPages = RealAllocSize / PAGESIZE + 1; + } + else { + MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES; + } + Status = CreateMemoryBlock( UhcDev, + &NewMemoryHeader, + MemoryBlockSizeInPages ); + if ( EFI_ERROR( Status ) ) { + return Status; + } + // + // Link the new Memory Block to the Memory Header list + // + InsertMemoryHeaderToList( MemoryHeader, NewMemoryHeader ); + + Status = AllocMemInMemoryBlock( NewMemoryHeader, + Pool, + RealAllocSize / 32 + ); + return Status; +} + + +EFI_STATUS AllocMemInMemoryBlock ( + MEMORY_MANAGE_HEADER *MemoryHeader, + VOID **Pool, + UINTN NumberOfMemoryUnit ) +{ + UINTN TempBytePos; + UINTN FoundBytePos = 0; + UINT8 i; + UINT8 FoundBitPos = 0; + UINT8 ByteValue; + UINT8 BitValue; + UINTN NumberOfZeros; + UINTN Count; + + ByteValue = MemoryHeader->BitArrayPtr[0]; + NumberOfZeros = 0; + i = 0; + for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes; + ) { + + // + // Pop out BitValue from a byte in TempBytePos. + // + BitValue = (UINT8) (ByteValue % 2); + + if (BitValue == 0) { + // + // Found a free bit, the NumberOfZeros only record the number + // of those consecutive zeros + // + NumberOfZeros++; + // + // Found enough consecutive free space, break the loop + // + if (NumberOfZeros >= NumberOfMemoryUnit) { + break; + } + } + else { + // + // Encountering a '1', meant the bit is ocupied. + // + if (NumberOfZeros >= NumberOfMemoryUnit) { + // + // Found enough consecutive free space,break the loop + // + break; + } + else { + // + // the NumberOfZeros only record the number of those consecutive zeros, + // so reset the NumberOfZeros to 0 when encountering '1' before finding + // enough consecutive '0's + // + NumberOfZeros = 0; + // + // reset the (FoundBytePos,FoundBitPos) to the position of '1' + // + FoundBytePos = TempBytePos; + FoundBitPos = i; + } + } + + // + // right shift the byte + // + ByteValue /= 2; + + // + // step forward a bit + // + i++; + if (i == 8) { + // + // step forward a byte, getting the byte value, + // and reset the bit pos. + // + TempBytePos += 1; + ByteValue = MemoryHeader->BitArrayPtr[TempBytePos]; + i = 0; + } + } + + if (NumberOfZeros < NumberOfMemoryUnit) { + return EFI_NOT_FOUND; + } + + // + // Found enough free space. + // + + // + // The values recorded in (FoundBytePos,FoundBitPos) have two conditions: + // 1)(FoundBytePos,FoundBitPos) record the position + // of the last '1' before the consecutive '0's, it must + // be adjusted to the start position of the consecutive '0's. + // 2)the start address of the consecutive '0's is just the start of + // the bitarray. so no need to adjust the values of + // (FoundBytePos,FoundBitPos). + // + if ( ( MemoryHeader->BitArrayPtr[0] & bit( 0 ) ) != 0 ) { + FoundBitPos += 1; + } + + // + // Have the (FoundBytePos,FoundBitPos) make sense. + // + if (FoundBitPos > 7) { + FoundBytePos += 1; + FoundBitPos -= 8; + } + + // + // Set the memory as allocated + // + for (TempBytePos = FoundBytePos, i = FoundBitPos, Count = 0; + Count < NumberOfMemoryUnit; Count++) { + + MemoryHeader->BitArrayPtr[TempBytePos] |= bit( i ); + i++; + if (i == 8) { + TempBytePos += 1; + i = 0; + } + } + + *Pool = MemoryHeader->MemoryBlockPtr + + (FoundBytePos * 8 + FoundBitPos) * 32; + + return EFI_SUCCESS; +} + + +VOID UhcFreePool ( + USB_UHC_DEV *UhcDev, + UINT8 Type, + UINT8 *Pool, + UINTN AllocSize ) +{ + MEMORY_MANAGE_HEADER *MemoryHeader; + MEMORY_MANAGE_HEADER *TempHeaderPtr; + UINTN StartBytePos; + UINTN i; + UINT8 StartBitPos; + UINT8 j; + UINTN Count; + UINTN RealAllocSize; + + // UINTN MemPages; + // EFI_PHYSICAL_ADDRESS TempPtr; + + switch (Type) + { + case MEM_QH_TD_TYPE: + MemoryHeader = UhcDev->Header1; + break; + + case MEM_DATA_BUFFER_TYPE: + MemoryHeader = UhcDev->Header2; + break; + + default: + return; + } + + // + // allocate unit is 32 byte (align on 32 byte) + // + if (AllocSize % 32) { + RealAllocSize = (AllocSize / 32 + 1) * 32; + } + else { + RealAllocSize = AllocSize; + } + //RealAllocSize = (AllocSize / 32 + 1) * 32; + + for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; + TempHeaderPtr = TempHeaderPtr->Next) { + + if ( (Pool >= TempHeaderPtr->MemoryBlockPtr) && + ( (Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr + + TempHeaderPtr-> + MemoryBlockSizeInBytes) ) ) { + + // + // Pool is in the Memory Block area, + // find the start byte and bit in the bit array + // + StartBytePos = ( (Pool - + TempHeaderPtr->MemoryBlockPtr) / 32 ) / 8; + StartBitPos = (UINT8) + ( ( (Pool - + TempHeaderPtr->MemoryBlockPtr) / 32 ) % 8 ); + + // + // reset associated bits in bit arry + // + for (i = StartBytePos, j = StartBitPos, Count = 0; + Count < (RealAllocSize / 32); Count++) { + + TempHeaderPtr->BitArrayPtr[i] ^= (UINT8) ( bit( j ) ); + j++; + if (j == 8) { + i += 1; + j = 0; + } + } + // + // break the loop + // + break; + } + } + +} + + +VOID InsertMemoryHeaderToList ( + MEMORY_MANAGE_HEADER *MemoryHeader, + MEMORY_MANAGE_HEADER *NewMemoryHeader ) +{ + MEMORY_MANAGE_HEADER *TempHeaderPtr; + + for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; + TempHeaderPtr = TempHeaderPtr->Next) { + if (TempHeaderPtr->Next == NULL) { + TempHeaderPtr->Next = NewMemoryHeader; + break; + } + } +} + + +BOOLEAN IsMemoryBlockEmptied ( + MEMORY_MANAGE_HEADER *MemoryHeaderPtr ) +{ + UINTN i; + + for (i = 0; i < MemoryHeaderPtr->BitArraySizeInBytes; i++) { + if (MemoryHeaderPtr->BitArrayPtr[i] != 0) { + return FALSE; + } + } + + return TRUE; +} + + +VOID DelinkMemoryBlock ( + MEMORY_MANAGE_HEADER *FirstMemoryHeader, + MEMORY_MANAGE_HEADER *FreeMemoryHeader ) +{ + MEMORY_MANAGE_HEADER *TempHeaderPtr; + + if ( (FirstMemoryHeader == NULL) || (FreeMemoryHeader == NULL) ) { + return; + } + for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; + TempHeaderPtr = TempHeaderPtr->Next) { + + if (TempHeaderPtr->Next == FreeMemoryHeader) { + // + // Link the before and after + // + TempHeaderPtr->Next = FreeMemoryHeader->Next; + break; + } + } +} + + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2006, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//**********************************************************************
\ No newline at end of file |