Import EhciDxe and UhciDxe into MdeModulePkg.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3191 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
vanjeff
2007-07-11 06:46:38 +00:00
parent 20b1aab609
commit 913cb9dc64
30 changed files with 13427 additions and 0 deletions

View File

@@ -0,0 +1,203 @@
/** @file
Copyright (c) 2004 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
ComponentName.c
Abstract:
**/
#include "uhci.h"
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
UhciComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
UhciComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle, OPTIONAL
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gUhciComponentName = {
UhciComponentNameGetDriverName,
UhciComponentNameGetControllerName,
"eng"
};
static EFI_UNICODE_STRING_TABLE mUhciDriverNameTable[] = {
{ "eng", L"Usb Uhci Driver" },
{ NULL, NULL }
};
EFI_STATUS
EFIAPI
UhciComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language - A pointer to a three character ISO 639-2 language identifier.
This is the language of the driver name that that the caller
is requesting, and it must match one of the languages specified
in SupportedLanguages. The number of languages supported by a
driver is up to the driver writer.
DriverName - A pointer to the Unicode string to return. This Unicode string
is the name of the driver specified by This in the language
specified by Language.
Returns:
EFI_SUCCESS - The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - DriverName is NULL.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gUhciComponentName.SupportedLanguages,
mUhciDriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
UhciComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle, OPTIONAL
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by an EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle - The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle - The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName - A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language
specified by Language from the point of view of the
driver specified by This.
Returns:
EFI_SUCCESS - The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - ControllerName is NULL.
EFI_UNSUPPORTED - The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
EFI_STATUS Status;
USB_HC_DEV *UhciDev;
EFI_USB_HC_PROTOCOL *UsbHc;
//
// This is a device driver, so ChildHandle must be NULL.
//
if (ChildHandle != NULL) {
return EFI_UNSUPPORTED;
}
//
// Make sure this driver is currently managing ControllerHandle
//
Status = EfiTestManagedDevice (
ControllerHandle,
gUhciDriverBinding.DriverBindingHandle,
&gEfiPciIoProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the device context
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiUsbHcProtocolGuid,
(VOID **) &UsbHc,
gUhciDriverBinding.DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
UhciDev = UHC_FROM_USB_HC_PROTO (UsbHc);
return LookupUnicodeString (
Language,
gUhciComponentName.SupportedLanguages,
UhciDev->CtrlNameTable,
ControllerName
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
/** @file
Copyright (c) 2004 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Uhci.h
Abstract:
The definition for UHCI driver model and HC protocol routines.
Revision History
**/
#ifndef _UHCI_H
#define _UHCI_H
//
// The package level header files this module uses
//
#include <PiDxe.h>
//
// The protocols, PPI and GUID defintions for this module
//
#include <Protocol/Usb2HostController.h>
#include <Protocol/UsbHostController.h>
#include <Protocol/PciIo.h>
//
// The Library classes this module consumes
//
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/MemoryAllocationLib.h>
#include <IndustryStandard/Pci22.h>
typedef struct _USB_HC_DEV USB_HC_DEV;
#include "UsbHcMem.h"
#include "UhciQueue.h"
#include "UhciReg.h"
#include "UhciSched.h"
#include "UhciDebug.h"
enum {
//
// Stall times
//
STALL_1_MS = 1000,
STALL_1_SECOND = 1000 *STALL_1_MS,
UHC_SYN_POLL = 50,
FORCE_GLOBAL_RESUME_TIME = 20 *STALL_1_MS,
ROOT_PORT_REST_TIME = 50 *STALL_1_MS,
PORT_RESET_RECOVERY_TIME = 10 *STALL_1_MS,
INTERRUPT_POLLING_TIME = 50 * 10000UL,
//
// UHC raises TPL to TPL_NOTIFY to serialize all its operations
// to protect shared data structures.
//
UHCI_TPL = TPL_NOTIFY,
USB_HC_DEV_SIGNATURE = EFI_SIGNATURE_32 ('u', 'h', 'c', 'i'),
};
#pragma pack(1)
typedef struct {
UINT8 PI;
UINT8 SubClassCode;
UINT8 BaseCode;
} USB_CLASSC;
#pragma pack()
#define UHC_FROM_USB_HC_PROTO(This) CR(This, USB_HC_DEV, UsbHc, USB_HC_DEV_SIGNATURE)
#define UHC_FROM_USB2_HC_PROTO(This) CR(This, USB_HC_DEV, Usb2Hc, USB_HC_DEV_SIGNATURE)
//
// USB_HC_DEV support the UHCI hardware controller. It schedules
// the asynchronous interrupt transfer with the same method as
// EHCI: a reversed tree structure. For synchronous interrupt,
// control and bulk transfer, it uses three static queue head to
// schedule them. SyncIntQh is for interrupt transfer. LsCtrlQh is
// for LOW speed control transfer, and FsCtrlBulkQh is for FULL
// speed control or bulk transfer. This is because FULL speed contrl
// or bulk transfer can reclaim the unused bandwidth. Some USB
// device requires this bandwidth reclamation capability.
//
typedef struct _USB_HC_DEV {
UINT32 Signature;
EFI_USB_HC_PROTOCOL UsbHc;
EFI_USB2_HC_PROTOCOL Usb2Hc;
EFI_PCI_IO_PROTOCOL *PciIo;
//
// Schedule data structures
//
UINT32 *FrameBase;
UHCI_QH_SW *SyncIntQh;
UHCI_QH_SW *CtrlQh;
UHCI_QH_SW *BulkQh;
//
// Structures to maintain asynchronus interrupt transfers.
// When asynchronous interrutp transfer is unlinked from
// the frame list, the hardware may still hold a pointer
// to it. To synchronize with hardware, its resoureces are
// released in two steps using Recycle and RecycleWait.
// Check the asynchronous interrupt management routines.
//
LIST_ENTRY AsyncIntList;
EFI_EVENT AsyncIntMonitor;
UHCI_ASYNC_REQUEST *Recycle;
UHCI_ASYNC_REQUEST *RecycleWait;
UINTN RootPorts;
USBHC_MEM_POOL *MemPool;
EFI_UNICODE_STRING_TABLE *CtrlNameTable;
VOID *FrameMapping;
} USB_HC_DEV;
extern EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding;
extern EFI_COMPONENT_NAME_PROTOCOL gUhciComponentName;
#endif

View File

@@ -0,0 +1,101 @@
#/** @file
# Component name for module Uhci
#
# Copyright (c) 2006, Intel Corporation. All right reserved.
#
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
#**/
################################################################################
#
# Defines Section - statements that will be processed to create a Makefile.
#
################################################################################
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Uhci
FILE_GUID = 2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = UhciDriverEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
################################################################################
#
# Sources Section - list of files that are required for the build to succeed.
#
################################################################################
[Sources.common]
UhciSched.c
UhciDebug.c
UsbHcMem.h
UhciDebug.h
UhciQueue.c
UhciReg.c
UsbHcMem.c
UhciQueue.h
Uhci.c
Uhci.h
UhciReg.h
UhciSched.h
ComponentName.c
################################################################################
#
# Package Dependency Section - list of Package files that are required for
# this module.
#
################################################################################
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
################################################################################
#
# Library Class Section - list of Library Classes that are required for
# this module.
#
################################################################################
[LibraryClasses]
MemoryAllocationLib
BaseLib
UefiLib
UefiBootServicesTableLib
UefiDriverEntryPoint
BaseMemoryLib
DebugLib
################################################################################
#
# Protocol C Name Section - list of Protocol and Protocol Notify C Names
# that this module uses or produces.
#
################################################################################
[Protocols]
gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiUsbHcProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiUsb2HcProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@@ -0,0 +1,84 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>Uhci</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module Uhci</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>
<License>All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>Uhci</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseMemoryLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>MemoryAllocationLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>ComponentName.c</Filename>
<Filename>uhci.h</Filename>
<Filename>UhciSched.h</Filename>
<Filename>UhciReg.h</Filename>
<Filename>uhci.c</Filename>
<Filename>UhciQueue.h</Filename>
<Filename>UsbHcMem.c</Filename>
<Filename>UhciReg.c</Filename>
<Filename>UhciQueue.c</Filename>
<Filename>UhciDebug.h</Filename>
<Filename>UsbHcMem.h</Filename>
<Filename>UhciDebug.c</Filename>
<Filename>UhciSched.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUsb2HcProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUsbHcProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>UhciDriverEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@@ -0,0 +1,183 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UhciDebug.c
Abstract:
This file provides the information dump support for Uhci when in debug mode.
You can dynamically adjust the debug level by changing variable gEHCDebugLevel
and gEHCErrorLevel.
Revision History
**/
#include "Uhci.h"
#include "UhciDebug.h"
#ifdef EFI_DEBUG
UINTN mUhciDebugMask = USB_DEBUG_FORCE_OUTPUT;
/**
Debug debug print interface for UHCI
@param Format String to use for the print, followed by print arguments
@return None
**/
VOID
UhciDebug (
IN CHAR8 *Format,
...
)
{
VA_LIST Marker;
VA_START (Marker, Format);
DebugVPrint (DEBUG_INFO, Format, Marker);
VA_END (Marker);
}
/**
Debug error print interface for UHCI
@param Format String to use for the print, followed by print arguments
@return None
**/
VOID
UhciError (
IN CHAR8 *Format,
...
)
{
VA_LIST Marker;
VA_START (Marker, Format);
DebugVPrint (DEBUG_ERROR, Format, Marker);
VA_END (Marker);
}
/**
Debug print interface for UHCI
@param Level Level to control debug print
@param Format String to use for the print, followed by print arguments
@return None
**/
VOID
UhciDebugPrint (
IN UINTN Level,
IN CHAR8 *Format,
...
)
{
VA_LIST Marker;
VA_START (Marker, Format);
if (Level & mUhciDebugMask) {
if (mUhciDebugMask & USB_DEBUG_FORCE_OUTPUT) {
DebugVPrint (DEBUG_ERROR, Format, Marker);
} else {
DebugVPrint (DEBUG_INFO, Format, Marker);
}
}
VA_END (Marker);
}
/**
Dump the content of QH structure
@param QhSw Pointer to software QH structure
@return None
**/
VOID
UhciDumpQh (
IN UHCI_QH_SW *QhSw
)
{
UINTN Level;
Level = UHCI_DEBUG_QH;
UhciDebugPrint (Level, "&QhSw @ 0x%x\n", QhSw);
UhciDebugPrint (Level, "QhSw.NextQh - 0x%x\n", QhSw->NextQh);
UhciDebugPrint (Level, "QhSw.TDs - 0x%x\n", QhSw->TDs);
UhciDebugPrint (Level, "QhSw.QhHw:\n");
UhciDebugPrint (Level, " Horizon Link - %x\n", QhSw->QhHw.HorizonLink);
UhciDebugPrint (Level, " Vertical Link - %x\n\n", QhSw->QhHw.VerticalLink);
}
/**
Dump the content of TD structure.
@param TdSw Pointer to software TD structure
@param IsCur Whether dump the whole list, or only dump the current TD
@return None
**/
VOID
UhciDumpTds (
IN UHCI_TD_SW *TdSw
)
{
UHCI_TD_SW *CurTdSw;
UINTN Level;
Level = UHCI_DEBUG_TD;
CurTdSw = TdSw;
while (CurTdSw != NULL) {
UhciDebugPrint (Level, "TdSw @ 0x%x\n", CurTdSw);
UhciDebugPrint (Level, "TdSw.NextTd - 0x%x\n", CurTdSw->NextTd);
UhciDebugPrint (Level, "TdSw.DataLen - %d\n", CurTdSw->DataLen);
UhciDebugPrint (Level, "TdSw.Data - 0x%x\n", CurTdSw->Data);
UhciDebugPrint (Level, "TdHw:\n");
UhciDebugPrint (Level, " NextLink - 0x%x\n", CurTdSw->TdHw.NextLink);
UhciDebugPrint (Level, " ActualLen - %d\n", CurTdSw->TdHw.ActualLen);
UhciDebugPrint (Level, " Status - 0x%x\n", CurTdSw->TdHw.Status);
UhciDebugPrint (Level, " IOC - %d\n", CurTdSw->TdHw.IntOnCpl);
UhciDebugPrint (Level, " IsIsoCh - %d\n", CurTdSw->TdHw.IsIsoch);
UhciDebugPrint (Level, " LowSpeed - %d\n", CurTdSw->TdHw.LowSpeed);
UhciDebugPrint (Level, " ErrorCount - %d\n", CurTdSw->TdHw.ErrorCount);
UhciDebugPrint (Level, " ShortPacket - %d\n", CurTdSw->TdHw.ShortPacket);
UhciDebugPrint (Level, " PidCode - 0x%x\n", CurTdSw->TdHw.PidCode);
UhciDebugPrint (Level, " DevAddr - %d\n", CurTdSw->TdHw.DeviceAddr);
UhciDebugPrint (Level, " EndPoint - %d\n", CurTdSw->TdHw.EndPoint);
UhciDebugPrint (Level, " DataToggle - %d\n", CurTdSw->TdHw.DataToggle);
UhciDebugPrint (Level, " MaxPacketLen - %d\n", CurTdSw->TdHw.MaxPacketLen);
UhciDebugPrint (Level, " DataBuffer - 0x%x\n\n",CurTdSw->TdHw.DataBuffer);
CurTdSw = CurTdSw->NextTd;
}
}
#endif

View File

@@ -0,0 +1,134 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UhciDebug.h
Abstract:
This file contains the definination for host controller debug support routines
Revision History
**/
#ifndef _EFI_UHCI_DEBUG_H_
#define _EFI_UHCI_DEBUG_H_
//
// DEBUG support
//
#define USB_DEBUG_FORCE_OUTPUT (UINTN) (1 << 0)
#define UHCI_DEBUG_QH (UINTN) (1 << 2)
#define UHCI_DEBUG_TD (UINTN) (1 << 3)
VOID
UhciDebugPrint (
IN UINTN Level,
IN CHAR8 *Format,
...
)
/*++
Routine Description:
Debug print interface for UHCI
Arguments:
Level - Level to control debug print
Format - String to use for the print, followed by print arguments
Returns:
None
--*/
;
/**
Debug print interface for UHCI
@param Format String to use for the print, followed by print arguments
@return None
**/
VOID
UhciDebug (
IN CHAR8 *Format,
...
)
;
/**
Debug error print interface for UHCI
@param Format String to use for the print, followed by print arguments
@return None
**/
VOID
UhciError (
IN CHAR8 *Format,
...
)
;
/**
Dump the content of QH structure
@param QhSw Pointer to software QH structure
@return None
**/
VOID
UhciDumpQh (
IN UHCI_QH_SW *QhSw
)
;
/**
Dump the content of TD structure.
@param TdSw Pointer to software TD structure
@return None
**/
VOID
UhciDumpTds (
IN UHCI_TD_SW *TdSw
)
;
#ifdef EFI_DEBUG
#define UHCI_DEBUG(arg) UhciDebug arg
#define UHCI_ERROR(arg) UhciError arg
#define UHCI_DUMP_TDS(arg) UhciDumpTds arg
#define UHCI_DUMP_QH(arg) UhciDumpQh arg
#else
#define UHCI_DEBUG(arg)
#define UHCI_ERROR(arg)
#define UHCI_DUMP_TDS(arg)
#define UHCI_DUMP_QH(arg)
#endif
#endif

View File

@@ -0,0 +1,703 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UhciQueue.c
Abstract:
The UHCI register operation routines.
Revision History
**/
#include "Uhci.h"
/**
Map address of request structure buffer
@param Uhc The UHCI device
@param Request The user request buffer
@param MappedAddr Mapped address of request
@param Map Identificaion of this mapping to return
@return EFI_SUCCESS : Success
@return EFI_DEVICE_ERROR : Fail to map the user request
**/
EFI_STATUS
UhciMapUserRequest (
IN USB_HC_DEV *Uhc,
IN OUT VOID *Request,
OUT UINT8 **MappedAddr,
OUT VOID **Map
)
{
EFI_STATUS Status;
UINTN Len;
EFI_PHYSICAL_ADDRESS PhyAddr;
Len = sizeof (EFI_USB_DEVICE_REQUEST);
Status = Uhc->PciIo->Map (
Uhc->PciIo,
EfiPciIoOperationBusMasterRead,
Request,
&Len,
&PhyAddr,
Map
);
if (!EFI_ERROR (Status)) {
*MappedAddr = (UINT8 *) (UINTN) PhyAddr;
}
return Status;
}
/**
Map address of user data buffer
@param Uhc The UHCI device
@param Direction direction of the data transfer
@param Data The user data buffer
@param Len Length of the user data
@param PktId Packet identificaion
@param MappedAddr mapped address to return
@param Map identificaion of this mapping to return
@return EFI_SUCCESS : Success
@return EFI_DEVICE_ERROR : Fail to map the user data
**/
EFI_STATUS
UhciMapUserData (
IN USB_HC_DEV *Uhc,
IN EFI_USB_DATA_DIRECTION Direction,
IN VOID *Data,
IN OUT UINTN *Len,
OUT UINT8 *PktId,
OUT UINT8 **MappedAddr,
OUT VOID **Map
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS PhyAddr;
Status = EFI_SUCCESS;
switch (Direction) {
case EfiUsbDataIn:
//
// BusMasterWrite means cpu read
//
*PktId = INPUT_PACKET_ID;
Status = Uhc->PciIo->Map (
Uhc->PciIo,
EfiPciIoOperationBusMasterWrite,
Data,
Len,
&PhyAddr,
Map
);
if (EFI_ERROR (Status)) {
goto EXIT;
}
*MappedAddr = (UINT8 *) (UINTN) PhyAddr;
break;
case EfiUsbDataOut:
*PktId = OUTPUT_PACKET_ID;
Status = Uhc->PciIo->Map (
Uhc->PciIo,
EfiPciIoOperationBusMasterRead,
Data,
Len,
&PhyAddr,
Map
);
if (EFI_ERROR (Status)) {
goto EXIT;
}
*MappedAddr = (UINT8 *) (UINTN) PhyAddr;
break;
case EfiUsbNoData:
if ((Len != NULL) && (*Len != 0)) {
Status = EFI_INVALID_PARAMETER;
goto EXIT;
}
*PktId = OUTPUT_PACKET_ID;
*Len = 0;
*MappedAddr = NULL;
*Map = NULL;
break;
default:
Status = EFI_INVALID_PARAMETER;
}
EXIT:
return Status;
}
/**
Link the TD To QH
@param Qh The queue head for the TD to link to
@param Td The TD to link
@return VOID
**/
VOID
UhciLinkTdToQh (
IN UHCI_QH_SW *Qh,
IN UHCI_TD_SW *Td
)
{
ASSERT ((Qh != NULL) && (Td != NULL));
Qh->QhHw.VerticalLink = QH_VLINK (Td, FALSE);
Qh->TDs = (VOID *) Td;
}
/**
Unlink TD from the QH
@param Qh The queue head to unlink from
@param Td The TD to unlink
@return VOID
**/
VOID
UhciUnlinkTdFromQh (
IN UHCI_QH_SW *Qh,
IN UHCI_TD_SW *Td
)
{
ASSERT ((Qh != NULL) && (Td != NULL));
Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
Qh->TDs = NULL;
}
/**
Append a new TD To the previous TD
@param PrevTd Previous UHCI_TD_SW to be linked to
@param ThisTd TD to link
@return VOID
**/
STATIC
VOID
UhciAppendTd (
IN UHCI_TD_SW *PrevTd,
IN UHCI_TD_SW *ThisTd
)
{
ASSERT ((PrevTd != NULL) && (ThisTd != NULL));
PrevTd->TdHw.NextLink = TD_LINK (ThisTd, TRUE, FALSE);
PrevTd->NextTd = (VOID *) ThisTd;
}
/**
Delete a list of TDs
@param Uhc The UHCI device
@param FirstTd TD link list head
@return VOID
**/
VOID
UhciDestoryTds (
IN USB_HC_DEV *Uhc,
IN UHCI_TD_SW *FirstTd
)
{
UHCI_TD_SW *NextTd;
UHCI_TD_SW *ThisTd;
NextTd = FirstTd;
while (NextTd != NULL) {
ThisTd = NextTd;
NextTd = ThisTd->NextTd;
UsbHcFreeMem (Uhc->MemPool, ThisTd, sizeof (UHCI_TD_SW));
}
}
/**
Create an initialize a new queue head
@param Uhc The UHCI device
@param Interval The polling interval for the queue
@return The newly created queue header
**/
UHCI_QH_SW *
UhciCreateQh (
IN USB_HC_DEV *Uhc,
IN UINTN Interval
)
{
UHCI_QH_SW *Qh;
Qh = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_QH_SW));
if (Qh == NULL) {
return NULL;
}
Qh->QhHw.HorizonLink = QH_HLINK (NULL, TRUE);
Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
Qh->Interval = Interval;
Qh->TDs = NULL;
Qh->NextQh = NULL;
return Qh;
}
/**
Create and intialize a TD
@param Uhc The UHCI device
@return The newly allocated and initialized TD
**/
STATIC
UHCI_TD_SW *
UhciCreateTd (
IN USB_HC_DEV *Uhc
)
{
UHCI_TD_SW *Td;
Td = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_TD_SW));
if (Td == NULL) {
return NULL;
}
Td->TdHw.NextLink = TD_LINK (NULL, FALSE, TRUE);
Td->NextTd = NULL;
Td->Data = NULL;
Td->DataLen = 0;
return Td;
}
/**
Create and initialize a TD for Setup Stage of a control transfer
@param Uhc The UHCI device
@param DevAddr Device address
@param Request Device request
@param IsLow Full speed or low speed
@return The created setup Td Pointer
**/
STATIC
UHCI_TD_SW *
UhciCreateSetupTd (
IN USB_HC_DEV *Uhc,
IN UINT8 DevAddr,
IN UINT8 *Request,
IN BOOLEAN IsLow
)
{
UHCI_TD_SW *Td;
Td = UhciCreateTd (Uhc);
if (Td == NULL) {
return NULL;
}
Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
Td->TdHw.ShortPacket = FALSE;
Td->TdHw.IsIsoch = FALSE;
Td->TdHw.IntOnCpl = FALSE;
Td->TdHw.ErrorCount = 0x03;
Td->TdHw.Status |= USBTD_ACTIVE;
Td->TdHw.DataToggle = 0;
Td->TdHw.EndPoint = 0;
Td->TdHw.LowSpeed = IsLow ? 1 : 0;
Td->TdHw.DeviceAddr = DevAddr & 0x7F;
Td->TdHw.MaxPacketLen = (UINT32) (sizeof (EFI_USB_DEVICE_REQUEST) - 1);
Td->TdHw.PidCode = SETUP_PACKET_ID;
Td->TdHw.DataBuffer = (UINT32) (UINTN) Request;
Td->Data = Request;
Td->DataLen = sizeof (EFI_USB_DEVICE_REQUEST);
return Td;
}
/**
Create a TD for data
@param Uhc The UHCI device
@param DevAddr Device address
@param Endpoint Endpoint number
@param DataPtr Data buffer
@param Len Data length
@param PktId Packet ID
@param Toggle Data toggle value
@param IsLow Full speed or low speed
@return Data Td pointer if success, otherwise NUL
**/
STATIC
UHCI_TD_SW *
UhciCreateDataTd (
IN USB_HC_DEV *Uhc,
IN UINT8 DevAddr,
IN UINT8 Endpoint,
IN UINT8 *DataPtr,
IN UINTN Len,
IN UINT8 PktId,
IN UINT8 Toggle,
IN BOOLEAN IsLow
)
{
UHCI_TD_SW *Td;
//
// Code as length - 1, and the max valid length is 0x500
//
ASSERT (Len <= 0x500);
Td = UhciCreateTd (Uhc);
if (Td == NULL) {
return NULL;
}
Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
Td->TdHw.ShortPacket = FALSE;
Td->TdHw.IsIsoch = FALSE;
Td->TdHw.IntOnCpl = FALSE;
Td->TdHw.ErrorCount = 0X03;
Td->TdHw.Status = USBTD_ACTIVE;
Td->TdHw.LowSpeed = IsLow ? 1 : 0;
Td->TdHw.DataToggle = Toggle & 0x01;
Td->TdHw.EndPoint = Endpoint & 0x0F;
Td->TdHw.DeviceAddr = DevAddr & 0x7F;
Td->TdHw.MaxPacketLen = (UINT32) (Len - 1);
Td->TdHw.PidCode = (UINT8) PktId;
Td->TdHw.DataBuffer = (UINT32) (UINTN) DataPtr;
Td->Data = DataPtr;
Td->DataLen = (UINT16) Len;
return Td;
}
/**
Create TD for the Status Stage of control transfer
@param Uhc The UHCI device
@param DevAddr Device address
@param PktId Packet ID
@param IsLow Full speed or low speed
@return Status Td Pointer
**/
STATIC
UHCI_TD_SW *
UhciCreateStatusTd (
IN USB_HC_DEV *Uhc,
IN UINT8 DevAddr,
IN UINT8 PktId,
IN BOOLEAN IsLow
)
{
UHCI_TD_SW *Td;
Td = UhciCreateTd (Uhc);
if (Td == NULL) {
return NULL;
}
Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
Td->TdHw.ShortPacket = FALSE;
Td->TdHw.IsIsoch = FALSE;
Td->TdHw.IntOnCpl = FALSE;
Td->TdHw.ErrorCount = 0x03;
Td->TdHw.Status |= USBTD_ACTIVE;
Td->TdHw.MaxPacketLen = 0x7FF; //0x7FF: there is no data (refer to UHCI spec)
Td->TdHw.DataToggle = 1;
Td->TdHw.EndPoint = 0;
Td->TdHw.LowSpeed = IsLow ? 1 : 0;
Td->TdHw.DeviceAddr = DevAddr & 0x7F;
Td->TdHw.PidCode = (UINT8) PktId;
Td->TdHw.DataBuffer = (UINT32) (UINTN) NULL;
Td->Data = NULL;
Td->DataLen = 0;
return Td;
}
/**
Create Tds list for Control Transfer
@param Uhc The UHCI device
@param DeviceAddr The device address
@param DataPktId Packet Identification of Data Tds
@param Request A pointer to request structure buffer to transfer
@param Data A pointer to user data buffer to transfer
@param DataLen Length of user data to transfer
@param MaxPacket Maximum packet size for control transfer
@param IsLow Full speed or low speed
@return The Td list head for the control transfer
**/
UHCI_TD_SW *
UhciCreateCtrlTds (
IN USB_HC_DEV *Uhc,
IN UINT8 DeviceAddr,
IN UINT8 DataPktId,
IN UINT8 *Request,
IN UINT8 *Data,
IN UINTN DataLen,
IN UINT8 MaxPacket,
IN BOOLEAN IsLow
)
{
UHCI_TD_SW *SetupTd;
UHCI_TD_SW *FirstDataTd;
UHCI_TD_SW *DataTd;
UHCI_TD_SW *PrevDataTd;
UHCI_TD_SW *StatusTd;
UINT8 DataToggle;
UINT8 StatusPktId;
UINTN ThisTdLen;
DataTd = NULL;
SetupTd = NULL;
FirstDataTd = NULL;
PrevDataTd = NULL;
StatusTd = NULL;
//
// Create setup packets for the transfer
//
SetupTd = UhciCreateSetupTd (Uhc, DeviceAddr, Request, IsLow);
if (SetupTd == NULL) {
return NULL;
}
//
// Create data packets for the transfer
//
DataToggle = 1;
while (DataLen > 0) {
//
// PktSize is the data load size in each Td.
//
ThisTdLen = (DataLen > MaxPacket ? MaxPacket : DataLen);
DataTd = UhciCreateDataTd (
Uhc,
DeviceAddr,
0,
Data,
ThisTdLen,
DataPktId,
DataToggle,
IsLow
);
if (DataTd == NULL) {
goto FREE_TD;
}
if (FirstDataTd == NULL) {
FirstDataTd = DataTd;
FirstDataTd->NextTd = NULL;
} else {
UhciAppendTd (PrevDataTd, DataTd);
}
DataToggle ^= 1;
PrevDataTd = DataTd;
Data += ThisTdLen;
DataLen -= ThisTdLen;
}
//
// Status packet is on the opposite direction to data packets
//
if (OUTPUT_PACKET_ID == DataPktId) {
StatusPktId = INPUT_PACKET_ID;
} else {
StatusPktId = OUTPUT_PACKET_ID;
}
StatusTd = UhciCreateStatusTd (Uhc, DeviceAddr, StatusPktId, IsLow);
if (StatusTd == NULL) {
goto FREE_TD;
}
//
// Link setup Td -> data Tds -> status Td together
//
if (FirstDataTd != NULL) {
UhciAppendTd (SetupTd, FirstDataTd);
UhciAppendTd (PrevDataTd, StatusTd);
} else {
UhciAppendTd (SetupTd, StatusTd);
}
return SetupTd;
FREE_TD:
if (SetupTd != NULL) {
UhciDestoryTds (Uhc, SetupTd);
}
if (FirstDataTd != NULL) {
UhciDestoryTds (Uhc, FirstDataTd);
}
return NULL;
}
/**
Create Tds list for Bulk/Interrupt Transfer
@param Uhc USB_HC_DEV
@param DevAddr Address of Device
@param EndPoint Endpoint Number
@param PktId Packet Identification of Data Tds
@param Data A pointer to user data buffer to transfer
@param DataLen Length of user data to transfer
@param DataToggle Data Toggle Pointer
@param MaxPacket Maximum packet size for Bulk/Interrupt transfer
@param IsLow Is Low Speed Device
@return The Tds list head for the bulk transfer
**/
UHCI_TD_SW *
UhciCreateBulkOrIntTds (
IN USB_HC_DEV *Uhc,
IN UINT8 DevAddr,
IN UINT8 EndPoint,
IN UINT8 PktId,
IN UINT8 *Data,
IN UINTN DataLen,
IN OUT UINT8 *DataToggle,
IN UINT8 MaxPacket,
IN BOOLEAN IsLow
)
{
UHCI_TD_SW *DataTd;
UHCI_TD_SW *FirstDataTd;
UHCI_TD_SW *PrevDataTd;
UINTN ThisTdLen;
DataTd = NULL;
FirstDataTd = NULL;
PrevDataTd = NULL;
//
// Create data packets for the transfer
//
while (DataLen > 0) {
//
// PktSize is the data load size that each Td.
//
ThisTdLen = DataLen;
if (DataLen > MaxPacket) {
ThisTdLen = MaxPacket;
}
DataTd = UhciCreateDataTd (
Uhc,
DevAddr,
EndPoint,
Data,
ThisTdLen,
PktId,
*DataToggle,
IsLow
);
if (DataTd == NULL) {
goto FREE_TD;
}
if (PktId == INPUT_PACKET_ID) {
DataTd->TdHw.ShortPacket = TRUE;
}
if (FirstDataTd == NULL) {
FirstDataTd = DataTd;
FirstDataTd->NextTd = NULL;
} else {
UhciAppendTd (PrevDataTd, DataTd);
}
*DataToggle ^= 1;
PrevDataTd = DataTd;
Data += ThisTdLen;
DataLen -= ThisTdLen;
}
return FirstDataTd;
FREE_TD:
if (FirstDataTd != NULL) {
UhciDestoryTds (Uhc, FirstDataTd);
}
return NULL;
}

