summaryrefslogtreecommitdiff
path: root/Core/EM/UsbRecovery/OhciPEI/OhciPei.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/UsbRecovery/OhciPEI/OhciPei.c')
-rw-r--r--Core/EM/UsbRecovery/OhciPEI/OhciPei.c1455
1 files changed, 1455 insertions, 0 deletions
diff --git a/Core/EM/UsbRecovery/OhciPEI/OhciPei.c b/Core/EM/UsbRecovery/OhciPEI/OhciPei.c
new file mode 100644
index 0000000..7ecb23d
--- /dev/null
+++ b/Core/EM/UsbRecovery/OhciPEI/OhciPei.c
@@ -0,0 +1,1455 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (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/OhciPei.c 12 11/24/12 5:44a Ryanchou $
+//
+// $Revision: 12 $
+//
+// $Date: 11/24/12 5:44a $
+//
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Modules/USBRecovery/OhciPei.c $
+//
+// 12 11/24/12 5:44a 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
+//
+// 11 8/23/12 9:59p 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
+//
+// 10 1/18/11 12:59a 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
+//
+// 9 10/11/10 4:51p Olegi
+// XHCI support added.
+//
+// 8 3/17/09 5:09p Olegi
+// Added TransactionTranslator for slow/full speed devices behind USB2
+// hub.
+//
+// 7 3/03/09 7:26p Olegi
+// MaximumPacketLength changed from UINT8 to UINT16.
+//
+// 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/29/08 5:50p Michaela
+// 1) Updated code to move most porting tasks to SDL
+// 2) Added more debug break points and improved interactive
+// debugging capability for when a serial port is not available.
+// 3) Updated help files
+//
+// 4 7/18/08 5:04p 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)
+//
+// 3 7/10/08 6:36p Michaela
+// Updated to support OHCI controllers
+//
+// 2 9/22/06 12:23p Sivagarn
+// - Included appropriate headers for flies and functions
+// - Updated copyright messages
+// - Merged multiple MAK and SDL files into one MAK and SDL file
+// - Removed unnecessary files
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------------
+//
+// Name: OhciPei.c
+//
+// Description:
+// This file is the main source file for the OHCI PEI USB
+// recovery module. Its entry point at OhciPeiUsbEntryPoint
+// will be executed from the UsbRecoveryInitialize INIT_LIST.
+//
+//----------------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+#include <PEI.h>
+#include <AmiPeiLib.h>
+#include <token.h>
+#include <PPI\PeiGetUCtrl.h>
+#include <PPI\OhciPPI.h>
+#include <PPI\stall.h>
+#include "Ppi\UsbHostController.h"
+#include "OhciPei.h"
+#include "usb.h"
+
+// List of PCI addresses for OHCI controllers
+extern PCI_BUS_DEV_FUNCTION gOhciControllerPciTable[];
+extern UINT16 gOhciControllerCount;
+
+extern EFI_GUID gPeiStallPpiGuid;
+extern EFI_GUID gPeiUsbHostControllerPpiGuid;
+extern EFI_STATUS OhciPeiBoardInit (
+ IN EFI_PEI_SERVICES **PeiServices,
+ EFI_PEI_PCI_CFG_PPI *PciCfgPpi,
+ EFI_PEI_STALL_PPI *StallPpi );
+extern VOID ZeroMem (
+ OUT VOID *Buffer,
+ IN UINTN Size );
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciGetOperationalRegisterBase
+//
+// Description:
+// This function uses ControllerIndex and the global PCI_BUS_DEV_FUNCTION
+// array to access a particular controller's PCI configuration space in
+// order to obtain the Operational Register base address.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- PEI Sevices table pointer
+// IN UINT16 ControllerIndex
+// -- Index of the controller in the global
+// PCI_BUS_DEV_FUNCTION array
+//
+// Output:
+// UINT32 (Return Value)
+// = Base address for this controller's operational
+// registers.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT32 OhciGetOperationalRegisterBase (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT16 ControllerIndex )
+{
+ UINT32 OhciBaseAddress;
+
+ (*PeiServices)->PciCfg->Read(
+ PeiServices,
+ (*PeiServices)->PciCfg,
+ EfiPeiPciCfgWidthUint32,
+ OHCI_PCI_ADDRESS( ControllerIndex, OHCI_BASE_ADDR_REG ),
+ &OhciBaseAddress
+ );
+
+
+ return OhciBaseAddress &= 0xfffffff0; // Mask lower bits
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciPeiUsbEntryPoint
+//
+// Description:
+// This is the entry point into the OHCI controller initialization
+// subsystem.
+//
+// Input:
+// IN EFI_FFS_FILE_HEADER *FfsHeader
+// -- EFI_FFS_FILE_HEADER pointer
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS OhciPeiUsbEntryPoint (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_PEI_SERVICES **PeiServices )
+{
+ UINT8 Index;
+ UINTN MemPages;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ PEI_OHCI_DEV *OhciDevPtr;
+ EFI_PEI_STALL_PPI *StallPpi;
+
+ //-------------------------------------------
+ // Initialize the EFI_PEI_STALL_PPI interface
+ //-------------------------------------------
+ Status = (**PeiServices).LocatePpi( PeiServices, &gPeiStallPpiGuid,
+ 0, NULL, &StallPpi );
+ if ( EFI_ERROR( Status ) ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //-----------------------------------------
+ // board specific initialization to program
+ // PCI bridges and enable MMIO
+ //-----------------------------------------
+
+ Status = OhciPeiBoardInit(
+ PeiServices,
+ (*PeiServices)->PciCfg,
+ StallPpi );
+ if ( EFI_ERROR( Status ) ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //----------------------------------------------------------
+ // Allocate OHCI DEVICE OBJECT that holds all necessary
+ // information for the Host Controller operational registers
+ // for each controller. Initialze the controller and setup
+ // data structures for ready for operation
+ //----------------------------------------------------------
+
+ for (Index = 0; Index < gOhciControllerCount; Index++)
+ {
+
+ // PAGESIZE = 0x1000
+ MemPages = sizeof (PEI_OHCI_DEV) / 0x1000 + 1;
+ Status = (**PeiServices).AllocatePages(
+ PeiServices,
+ EfiConventionalMemory,
+ MemPages,
+ &TempPtr
+ );
+ if ( EFI_ERROR( Status ) )
+ {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OhciDevPtr = (PEI_OHCI_DEV *) ( (UINTN) TempPtr );
+ OhciDevPtr->Signature = PEI_OHCI_DEV_SIGNATURE;
+ OhciDevPtr->PeiServices = PeiServices;
+ OhciDevPtr->CpuIoPpi = (*PeiServices)->CpuIo;
+ OhciDevPtr->StallPpi = StallPpi;
+ OhciDevPtr->PciCfgPpi = (*PeiServices)->PciCfg;
+ ;
+ OhciDevPtr->UsbHostControllerBaseAddress =
+ OhciGetOperationalRegisterBase( PeiServices, Index );
+
+ //Initialize the OHCI Controller for operation
+
+ OhciInitHC( PeiServices, OhciDevPtr, Index ); // 0xff03
+
+ //Setup PPI entry point
+ OhciDevPtr->UsbHostControllerPpi.ControlTransfer =
+ OhciHcControlTransfer;
+ OhciDevPtr->UsbHostControllerPpi.BulkTransfer =
+ OhciHcBulkTransfer;
+ OhciDevPtr->UsbHostControllerPpi.GetRootHubPortNumber =
+ OhciHcGetRootHubPortNumber;
+ OhciDevPtr->UsbHostControllerPpi.GetRootHubPortStatus =
+ OhciHcGetRootHubPortStatus;
+ OhciDevPtr->UsbHostControllerPpi.SetRootHubPortFeature =
+ OhciHcSetRootHubPortFeature;
+ OhciDevPtr->UsbHostControllerPpi.ClearRootHubPortFeature =
+ OhciHcClearRootHubPortFeature;
+ OhciDevPtr->UsbHostControllerPpi.PreConfigureDevice = NULL;
+ OhciDevPtr->UsbHostControllerPpi.EnableEndpoints = NULL;
+
+ OhciDevPtr->PpiDescriptor.Flags =
+ (EFI_PEI_PPI_DESCRIPTOR_PPI |
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ OhciDevPtr->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid;
+ OhciDevPtr->PpiDescriptor.Ppi = &OhciDevPtr->UsbHostControllerPpi;
+
+ //Now is the time to install the PPI
+ Status = (**PeiServices).InstallPpi(
+ PeiServices, &OhciDevPtr->PpiDescriptor );
+ if ( EFI_ERROR( Status ) )
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciInitHcca
+//
+// Description:
+// This routine allocates memory for the the Host Controller
+// Communications Area (HCCA), aligned on a 256 byte boundary,
+// and updates the HcHcca operational register pointer, as
+// well as the corresponding PEI_OHCI_DEV.pFrameList
+// pointer.
+//
+// Input:
+// IN PEI_OHCI_DEV *OhciDevPtr
+// -- This is a pointer to a PEI_OHCI_DEV structure
+// for an OHCI controller.
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS OhciInitHcca (
+ IN PEI_OHCI_DEV *OhciDevPtr )
+{
+ OHCI_HC_REGISTERS *OhciHcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+
+ // Allocate 256 byte aligned Communication Channel area
+ // to the PEI_OHCI_DEV.pFrameList pointer.
+ ABORT_ON_ERROR(
+ (*OhciDevPtr->PeiServices)->AllocatePages(
+ OhciDevPtr->PeiServices,
+ EfiConventionalMemory,
+ (UINTN) (256 / 0x1000) + 1,
+ (EFI_PHYSICAL_ADDRESS *) &OhciDevPtr->pFrameList )
+ );
+
+ // Zero the memory and update the HcHCCA Host Controller
+ // Operational Register.
+ ZeroMem((VOID*)OhciDevPtr->pFrameList, sizeof(HC_HCCA));
+ OhciHcReg->HcHcca = (HC_HCCA*) OhciDevPtr->pFrameList;
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciInitHC
+//
+// Description: All leading whitespace on this line is removed by Helpbuilder
+// Description of this function can be block aligned in this section.
+// The first tab that Helpbuilder will recognize will be at tab stop 21,
+// which will indent 4 spaces in Helpbuilder.
+//
+// This text is indented 4 spaces in Helpbuilder
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_OHCI_DEV *OhciDevPtr
+// -- PEI_OHCI_DEV pointer
+// IN UINT8 Index
+// -- Index of this controller in the global
+// PCI_BUS_DEV_FUNCTION array
+//
+// Output:
+// VOID (Return Value)
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID OhciInitHC (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_OHCI_DEV *OhciDevPtr,
+ IN UINT8 Index )
+{
+ UINT8 bPortNum;
+ UINT8 *pPtr;
+ UINTN MemPages;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ EFI_PEI_PCI_CFG_PPI *PciCfgPpi = OhciDevPtr->PciCfgPpi;
+ POHCI_DESC_PTRS pstOHCIDescPtrs = &(OhciDevPtr->stOHCIDescPtrs);
+ OHCI_HC_REGISTERS *OhciHcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+
+ OhciDevPtr->wAsyncListSize = 0; // not used
+ OhciDevPtr->dMaxBulkDataSize = MAX_OHCI_BULK_DATA_SIZE;
+ //OhciDevPtr->wEndp0MaxPacket = 0x40;
+ //OhciDevPtr->bEndpointSpeed = USBSPEED_FULL;
+
+
+ // Do a Host Controller reset first
+ OhciHcReset( PeiServices, OhciDevPtr );
+
+
+ //-----------------------------------------------------------------
+ // Allocate and initialize the Host Controller Communication
+ // area aligned on a 256 byte boundary.
+ //
+ // This is needed only to poll the HccaDoneHead register
+ // in the HCCA, as the periodic list is not implemented.
+ //-----------------------------------------------------------------
+
+ // Store number of downstream ports into PEI_OHCI_DEV struct
+ OhciDevPtr->bNumPorts =
+ OhciHcReg->HcRhDescriptorA.Field.NumberDownstreamPorts;
+
+ // Program root hub characteristics:
+ OhciHcReg->HcRhDescriptorA.AllBits =
+ (NO_OVERCURRENT_PROTECTION | // No over current protection
+ POWERED_INDIVIDUALLY | // Ports powered individually
+ POWER_SWITCHED); // Ports individually power switched
+ OhciHcReg->HcRhDescriptorB.AllBits =
+ (ALL_REMOVEABLE | // All devices are removbale
+ ALL_PER_PORT_POWER_SWITCHED); // Power control is per-port
+
+ OhciHcReg->HcRhStatus.Field.LocalPowerStatusChange =
+ SET_GLOBAL_POWER; // Turn on power to all ports
+
+ // Initialize the frame interval register
+ OhciHcReg->HcFmInterval.Field.FrameInterval =
+ FM_INTERVAL_DEFAULT; // Between Start of Frames (SOFs)
+ OhciHcReg->HcFmInterval.Field.FsLargestDataPacket =
+ FS_LARGEST_PACKET_DEFAULT; // Largest for single transaction
+
+ // Enable the host controller list processing (Bulk/Control only)
+ OhciHcReg->HcControl.Field.BulkListEnable = TRUE;
+ OhciHcReg->HcControl.Field.ControlListEnable = TRUE;
+
+ // Set the operational bit in the host controller so that power
+ // can be applied to the ports.
+ OhciHcReg->HcControl.Field.HostControllerFunctionalState =
+ SET_USB_OPERATIONAL;
+
+ // Enable all the ports.
+ for ( bPortNum = 0; bPortNum < OhciDevPtr->bNumPorts; bPortNum++ ) {
+ OhciHcReg->HcRhPortStatus[bPortNum].AllBits = SET_PORT_POWER;
+ }
+
+ // Allocate a block of memory and define/initialize
+ // Setup Control and Bulk EDs/TDs
+ pstOHCIDescPtrs = &(OhciDevPtr->stOHCIDescPtrs);
+
+ MemPages = ( 3 *
+ sizeof (OHCI_ED) ) + ( 5 * sizeof(OHCI_TD) ) / 0x1000 + 1;
+ Status = (**PeiServices).AllocatePages(
+ PeiServices,
+ EfiConventionalMemory,
+ MemPages,
+ &TempPtr
+ );
+
+ pPtr = (UINT8 *) ( (UINTN) TempPtr );
+ MemSet( pPtr, 3 * sizeof (OHCI_ED) + 5 * sizeof(OHCI_TD), 0 );
+ if (!pPtr) {
+ return;
+ }
+ pstOHCIDescPtrs->pstEDControl = (POHCI_ED) pPtr;
+ pPtr += sizeof (OHCI_ED); //This should be okay
+ pstOHCIDescPtrs->pstTDControlSetup = (POHCI_TD) pPtr;
+ pPtr += sizeof (OHCI_TD);
+ pstOHCIDescPtrs->pstTDControlData = (POHCI_TD) pPtr;
+ pPtr += sizeof (OHCI_TD);
+ pstOHCIDescPtrs->pstTDControlStatus = (POHCI_TD) pPtr;
+ pPtr += sizeof (OHCI_TD);
+ pstOHCIDescPtrs->pstEDBulk = (POHCI_ED) pPtr;
+ pPtr += sizeof (OHCI_ED);
+ pstOHCIDescPtrs->pstTDBulkData = (POHCI_TD) pPtr;
+ pPtr += sizeof (OHCI_TD);
+ pstOHCIDescPtrs->pstEDInterrupt = (POHCI_ED) pPtr;
+ pPtr += sizeof (OHCI_ED);
+ pstOHCIDescPtrs->pstTDInterruptData = (POHCI_TD) pPtr;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciHcReset
+//
+// Description:
+// This function performs a software reset of the host controller.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_OHCI_DEV *OhciDevPtr
+// -- PEI_OHCI_DEV pointer
+//
+// Output:
+// VOID (Return Value)
+//
+// Notes:
+// It is assumed that all necessary operational register data has been
+// saved prior to calling this function.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID OhciHcReset (
+ EFI_PEI_SERVICES **PeiServices,
+ PEI_OHCI_DEV *OhciDevPtr )
+{
+ OHCI_HC_REGISTERS *OhciHcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+
+ // Initiate a software reset
+ OhciHcReg->HcCommandStatus.AllBits = SET_CONTROLLER_RESET;
+
+ //Wait for 2ms
+ OHCI_FIXED_DELAY_MS( OhciDevPtr, 2);
+
+ //Do USBRESET to reset roothub and downstream port
+ OhciHcReg->HcControl.Field.HostControllerFunctionalState = SET_USB_RESET;
+
+ //wait for 10ms
+ OHCI_FIXED_DELAY_MS( OhciDevPtr, 10);
+
+ // Note: HcInterruptStatus.Field.RootHubStatusChange bit should
+ // now be set if any devices are connected to a port
+ // on this controller.
+
+ return;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciHcGetRootHubPortStatus
+//
+// Description:
+// This function obtains the port status and port change status for
+// a port specified by PortNumber and updates the EFI_USB_PORT_STATUS
+// data structure as specified the the PortStatus pointer parameter.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_USB_HOST_CONTROLLER_PPI *This
+// -- PEI_USB_HOST_CONTROLLER_PPI pointer
+// IN UINT8 PortNumber
+// -- Port number for which status is requested
+// OUT EFI_USB_PORT_STATUS *PortStatus
+// -- EFI_USB_PORT_STATUS pointer's data is updated
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS OhciHcGetRootHubPortStatus (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus )
+{
+ PEI_OHCI_DEV *OhciDevPtr =
+ PEI_RECOVERY_USB_OHCI_DEV_FROM_THIS( This );
+ HC_RH_PORT_STATUS HcPortStatus;
+
+ HcPortStatus = ( (OHCI_HC_REGISTERS *)
+ OhciDevPtr->UsbHostControllerBaseAddress )->
+ HcRhPortStatus[PortNumber - 1];
+
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ if (HcPortStatus.Field.CurrentConnectStatus) {
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+ }
+ if (HcPortStatus.Field.PortEnableStatus) {
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+ }
+ if (HcPortStatus.Field.PortSuspendStatus) {
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+ }
+ if (HcPortStatus.Field.PortResetStatus) {
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+ }
+ if (HcPortStatus.Field.LowSpeedDeviceAttached) {
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ }
+ if (HcPortStatus.Field.ConnectStatusChange) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+ }
+ if (HcPortStatus.Field.PortEnableStatusChange) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+ }
+ if (HcPortStatus.Field.CurrentConnectStatus) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciHcGetRootHubPortNumber
+//
+// Description:
+// This function returns the number of downstream ports as specified
+// in the HcRhDescriptorA operational register.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_USB_HOST_CONTROLLER_PPI *This
+// -- PEI_USB_HOST_CONTROLLER_PPI pointer
+// OUT UINT8 *PortNumber
+// -- Number of downstream ports
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS OhciHcGetRootHubPortNumber (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ OUT UINT8 *PortNumber )
+{
+
+ PEI_OHCI_DEV *OhciDevPtr = PEI_RECOVERY_USB_OHCI_DEV_FROM_THIS( This );
+ OHCI_HC_REGISTERS *OhciHcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+
+ if (PortNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *PortNumber = OhciHcReg->HcRhDescriptorA.Field.NumberDownstreamPorts;
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciHcSetRootHubPortFeature
+//
+// Description:
+// This function sets an OHCI specification port feature as specified by
+// PortFeature for the port specified by PortNumber.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_USB_HOST_CONTROLLER_PPI *This
+// -- PEI_USB_HOST_CONTROLLER_PPI pointer
+// IN UINT8 PortNumber
+// -- Port number whose feature is to be set
+// IN EFI_USB_PORT_FEATURE PortFeature
+// -- Feature to set
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS OhciHcSetRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature )
+{
+ PEI_OHCI_DEV *OhciDevPtr =
+ PEI_RECOVERY_USB_OHCI_DEV_FROM_THIS( This );
+ OHCI_HC_REGISTERS *OhciHcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+
+ if (PortNumber > OhciHcReg->HcRhDescriptorA.Field.NumberDownstreamPorts){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (PortFeature)
+ {
+
+ case EfiUsbPortSuspend:
+ OhciHcReg->HcRhPortStatus[PortNumber - 1].AllBits = SET_PORT_SUSPEND;
+ break;
+
+ case EfiUsbPortReset:
+ OhciHcReg->HcRhPortStatus[PortNumber - 1].AllBits = SET_PORT_RESET;
+ break;
+
+ case EfiUsbPortPower:
+ break;
+
+ case EfiUsbPortEnable:
+ OhciHcReg->HcRhPortStatus[PortNumber - 1].AllBits = SET_PORT_ENABLE;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciHcClearRootHubPortFeature
+//
+// Description:
+// This function clears an OHCI specification port feature as specified
+// by PortFeature for the port specified by PortNumber.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_USB_HOST_CONTROLLER_PPI *This
+// -- PEI_USB_HOST_CONTROLLER_PPI pointer
+// IN UINT8 PortNumber
+// -- Port number whose feature is to be set
+// IN EFI_USB_PORT_FEATURE PortFeature
+// -- Feature to set
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS OhciHcClearRootHubPortFeature (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature )
+{
+ PEI_OHCI_DEV *OhciDevPtr =
+ PEI_RECOVERY_USB_OHCI_DEV_FROM_THIS( This );
+ OHCI_HC_REGISTERS *OhciHcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+ HC_RH_PORT_STATUS *Pstatus;
+
+ if (PortNumber > OhciHcReg->HcRhDescriptorA.Field.NumberDownstreamPorts){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Pstatus = &OhciHcReg->HcRhPortStatus[PortNumber - 1];
+
+ switch (PortFeature)
+ {
+ // clear PORT_ENABLE feature means disable port.
+ // This is accomplished by writing a 1 to the CurrentConnectStatus
+ // field.
+ case EfiUsbPortEnable:
+ Pstatus->AllBits = CLEAR_PORT_ENABLE;
+ break;
+
+ // clear PORT_SUSPEND feature means resume the port.
+ // (cause a resume on the specified port if in suspend mode)
+ // This is accomplished by writing a 1 to the PortOverCurrentIndicator
+ // field.
+ case EfiUsbPortSuspend:
+ Pstatus->AllBits = CLEAR_SUSPEND_STATUS;
+ break;
+
+ case EfiUsbPortPower:
+ break;
+
+
+ // clear PORT_RESET means clear the reset signal.
+ // This is accomplished by writing a 1 to the PortResetStatusChange
+ // field. No assumption is made that the appropriate delay
+ // was implemented.
+ case EfiUsbPortReset:
+
+ break;
+
+ // clear connect status change by writing
+ // a 1 to the ConnectStatusChange field
+ case EfiUsbPortConnectChange:
+ Pstatus->AllBits = CLEAR_CONNECT_STATUS_CHANGE;
+ break;
+
+ // clear enable/disable status change by writing
+ // a 1 to the PortEnableStatusChange field
+ case EfiUsbPortEnableChange:
+ Pstatus->AllBits = CLEAR_PORT_ENABLE_STATUS_CHANGE;
+ break;
+
+ // root hub does not support these requests
+ case EfiUsbPortSuspendChange:
+ case EfiUsbPortOverCurrentChange:
+ case EfiUsbPortResetChange:
+ Pstatus->AllBits = CLEAR_PORT_RESET_STATUS_CHANGE;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciHcControlTransfer
+//
+// Description:
+// This function intiates a USB control transfer and waits on it to
+// complete.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_USB_HOST_CONTROLLER_PPI *This
+// -- PEI_USB_HOST_CONTROLLER_PPI pointer
+// IN UINT8 bDeviceAddress
+// -- USB address of the device for which the control
+// transfer is to be issued
+// IN UINT8 DeviceType
+// -- Not used
+// IN UINT8 MaximumPacketLength
+// -- Maximum number of bytes that can be sent to or
+// received from the endpoint in a single data packet
+// IN EFI_USB_DEVICE_REQUEST *Request
+// -- EFI_USB_DEVICE_REQUEST pointer
+// IN EFI_USB_DATA_DIRECTION TransferDirection
+// -- Direction of transfer
+// OPTIONAL IN OUT VOID *DataBuffer
+// -- Pointer to source or destination buffer
+// OPTIONAL IN OUT UINTN *DataLength
+// -- Length of buffer
+// IN UINTN TimeOut
+// -- Not used
+// OUT UINT32 *TransferResult
+// -- Not used
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+typedef struct _D_REQUEST
+{
+ UINT8 RequestType;
+ UINT8 Request;
+ UINT16 Value;
+ UINT16 Index;
+ UINT16 Length;
+} D_REQUEST;
+
+EFI_STATUS OhciHcControlTransfer (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,
+ IN UINT8 bDeviceAddress,
+ 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 *DataBuffer OPTIONAL,
+ IN OUT UINTN *DataLength OPTIONAL,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult )
+{
+ UINT16 *fpData;
+ POHCI_ED fpED;
+ POHCI_TD fpTD;
+ UINT32 DwordData;
+ UINT16 WordData;
+ UINT16 WordRequest;
+ UINT16 WordIndex;
+ UINT16 WordValue;
+ EFI_STATUS Status = EFI_SUCCESS;
+ PEI_OHCI_DEV *OhciDevPtr =
+ PEI_RECOVERY_USB_OHCI_DEV_FROM_THIS( This );
+ POHCI_DESC_PTRS fpDescPtrs =
+ &(OhciDevPtr->stOHCIDescPtrs);
+ OHCI_HC_REGISTERS *HcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+
+ // 5 ms delay is necessary for OHCI host controllers
+ OHCI_FIXED_DELAY_MS( OhciDevPtr, 5 );
+
+ WordRequest = (Request->Request << 8) | Request->RequestType;
+ WordValue = Request->Value;
+ WordIndex = Request->Index;
+
+ //
+ // Build the device request in the data area of the control setup qTD
+ //
+ fpData = (UINT16 *) fpDescPtrs->pstTDControlSetup->aSetupData;
+ *fpData++ = WordRequest;
+ *fpData++ = WordValue;
+ *fpData++ = WordIndex;
+ *fpData++ = (UINT16) *DataLength;
+ *(UINT32 *) fpData = (UINT32) DataBuffer;
+
+ //
+ // Prepare some registers that will be used in building the TDs below.
+ // wLength contains the data length.
+ // fpBuffer contains the absolute address of the data buffer.
+ // WordRequest contains the request type (bit 7 = 0/1 for Out/In).
+ // fpDevInfo will contain a pointer to the DeviceInfo structure for
+ // the given device.
+ //
+ // Ready the EDControl for the control transfer.
+ //
+ fpED = fpDescPtrs->pstEDControl;
+ //
+ // The ED control field will be set so
+ // Function address & Endpoint number = ESI,
+ // Direction = From TD,
+ // Speed = DeviceInfo.bEndpointSpeed,
+ // Skip = 1, Format = 0,
+ // Max packet size = DeviceInfo.wEndp0MaxPacket
+ // The HeadPointer field will be set to TDControlSetup
+ // The TailPointer field will be set to OHCI_TERMINATE
+ // The LinkPointer field will be set to OHCI_TERMINATE
+ //
+
+ // if wEndp0MaxPacket is NULL, then use default
+ // packet size
+ DwordData = MaximumPacketLength;
+
+ // Force the max packet size to 64 bytes
+ if (DwordData > 0x40 || DwordData == 0) {
+ DwordData = 0x40;
+ }
+ DwordData <<= 16; // DwordData[26:16] = device's packet size
+ WordData = (UINT16) DeviceSpeed; // 00/01/10 for HI/LO/FULL
+ WordData = (WordData & 1) << 13; // WordData[13] = full/low speed flag
+ WordData |= bDeviceAddress | ED_SKIP_TDQ;
+ fpED->dControl = DwordData | WordData;
+ fpED->fpTailPointer = 0;
+ fpED->fpEDLinkPointer = 0;
+
+ fpTD = fpDescPtrs->pstTDControlSetup;
+ //
+ // The ControlStatus field will be set so
+ // Buffer Rounding = 1,
+ // Direction PID = GTD_SETUP_PACKET,
+ // Delay Interrupt = GTD_INTD,
+ // Data Toggle = GTD_SETUP_TOGGLE,
+ // Error Count = GTD_NO_ERRORS,
+ // Condition Code = GTD_NOT_ACCESSED
+ // The CurrentBufferPointer field will point to the TD's SetupData buffer
+ // which was before initialized to contain a DeviceRequest struc.
+ // The BufferEnd field will point to the last byte of the TD's SetupData
+ // buffer.
+ // The LinkPointer field will point to the TDControlData if data will
+ // be sent/received or to the TDControlStatus if no data is expected.
+ // The CSReloadValue field will contain 0 because this is a "one shot"
+ // packet.
+ // The pCallback will be set to point to the OHCI_ControlTDCallback
+ // routine.
+ // The ActiveFlag field will be set to TRUE.
+ // The DeviceAddress field does not need to be set since the Control TDs
+ // do not need rebinding to the EDControl.
+ //
+ fpTD->dControlStatus = (UINT32) ( GTD_BUFFER_ROUNDING |
+ GTD_SETUP_PACKET | GTD_SETUP_TOGGLE |
+ GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28) );
+
+ fpTD->fpCurrentBufferPointer = fpTD->aSetupData;
+ fpTD->fpBufferEnd = fpTD->aSetupData + 7; // size of aSetupData - 1
+
+ if (*DataLength) { // some data to transfer
+
+ // Fill in various fields in the TDControlData.
+ fpTD = fpDescPtrs->pstTDControlData;
+ //
+ // The ControlStatus field will be set so
+ // Buffer Rounding = 1,
+ // Direction PID = GTD_OUT_PACKET/GTD_IN_PACKET,
+ // Delay Interrupt = GTD_INTD,
+ // Data Toggle = GTD_DATA1_TOGGLE,
+ // Error Count = GTD_NO_ERRORS,
+ // Condition Code = GTD_NOT_ACCESSED
+ // The CurrentBufferPointer field will point to the caller's buffer
+ // which is now in EBP.
+ // The BufferEnd field will point to the last byte of the caller's
+ // buffer.
+ // The LinkPointer field will point to the TDControlStatus.
+ // The CSReloadValue field will contain 0 because this is a
+ // "one shot" packet.
+ // The pCallback will be set to point to the OHCI_ControlTDCallback
+ // routine.
+ // The ActiveFlag field will be set to TRUE.
+ // The DeviceAddress field does not need to be set since the Control
+ // TDs do not need rebinding to the EDControl.
+ // The CSReloadValue field will contain 0 because this is a
+ // "one shot" packet.
+ // The pCallback will be set to point to the OHCI_ControlTDCallback
+ // routine.
+ // The ActiveFlag field will be set to TRUE. return USB_SUCCESS;
+ // The DeviceAddress field does not need to be set since the Control
+ // TDs do not need rebinding to the EDControl.
+ //
+ DwordData = (UINT32) ( GTD_BUFFER_ROUNDING | GTD_DATA1_TOGGLE
+ | GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28) );
+ DwordData = (WordRequest & BIT7)
+ ? (DwordData | GTD_IN_PACKET | GTD_INTD)
+ : (DwordData | GTD_OUT_PACKET);
+ fpTD->dControlStatus = DwordData;
+ fpTD->fpCurrentBufferPointer = (UINT8 *) DataBuffer;
+
+ WordData = (*DataLength < MAX_CONTROL_DATA_SIZE)
+ ? *DataLength
+ : MAX_CONTROL_DATA_SIZE;
+ fpTD->fpBufferEnd = (UINT8 *) DataBuffer + WordData - 1;
+ }
+
+ // Fill in various fields in the TDControlStatus.
+ fpTD = fpDescPtrs->pstTDControlStatus;
+ //
+ // The ControlStaus field will be set so
+ // Buffer Rounding = 1,
+ // Direction PID = GTD_OUT_PACKET/GTD_IN_PACKET,
+ // Delay Interrupt = GTD_INTD,
+ // Data Toggle = GTD_DATA1_TOGGLE,
+ // Error Count = GTD_NO_ERRORS,
+ // Condition Code = GTD_NOT_ACCESSED
+ // The CurrentBufferPointer field will point to NULL
+ // The BufferEnd field will point to NULL.
+ // The LinkPointer field will point to OHCI_TERMINATE.
+ // The CSReloadValue field will contain 0 because this is a
+ // "one shot" packet.
+ // The pCallback will be set to point to the OHCI_ControlTdCallback
+ // routine.
+ // The ActiveFlag field will be set to TRUE.
+ // The DeviceAddress field does not need to be set since the Control
+ // TDs do not need rebinding to the EdControl.
+ //
+ // Note: For OUT control transfer status should be IN and
+ // for IN cotrol transfer, status should be OUT.
+ //
+ DwordData = (UINT32) ( GTD_BUFFER_ROUNDING | GTD_DATA1_TOGGLE
+ | GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28) );
+ DwordData = (WordRequest & BIT7)
+ ? (DwordData | GTD_OUT_PACKET)
+ : (DwordData | GTD_IN_PACKET | GTD_INTD);
+ fpTD->dControlStatus = DwordData;
+ fpTD->fpCurrentBufferPointer = NULL;
+ fpTD->fpBufferEnd = NULL;
+ fpTD->fpLinkPointer = NULL;
+
+ //
+ // Link all the pointers together
+ //
+ fpTD = fpDescPtrs->pstTDControlSetup;
+ fpED->fpHeadPointer = fpTD;
+ if (*DataLength) { // chain in data TD
+ fpTD->fpLinkPointer = (UINT8 *) fpDescPtrs->pstTDControlData;
+ fpTD = fpDescPtrs->pstTDControlData;
+ }
+ fpTD->fpLinkPointer = (UINT8 *) fpDescPtrs->pstTDControlStatus;
+
+ fpDescPtrs->pstTDControlStatus->fpLinkPointer = NULL;
+
+ fpTD = fpDescPtrs->pstTDControlSetup;
+ do {
+ fpTD->dCSReloadValue = 0;
+ fpTD->bActiveFlag = TRUE;
+ fpTD = (POHCI_TD) fpTD->fpLinkPointer;
+ } while (fpTD);
+
+ // clear the WriteBackDoneHead status bit in
+ // the HcInterruptStatus register
+ HcReg->HcInterruptStatus.Field.WriteBackDoneHead = HCINT_STATUS_CLEAR;
+
+ //
+ // Now control queue is complete, so set ED_SKIP_TDQ=0
+ //
+ fpED->dControl &= ~ED_SKIP_TDQ;
+ //
+ // Set the HcControlHeadED register to point to the EDControl.
+ //
+ HcReg->HcControlHeadEd = (UINTN) fpED;
+
+ //
+ // Now put the control setup, data and status into the HC's schedule by
+ // setting the ControllListFilled field of HcCommandStatus reg.
+ // This will cause the HC to execute the transaction in the next
+ // active frame.
+ //
+ HcReg->HcCommandStatus.AllBits = SET_CONTROL_LIST_FILLED;
+
+ //
+ // Now wait for the control status TD to complete. When it has completed,
+ // the OHCI_ControlTDCallback will set its active flag to FALSE.
+ Status = OhciHcWaitForTransferComplete( PeiServices, OhciDevPtr,
+ fpDescPtrs->pstTDControlStatus );
+
+ //
+ // Stop the HC from processing the EDControl by setting its Skip bit.
+ //
+ fpED->dControl |= ED_SKIP_TDQ;
+
+ //
+ // Finally check for any error bits set in both the TDControlStatus.
+ // If the TD did not complete successfully, return STC.
+ //
+
+ // DwordData[3:0] = Completion status
+ DwordData = fpDescPtrs->pstTDControlStatus->dControlStatus >> 28;
+
+ return ( (UINT8) DwordData == 0 ) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+ //TODO: CHange the return status more meaningfull
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciHcBulkTransfer
+//
+// Description:
+// This function intiates a USB bulk transfer and waits on it to
+// complete.
+//
+// Input:
+// IN EFI_PEI_SERVICES **PeiServices
+// -- EFI_PEI_SERVICES pointer
+// IN PEI_USB_HOST_CONTROLLER_PPI *This
+// -- PEI_USB_HOST_CONTROLLER_PPI pointer
+// IN UINT8 DeviceAddress
+// -- USB address of the device for which the control
+// transfer is to be issued
+// IN UINT8 EndPointAddress
+// -- Particular endpoint for the device
+// IN UINT8 MaximumPacketLength
+// -- Maximum number of bytes that can be sent to or
+// received from the endpoint in a single data packet
+// OPTIONAL IN OUT VOID *DataBuffer
+// -- Pointer to source or destination buffer
+// OPTIONAL IN OUT UINTN *DataLength
+// -- Length of buffer
+// IN OUT UINT8 *DataToggle
+// -- Used to update the control/status DataToggle field
+// of the Transfer Descriptor
+// IN UINTN TimeOut
+// -- Not used
+// OUT UINT32 *TransferResult
+// -- Not used
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS OhciHcBulkTransfer (
+ 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 *DataBuffer,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult )
+{
+ UINT32 DwordData;
+ UINT8 ByteData;
+ UINT16 wMaxPkt;
+ EFI_STATUS Status;
+ UINT8 bEndp;
+ UINT8 Toggle;
+ PEI_OHCI_DEV *OhciDevPtr =
+ PEI_RECOVERY_USB_OHCI_DEV_FROM_THIS( This );
+ POHCI_DESC_PTRS fpDescPtrs = &(OhciDevPtr->stOHCIDescPtrs);
+ OHCI_HC_REGISTERS *HcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+
+ wMaxPkt = MaximumPacketLength;
+
+ if (wMaxPkt == 0) {
+ *DataLength = 0;
+ return EFI_NOT_FOUND;
+ }
+
+ //Clear Bulk ED and TD
+ MemSet( fpDescPtrs->pstEDBulk, sizeof(OHCI_ED), 0 );
+ MemSet( fpDescPtrs->pstTDBulkData, sizeof(OHCI_TD), 0 );
+ //
+ // Set the SKIP bit in the EdBulk to avoid accidental scheduling
+ //
+ fpDescPtrs->pstEDBulk->dControl = ED_SKIP_TDQ;
+ //
+ // Set the ED's head pointer field to bulk data TD and tail pointer
+ // field to OHCI_TERMINATE. Also set ED's link pointer to
+ // OHCI_TERMINATE.
+ //
+ fpDescPtrs->pstEDBulk->fpHeadPointer = fpDescPtrs->pstTDBulkData;
+ fpDescPtrs->pstEDBulk->fpTailPointer = OHCI_TERMINATE;
+ fpDescPtrs->pstEDBulk->fpEDLinkPointer = OHCI_TERMINATE;
+ //
+ // Form the data needed for ED's control field with the available
+ // information
+ //
+ bEndp = EndPointAddress & 0x7f;
+ DwordData = (EndPointAddress & 0x80) ? ED_IN_PACKET : ED_OUT_PACKET;
+ DwordData |= DeviceAddress;
+ DwordData |= (UINT16) bEndp << 7;
+ DwordData |= (UINT32) wMaxPkt << 16;
+
+ //
+ // Update the ED's control field with the data formed
+ // ASSUME ALL MASS DEVICES ARE FULL SPEED DEVICES.
+ //
+ fpDescPtrs->pstEDBulk->dControl = DwordData;
+ //
+ // Fill the general bulk data TD with relevant information. Set the
+ // TD's control field with buffer rounding set to 1, direction PID to
+ // don't care, delay interrupt to INTD, data toggle to the latest data
+ // toggle value, error count to no errors and condition code to not
+ // accessed.
+ //
+ // Set the data toggle to DATA0 (SETUP_TOGGLE)
+ fpDescPtrs->pstTDBulkData->dControlStatus = (UINT32) (
+ GTD_BUFFER_ROUNDING |
+ GTD_IN_PACKET |
+ GTD_INTD |
+ GTD_SETUP_TOGGLE |
+ GTD_NO_ERRORS |
+ (GTD_NOT_ACCESSED << 28)
+ );
+ fpDescPtrs->pstTDBulkData->dControlStatus |= (UINT32) *DataToggle << 24;
+
+ //
+ // GTD current buffer pointer field will point to the caller's buffer which
+ // now in the variable fpBuffer
+ //
+ fpDescPtrs->pstTDBulkData->fpCurrentBufferPointer = (UINT8 *) DataBuffer;
+ fpDescPtrs->pstTDBulkData->fpBufferEnd = (UINT8 *) DataBuffer +
+ *DataLength - 1;
+ fpDescPtrs->pstTDBulkData->fpLinkPointer = OHCI_TERMINATE;
+ //
+ // GTD's CSReloadValue field will contain 0 because this is a
+ // "one shot" packet
+ //
+ fpDescPtrs->pstTDBulkData->dCSReloadValue = 0;
+ fpDescPtrs->pstTDBulkData->bActiveFlag = TRUE;
+
+ // Set the HCBulkHeadED register to point to the bulk ED
+ fpDescPtrs->pstEDBulk->dControl &= ~ED_SKIP_TDQ;
+ HcReg->HcBulkHeadEd = (UINT32) fpDescPtrs->pstEDBulk;
+
+ // Enable the bulk list processing
+ HcReg->HcCommandStatus.AllBits = SET_BULK_LIST_FILLED;
+
+ Status = OhciHcWaitForTransferComplete( PeiServices, OhciDevPtr,
+ fpDescPtrs->pstTDBulkData );
+ //
+ // Stop the HC from processing the EDBulk by setting its Skip bit.
+ //
+ fpDescPtrs->pstEDBulk->dControl |= ED_SKIP_TDQ;
+ //
+ // Update the data toggle value into the mass info structure
+ //
+
+ *DataToggle = (UINT8) ( ( (fpDescPtrs->pstTDBulkData->dControlStatus &
+ GTD_DATA_TOGGLE) >> 24 ) & 1 );
+ Toggle = (UINT8) ( (fpDescPtrs->pstTDBulkData->dControlStatus &
+ GTD_DATA_TOGGLE) >> 24 );
+ if ( (Toggle & 0x02) == 0 )
+ {
+ //Use the Carry
+ DwordData = (UINT32) fpDescPtrs->pstEDBulk->fpHeadPointer;
+ DwordData &= 0x00000002;
+ DwordData = DwordData >> 1;
+ DwordData &= 0x00000001;
+ *DataToggle = DwordData;
+ }
+ //
+ // Check for the error conditions - if possible recover from them
+ //
+ ByteData = (UINT8) (fpDescPtrs->pstTDBulkData->dControlStatus >> 28);
+ if (ByteData) {
+ if (ByteData == GTD_DEVICE_NOT_RESPOND) {
+ //TODO fpUSBData->bLastCommandStatus |= USB_BULK_TIMEDOUT;
+ *DataLength = 0;
+ return EFI_NOT_FOUND;
+ }
+ if (ByteData == GTD_STALL) {
+ //TODO fpUSBData->bLastCommandStatus |= USB_BULK_STALLED;
+ *DataLength = 0;
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Get the size of data transferred
+ //
+ // Size transferred is calculated by subtracting end address with current
+ // buffer pointer and subtracting that value from the total size
+ //
+ if (!fpDescPtrs->pstTDBulkData->fpCurrentBufferPointer)
+ {
+ //All data are transfered.
+ return EFI_SUCCESS;
+ }
+ DwordData = (UINT32) fpDescPtrs->pstTDBulkData->fpBufferEnd;
+ DwordData = DwordData -
+ (UINT32) fpDescPtrs->pstTDBulkData->fpCurrentBufferPointer;
+ if (DwordData != 0)
+ {
+ *DataLength = *DataLength - DwordData - 1;
+ }
+ else {
+ ;
+ }
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: OhciHcWaitForTransferComplete
+//
+// Description:
+// This function waits for a tranfer to complete by polling the
+// HcInterruptStatus register's WritebackDoneHead field.
+//
+// Input:
+// IN PEI_OHCI_DEV *OhciDevPtr
+// -- PEI_OHCI_DEV pointer
+// IN POHCI_TD Td
+// -- Not used
+//
+// Output:
+// EFI_STATUS (Return Value)
+// = EFI_SUCCESS on successful completion
+// or valid EFI error code
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS OhciHcWaitForTransferComplete (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_OHCI_DEV *OhciDevPtr,
+ IN POHCI_TD Td )
+{
+ UINT32 Count;
+ OHCI_HC_REGISTERS *HcReg =
+ (OHCI_HC_REGISTERS *) OhciDevPtr->UsbHostControllerBaseAddress;
+ HC_INTERRUPT_STATUS *HcIntStatus = &HcReg->HcInterruptStatus;
+ UINT32 DoneHead = 0;
+
+ // Poll (up to 4 seconds) or until the
+ // WriteBackDoneHead status bit is set in
+ // the HcInterruptStatus operational register.
+
+ // if the WriteBackDoneHead is set, then clear
+ // HccaDoneHead in the HCCA and WriteBackDoneHead
+ // and then return EFI_SUCCESS to continue execution.
+
+ for (Count = 0; Count < 1000; Count++) {
+ if (HcIntStatus->Field.WriteBackDoneHead == HCINT_WB_DONE ) {
+ DoneHead = HcReg->HcHcca->HccaDoneHead;
+ HcReg->HcHcca->HccaDoneHead = 0;
+ HcIntStatus->Field.WriteBackDoneHead = HCINT_STATUS_CLEAR;
+ if (DoneHead == (UINT32)Td) {
+ return EFI_SUCCESS;
+ }
+ }
+ OHCI_FIXED_DELAY_MS( OhciDevPtr, 4 ); // 4 ms
+
+ }
+
+ PEI_TRACE ((EFI_D_ERROR, PeiServices, "OHCI Time-Out:\n"));
+ return EFI_NOT_FOUND;
+
+}
+
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (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