summaryrefslogtreecommitdiff
path: root/Core/EM/UsbRecovery/UhcPeimSrc/UhcPeim.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/UsbRecovery/UhcPeimSrc/UhcPeim.c')
-rw-r--r--Core/EM/UsbRecovery/UhcPeimSrc/UhcPeim.c3575
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