View File

@@ -0,0 +1,283 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UhciQueue.h
Abstract:
The definition for UHCI register operation routines.
Revision History
**/
#ifndef _EFI_UHCI_QUEUE_H_
#define _EFI_UHCI_QUEUE_H_
//
// Macroes used to set various links in UHCI's driver.
// In this UHCI driver, QH's horizontal link always pointers to other QH,
// and its vertical link always pointers to TD. TD's next pointer always
// pointers to other sibling TD. Frame link always pointers to QH because
// ISO transfer isn't supported.
//
// We should use UINT32 to access these pointers to void race conditions
// with hardware.
//
#define QH_HLINK(Pointer, Terminate) \
(((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | 0x02 | ((Terminate) ? 0x01 : 0))
#define QH_VLINK(Pointer, Terminate) \
(((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | ((Terminate) ? 0x01 : 0))
#define TD_LINK(Pointer, VertFirst, Terminate) \
(((UINT32) ((UINTN) (Pointer)) & 0xFFFFFFF0) | \
((VertFirst) ? 0x04 : 0) | ((Terminate) ? 0x01 : 0))
#define LINK_TERMINATED(Link) (((Link) & 0x01) != 0)
#define UHCI_ADDR(QhOrTd) ((VOID *) (UINTN) ((QhOrTd) & 0xFFFFFFF0))
#pragma pack(1)
//
// Both links in QH has this internal structure:
// Next pointer: 28, Reserved: 2, NextIsQh: 1, Terminate: 1
// This is the same as frame list entry.
//
typedef struct {
UINT32 HorizonLink;
UINT32 VerticalLink;
} UHCI_QH_HW;
//
// Next link in TD has this internal structure:
// Next pointer: 28, Reserved: 1, Vertical First: 1, NextIsQh: 1, Terminate: 1
//
typedef struct {
UINT32 NextLink;
UINT32 ActualLen : 11;
UINT32 Reserved1 : 5;
UINT32 Status : 8;
UINT32 IntOnCpl : 1;
UINT32 IsIsoch : 1;
UINT32 LowSpeed : 1;
UINT32 ErrorCount : 2;
UINT32 ShortPacket : 1;
UINT32 Reserved2 : 2;
UINT32 PidCode : 8;
UINT32 DeviceAddr : 7;
UINT32 EndPoint : 4;
UINT32 DataToggle : 1;
UINT32 Reserved3 : 1;
UINT32 MaxPacketLen: 11;
UINT32 DataBuffer;
} UHCI_TD_HW;
#pragma pack()
typedef struct _UHCI_TD_SW UHCI_TD_SW;
typedef struct _UHCI_QH_SW UHCI_QH_SW;
typedef struct _UHCI_QH_SW {
UHCI_QH_HW QhHw;
UHCI_QH_SW *NextQh;
UHCI_TD_SW *TDs;
UINTN Interval;
} UHCI_QH_SW;
typedef struct _UHCI_TD_SW {
UHCI_TD_HW TdHw;
UHCI_TD_SW *NextTd;
UINT8 *Data;
UINT16 DataLen;
} UHCI_TD_SW;
/**
Link the TD To QH
@param Qh The queue head for the TD to link to
@param Td The TD to link
@return VOID
**/
VOID
UhciLinkTdToQh (
IN UHCI_QH_SW *Qh,
IN UHCI_TD_SW *Td
)
;
/**
Unlink TD from the QH
@param Qh The queue head to unlink from
@param Td The TD to unlink
@return VOID
**/
VOID
UhciUnlinkTdFromQh (
IN UHCI_QH_SW *Qh,
IN UHCI_TD_SW *Td
)
;
/**
Map address of request structure buffer
@param Uhc The UHCI device
@param Request The user request buffer
@param MappedAddr Mapped address of request
@param Map Identificaion of this mapping to return
@return EFI_SUCCESS : Success
@return EFI_DEVICE_ERROR : Fail to map the user request
**/
EFI_STATUS
UhciMapUserRequest (
IN USB_HC_DEV *Uhc,
IN OUT VOID *Request,
OUT UINT8 **MappedAddr,
OUT VOID **Map
)
;
/**
Map address of user data buffer
@param Uhc The UHCI device
@param Direction direction of the data transfer
@param Data The user data buffer
@param Len Length of the user data
@param PktId Packet identificaion
@param MappedAddr mapped address to return
@param Map identificaion of this mapping to return
@return EFI_SUCCESS : Success
@return EFI_DEVICE_ERROR : Fail to map the user data
**/
EFI_STATUS
UhciMapUserData (
IN USB_HC_DEV *Uhc,
IN EFI_USB_DATA_DIRECTION Direction,
IN VOID *Data,
IN OUT UINTN *Len,
OUT UINT8 *PktId,
OUT UINT8 **MappedAddr,
OUT VOID **Map
)
;
/**
Delete a list of TDs
@param Uhc The UHCI device
@param FirstTd TD link list head
@return VOID
**/
VOID
UhciDestoryTds (
IN USB_HC_DEV *Uhc,
IN UHCI_TD_SW *FirstTd
)
;
/**
Create an initialize a new queue head
@param Uhc The UHCI device
@param Interval The polling interval for the queue
@return The newly created queue header
**/
UHCI_QH_SW *
UhciCreateQh (
IN USB_HC_DEV *Uhc,
IN UINTN Interval
)
;
/**
Create Tds list for Control Transfer
@param Uhc The UHCI device
@param DeviceAddr The device address
@param DataPktId Packet Identification of Data Tds
@param Request A pointer to request structure buffer to transfer
@param Data A pointer to user data buffer to transfer
@param DataLen Length of user data to transfer
@param MaxPacket Maximum packet size for control transfer
@param IsLow Full speed or low speed
@return The Td list head for the control transfer
**/
UHCI_TD_SW *
UhciCreateCtrlTds (
IN USB_HC_DEV *Uhc,
IN UINT8 DeviceAddr,
IN UINT8 DataPktId,
IN UINT8 *Request,
IN UINT8 *Data,
IN UINTN DataLen,
IN UINT8 MaxPacket,
IN BOOLEAN IsLow
)
;
/**
Create Tds list for Bulk/Interrupt Transfer
@param Uhc USB_HC_DEV
@param DevAddr Address of Device
@param EndPoint Endpoint Number
@param PktId Packet Identification of Data Tds
@param Data A pointer to user data buffer to transfer
@param DataLen Length of user data to transfer
@param DataToggle Data Toggle Pointer
@param MaxPacket Maximum packet size for Bulk/Interrupt transfer
@param IsLow Is Low Speed Device
@return The Tds list head for the bulk transfer
**/
UHCI_TD_SW *
UhciCreateBulkOrIntTds (
IN USB_HC_DEV *Uhc,
IN UINT8 DevAddr,
IN UINT8 EndPoint,
IN UINT8 PktId,
IN UINT8 *Data,
IN UINTN DataLen,
IN OUT UINT8 *DataToggle,
IN UINT8 MaxPacket,
IN BOOLEAN IsLow
)
;
#endif

View File

@@ -0,0 +1,303 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UhciReg.c
Abstract:
The UHCI register operation routines.
Revision History
**/
#include "Uhci.h"
/**
Read a UHCI register
@param PciIo The EFI_PCI_IO_PROTOCOL to use
@param Offset Register offset to USB_BAR_INDEX
@return Content of register
**/
UINT16
UhciReadReg (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT32 Offset
)
{
UINT16 Data;
EFI_STATUS Status;
Status = PciIo->Io.Read (
PciIo,
EfiPciIoWidthUint16,
USB_BAR_INDEX,
Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
UHCI_ERROR (("UhciReadReg: PciIo Io.Read error: %r at offset %d\n", Status, Offset));
Data = 0xFFFF;
}
return Data;
}
/**
Write data to UHCI register
@param PciIo The EFI_PCI_IO_PROTOCOL to use
@param Offset Register offset to USB_BAR_INDEX
@param Data Data to write
@return VOID
**/
VOID
UhciWriteReg (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT32 Offset,
IN UINT16 Data
)
{
EFI_STATUS Status;
Status = PciIo->Io.Write (
PciIo,
EfiPciIoWidthUint16,
USB_BAR_INDEX,
Offset,
1,
&Data
);
if (EFI_ERROR (Status)) {
UHCI_ERROR (("UhciWriteReg: PciIo Io.Write error: %r at offset %d\n", Status, Offset));
}
}
/**
Set a bit of the UHCI Register
@param PciIo The EFI_PCI_IO_PROTOCOL to use
@param Offset Register offset to USB_BAR_INDEX
@param Bit The bit to set
@return None
**/
VOID
UhciSetRegBit (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT32 Offset,
IN UINT16 Bit
)
{
UINT16 Data;
Data = UhciReadReg (PciIo, Offset);
Data |= Bit;
UhciWriteReg (PciIo, Offset, Data);
}
/**
Clear a bit of the UHCI Register
@param PciIo The PCI_IO protocol to access the PCI
@param Offset Register offset to USB_BAR_INDEX
@param Bit The bit to clear
@return None
**/
VOID
UhciClearRegBit (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT32 Offset,
IN UINT16 Bit
)
{
UINT16 Data;
Data = UhciReadReg (PciIo, Offset);
Data &= ~Bit;
UhciWriteReg (PciIo, Offset, Data);
}
/**
Clear all the interrutp status bits, these bits
are Write-Clean
@param Uhc The UHCI device
@return None
**/
VOID
UhciAckAllInterrupt (
IN USB_HC_DEV *Uhc
)
{
UhciWriteReg (Uhc->PciIo, USBSTS_OFFSET, 0x3F);
//
// If current HC is halted, re-enable it. Host Controller Process Error
// is a temporary error status.
//
if (!UhciIsHcWorking (Uhc->PciIo)) {
UHCI_ERROR (("UhciAckAllInterrupt: re-enable the UHCI from system error\n"));
Uhc->UsbHc.SetState (&Uhc->UsbHc, EfiUsbHcStateOperational);
}
}
/**
Stop the host controller
@param Uhc The UHCI device
@param Timeout Max time allowed
@retval EFI_SUCCESS The host controller is stopped
@retval EFI_TIMEOUT Failed to stop the host controller
**/
EFI_STATUS
UhciStopHc (
IN USB_HC_DEV *Uhc,
IN UINTN Timeout
)
{
UINT16 UsbSts;
UINTN Index;
UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS);
//
// ensure the HC is in halt status after send the stop command
// Timeout is in us unit.
//
for (Index = 0; Index < (Timeout / 50) + 1; Index++) {
UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {
return EFI_SUCCESS;
}
gBS->Stall (50);
}
return EFI_TIMEOUT;
}
/**
Check whether the host controller operates well
@param PciIo The PCI_IO protocol to use
@retval TRUE Host controller is working
@retval FALSE Host controller is halted or system error
**/
BOOLEAN
UhciIsHcWorking (
IN EFI_PCI_IO_PROTOCOL *PciIo
)
{
UINT16 UsbSts;
UsbSts = UhciReadReg (PciIo, USBSTS_OFFSET);
if (UsbSts & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) {
UHCI_ERROR (("UhciIsHcWorking: current USB state is %x\n", UsbSts));
return FALSE;
}
return TRUE;
}
/**
Set the UHCI frame list base address. It can't use
UhciWriteReg which access memory in UINT16.
@param PciIo The EFI_PCI_IO_PROTOCOL to use
@param Addr Address to set
@return VOID
**/
VOID
UhciSetFrameListBaseAddr (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN VOID *Addr
)
{
EFI_STATUS Status;
UINT32 Data;
Data = (UINT32) ((UINTN) Addr & 0xFFFFF000);
Status = PciIo->Io.Write (
PciIo,
EfiPciIoWidthUint32,
USB_BAR_INDEX,
(UINT64) USB_FRAME_BASE_OFFSET,
1,
&Data
);
if (EFI_ERROR (Status)) {
UHCI_ERROR (("UhciSetFrameListBaseAddr: PciIo Io.Write error: %r\n", Status));
}
}
/**
Disable USB Emulation
@param PciIo The EFI_PCI_IO_PROTOCOL protocol to use
@return VOID
**/
VOID
UhciTurnOffUsbEmulation (
IN EFI_PCI_IO_PROTOCOL *PciIo
)
{
UINT16 Command;
Command = 0;
PciIo->Pci.Write (
PciIo,
EfiPciIoWidthUint16,
USB_EMULATION_OFFSET,
1,
&Command
);
}

View File

@@ -0,0 +1,264 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UhciReg.h
Abstract:
The definition for UHCI register operation routines.
Revision History
**/
#ifndef _EFI_UHCI_REG_H_
#define _EFI_UHCI_REG_H_
#define BIT(a) (1 << (a))
enum {
UHCI_FRAME_NUM = 1024,
//
// Register offset and PCI related staff
//
CLASSC_OFFSET = 0x09,
USBBASE_OFFSET = 0x20,
USB_BAR_INDEX = 4,
PCI_CLASSC_PI_UHCI = 0x00,
USBCMD_OFFSET = 0,
USBSTS_OFFSET = 2,
USBINTR_OFFSET = 4,
USBPORTSC_OFFSET = 0x10,
USB_FRAME_NO_OFFSET = 6,
USB_FRAME_BASE_OFFSET = 8,
USB_EMULATION_OFFSET = 0xC0,
//
// Packet IDs
//
SETUP_PACKET_ID = 0x2D,
INPUT_PACKET_ID = 0x69,
OUTPUT_PACKET_ID = 0xE1,
ERROR_PACKET_ID = 0x55,
//
// USB port status and control bit definition.
//
USBPORTSC_CCS = BIT(0), // Current Connect Status
USBPORTSC_CSC = BIT(1), // Connect Status Change
USBPORTSC_PED = BIT(2), // Port Enable / Disable
USBPORTSC_PEDC = BIT(3), // Port Enable / Disable Change
USBPORTSC_LSL = BIT(4), // Line Status Low BIT
USBPORTSC_LSH = BIT(5), // Line Status High BIT
USBPORTSC_RD = BIT(6), // Resume Detect
USBPORTSC_LSDA = BIT(8), // Low Speed Device Attached
USBPORTSC_PR = BIT(9), // Port Reset
USBPORTSC_SUSP = BIT(12), // Suspend
USB_MAX_ROOTHUB_PORT = 0x0F, // Max number of root hub port
//
// Command register bit definitions
//
USBCMD_RS = BIT(0), // Run/Stop
USBCMD_HCRESET = BIT(1), // Host reset
USBCMD_GRESET = BIT(2), // Global reset
USBCMD_EGSM = BIT(3), // Global Suspend Mode
USBCMD_FGR = BIT(4), // Force Global Resume
USBCMD_SWDBG = BIT(5), // SW Debug mode
USBCMD_CF = BIT(6), // Config Flag (sw only)
USBCMD_MAXP = BIT(7), // Max Packet (0 = 32, 1 = 64)
//
// USB Status register bit definitions
//
USBSTS_USBINT = BIT(0), // Interrupt due to IOC
USBSTS_ERROR = BIT(1), // Interrupt due to error
USBSTS_RD = BIT(2), // Resume Detect
USBSTS_HSE = BIT(3), // Host System Error
USBSTS_HCPE = BIT(4), // Host Controller Process Error
USBSTS_HCH = BIT(5), // HC Halted
USBTD_ACTIVE = BIT(7), // TD is still active
USBTD_STALLED = BIT(6), // TD is stalled
USBTD_BUFFERR = BIT(5), // Buffer underflow or overflow
USBTD_BABBLE = BIT(4), // Babble condition
USBTD_NAK = BIT(3), // NAK is received
USBTD_CRC = BIT(2), // CRC/Time out error
USBTD_BITSTUFF = BIT(1), // Bit stuff error
};
/**
Read a UHCI register
@param PciIo The EFI_PCI_IO_PROTOCOL to use
@param Offset Register offset to USB_BAR_INDEX
@return Content of register
**/
UINT16
UhciReadReg (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT32 Offset
)
;
/**
Write data to UHCI register
@param PciIo The EFI_PCI_IO_PROTOCOL to use
@param Offset Register offset to USB_BAR_INDEX
@param Data Data to write
@return VOID
**/
VOID
UhciWriteReg (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT32 Offset,
IN UINT16 Data
)
;
/**
Set a bit of the UHCI Register
@param PciIo The EFI_PCI_IO_PROTOCOL to use
@param Offset Register offset to USB_BAR_INDEX
@param Bit The bit to set
@return None
**/
VOID
UhciSetRegBit (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT32 Offset,
IN UINT16 Bit
)
;
/**
Clear a bit of the UHCI Register
@param PciIo The PCI_IO protocol to access the PCI
@param Offset Register offset to USB_BAR_INDEX
@param Bit The bit to clear
@return None
**/
VOID
UhciClearRegBit (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT32 Offset,
IN UINT16 Bit
)
;
/**
Clear all the interrutp status bits, these bits
are Write-Clean
@param Uhc The UHCI device
@return None
**/
VOID
UhciAckAllInterrupt (
IN USB_HC_DEV *Uhc
)
;
/**
Stop the host controller
@param Uhc The UHCI device
@param Timeout Max time allowed
@retval EFI_SUCCESS The host controller is stopped
@retval EFI_TIMEOUT Failed to stop the host controller
**/
EFI_STATUS
UhciStopHc (
IN USB_HC_DEV *Uhc,
IN UINTN Timeout
)
;
/**
Check whether the host controller operates well
@param PciIo The PCI_IO protocol to use
@retval TRUE Host controller is working
@retval FALSE Host controller is halted or system error
**/
BOOLEAN
UhciIsHcWorking (
IN EFI_PCI_IO_PROTOCOL *PciIo
)
;
/**
Set the UHCI frame list base address. It can't use
UhciWriteReg which access memory in UINT16.
@param PciIo The EFI_PCI_IO_PROTOCOL to use
@param Addr Address to set
@return VOID
**/
VOID
UhciSetFrameListBaseAddr (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN VOID *Addr
)
;
/**
Disable USB Emulation
@param PciIo The EFI_PCI_IO_PROTOCOL protocol to use
@return VOID
**/
VOID
UhciTurnOffUsbEmulation (
IN EFI_PCI_IO_PROTOCOL *PciIo
)
;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,305 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UhciSched.h
Abstract:
The definition for EHCI register operation routines.
Revision History
**/
#ifndef _EFI_UHCI_SCHED_H_
#define _EFI_UHCI_SCHED_H_
enum {
UHCI_ASYNC_INT_SIGNATURE = EFI_SIGNATURE_32 ('u', 'h', 'c', 'a'),
//
// The failure mask for USB transfer return status. If any of
// these bit is set, the transfer failed. EFI_USB_ERR_NOEXECUTE
// and EFI_USB_ERR_NAK are not considered as error condition:
// the transfer is still going on.
//
USB_ERR_FAIL_MASK = EFI_USB_ERR_STALL | EFI_USB_ERR_BUFFER |
EFI_USB_ERR_BABBLE | EFI_USB_ERR_CRC |
EFI_USB_ERR_TIMEOUT | EFI_USB_ERR_BITSTUFF |
EFI_USB_ERR_SYSTEM,
};
//
// Structure to return the result of UHCI QH execution.
// Result is the final result of the QH's QTD. NextToggle
// is the next data toggle to use. Complete is the actual
// length of data transferred.
//
typedef struct {
UINT32 Result;
UINT8 NextToggle;
UINTN Complete;
} UHCI_QH_RESULT;
typedef struct _UHCI_ASYNC_REQUEST UHCI_ASYNC_REQUEST;
//
// Structure used to manager the asynchronous interrupt transfers.
//
typedef struct _UHCI_ASYNC_REQUEST{
UINTN Signature;
LIST_ENTRY Link;
UHCI_ASYNC_REQUEST *Recycle;
//
// Endpoint attributes
//
UINT8 DevAddr;
UINT8 EndPoint;
BOOLEAN IsLow;
UINTN Interval;
//
// Data and UHC structures
//
UHCI_QH_SW *QhSw;
UHCI_TD_SW *FirstTd;
UINT8 *Data; // Allocated host memory, not mapped memory
UINTN DataLen;
VOID *Mapping;
//
// User callback and its context
//
EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
VOID *Context;
} UHCI_ASYNC_REQUEST;
#define UHCI_ASYNC_INT_FROM_LINK(a) \
CR (a, UHCI_ASYNC_REQUEST, Link, UHCI_ASYNC_INT_SIGNATURE)
EFI_STATUS
UhciInitFrameList (
IN USB_HC_DEV *Uhc
)
/*++
Routine Description:
Create Frame List Structure
Arguments:
Uhc - UHCI device
Returns:
EFI_OUT_OF_RESOURCES - Can't allocate memory resources
EFI_UNSUPPORTED - Map memory fail
EFI_SUCCESS - Success
--*/
;
/**
Destory FrameList buffer
@param Uhc The UHCI device
@return VOID
**/
VOID
UhciDestoryFrameList (
IN USB_HC_DEV *Uhc
)
;
/**
Convert the poll rate to the maxium 2^n that is smaller
than Interval
@param Interval The poll rate to convert
@return The converted poll rate
**/
UINTN
UhciConvertPollRate (
IN UINTN Interval
)
;
/**
Link a queue head (for asynchronous interrupt transfer) to
the frame list.
@param FrameBase The base of the frame list
@param Qh The queue head to link into
@return None
**/
VOID
UhciLinkQhToFrameList (
UINT32 *FrameBase,
UHCI_QH_SW *Qh
)
;
/**
Unlink QH from the frame list is easier: find all
the precedence node, and pointer there next to QhSw's
next.
@param FrameBase The base address of the frame list
@param Qh The queue head to unlink
@return None
**/
VOID
UhciUnlinkQhFromFrameList (
UINT32 *FrameBase,
UHCI_QH_SW *Qh
)
;
/**
Check the result of the transfer
@param Uhc The UHCI device
@param Td The first TDs of the transfer
@param TimeOut TimeOut value in milliseconds
@param IsLow Is Low Speed Device
@param QhResult The variable to return result
@retval EFI_SUCCESS The transfer finished with success
@retval EFI_DEVICE_ERROR Transfer failed
**/
EFI_STATUS
UhciExecuteTransfer (
IN USB_HC_DEV *Uhc,
IN UHCI_QH_SW *Qh,
IN UHCI_TD_SW *Td,
IN UINTN TimeOut,
IN BOOLEAN IsLow,
OUT UHCI_QH_RESULT *QhResult
)
;
/**
Create Async Request node, and Link to List
@param Uhc The UHCI device
@param Qh The queue head of the transfer
@param FirstTd First TD of the transfer
@param DevAddr Device Address
@param EndPoint EndPoint Address
@param Toggle Data Toggle
@param DataLen Data length
@param Interval Polling Interval when inserted to frame list
@param Mapping Mapping value
@param Data Data buffer, unmapped
@param Callback Callback after interrupt transfeer
@param Context Callback Context passed as function parameter
@param IsLow Is Low Speed
@retval EFI_SUCCESS An asynchronous transfer is created
@retval EFI_INVALID_PARAMETER Paremeter is error
@retval EFI_OUT_OF_RESOURCES Failed because of resource shortage.
**/
EFI_STATUS
UhciCreateAsyncReq (
IN USB_HC_DEV *Uhc,
IN UHCI_QH_SW *Qh,
IN UHCI_TD_SW *FirstTd,
IN UINT8 DevAddr,
IN UINT8 EndPoint,
IN UINTN DataLen,
IN UINTN Interval,
IN VOID *Mapping,
IN UINT8 *Data,
IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
IN VOID *Context,
IN BOOLEAN IsLow
)
;
/**
Delete Async Interrupt QH and TDs
@param Uhc The UHCI device
@param DevAddr Device Address
@param EndPoint EndPoint Address
@param Toggle The next data toggle to use
@retval EFI_SUCCESS The request is deleted
@retval EFI_INVALID_PARAMETER Paremeter is error
@retval EFI_NOT_FOUND The asynchronous isn't found
**/
EFI_STATUS
UhciRemoveAsyncReq (
IN USB_HC_DEV *Uhc,
IN UINT8 DevAddr,
IN UINT8 EndPoint,
OUT UINT8 *Toggle
)
;
/**
Release all the asynchronous transfers on the lsit.
@param Uhc The UHCI device
@return VOID
**/
VOID
UhciFreeAllAsyncReq (
IN USB_HC_DEV *Uhc
)
;
/**
Interrupt transfer periodic check handler
@param Event The event of the time
@param Context Context of the event, pointer to USB_HC_DEV
@return VOID
**/
VOID
UhciMonitorAsyncReqList (
IN EFI_EVENT Event,
IN VOID *Context
)
;
#endif

View File

@@ -0,0 +1,548 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EhciMem.c
Abstract:
Revision History
**/
#include "Uhci.h"
UINTN mUsbHcDebugLevel = DEBUG_INFO;
/**
Allocate a block of memory to be used by the buffer pool
@param Pool The buffer pool to allocate memory for
@param Pages How many pages to allocate
@return The allocated memory block or NULL if failed
**/
STATIC
USBHC_MEM_BLOCK *
UsbHcAllocMemBlock (
IN USBHC_MEM_POOL *Pool,
IN UINTN Pages
)
{
USBHC_MEM_BLOCK *Block;
EFI_PCI_IO_PROTOCOL *PciIo;
VOID *BufHost;
VOID *Mapping;
EFI_PHYSICAL_ADDRESS MappedAddr;
UINTN Bytes;
EFI_STATUS Status;
PciIo = Pool->PciIo;
Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));
if (Block == NULL) {
return NULL;
}
//
// each bit in the bit array represents USBHC_MEM_UNIT
// bytes of memory in the memory block.
//
ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
Block->Bits = AllocateZeroPool (Block->BitsLen);
if (Block->Bits == NULL) {
gBS->FreePool (Block);
return NULL;
}
//
// Allocate the number of Pages of memory, then map it for
// bus master read and write.
//
Status = PciIo->AllocateBuffer (
PciIo,
AllocateAnyPages,
EfiBootServicesData,
Pages,
&BufHost,
0
);
if (EFI_ERROR (Status)) {
goto FREE_BITARRAY;
}
Bytes = EFI_PAGES_TO_SIZE (Pages);
Status = PciIo->Map (
PciIo,
EfiPciIoOperationBusMasterCommonBuffer,
BufHost,
&Bytes,
&MappedAddr,
&Mapping
);
if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
goto FREE_BUFFER;
}
//
// Check whether the data structure used by the host controller
// should be restricted into the same 4G
//
if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
PciIo->Unmap (PciIo, Mapping);
goto FREE_BUFFER;
}
Block->BufHost = BufHost;
Block->Buf = (UINT8 *) ((UINTN) MappedAddr);
Block->Mapping = Mapping;
DEBUG ((mUsbHcDebugLevel, "UsbHcAllocMemBlock: block %x created with buffer %x\n",
Block, Block->Buf));
return Block;
FREE_BUFFER:
PciIo->FreeBuffer (PciIo, Pages, BufHost);
FREE_BITARRAY:
gBS->FreePool (Block->Bits);
gBS->FreePool (Block);
return NULL;
}
/**
Free the memory block from the memory pool
@param Pool The memory pool to free the block from
@param Block The memory block to free
@return VOID
**/
STATIC
VOID
UsbHcFreeMemBlock (
IN USBHC_MEM_POOL *Pool,
IN USBHC_MEM_BLOCK *Block
)
{
EFI_PCI_IO_PROTOCOL *PciIo;
ASSERT ((Pool != NULL) && (Block != NULL));
PciIo = Pool->PciIo;
//
// Unmap the common buffer then free the structures
//
PciIo->Unmap (PciIo, Block->Mapping);
PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);
gBS->FreePool (Block->Bits);
gBS->FreePool (Block);
}
/**
Alloc some memory from the block
@param Block The memory block to allocate memory from
@param Mem The variable to store the memory allocated
@param Units Number of memory units to allocate
@return EFI_SUCCESS : The needed memory is allocated
@return EFI_NOT_FOUND : Can't find the free memory
**/
STATIC
VOID *
UsbHcAllocMemFromBlock (
IN USBHC_MEM_BLOCK *Block,
IN UINTN Units
)
{
UINTN Byte;
UINT8 Bit;
UINTN StartByte;
UINT8 StartBit;
UINTN Available;
UINTN Count;
ASSERT ((Block != 0) && (Units != 0));
StartByte = 0;
StartBit = 0;
Available = 0;
for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
//
// If current bit is zero, the corresponding memory unit is
// available, otherwise we need to restart our searching.
// Available counts the consective number of zero bit.
//
if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
Available++;
if (Available >= Units) {
break;
}
NEXT_BIT (Byte, Bit);
} else {
NEXT_BIT (Byte, Bit);
Available = 0;
StartByte = Byte;
StartBit = Bit;
}
}
if (Available < Units) {
return NULL;
}
//
// Mark the memory as allocated
//
Byte = StartByte;
Bit = StartBit;
for (Count = 0; Count < Units; Count++) {
ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
Block->Bits[Byte] |= USB_HC_BIT (Bit);
NEXT_BIT (Byte, Bit);
}
return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
}
/**
Insert the memory block to the pool's list of the blocks
@param Head The head of the memory pool's block list
@param Block The memory block to insert
@return VOID
**/
STATIC
VOID
UsbHcInsertMemBlockToPool (
IN USBHC_MEM_BLOCK *Head,
IN USBHC_MEM_BLOCK *Block
)
{
ASSERT ((Head != NULL) && (Block != NULL));
Block->Next = Head->Next;
Head->Next = Block;
}
/**
Is the memory block empty?
@param Block The memory block to check
@return TRUE : The memory block is empty
@return FALSE : The memory block isn't empty
**/
STATIC
BOOLEAN
UsbHcIsMemBlockEmpty (
IN USBHC_MEM_BLOCK *Block
)
{
UINTN Index;
for (Index = 0; Index < Block->BitsLen; Index++) {
if (Block->Bits[Index] != 0) {
return FALSE;
}
}
return TRUE;
}
/**
Unlink the memory block from the pool's list
@param Head The block list head of the memory's pool
@param BlockToUnlink The memory block to unlink.
@return VOID
**/
STATIC
VOID
UsbHcUnlinkMemBlock (
IN USBHC_MEM_BLOCK *Head,
IN USBHC_MEM_BLOCK *BlockToUnlink
)
{
USBHC_MEM_BLOCK *Block;
ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
for (Block = Head; Block != NULL; Block = Block->Next) {
if (Block->Next == BlockToUnlink) {
Block->Next = BlockToUnlink->Next;
BlockToUnlink->Next = NULL;
break;
}
}
}
/**
Initialize the memory management pool for the host controller
@param Pool The USB memory pool to initialize
@param PciIo The PciIo that can be used to access the host controller
@param Check4G Whether the host controller requires allocated memory
from one 4G address space.
@param Which4G The 4G memory area each memory allocated should be from
@return EFI_SUCCESS : The memory pool is initialized
@return EFI_OUT_OF_RESOURCE : Fail to init the memory pool
**/
USBHC_MEM_POOL *
UsbHcInitMemPool (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN BOOLEAN Check4G,
IN UINT32 Which4G
)
{
USBHC_MEM_POOL *Pool;
Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
if (Pool == NULL) {
return Pool;
}
Pool->PciIo = PciIo;
Pool->Check4G = Check4G;
Pool->Which4G = Which4G;
Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
if (Pool->Head == NULL) {
gBS->FreePool (Pool);
Pool = NULL;
}
return Pool;
}
/**
Release the memory management pool
@param Pool The USB memory pool to free
@return EFI_SUCCESS : The memory pool is freed
@return EFI_DEVICE_ERROR : Failed to free the memory pool
**/
EFI_STATUS
UsbHcFreeMemPool (
IN USBHC_MEM_POOL *Pool
)
{
USBHC_MEM_BLOCK *Block;
ASSERT (Pool->Head != NULL);
//
// Unlink all the memory blocks from the pool, then free them.
// UsbHcUnlinkMemBlock can't be used to unlink and free the
// first block.
//
for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
UsbHcUnlinkMemBlock (Pool->Head, Block);
UsbHcFreeMemBlock (Pool, Block);
}
UsbHcFreeMemBlock (Pool, Pool->Head);
gBS->FreePool (Pool);
return EFI_SUCCESS;
}
/**
Allocate some memory from the host controller's memory pool
which can be used to communicate with host controller.
@param Pool The host controller's memory pool
@param Size Size of the memory to allocate
@return The allocated memory or NULL
**/
VOID *
UsbHcAllocateMem (
IN USBHC_MEM_POOL *Pool,
IN UINTN Size
)
{
USBHC_MEM_BLOCK *Head;
USBHC_MEM_BLOCK *Block;
USBHC_MEM_BLOCK *NewBlock;
VOID *Mem;
UINTN AllocSize;
UINTN Pages;
Mem = NULL;
AllocSize = USBHC_MEM_ROUND (Size);
Head = Pool->Head;
ASSERT (Head != NULL);
//
// First check whether current memory blocks can satisfy the allocation.
//
for (Block = Head; Block != NULL; Block = Block->Next) {
Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
if (Mem != NULL) {
ZeroMem (Mem, Size);
break;
}
}
if (Mem != NULL) {
return Mem;
}
//
// Create a new memory block if there is not enough memory
// in the pool. If the allocation size is larger than the
// default page number, just allocate a large enough memory
// block. Otherwise allocate default pages.
//
if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
} else {
Pages = USBHC_MEM_DEFAULT_PAGES;
}
NewBlock = UsbHcAllocMemBlock (Pool, Pages);
if (NewBlock == NULL) {
DEBUG ((mUsbHcDebugLevel, "UsbHcAllocateMem: failed to allocate block\n"));
return NULL;
}
//
// Add the new memory block to the pool, then allocate memory from it
//
UsbHcInsertMemBlockToPool (Head, NewBlock);
Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
if (Mem != NULL) {
ZeroMem (Mem, Size);
}
return Mem;
}
/**
Free the allocated memory back to the memory pool
@param Pool The memory pool of the host controller
@param Mem The memory to free
@param Size The size of the memory to free
@return VOID
**/
VOID
UsbHcFreeMem (
IN USBHC_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
)
{
USBHC_MEM_BLOCK *Head;
USBHC_MEM_BLOCK *Block;
UINT8 *ToFree;
UINTN AllocSize;
UINTN Byte;
UINTN Bit;
UINTN Count;
Head = Pool->Head;
AllocSize = USBHC_MEM_ROUND (Size);
ToFree = (UINT8 *) Mem;
for (Block = Head; Block != NULL; Block = Block->Next) {
//
// scan the memory block list for the memory block that
// completely contains the memory to free.
//
if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
//
// compute the start byte and bit in the bit array
//
Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;
Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;
//
// reset associated bits in bit arry
//
for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
Block->Bits[Byte] ^= (UINT8) USB_HC_BIT (Bit);
NEXT_BIT (Byte, Bit);
}
break;
}
}
//
// If Block == NULL, it means that the current memory isn't
// in the host controller's pool. This is critical because
// the caller has passed in a wrong memory point
//
ASSERT (Block != NULL);
//
// Release the current memory block if it is empty and not the head
//
if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
DEBUG ((mUsbHcDebugLevel, "UsbHcFreeMem: block %x is empty, recycle\n", Block));
UsbHcUnlinkMemBlock (Head, Block);
UsbHcFreeMemBlock (Pool, Block);
}
return ;
}

View File

@@ -0,0 +1,167 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EhciMem.h
Abstract:
This file contains the definination for host controller memory management routines
Revision History
**/
#ifndef _EFI_EHCI_MEM_H_
#define _EFI_EHCI_MEM_H_
#include <IndustryStandard/Pci22.h>
#define USB_HC_BIT(a) ((UINTN)(1 << (a)))
#define USB_HC_BIT_IS_SET(Data, Bit) \
((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))
#define USB_HC_HIGH_32BIT(Addr64) \
((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;
typedef struct _USBHC_MEM_BLOCK {
UINT8 *Bits; // Bit array to record which unit is allocated
UINTN BitsLen;
UINT8 *Buf;
UINT8 *BufHost;
UINTN BufLen; // Memory size in bytes
VOID *Mapping;
USBHC_MEM_BLOCK *Next;
} USBHC_MEM_BLOCK;
//
// USBHC_MEM_POOL is used to manage the memory used by USB
// host controller. EHCI requires the control memory and transfer
// data to be on the same 4G memory.
//
typedef struct _USBHC_MEM_POOL {
EFI_PCI_IO_PROTOCOL *PciIo;
BOOLEAN Check4G;
UINT32 Which4G;
USBHC_MEM_BLOCK *Head;
} USBHC_MEM_POOL;
enum {
USBHC_MEM_UNIT = 64, // Memory allocation unit, must be 2^n, n>4
USBHC_MEM_UNIT_MASK = USBHC_MEM_UNIT - 1,
USBHC_MEM_DEFAULT_PAGES = 16,
};
#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
//
// Advance the byte and bit to the next bit, adjust byte accordingly.
//
#define NEXT_BIT(Byte, Bit) \
do { \
(Bit)++; \
if ((Bit) > 7) { \
(Byte)++; \
(Bit) = 0; \
} \
} while (0)
USBHC_MEM_POOL *
UsbHcInitMemPool (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN BOOLEAN Check4G,
IN UINT32 Which4G
)
/*++
Routine Description:
Initialize the memory management pool for the host controller
Arguments:
Pool - The USB memory pool to initialize
PciIo - The PciIo that can be used to access the host controller
Check4G - Whether the host controller requires allocated memory
from one 4G address space.
Which4G - The 4G memory area each memory allocated should be from
Returns:
EFI_SUCCESS : The memory pool is initialized
EFI_OUT_OF_RESOURCE : Fail to init the memory pool
--*/
;
/**
Release the memory management pool
@param Pool The USB memory pool to free
@return EFI_SUCCESS : The memory pool is freed
@return EFI_DEVICE_ERROR : Failed to free the memory pool
**/
EFI_STATUS
UsbHcFreeMemPool (
IN USBHC_MEM_POOL *Pool
)
;
/**
Allocate some memory from the host controller's memory pool
which can be used to communicate with host controller.
@param Pool The host controller's memory pool
@param Size Size of the memory to allocate
@return The allocated memory or NULL
**/
VOID *
UsbHcAllocateMem (
IN USBHC_MEM_POOL *Pool,
IN UINTN Size
)
;
/**
Free the allocated memory back to the memory pool
@param Pool The memory pool of the host controller
@param Mem The memory to free
@param Size The size of the memory to free
@return VOID
**/
VOID
UsbHcFreeMem (
IN USBHC_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
)
;
#endif