mirror of https://github.com/acidanthera/audk.git
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:
parent
20b1aab609
commit
913cb9dc64
|
@ -0,0 +1,200 @@
|
|||
/** @file
|
||||
|
||||
Copyright 2006 - 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 "Ehci.h"
|
||||
|
||||
//
|
||||
// EFI Component Name Functions
|
||||
//
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EhciComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EhciComponentNameGetControllerName (
|
||||
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 gEhciComponentName = {
|
||||
EhciComponentNameGetDriverName,
|
||||
EhciComponentNameGetControllerName,
|
||||
"eng"
|
||||
};
|
||||
|
||||
static EFI_UNICODE_STRING_TABLE mEhciDriverNameTable[] = {
|
||||
{ "eng", L"Usb Ehci Driver" },
|
||||
{ NULL , NULL }
|
||||
};
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EhciComponentNameGetDriverName (
|
||||
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,
|
||||
gEhciComponentName.SupportedLanguages,
|
||||
mEhciDriverNameTable,
|
||||
DriverName
|
||||
);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EhciComponentNameGetControllerName (
|
||||
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;
|
||||
USB2_HC_DEV *EhciDev;
|
||||
EFI_USB2_HC_PROTOCOL *Usb2Hc;
|
||||
|
||||
//
|
||||
// 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,
|
||||
gEhciDriverBinding.DriverBindingHandle,
|
||||
&gEfiPciIoProtocolGuid
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
//
|
||||
// Get the device context
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiUsb2HcProtocolGuid,
|
||||
(VOID **) &Usb2Hc,
|
||||
gEhciDriverBinding.DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
EhciDev = EHC_FROM_THIS (Usb2Hc);
|
||||
|
||||
return LookupUnicodeString (
|
||||
Language,
|
||||
gEhciComponentName.SupportedLanguages,
|
||||
EhciDev->ControllerNameTable,
|
||||
ControllerName
|
||||
);
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,152 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2006 - 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:
|
||||
|
||||
Ehci.h
|
||||
|
||||
Abstract:
|
||||
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _EFI_EHCI_H_
|
||||
#define _EFI_EHCI_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/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 _USB2_HC_DEV USB2_HC_DEV;
|
||||
|
||||
#include "UsbHcMem.h"
|
||||
#include "EhciReg.h"
|
||||
#include "EhciUrb.h"
|
||||
#include "EhciSched.h"
|
||||
#include "EhciDebug.h"
|
||||
|
||||
enum {
|
||||
USB2_HC_DEV_SIGNATURE = EFI_SIGNATURE_32 ('e', 'h', 'c', 'i'),
|
||||
EHC_STALL_1_MICROSECOND = 1,
|
||||
EHC_STALL_1_MILLISECOND = 1000 * EHC_STALL_1_MICROSECOND,
|
||||
EHC_STALL_1_SECOND = 1000 * EHC_STALL_1_MILLISECOND,
|
||||
|
||||
EHC_SET_PORT_RESET_TIME = 50 * EHC_STALL_1_MILLISECOND,
|
||||
EHC_CLEAR_PORT_RESET_TIME = EHC_STALL_1_MILLISECOND,
|
||||
EHC_GENERIC_TIME = 10 * EHC_STALL_1_MILLISECOND,
|
||||
EHC_SYNC_POLL_TIME = 20 * EHC_STALL_1_MICROSECOND,
|
||||
EHC_ASYNC_POLL_TIME = 50 * 10000UL, // The unit of time is 100us
|
||||
|
||||
EHC_TPL = TPL_NOTIFY,
|
||||
};
|
||||
|
||||
//
|
||||
//Iterate through the doule linked list. NOT delete safe
|
||||
//
|
||||
#define EFI_LIST_FOR_EACH(Entry, ListHead) \
|
||||
for(Entry = (ListHead)->ForwardLink; Entry != (ListHead); Entry = Entry->ForwardLink)
|
||||
|
||||
//
|
||||
//Iterate through the doule linked list. This is delete-safe.
|
||||
//Don't touch NextEntry
|
||||
//
|
||||
#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \
|
||||
for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\
|
||||
Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink)
|
||||
|
||||
#define EFI_LIST_CONTAINER(Entry, Type, Field) _CR(Entry, Type, Field)
|
||||
|
||||
|
||||
#define EHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))
|
||||
#define EHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))
|
||||
#define EHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
|
||||
|
||||
#define EHC_REG_BIT_IS_SET(Ehc, Offset, Bit) \
|
||||
(EHC_BIT_IS_SET(EhcReadOpReg ((Ehc), (Offset)), (Bit)))
|
||||
|
||||
#define EHC_FROM_THIS(a) CR(a, USB2_HC_DEV, Usb2Hc, USB2_HC_DEV_SIGNATURE)
|
||||
|
||||
typedef struct _USB2_HC_DEV {
|
||||
UINTN Signature;
|
||||
EFI_USB2_HC_PROTOCOL Usb2Hc;
|
||||
|
||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||
USBHC_MEM_POOL *MemPool;
|
||||
|
||||
//
|
||||
// Schedule data shared between asynchronous and periodic
|
||||
// transfers:
|
||||
// ShortReadStop, as its name indicates, is used to terminate
|
||||
// the short read except the control transfer. EHCI follows
|
||||
// the alternative next QTD point when a short read happens.
|
||||
// For control transfer, even the short read happens, try the
|
||||
// status stage.
|
||||
//
|
||||
EHC_QTD *ShortReadStop;
|
||||
EFI_EVENT PollTimer;
|
||||
|
||||
//
|
||||
// Asynchronous(bulk and control) transfer schedule data:
|
||||
// ReclaimHead is used as the head of the asynchronous transfer
|
||||
// list. It acts as the reclamation header.
|
||||
//
|
||||
EHC_QH *ReclaimHead;
|
||||
|
||||
//
|
||||
// Peroidic (interrupt) transfer schedule data:
|
||||
//
|
||||
VOID *PeriodFrame; // Mapped as common buffer
|
||||
VOID *PeriodFrameHost;
|
||||
VOID *PeriodFrameMap;
|
||||
|
||||
EHC_QH *PeriodOne;
|
||||
LIST_ENTRY AsyncIntTransfers;
|
||||
|
||||
//
|
||||
// EHCI configuration data
|
||||
//
|
||||
UINT32 HcStructParams; // Cache of HC structure parameter, EHC_HCSPARAMS_OFFSET
|
||||
UINT32 HcCapParams; // Cache of HC capability parameter, HCCPARAMS
|
||||
UINT32 CapLen; // Capability length
|
||||
UINT32 High32bitAddr;
|
||||
|
||||
//
|
||||
// Misc
|
||||
//
|
||||
EFI_UNICODE_STRING_TABLE *ControllerNameTable;
|
||||
} USB2_HC_DEV;
|
||||
|
||||
|
||||
extern EFI_DRIVER_BINDING_PROTOCOL gEhciDriverBinding;
|
||||
extern EFI_COMPONENT_NAME_PROTOCOL gEhciComponentName;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,100 @@
|
|||
#/** @file
|
||||
# Component name for module Ehci
|
||||
#
|
||||
# FIX ME!
|
||||
# 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 = Ehci
|
||||
FILE_GUID = BDFE430E-8F2A-4db0-9991-6F856594777E
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
EDK_RELEASE_VERSION = 0x00020000
|
||||
EFI_SPECIFICATION_VERSION = 0x00020000
|
||||
|
||||
ENTRY_POINT = EhcDriverEntryPoint
|
||||
|
||||
#
|
||||
# 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]
|
||||
UsbHcMem.h
|
||||
EhciUrb.c
|
||||
EhciReg.h
|
||||
UsbHcMem.c
|
||||
EhciSched.c
|
||||
EhciDebug.c
|
||||
EhciReg.c
|
||||
EhciDebug.h
|
||||
ComponentName.c
|
||||
EhciUrb.h
|
||||
Ehci.h
|
||||
EhciSched.h
|
||||
Ehci.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
|
||||
gEfiUsb2HcProtocolGuid # PROTOCOL ALWAYS_CONSUMED
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<MsaHeader>
|
||||
<ModuleName>Ehci</ModuleName>
|
||||
<ModuleType>DXE_DRIVER</ModuleType>
|
||||
<GuidValue>BDFE430E-8F2A-4db0-9991-6F856594777E</GuidValue>
|
||||
<Version>1.0</Version>
|
||||
<Abstract>Component name for module Ehci</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>Ehci</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>Ehci.c</Filename>
|
||||
<Filename>EhciSched.h</Filename>
|
||||
<Filename>Ehci.h</Filename>
|
||||
<Filename>EhciUrb.h</Filename>
|
||||
<Filename>ComponentName.c</Filename>
|
||||
<Filename>EhciDebug.h</Filename>
|
||||
<Filename>EhciReg.c</Filename>
|
||||
<Filename>EhciDebug.c</Filename>
|
||||
<Filename>EhciSched.c</Filename>
|
||||
<Filename>UsbHcMem.c</Filename>
|
||||
<Filename>EhciReg.h</Filename>
|
||||
<Filename>EhciUrb.c</Filename>
|
||||
<Filename>UsbHcMem.h</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>gEfiPciIoProtocolGuid</ProtocolCName>
|
||||
</Protocol>
|
||||
</Protocols>
|
||||
<Externs>
|
||||
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
|
||||
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
|
||||
<Extern>
|
||||
<ModuleEntryPoint>EhcDriverEntryPoint</ModuleEntryPoint>
|
||||
</Extern>
|
||||
</Externs>
|
||||
</ModuleSurfaceArea>
|
|
@ -0,0 +1,345 @@
|
|||
/** @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:
|
||||
|
||||
EhciDebug.c
|
||||
|
||||
Abstract:
|
||||
This file provides the information dump support for EHCI when in debug mode.
|
||||
You can dynamically adjust the debug level by changing variable mEhcDebugLevel
|
||||
and mEhcErrorLevel.
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#include "Ehci.h"
|
||||
|
||||
#ifdef EFI_DEBUG
|
||||
UINTN mEhcDebugMask = USB_DEBUG_FORCE_OUTPUT;
|
||||
|
||||
|
||||
/**
|
||||
EHCI's debug output function. It determines whether
|
||||
to output by the mask and level
|
||||
|
||||
@param Level The output level
|
||||
@param Format The format parameters to the print
|
||||
@param ... The variable length parameters after format
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhciDebugPrint (
|
||||
IN UINTN Level,
|
||||
IN CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
{
|
||||
|
||||
VA_LIST Marker;
|
||||
|
||||
VA_START (Marker, Format);
|
||||
|
||||
if (Level & mEhcDebugMask) {
|
||||
if (mEhcDebugMask & USB_DEBUG_FORCE_OUTPUT) {
|
||||
DebugVPrint (DEBUG_ERROR, Format, Marker);
|
||||
} else {
|
||||
DebugVPrint (DEBUG_INFO, Format, Marker);
|
||||
}
|
||||
}
|
||||
|
||||
VA_END (Marker);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
EHCI's debug output function. It determines whether
|
||||
to output by the mask and level
|
||||
|
||||
@param Format The format parameters to the print
|
||||
@param ... The variable length parameters after format
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcDebug (
|
||||
IN CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
{
|
||||
VA_LIST Marker;
|
||||
|
||||
VA_START (Marker, Format);
|
||||
DebugVPrint (DEBUG_INFO, Format, Marker);
|
||||
VA_END (Marker);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
EHCI's error output function. It determines whether
|
||||
to output by the mask and level
|
||||
|
||||
@param Format The format parameters to the print
|
||||
@param ... The variable length parameters after format
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcError (
|
||||
IN CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
{
|
||||
|
||||
VA_LIST Marker;
|
||||
|
||||
VA_START (Marker, Format);
|
||||
DebugVPrint (DEBUG_ERROR, Format, Marker);
|
||||
VA_END (Marker);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Dump the status byte in QTD/QH to a more friendly
|
||||
format
|
||||
|
||||
@param State The state in the QTD/QH
|
||||
@param Level The output level
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EhcDumpStatus (
|
||||
IN UINT32 State,
|
||||
IN UINTN Level
|
||||
)
|
||||
{
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_DO_PING)) {
|
||||
EhciDebugPrint (Level, " Do_Ping");
|
||||
} else {
|
||||
EhciDebugPrint (Level, " Do_Out");
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_DO_CS)) {
|
||||
EhciDebugPrint (Level, " Do_CS");
|
||||
} else {
|
||||
EhciDebugPrint (Level, " Do_SS");
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR)) {
|
||||
EhciDebugPrint (Level, " Transfer_Error");
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {
|
||||
EhciDebugPrint (Level, " Babble_Error");
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {
|
||||
EhciDebugPrint (Level, " Buffer_Error");
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {
|
||||
EhciDebugPrint (Level, " Halted");
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {
|
||||
EhciDebugPrint (Level, " Active");
|
||||
}
|
||||
|
||||
EhciDebugPrint (Level, "\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Dump the fields of a QTD
|
||||
|
||||
@param Qtd The QTD to dump
|
||||
@param Msg The message to print before the dump
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcDumpQtd (
|
||||
IN EHC_QTD *Qtd,
|
||||
IN UINT8 *Msg
|
||||
)
|
||||
{
|
||||
QTD_HW *QtdHw;
|
||||
UINTN Index;
|
||||
UINTN Level;
|
||||
|
||||
Level = EHC_DEBUG_QTD;
|
||||
|
||||
if (Msg != NULL) {
|
||||
EhciDebugPrint (Level, Msg);
|
||||
}
|
||||
|
||||
EhciDebugPrint (Level, "Queue TD @ 0x%x, data length %d\n", Qtd, Qtd->DataLen);
|
||||
|
||||
QtdHw = &Qtd->QtdHw;
|
||||
|
||||
EhciDebugPrint (Level, "Next QTD : %x\n", QtdHw->NextQtd);
|
||||
EhciDebugPrint (Level, "AltNext QTD : %x\n", QtdHw->AltNext);
|
||||
EhciDebugPrint (Level, "Status : %x\n", QtdHw->Status);
|
||||
EhcDumpStatus (QtdHw->Status, Level);
|
||||
|
||||
if (QtdHw->Pid == QTD_PID_SETUP) {
|
||||
EhciDebugPrint (Level, "PID : Setup\n");
|
||||
|
||||
} else if (QtdHw->Pid == QTD_PID_INPUT) {
|
||||
EhciDebugPrint (Level, "PID : IN\n");
|
||||
|
||||
} else if (QtdHw->Pid == QTD_PID_OUTPUT) {
|
||||
EhciDebugPrint (Level, "PID : OUT\n");
|
||||
|
||||
}
|
||||
|
||||
EhciDebugPrint (Level, "Error Count : %d\n", QtdHw->ErrCnt);
|
||||
EhciDebugPrint (Level, "Current Page : %d\n", QtdHw->CurPage);
|
||||
EhciDebugPrint (Level, "IOC : %d\n", QtdHw->IOC);
|
||||
EhciDebugPrint (Level, "Total Bytes : %d\n", QtdHw->TotalBytes);
|
||||
EhciDebugPrint (Level, "Data Toggle : %d\n", QtdHw->DataToggle);
|
||||
|
||||
for (Index = 0; Index < 5; Index++) {
|
||||
EhciDebugPrint (Level, "Page[%d] : 0x%x\n", Index, QtdHw->Page[Index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Dump the queue head
|
||||
|
||||
@param Qh The queue head to dump
|
||||
@param Msg The message to print before the dump
|
||||
@param DumpBuf Whether to dump the memory buffer of the associated QTD
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcDumpQh (
|
||||
IN EHC_QH *Qh,
|
||||
IN UINT8 *Msg,
|
||||
IN BOOLEAN DumpBuf
|
||||
)
|
||||
{
|
||||
EHC_QTD *Qtd;
|
||||
QH_HW *QhHw;
|
||||
LIST_ENTRY *Entry;
|
||||
UINTN Index;
|
||||
UINTN Level;
|
||||
|
||||
Level = EHC_DEBUG_QH;
|
||||
|
||||
if (Msg != NULL) {
|
||||
EhciDebugPrint (Level, Msg);
|
||||
}
|
||||
|
||||
EhciDebugPrint (Level, "Queue head @ 0x%x, interval %d, next qh %x\n",
|
||||
Qh, Qh->Interval, Qh->NextQh);
|
||||
|
||||
QhHw = &Qh->QhHw;
|
||||
|
||||
EhciDebugPrint (Level, "Hoziontal link: %x\n", QhHw->HorizonLink);
|
||||
EhciDebugPrint (Level, "Device address: %d\n", QhHw->DeviceAddr);
|
||||
EhciDebugPrint (Level, "Inactive : %d\n", QhHw->Inactive);
|
||||
EhciDebugPrint (Level, "EP number : %d\n", QhHw->EpNum);
|
||||
EhciDebugPrint (Level, "EP speed : %d\n", QhHw->EpSpeed);
|
||||
EhciDebugPrint (Level, "DT control : %d\n", QhHw->DtCtrl);
|
||||
EhciDebugPrint (Level, "Reclaim head : %d\n", QhHw->ReclaimHead);
|
||||
EhciDebugPrint (Level, "Max packet len: %d\n", QhHw->MaxPacketLen);
|
||||
EhciDebugPrint (Level, "Ctrl EP : %d\n", QhHw->CtrlEp);
|
||||
EhciDebugPrint (Level, "Nak reload : %d\n", QhHw->NakReload);
|
||||
|
||||
EhciDebugPrint (Level, "SMask : %x\n", QhHw->SMask);
|
||||
EhciDebugPrint (Level, "CMask : %x\n", QhHw->CMask);
|
||||
EhciDebugPrint (Level, "Hub address : %d\n", QhHw->HubAddr);
|
||||
EhciDebugPrint (Level, "Hub port : %d\n", QhHw->PortNum);
|
||||
EhciDebugPrint (Level, "Multiplier : %d\n", QhHw->Multiplier);
|
||||
|
||||
EhciDebugPrint (Level, "Cur QTD : %x\n", QhHw->CurQtd);
|
||||
|
||||
EhciDebugPrint (Level, "Next QTD : %x\n", QhHw->NextQtd);
|
||||
EhciDebugPrint (Level, "AltNext QTD : %x\n", QhHw->AltQtd);
|
||||
EhciDebugPrint (Level, "Status : %x\n", QhHw->Status);
|
||||
EhcDumpStatus (QhHw->Status, Level);
|
||||
|
||||
if (QhHw->Pid == QTD_PID_SETUP) {
|
||||
EhciDebugPrint (Level, "PID : Setup\n");
|
||||
|
||||
} else if (QhHw->Pid == QTD_PID_INPUT) {
|
||||
EhciDebugPrint (Level, "PID : IN\n");
|
||||
|
||||
} else if (QhHw->Pid == QTD_PID_OUTPUT) {
|
||||
EhciDebugPrint (Level, "PID : OUT\n");
|
||||
}
|
||||
|
||||
EhciDebugPrint (Level, "Error Count : %d\n", QhHw->ErrCnt);
|
||||
EhciDebugPrint (Level, "Current Page : %d\n", QhHw->CurPage);
|
||||
EhciDebugPrint (Level, "IOC : %d\n", QhHw->IOC);
|
||||
EhciDebugPrint (Level, "Total Bytes : %d\n", QhHw->TotalBytes);
|
||||
EhciDebugPrint (Level, "Data Toggle : %d\n", QhHw->DataToggle);
|
||||
|
||||
for (Index = 0; Index < 5; Index++) {
|
||||
EhciDebugPrint (Level, "Page[%d] : 0x%x\n", Index, QhHw->Page[Index]);
|
||||
}
|
||||
|
||||
EhciDebugPrint (Level, "\n");
|
||||
|
||||
EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {
|
||||
Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
|
||||
EhcDumpQtd (Qtd, NULL);
|
||||
|
||||
if (DumpBuf && (Qtd->DataLen != 0)) {
|
||||
EhcDumpBuf (Qtd->Data, Qtd->DataLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Dump the buffer in the form of hex
|
||||
|
||||
@param Buf The buffer to dump
|
||||
@param Len The length of buffer
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcDumpBuf (
|
||||
IN UINT8 *Buf,
|
||||
IN UINTN Len
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
for (Index = 0; Index < Len; Index++) {
|
||||
if (Index % 16 == 0) {
|
||||
EhciDebugPrint (EHC_DEBUG_BUF, "\n");
|
||||
}
|
||||
|
||||
EhciDebugPrint (EHC_DEBUG_BUF, "%02x ", Buf[Index]);
|
||||
}
|
||||
|
||||
EhciDebugPrint (EHC_DEBUG_BUF, "\n");
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,159 @@
|
|||
/** @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:
|
||||
|
||||
EhciDebug.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This file contains the definination for host controller debug support routines
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _EFI_EHCI_DEBUG_H_
|
||||
#define _EFI_EHCI_DEBUG_H_
|
||||
|
||||
|
||||
enum {
|
||||
USB_DEBUG_FORCE_OUTPUT = (UINTN)(1 << 0),
|
||||
|
||||
EHC_DEBUG_QH = (UINTN)(1 << 8),
|
||||
EHC_DEBUG_QTD = (UINTN)(1 << 9),
|
||||
EHC_DEBUG_BUF = (UINTN)(1 << 10),
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
EHCI's debug output function. It determines whether
|
||||
to output by the mask and level
|
||||
|
||||
@param Level The output level
|
||||
@param Format The format parameters to the print
|
||||
@param ... The variable length parameters after format
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhciDebugPrint (
|
||||
IN UINTN Level,
|
||||
IN CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
EHCI's debug output function. It determines whether
|
||||
to output by the mask and level
|
||||
|
||||
@param Format The format parameters to the print
|
||||
@param ... The variable length parameters after format
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcDebug (
|
||||
IN CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
EHCI's error output function. It determines whether
|
||||
to output by the mask and level
|
||||
|
||||
@param Format The format parameters to the print
|
||||
@param ... The variable length parameters after format
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcError (
|
||||
IN CHAR8 *Format,
|
||||
...
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Dump the fields of a QTD
|
||||
|
||||
@param Qtd The QTD to dump
|
||||
@param Msg The message to print before the dump
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcDumpQtd (
|
||||
IN EHC_QTD *Qtd,
|
||||
IN UINT8 *Msg
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Dump the queue head
|
||||
|
||||
@param Qh The queue head to dump
|
||||
@param Msg The message to print before the dump
|
||||
@param DumpBuf Whether to dump the memory buffer of the associated QTD
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcDumpQh (
|
||||
IN EHC_QH *Qh,
|
||||
IN UINT8 *Msg,
|
||||
IN BOOLEAN DumpBuf
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Dump the buffer in the form of hex
|
||||
|
||||
@param Buf The buffer to dump
|
||||
@param Len The length of buffer
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcDumpBuf (
|
||||
IN UINT8 *Buf,
|
||||
IN UINTN Len
|
||||
)
|
||||
;
|
||||
|
||||
#ifdef EFI_DEBUG
|
||||
#define EHC_DEBUG(arg) EhcDebug arg
|
||||
#define EHC_ERROR(arg) EhcError arg
|
||||
#define EHC_DUMP_QH(arg) EhcDumpQh arg
|
||||
#else
|
||||
#define EHC_DEBUG(arg)
|
||||
#define EHC_ERROR(arg)
|
||||
#define EHC_DUMP_QH(arg)
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,634 @@
|
|||
/** @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:
|
||||
|
||||
EhciReg.c
|
||||
|
||||
Abstract:
|
||||
|
||||
The EHCI register operation routines.
|
||||
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#include "Ehci.h"
|
||||
|
||||
|
||||
/**
|
||||
Read EHCI capability register
|
||||
|
||||
@param Ehc The Ehc device
|
||||
@param Offset Capability register address
|
||||
|
||||
@return The register content read
|
||||
|
||||
**/
|
||||
UINT32
|
||||
EhcReadCapRegister (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset
|
||||
)
|
||||
{
|
||||
UINT32 Data;
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = Ehc->PciIo->Mem.Read (
|
||||
Ehc->PciIo,
|
||||
EfiPciIoWidthUint32,
|
||||
EHC_BAR_INDEX,
|
||||
(UINT64) Offset,
|
||||
1,
|
||||
&Data
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
EHC_ERROR (("EhcReadCapRegister: Pci Io read error - %r at %d\n", Status, Offset));
|
||||
Data = 0xFFFF;
|
||||
}
|
||||
|
||||
return Data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read Ehc Operation register
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Offset The operation register offset
|
||||
|
||||
@return The register content read
|
||||
|
||||
**/
|
||||
UINT32
|
||||
EhcReadOpReg (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset
|
||||
)
|
||||
{
|
||||
UINT32 Data;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (Ehc->CapLen != 0);
|
||||
|
||||
Status = Ehc->PciIo->Mem.Read (
|
||||
Ehc->PciIo,
|
||||
EfiPciIoWidthUint32,
|
||||
EHC_BAR_INDEX,
|
||||
(UINT64) (Ehc->CapLen + Offset),
|
||||
1,
|
||||
&Data
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
EHC_ERROR (("EhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));
|
||||
Data = 0xFFFF;
|
||||
}
|
||||
|
||||
return Data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Write the data to the EHCI operation register
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Offset EHCI operation register offset
|
||||
@param Data The data to write
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcWriteOpReg (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset,
|
||||
IN UINT32 Data
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (Ehc->CapLen != 0);
|
||||
|
||||
Status = Ehc->PciIo->Mem.Write (
|
||||
Ehc->PciIo,
|
||||
EfiPciIoWidthUint32,
|
||||
EHC_BAR_INDEX,
|
||||
(UINT64) (Ehc->CapLen + Offset),
|
||||
1,
|
||||
&Data
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
EHC_ERROR (("EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set one bit of the operational register while keeping other bits
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Offset The offset of the operational register
|
||||
@param Bit The bit mask of the register to set
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EhcSetOpRegBit (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset,
|
||||
IN UINT32 Bit
|
||||
)
|
||||
{
|
||||
UINT32 Data;
|
||||
|
||||
Data = EhcReadOpReg (Ehc, Offset);
|
||||
Data |= Bit;
|
||||
EhcWriteOpReg (Ehc, Offset, Data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Clear one bit of the operational register while keeping other bits
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Offset The offset of the operational register
|
||||
@param Bit The bit mask of the register to clear
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EhcClearOpRegBit (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset,
|
||||
IN UINT32 Bit
|
||||
)
|
||||
{
|
||||
UINT32 Data;
|
||||
|
||||
Data = EhcReadOpReg (Ehc, Offset);
|
||||
Data &= ~Bit;
|
||||
EhcWriteOpReg (Ehc, Offset, Data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Wait the operation register's bit as specified by Bit
|
||||
to become set (or clear)
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Offset The offset of the operation register
|
||||
@param Bit The bit of the register to wait for
|
||||
@param WaitToSet Wait the bit to set or clear
|
||||
@param Timeout The time to wait before abort (in millisecond)
|
||||
|
||||
@retval EFI_SUCCESS The bit successfully changed by host controller
|
||||
@retval EFI_TIMEOUT The time out occurred
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EhcWaitOpRegBit (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset,
|
||||
IN UINT32 Bit,
|
||||
IN BOOLEAN WaitToSet,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
UINT32 Index;
|
||||
|
||||
for (Index = 0; Index < Timeout / EHC_SYNC_POLL_TIME + 1; Index++) {
|
||||
if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
gBS->Stall (EHC_SYNC_POLL_TIME);
|
||||
}
|
||||
|
||||
return EFI_TIMEOUT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Add support for UEFI Over Legacy (UoL) feature, stop
|
||||
the legacy USB SMI support
|
||||
|
||||
@param Ehc The EHCI device.
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcClearLegacySupport (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
UINT32 ExtendCap;
|
||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||
UINT32 Value;
|
||||
UINT32 TimeOut;
|
||||
|
||||
EHC_DEBUG (("EhcClearLegacySupport: called to clear legacy support\n"));
|
||||
|
||||
PciIo = Ehc->PciIo;
|
||||
ExtendCap = (Ehc->HcCapParams >> 8) & 0xFF;
|
||||
|
||||
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
|
||||
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);
|
||||
|
||||
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
|
||||
Value |= (0x1 << 24);
|
||||
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
|
||||
|
||||
TimeOut = 40;
|
||||
while (TimeOut--) {
|
||||
gBS->Stall (500);
|
||||
|
||||
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
|
||||
|
||||
if ((Value & 0x01010000) == 0x01000000) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);
|
||||
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Set door bell and wait it to be ACKed by host controller.
|
||||
This function is used to synchronize with the hardware.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout The time to wait before abort (in millisecond, ms)
|
||||
|
||||
@return EFI_SUCCESS : Synchronized with the hardware
|
||||
@return EFI_TIMEOUT : Time out happened while waiting door bell to set
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcSetAndWaitDoorBell (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT32 Data;
|
||||
|
||||
EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);
|
||||
|
||||
Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);
|
||||
|
||||
//
|
||||
// ACK the IAA bit in USBSTS register. Make sure other
|
||||
// interrupt bits are not ACKed. These bits are WC (Write Clean).
|
||||
//
|
||||
Data = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);
|
||||
Data &= ~USBSTS_INTACK_MASK;
|
||||
Data |= USBSTS_IAA;
|
||||
|
||||
EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Clear all the interrutp status bits, these bits
|
||||
are Write-Clean
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcAckAllInterrupt (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Enable the periodic schedule then wait EHC to
|
||||
actually enable it.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout The time to wait before abort (in millisecond, ms)
|
||||
|
||||
@return EFI_SUCCESS : The periodical schedule is enabled
|
||||
@return EFI_TIMEOUT : Time out happened while enabling periodic schedule
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EhcEnablePeriodSchd (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);
|
||||
|
||||
Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Disable periodic schedule
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort (in millisecond, ms)
|
||||
|
||||
@return EFI_SUCCESS : Periodic schedule is disabled.
|
||||
@return EFI_DEVICE_ERROR : Fail to disable periodic schedule
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EhcDisablePeriodSchd (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);
|
||||
|
||||
Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, FALSE, Timeout);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Enable asynchrounous schedule
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort
|
||||
|
||||
@return EFI_SUCCESS : The EHCI asynchronous schedule is enabled
|
||||
@return Others : Failed to enable the asynchronous scheudle
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EhcEnableAsyncSchd (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
|
||||
|
||||
Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Disable asynchrounous schedule
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort (in millisecond, ms)
|
||||
|
||||
@return EFI_SUCCESS : The asynchronous schedule is disabled
|
||||
@return Others : Failed to disable the asynchronous schedule
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EhcDisableAsyncSchd (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);
|
||||
|
||||
Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, FALSE, Timeout);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Whether Ehc is halted
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return TRUE : The controller is halted
|
||||
@return FALSE : It isn't halted
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EhcIsHalt (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Whether system error occurred
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return TRUE : System error happened
|
||||
@return FALSE : No system error
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EhcIsSysError (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reset the host controller
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort (in millisecond, ms)
|
||||
|
||||
@return EFI_SUCCESS : The host controller is reset
|
||||
@return Others : Failed to reset the host
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcResetHC (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Host can only be reset when it is halt. If not so, halt it
|
||||
//
|
||||
if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
|
||||
Status = EhcHaltHC (Ehc, Timeout);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);
|
||||
Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Halt the host controller
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort
|
||||
|
||||
@return EFI_SUCCESS : The EHCI is halt
|
||||
@return EFI_TIMEOUT : Failed to halt the controller before Timeout
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcHaltHC (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
|
||||
Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the EHCI to run
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort
|
||||
|
||||
@return EFI_SUCCESS : The EHCI is running
|
||||
@return Others : Failed to set the EHCI to run
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcRunHC (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
|
||||
Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the HC hardware.
|
||||
EHCI spec lists the five things to do to initialize the hardware
|
||||
1. Program CTRLDSSEGMENT
|
||||
2. Set USBINTR to enable interrupts
|
||||
3. Set periodic list base
|
||||
4. Set USBCMD, interrupt threshold, frame list size etc
|
||||
5. Write 1 to CONFIGFLAG to route all ports to EHCI
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return EFI_SUCCESS : The EHCI has come out of halt state
|
||||
@return EFI_TIMEOUT : Time out happened
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcInitHC (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (EhcIsHalt (Ehc));
|
||||
|
||||
//
|
||||
// Allocate the periodic frame and associated memeory
|
||||
// management facilities if not already done.
|
||||
//
|
||||
if (Ehc->PeriodFrame != NULL) {
|
||||
EhcFreeSched (Ehc);
|
||||
}
|
||||
|
||||
Status = EhcInitSched (Ehc);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
//
|
||||
// 1. Program the CTRLDSSEGMENT register with the high 32 bit addr
|
||||
//
|
||||
EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);
|
||||
|
||||
//
|
||||
// 2. Clear USBINTR to disable all the interrupt. UEFI works by polling
|
||||
//
|
||||
EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);
|
||||
|
||||
//
|
||||
// 3. Program periodic frame list, already done in EhcInitSched
|
||||
// 4. Start the Host Controller
|
||||
//
|
||||
EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);
|
||||
|
||||
//
|
||||
// 5. Set all ports routing to EHC
|
||||
//
|
||||
EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
|
||||
|
||||
Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIME);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
EHC_ERROR (("EhcInitHC: failed to enable period schedule\n"));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIME);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
EHC_ERROR (("EhcInitHC: failed to enable async schedule\n"));
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
/** @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:
|
||||
|
||||
EhciReg.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This file contains the definination for host controller register operation routines
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _EFI_EHCI_REG_H_
|
||||
#define _EFI_EHCI_REG_H_
|
||||
|
||||
|
||||
enum {
|
||||
//
|
||||
// Capability register offset
|
||||
//
|
||||
EHC_CAPLENGTH_OFFSET = 0, // Capability register length offset
|
||||
EHC_HCSPARAMS_OFFSET = 0x04, // Structural Parameters 04-07h
|
||||
EHC_HCCPARAMS_OFFSET = 0x08, // Capability parameters offset
|
||||
|
||||
//
|
||||
// Capability register bit definition
|
||||
//
|
||||
HCSP_NPORTS = 0x0F, // Number of root hub port
|
||||
HCCP_64BIT = 0x01, // 64-bit addressing capability
|
||||
|
||||
//
|
||||
// Operational register offset
|
||||
//
|
||||
EHC_USBCMD_OFFSET = 0x0, // USB command register offset
|
||||
EHC_USBSTS_OFFSET = 0x04, // Statue register offset
|
||||
EHC_USBINTR_OFFSET = 0x08, // USB interrutp offset
|
||||
EHC_FRINDEX_OFFSET = 0x0C, // Frame index offset
|
||||
EHC_CTRLDSSEG_OFFSET = 0x10, // Control data structure segment offset
|
||||
EHC_FRAME_BASE_OFFSET = 0x14, // Frame list base address offset
|
||||
EHC_ASYNC_HEAD_OFFSET = 0x18, // Next asynchronous list address offset
|
||||
EHC_CONFIG_FLAG_OFFSET = 0x40, // Configure flag register offset
|
||||
EHC_PORT_STAT_OFFSET = 0x44, // Port status/control offset
|
||||
|
||||
EHC_FRAME_LEN = 1024,
|
||||
|
||||
//
|
||||
// Register bit definition
|
||||
//
|
||||
CONFIGFLAG_ROUTE_EHC = 0x01, // Route port to EHC
|
||||
|
||||
USBCMD_RUN = 0x01, // Run/stop
|
||||
USBCMD_RESET = 0x02, // Start the host controller reset
|
||||
USBCMD_ENABLE_PERIOD = 0x10, // Enable periodic schedule
|
||||
USBCMD_ENABLE_ASYNC = 0x20, // Enable asynchronous schedule
|
||||
USBCMD_IAAD = 0x40, // Interrupt on async advance doorbell
|
||||
|
||||
USBSTS_IAA = 0x20, // Interrupt on async advance
|
||||
USBSTS_PERIOD_ENABLED = 0x4000, // Periodic schedule status
|
||||
USBSTS_ASYNC_ENABLED = 0x8000, // Asynchronous schedule status
|
||||
USBSTS_HALT = 0x1000, // Host controller halted
|
||||
USBSTS_SYS_ERROR = 0x10, // Host system error
|
||||
USBSTS_INTACK_MASK = 0x003F, // Mask for the interrupt ACK, the WC
|
||||
// (write clean) bits in USBSTS register
|
||||
|
||||
PORTSC_CONN = 0x01, // Current Connect Status
|
||||
PORTSC_CONN_CHANGE = 0x02, // Connect Status Change
|
||||
PORTSC_ENABLED = 0x04, // Port Enable / Disable
|
||||
PORTSC_ENABLE_CHANGE = 0x08, // Port Enable / Disable Change
|
||||
PORTSC_OVERCUR = 0x10, // Over current Active
|
||||
PORTSC_OVERCUR_CHANGE = 0x20, // Over current Change
|
||||
PORSTSC_RESUME = 0x40, // Force Port Resume
|
||||
PORTSC_SUSPEND = 0x80, // Port Suspend State
|
||||
PORTSC_RESET = 0x100, // Port Reset
|
||||
PORTSC_LINESTATE_K = 0x400, // Line Status K-state
|
||||
PORTSC_LINESTATE_J = 0x800, // Line Status J-state
|
||||
PORTSC_POWER = 0x1000, // Port Power
|
||||
PORTSC_OWNER = 0x2000, // Port Owner
|
||||
PORTSC_CHANGE_MASK = 0x2A, // Mask of the port change bits,
|
||||
// they are WC (write clean)
|
||||
//
|
||||
// PCI Configuration Registers
|
||||
//
|
||||
EHC_PCI_CLASSC = 0x09,
|
||||
EHC_PCI_CLASSC_PI = 0x20,
|
||||
EHC_BAR_INDEX = 0, /* how many bytes away from USB_BASE to 0x10 */
|
||||
};
|
||||
|
||||
#define EHC_LINK_TERMINATED(Link) (((Link) & 0x01) != 0)
|
||||
|
||||
#define EHC_ADDR(High, QhHw32) \
|
||||
((VOID *) (UINTN) (LShiftU64 ((High), 32) | ((QhHw32) & 0xFFFFFFF0)))
|
||||
|
||||
#define EHCI_IS_DATAIN(EndpointAddr) EHC_BIT_IS_SET((EndpointAddr), 0x80)
|
||||
|
||||
//
|
||||
// Structure to map the hardware port states to the
|
||||
// UEFI's port states.
|
||||
//
|
||||
typedef struct {
|
||||
UINT16 HwState;
|
||||
UINT16 UefiState;
|
||||
} USB_PORT_STATE_MAP;
|
||||
|
||||
//
|
||||
// Ehci Data and Ctrl Structures
|
||||
//
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
UINT8 PI;
|
||||
UINT8 SubClassCode;
|
||||
UINT8 BaseCode;
|
||||
} USB_CLASSC;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
UINT32
|
||||
EhcReadCapRegister (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Read EHCI capability register
|
||||
|
||||
Arguments:
|
||||
|
||||
Ehc - The Ehc device
|
||||
Offset - Capability register address
|
||||
|
||||
Returns:
|
||||
|
||||
The register content read
|
||||
|
||||
--*/
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Read Ehc Operation register
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Offset The operation register offset
|
||||
|
||||
@return The register content read
|
||||
|
||||
**/
|
||||
UINT32
|
||||
EhcReadOpReg (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Write the data to the EHCI operation register
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Offset EHCI operation register offset
|
||||
@param Data The data to write
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcWriteOpReg (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Offset,
|
||||
IN UINT32 Data
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Add support for UEFI Over Legacy (UoL) feature, stop
|
||||
the legacy USB SMI support
|
||||
|
||||
@param Ehc The EHCI device.
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcClearLegacySupport (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Set door bell and wait it to be ACKed by host controller.
|
||||
This function is used to synchronize with the hardware.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout The time to wait before abort (in millisecond, ms)
|
||||
|
||||
@return EFI_SUCCESS : Synchronized with the hardware
|
||||
@return EFI_TIMEOUT : Time out happened while waiting door bell to set
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcSetAndWaitDoorBell (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Clear all the interrutp status bits, these bits
|
||||
are Write-Clean
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcAckAllInterrupt (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Whether Ehc is halted
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return TRUE : The controller is halted
|
||||
@return FALSE : It isn't halted
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EhcIsHalt (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Whether system error occurred
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return TRUE : System error happened
|
||||
@return FALSE : No system error
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EhcIsSysError (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Reset the host controller
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort (in millisecond, ms)
|
||||
|
||||
@return EFI_SUCCESS : The host controller is reset
|
||||
@return Others : Failed to reset the host
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcResetHC (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Halt the host controller
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort
|
||||
|
||||
@return EFI_SUCCESS : The EHCI is halt
|
||||
@return EFI_TIMEOUT : Failed to halt the controller before Timeout
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcHaltHC (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Set the EHCI to run
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Timeout Time to wait before abort
|
||||
|
||||
@return EFI_SUCCESS : The EHCI is running
|
||||
@return Others : Failed to set the EHCI to run
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcRunHC (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT32 Timeout
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Initialize the HC hardware.
|
||||
EHCI spec lists the five things to do to initialize the hardware
|
||||
1. Program CTRLDSSEGMENT
|
||||
2. Set USBINTR to enable interrupts
|
||||
3. Set periodic list base
|
||||
4. Set USBCMD, interrupt threshold, frame list size etc
|
||||
5. Write 1 to CONFIGFLAG to route all ports to EHCI
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return EFI_SUCCESS : The EHCI has come out of halt state
|
||||
@return EFI_TIMEOUT : Time out happened
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcInitHC (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,941 @@
|
|||
/** @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:
|
||||
|
||||
EhciSched.c
|
||||
|
||||
Abstract:
|
||||
|
||||
EHCI transfer scheduling routines
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
#include "Ehci.h"
|
||||
|
||||
|
||||
/**
|
||||
Create helper QTD/QH for the EHCI device
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for helper QTD/QH
|
||||
@retval EFI_SUCCESS Helper QH/QTD are created
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EhcCreateHelpQ (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
USB_ENDPOINT Ep;
|
||||
EHC_QH *Qh;
|
||||
QH_HW *QhHw;
|
||||
EHC_QTD *Qtd;
|
||||
|
||||
//
|
||||
// Create an inactive Qtd to terminate the short packet read.
|
||||
//
|
||||
Qtd = EhcCreateQtd (Ehc, NULL, 0, QTD_PID_INPUT, 0, 64);
|
||||
|
||||
if (Qtd == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Qtd->QtdHw.Status = QTD_STAT_HALTED;
|
||||
Ehc->ShortReadStop = Qtd;
|
||||
|
||||
//
|
||||
// Create a QH to act as the EHC reclamation header.
|
||||
// Set the header to loopback to itself.
|
||||
//
|
||||
Ep.DevAddr = 0;
|
||||
Ep.EpAddr = 1;
|
||||
Ep.Direction = EfiUsbDataIn;
|
||||
Ep.DevSpeed = EFI_USB_SPEED_HIGH;
|
||||
Ep.MaxPacket = 64;
|
||||
Ep.HubAddr = 0;
|
||||
Ep.HubPort = 0;
|
||||
Ep.Toggle = 0;
|
||||
Ep.Type = EHC_BULK_TRANSFER;
|
||||
Ep.PollRate = 1;
|
||||
|
||||
Qh = EhcCreateQh (Ehc, &Ep);
|
||||
|
||||
if (Qh == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
QhHw = &Qh->QhHw;
|
||||
QhHw->HorizonLink = QH_LINK (QhHw, EHC_TYPE_QH, FALSE);
|
||||
QhHw->Status = QTD_STAT_HALTED;
|
||||
QhHw->ReclaimHead = 1;
|
||||
Ehc->ReclaimHead = Qh;
|
||||
|
||||
//
|
||||
// Create a dummy QH to act as the terminator for periodical schedule
|
||||
//
|
||||
Ep.EpAddr = 2;
|
||||
Ep.Type = EHC_INT_TRANSFER_SYNC;
|
||||
|
||||
Qh = EhcCreateQh (Ehc, &Ep);
|
||||
|
||||
if (Qh == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Qh->QhHw.Status = QTD_STAT_HALTED;
|
||||
Ehc->PeriodOne = Qh;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Initialize the schedule data structure such as frame list
|
||||
|
||||
@param Ehc The EHCI device to init schedule data for
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data
|
||||
@retval EFI_SUCCESS The schedule data is initialized
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcInitSched (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||
VOID *Buf;
|
||||
EFI_PHYSICAL_ADDRESS PhyAddr;
|
||||
VOID *Map;
|
||||
UINTN Pages;
|
||||
UINTN Bytes;
|
||||
UINTN Index;
|
||||
UINT32 *Desc;
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// First initialize the periodical schedule data:
|
||||
// 1. Allocate and map the memory for the frame list
|
||||
// 2. Create the help QTD/QH
|
||||
// 3. Initialize the frame entries
|
||||
// 4. Set the frame list register
|
||||
//
|
||||
PciIo = Ehc->PciIo;
|
||||
|
||||
Bytes = 4096;
|
||||
Pages = EFI_SIZE_TO_PAGES (Bytes);
|
||||
|
||||
Status = PciIo->AllocateBuffer (
|
||||
PciIo,
|
||||
AllocateAnyPages,
|
||||
EfiBootServicesData,
|
||||
Pages,
|
||||
&Buf,
|
||||
0
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = PciIo->Map (
|
||||
PciIo,
|
||||
EfiPciIoOperationBusMasterCommonBuffer,
|
||||
Buf,
|
||||
&Bytes,
|
||||
&PhyAddr,
|
||||
&Map
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status) || (Bytes != 4096)) {
|
||||
PciIo->FreeBuffer (PciIo, Pages, Buf);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Ehc->PeriodFrameHost = Buf;
|
||||
Ehc->PeriodFrame = (VOID *) ((UINTN) PhyAddr);
|
||||
Ehc->PeriodFrameMap = Map;
|
||||
Ehc->High32bitAddr = EHC_HIGH_32BIT (PhyAddr);
|
||||
|
||||
//
|
||||
// Init memory pool management then create the helper
|
||||
// QTD/QH. If failed, previously allocated resources
|
||||
// will be freed by EhcFreeSched
|
||||
//
|
||||
Ehc->MemPool = UsbHcInitMemPool (
|
||||
PciIo,
|
||||
EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT),
|
||||
Ehc->High32bitAddr
|
||||
);
|
||||
|
||||
if (Ehc->MemPool == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = EhcCreateHelpQ (Ehc);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the frame list entries then set the registers
|
||||
//
|
||||
Desc = (UINT32 *) Ehc->PeriodFrame;
|
||||
|
||||
for (Index = 0; Index < EHC_FRAME_LEN; Index++) {
|
||||
Desc[Index] = QH_LINK (Ehc->PeriodOne, EHC_TYPE_QH, FALSE);
|
||||
}
|
||||
|
||||
EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (Ehc->PeriodFrame));
|
||||
|
||||
//
|
||||
// Second initialize the asynchronous schedule:
|
||||
// Only need to set the AsynListAddr register to
|
||||
// the reclamation header
|
||||
//
|
||||
EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (Ehc->ReclaimHead));
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Free the schedule data. It may be partially initialized.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcFreeSched (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||
|
||||
EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0);
|
||||
EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0);
|
||||
|
||||
if (Ehc->PeriodOne != NULL) {
|
||||
UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
|
||||
Ehc->PeriodOne = NULL;
|
||||
}
|
||||
|
||||
if (Ehc->ReclaimHead != NULL) {
|
||||
UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
|
||||
Ehc->ReclaimHead = NULL;
|
||||
}
|
||||
|
||||
if (Ehc->ShortReadStop != NULL) {
|
||||
UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
|
||||
Ehc->ShortReadStop = NULL;
|
||||
}
|
||||
|
||||
if (Ehc->MemPool != NULL) {
|
||||
UsbHcFreeMemPool (Ehc->MemPool);
|
||||
Ehc->MemPool = NULL;
|
||||
}
|
||||
|
||||
if (Ehc->PeriodFrame != NULL) {
|
||||
PciIo = Ehc->PciIo;
|
||||
ASSERT (PciIo != NULL);
|
||||
|
||||
PciIo->Unmap (PciIo, Ehc->PeriodFrameMap);
|
||||
|
||||
PciIo->FreeBuffer (
|
||||
PciIo,
|
||||
EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE),
|
||||
Ehc->PeriodFrameHost
|
||||
);
|
||||
|
||||
Ehc->PeriodFrame = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Link the queue head to the asynchronous schedule list.
|
||||
UEFI only supports one CTRL/BULK transfer at a time
|
||||
due to its interfaces. This simplifies the AsynList
|
||||
management: A reclamation header is always linked to
|
||||
the AsyncListAddr, the only active QH is appended to it.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qh The queue head to link
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcLinkQhToAsync (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN EHC_QH *Qh
|
||||
)
|
||||
{
|
||||
EHC_QH *Head;
|
||||
|
||||
//
|
||||
// Append the queue head after the reclaim header, then
|
||||
// fix the hardware visiable parts (EHCI R1.0 page 72).
|
||||
// ReclaimHead is always linked to the EHCI's AsynListAddr.
|
||||
//
|
||||
Head = Ehc->ReclaimHead;
|
||||
|
||||
Qh->NextQh = Head->NextQh;
|
||||
Head->NextQh = Qh;
|
||||
|
||||
Qh->QhHw.HorizonLink = QH_LINK (Head, EHC_TYPE_QH, FALSE);;
|
||||
Head->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Unlink a queue head from the asynchronous schedule list.
|
||||
Need to synchronize with hardware
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qh The queue head to unlink
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcUnlinkQhFromAsync (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN EHC_QH *Qh
|
||||
)
|
||||
{
|
||||
EHC_QH *Head;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (Ehc->ReclaimHead->NextQh == Qh);
|
||||
|
||||
//
|
||||
// Remove the QH from reclamation head, then update the hardware
|
||||
// visiable part: Only need to loopback the ReclaimHead. The Qh
|
||||
// is pointing to ReclaimHead (which is staill in the list).
|
||||
//
|
||||
Head = Ehc->ReclaimHead;
|
||||
|
||||
Head->NextQh = Qh->NextQh;
|
||||
Qh->NextQh = NULL;
|
||||
|
||||
Head->QhHw.HorizonLink = QH_LINK (Head, EHC_TYPE_QH, FALSE);
|
||||
|
||||
//
|
||||
// Set and wait the door bell to synchronize with the hardware
|
||||
//
|
||||
Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIME);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
EHC_ERROR (("EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Link a queue head for interrupt transfer to the periodic
|
||||
schedule frame list. This code is very much the same as
|
||||
that in UHCI.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qh The queue head to link
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcLinkQhToPeriod (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN EHC_QH *Qh
|
||||
)
|
||||
{
|
||||
UINT32 *Frames;
|
||||
UINTN Index;
|
||||
EHC_QH *Prev;
|
||||
EHC_QH *Next;
|
||||
|
||||
Frames = Ehc->PeriodFrame;
|
||||
|
||||
for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {
|
||||
//
|
||||
// First QH can't be NULL because we always keep PeriodOne
|
||||
// heads on the frame list
|
||||
//
|
||||
ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));
|
||||
Next = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);
|
||||
Prev = NULL;
|
||||
|
||||
//
|
||||
// Now, insert the queue head (Qh) into this frame:
|
||||
// 1. Find a queue head with the same poll interval, just insert
|
||||
// Qh after this queue head, then we are done.
|
||||
//
|
||||
// 2. Find the position to insert the queue head into:
|
||||
// Previous head's interval is bigger than Qh's
|
||||
// Next head's interval is less than Qh's
|
||||
// Then, insert the Qh between then
|
||||
//
|
||||
while (Next->Interval > Qh->Interval) {
|
||||
Prev = Next;
|
||||
Next = Next->NextQh;
|
||||
}
|
||||
|
||||
ASSERT (Next != NULL);
|
||||
|
||||
//
|
||||
// The entry may have been linked into the frame by early insertation.
|
||||
// For example: if insert a Qh with Qh.Interval == 4, and there is a Qh
|
||||
// with Qh.Interval == 8 on the frame. If so, we are done with this frame.
|
||||
// It isn't necessary to compare all the QH with the same interval to
|
||||
// Qh. This is because if there is other QH with the same interval, Qh
|
||||
// should has been inserted after that at Frames[0] and at Frames[0] it is
|
||||
// impossible for (Next == Qh)
|
||||
//
|
||||
if (Next == Qh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Next->Interval == Qh->Interval) {
|
||||
//
|
||||
// If there is a QH with the same interval, it locates at
|
||||
// Frames[0], and we can simply insert it after this QH. We
|
||||
// are all done.
|
||||
//
|
||||
ASSERT ((Index == 0) && (Qh->NextQh == NULL));
|
||||
|
||||
Prev = Next;
|
||||
Next = Next->NextQh;
|
||||
|
||||
Qh->NextQh = Next;
|
||||
Prev->NextQh = Qh;
|
||||
|
||||
Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink;
|
||||
Prev->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// OK, find the right position, insert it in. If Qh's next
|
||||
// link has already been set, it is in position. This is
|
||||
// guarranted by 2^n polling interval.
|
||||
//
|
||||
if (Qh->NextQh == NULL) {
|
||||
Qh->NextQh = Next;
|
||||
Qh->QhHw.HorizonLink = QH_LINK (Next, EHC_TYPE_QH, FALSE);
|
||||
}
|
||||
|
||||
if (Prev == NULL) {
|
||||
Frames[Index] = QH_LINK (Qh, EHC_TYPE_QH, FALSE);
|
||||
} else {
|
||||
Prev->NextQh = Qh;
|
||||
Prev->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Unlink an interrupt queue head from the periodic
|
||||
schedule frame list
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qh The queue head to unlink
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcUnlinkQhFromPeriod (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN EHC_QH *Qh
|
||||
)
|
||||
{
|
||||
UINT32 *Frames;
|
||||
UINTN Index;
|
||||
EHC_QH *Prev;
|
||||
EHC_QH *This;
|
||||
|
||||
Frames = Ehc->PeriodFrame;
|
||||
|
||||
for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {
|
||||
//
|
||||
// Frame link can't be NULL because we always keep PeroidOne
|
||||
// on the frame list
|
||||
//
|
||||
ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));
|
||||
This = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);
|
||||
Prev = NULL;
|
||||
|
||||
//
|
||||
// Walk through the frame's QH list to find the
|
||||
// queue head to remove
|
||||
//
|
||||
while ((This != NULL) && (This != Qh)) {
|
||||
Prev = This;
|
||||
This = This->NextQh;
|
||||
}
|
||||
|
||||
//
|
||||
// Qh may have already been unlinked from this frame
|
||||
// by early action. See the comments in EhcLinkQhToPeriod.
|
||||
//
|
||||
if (This == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Prev == NULL) {
|
||||
//
|
||||
// Qh is the first entry in the frame
|
||||
//
|
||||
Frames[Index] = Qh->QhHw.HorizonLink;
|
||||
} else {
|
||||
Prev->NextQh = Qh->NextQh;
|
||||
Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Check the URB's execution result and update the URB's
|
||||
result accordingly.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Urb The URB to check result
|
||||
|
||||
@return Whether the result of URB transfer is finialized.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
EhcCheckUrbResult (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN URB *Urb
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
EHC_QTD *Qtd;
|
||||
QTD_HW *QtdHw;
|
||||
UINT8 State;
|
||||
BOOLEAN Finished;
|
||||
|
||||
ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));
|
||||
|
||||
Finished = TRUE;
|
||||
Urb->Completed = 0;
|
||||
|
||||
Urb->Result = EFI_USB_NOERROR;
|
||||
|
||||
if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
|
||||
Urb->Result |= EFI_USB_ERR_SYSTEM;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
|
||||
Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
|
||||
QtdHw = &Qtd->QtdHw;
|
||||
State = (UINT8) QtdHw->Status;
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {
|
||||
//
|
||||
// EHCI will halt the queue head when met some error.
|
||||
// If it is halted, the result of URB is finialized.
|
||||
//
|
||||
if ((State & QTD_STAT_ERR_MASK) == 0) {
|
||||
Urb->Result |= EFI_USB_ERR_STALL;
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {
|
||||
Urb->Result |= EFI_USB_ERR_BABBLE;
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {
|
||||
Urb->Result |= EFI_USB_ERR_BUFFER;
|
||||
}
|
||||
|
||||
if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) {
|
||||
Urb->Result |= EFI_USB_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
Finished = TRUE;
|
||||
goto ON_EXIT;
|
||||
|
||||
} else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {
|
||||
//
|
||||
// The QTD is still active, no need to check furthur.
|
||||
//
|
||||
Urb->Result |= EFI_USB_ERR_NOTEXECUTE;
|
||||
|
||||
Finished = FALSE;
|
||||
goto ON_EXIT;
|
||||
|
||||
} else {
|
||||
//
|
||||
// This QTD is finished OK or met short packet read. Update the
|
||||
// transfer length if it isn't a setup.
|
||||
//
|
||||
if (QtdHw->Pid != QTD_PID_SETUP) {
|
||||
Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes;
|
||||
}
|
||||
|
||||
if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {
|
||||
EHC_DUMP_QH ((Urb->Qh, "Short packet read", FALSE));
|
||||
|
||||
//
|
||||
// Short packet read condition. If it isn't a setup transfer,
|
||||
// no need to check furthur: the queue head will halt at the
|
||||
// ShortReadStop. If it is a setup transfer, need to check the
|
||||
// Status Stage of the setup transfer to get the finial result
|
||||
//
|
||||
if (QtdHw->AltNext == QTD_LINK (Ehc->ShortReadStop, FALSE)) {
|
||||
EHC_DEBUG (("EhcCheckUrbResult: Short packet read, break\n"));
|
||||
|
||||
Finished = TRUE;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
EHC_DEBUG (("EhcCheckUrbResult: Short packet read, continue\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ON_EXIT:
|
||||
//
|
||||
// Return the data toggle set by EHCI hardware, bulk and interrupt
|
||||
// transfer will use this to initialize the next transaction. For
|
||||
// Control transfer, it always start a new data toggle sequence for
|
||||
// new transfer.
|
||||
//
|
||||
// NOTICE: don't move DT update before the loop, otherwise there is
|
||||
// a race condition that DT is wrong.
|
||||
//
|
||||
Urb->DataToggle = (UINT8) Urb->Qh->QhHw.DataToggle;
|
||||
|
||||
return Finished;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Execute the transfer by polling the URB. This is a synchronous operation.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Urb The URB to execute
|
||||
@param TimeOut The time to wait before abort, in millisecond.
|
||||
|
||||
@return EFI_DEVICE_ERROR : The transfer failed due to transfer error
|
||||
@return EFI_TIMEOUT : The transfer failed due to time out
|
||||
@return EFI_SUCCESS : The transfer finished OK
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcExecTransfer (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN URB *Urb,
|
||||
IN UINTN TimeOut
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
UINTN Loop;
|
||||
BOOLEAN Finished;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
Loop = (TimeOut * EHC_STALL_1_MILLISECOND / EHC_SYNC_POLL_TIME) + 1;
|
||||
Finished = FALSE;
|
||||
|
||||
for (Index = 0; Index < Loop; Index++) {
|
||||
Finished = EhcCheckUrbResult (Ehc, Urb);
|
||||
|
||||
if (Finished) {
|
||||
break;
|
||||
}
|
||||
|
||||
gBS->Stall (EHC_SYNC_POLL_TIME);
|
||||
}
|
||||
|
||||
if (!Finished) {
|
||||
EHC_ERROR (("EhcExecTransfer: transfer not finished in %dms\n", TimeOut));
|
||||
EHC_DUMP_QH ((Urb->Qh, NULL, FALSE));
|
||||
|
||||
Status = EFI_TIMEOUT;
|
||||
|
||||
} else if (Urb->Result != EFI_USB_NOERROR) {
|
||||
EHC_ERROR (("EhcExecTransfer: transfer failed with %x\n", Urb->Result));
|
||||
EHC_DUMP_QH ((Urb->Qh, NULL, FALSE));
|
||||
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Delete a single asynchronous interrupt transfer for
|
||||
the device and endpoint
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param DevAddr The address of the target device
|
||||
@param EpNum The endpoint of the target
|
||||
@param DataToggle Return the next data toggle to use
|
||||
|
||||
@retval EFI_SUCCESS An asynchronous transfer is removed
|
||||
@retval EFI_NOT_FOUND No transfer for the device is found
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhciDelAsyncIntTransfer (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT8 DevAddr,
|
||||
IN UINT8 EpNum,
|
||||
OUT UINT8 *DataToggle
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
URB *Urb;
|
||||
EFI_USB_DATA_DIRECTION Direction;
|
||||
|
||||
Direction = ((EpNum & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
|
||||
EpNum &= 0x0F;
|
||||
|
||||
EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
|
||||
Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
|
||||
|
||||
if ((Urb->Ep.DevAddr == DevAddr) && (Urb->Ep.EpAddr == EpNum) &&
|
||||
(Urb->Ep.Direction == Direction)) {
|
||||
//
|
||||
// Check the URB status to retrieve the next data toggle
|
||||
// from the associated queue head.
|
||||
//
|
||||
EhcCheckUrbResult (Ehc, Urb);
|
||||
*DataToggle = Urb->DataToggle;
|
||||
|
||||
EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
|
||||
RemoveEntryList (&Urb->UrbList);
|
||||
|
||||
gBS->FreePool (Urb->Data);
|
||||
EhcFreeUrb (Ehc, Urb);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove all the asynchronous interrutp transfers
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhciDelAllAsyncIntTransfers (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
URB *Urb;
|
||||
|
||||
EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
|
||||
Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
|
||||
|
||||
EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
|
||||
RemoveEntryList (&Urb->UrbList);
|
||||
|
||||
gBS->FreePool (Urb->Data);
|
||||
EhcFreeUrb (Ehc, Urb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Update the queue head for next round of asynchronous transfer
|
||||
|
||||
@param Urb The URB to update
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EhcUpdateAsyncRequest (
|
||||
IN URB *Urb
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
EHC_QTD *FirstQtd;
|
||||
QH_HW *QhHw;
|
||||
EHC_QTD *Qtd;
|
||||
QTD_HW *QtdHw;
|
||||
UINTN Index;
|
||||
|
||||
Qtd = NULL;
|
||||
|
||||
if (Urb->Result == EFI_USB_NOERROR) {
|
||||
FirstQtd = NULL;
|
||||
|
||||
EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
|
||||
Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
|
||||
|
||||
if (FirstQtd == NULL) {
|
||||
FirstQtd = Qtd;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the QTD for next round of transfer. Host control
|
||||
// may change dt/Total Bytes to Transfer/C_Page/Cerr/Status/
|
||||
// Current Offset. These fields need to be updated. DT isn't
|
||||
// used by interrupt transfer. It uses DT in queue head.
|
||||
// Current Offset is in Page[0], only need to reset Page[0]
|
||||
// to initial data buffer.
|
||||
//
|
||||
QtdHw = &Qtd->QtdHw;
|
||||
QtdHw->Status = QTD_STAT_ACTIVE;
|
||||
QtdHw->ErrCnt = QTD_MAX_ERR;
|
||||
QtdHw->CurPage = 0;
|
||||
QtdHw->TotalBytes = (UINT32) Qtd->DataLen;
|
||||
QtdHw->Page[0] = EHC_LOW_32BIT (Qtd->Data);
|
||||
}
|
||||
|
||||
//
|
||||
// Update QH for next round of transfer. Host control only
|
||||
// touch the fields in transfer overlay area. Only need to
|
||||
// zero out the overlay area and set NextQtd to the first
|
||||
// QTD. DateToggle bit is left untouched.
|
||||
//
|
||||
QhHw = &Urb->Qh->QhHw;
|
||||
QhHw->CurQtd = QTD_LINK (0, TRUE);
|
||||
QhHw->AltQtd = 0;
|
||||
|
||||
QhHw->Status = 0;
|
||||
QhHw->Pid = 0;
|
||||
QhHw->ErrCnt = 0;
|
||||
QhHw->CurPage = 0;
|
||||
QhHw->IOC = 0;
|
||||
QhHw->TotalBytes = 0;
|
||||
|
||||
for (Index = 0; Index < 5; Index++) {
|
||||
QhHw->Page[Index] = 0;
|
||||
QhHw->PageHigh[Index] = 0;
|
||||
}
|
||||
|
||||
QhHw->NextQtd = QTD_LINK (FirstQtd, FALSE);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Interrupt transfer periodic check handler
|
||||
|
||||
@param Event Interrupt event
|
||||
@param Context Pointer to USB2_HC_DEV
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcMoniteAsyncRequests (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
USB2_HC_DEV *Ehc;
|
||||
EFI_TPL OldTpl;
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
BOOLEAN Finished;
|
||||
UINT8 *ProcBuf;
|
||||
URB *Urb;
|
||||
|
||||
OldTpl = gBS->RaiseTPL (EHC_TPL);
|
||||
Ehc = (USB2_HC_DEV *) Context;
|
||||
|
||||
EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
|
||||
Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
|
||||
|
||||
//
|
||||
// Check the result of URB execution. If it is still
|
||||
// active, check the next one.
|
||||
//
|
||||
Finished = EhcCheckUrbResult (Ehc, Urb);
|
||||
|
||||
if (!Finished) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate a buffer then copy the transferred data for user.
|
||||
// If failed to allocate the buffer, update the URB for next
|
||||
// round of transfer. Ignore the data of this round.
|
||||
//
|
||||
ProcBuf = NULL;
|
||||
|
||||
if (Urb->Result == EFI_USB_NOERROR) {
|
||||
ASSERT (Urb->Completed <= Urb->DataLen);
|
||||
|
||||
ProcBuf = AllocatePool (Urb->Completed);
|
||||
|
||||
if (ProcBuf == NULL) {
|
||||
EhcUpdateAsyncRequest (Urb);
|
||||
continue;
|
||||
}
|
||||
|
||||
CopyMem (ProcBuf, Urb->Data, Urb->Completed);
|
||||
}
|
||||
|
||||
EhcUpdateAsyncRequest (Urb);
|
||||
|
||||
//
|
||||
// Leave error recovery to its related device driver. A
|
||||
// common case of the error recovery is to re-submit the
|
||||
// interrupt transfer which is linked to the head of the
|
||||
// list. This function scans from head to tail. So the
|
||||
// re-submitted interrupt transfer's callback function
|
||||
// will not be called again in this round. Don't touch this
|
||||
// URB after the callback, it may have been removed by the
|
||||
// callback.
|
||||
//
|
||||
if (Urb->Callback != NULL) {
|
||||
//
|
||||
// Restore the old TPL, USB bus maybe connect device in
|
||||
// his callback. Some drivers may has a lower TPL restriction.
|
||||
//
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
(Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
|
||||
OldTpl = gBS->RaiseTPL (EHC_TPL);
|
||||
}
|
||||
|
||||
if (ProcBuf != NULL) {
|
||||
gBS->FreePool (ProcBuf);
|
||||
}
|
||||
}
|
||||
|
||||
gBS->RestoreTPL (OldTpl);
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
/** @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:
|
||||
|
||||
EhciSched.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This file contains the definination for host controller schedule routines
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _EFI_EHCI_SCHED_H_
|
||||
#define _EFI_EHCI_SCHED_H_
|
||||
|
||||
EFI_STATUS
|
||||
EhcInitSched (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize the schedule data structure such as frame list
|
||||
|
||||
Arguments:
|
||||
|
||||
Ehc - The EHCI device to init schedule data for
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_OUT_OF_RESOURCES - Failed to allocate resource to init schedule data
|
||||
EFI_SUCCESS - The schedule data is initialized
|
||||
|
||||
--*/
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Free the schedule data. It may be partially initialized.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcFreeSched (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Link the queue head to the asynchronous schedule list.
|
||||
UEFI only supports one CTRL/BULK transfer at a time
|
||||
due to its interfaces. This simplifies the AsynList
|
||||
management: A reclamation header is always linked to
|
||||
the AsyncListAddr, the only active QH is appended to it.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qh The queue head to link
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcLinkQhToAsync (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN EHC_QH *Qh
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Unlink a queue head from the asynchronous schedule list.
|
||||
Need to synchronize with hardware
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qh The queue head to unlink
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcUnlinkQhFromAsync (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN EHC_QH *Qh
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Link a queue head for interrupt transfer to the periodic
|
||||
schedule frame list. This code is very much the same as
|
||||
that in UHCI.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qh The queue head to link
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcLinkQhToPeriod (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN EHC_QH *Qh
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Unlink an interrupt queue head from the periodic
|
||||
schedule frame list
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qh The queue head to unlink
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcUnlinkQhFromPeriod (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN EHC_QH *Qh
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Execute the transfer by polling the URB. This is a synchronous operation.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Urb The URB to execute
|
||||
@param TimeOut The time to wait before abort, in millisecond.
|
||||
|
||||
@return EFI_DEVICE_ERROR : The transfer failed due to transfer error
|
||||
@return EFI_TIMEOUT : The transfer failed due to time out
|
||||
@return EFI_SUCCESS : The transfer finished OK
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhcExecTransfer (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN URB *Urb,
|
||||
IN UINTN TimeOut
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Delete a single asynchronous interrupt transfer for
|
||||
the device and endpoint
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param DevAddr The address of the target device
|
||||
@param EpNum The endpoint of the target
|
||||
@param DataToggle Return the next data toggle to use
|
||||
|
||||
@retval EFI_SUCCESS An asynchronous transfer is removed
|
||||
@retval EFI_NOT_FOUND No transfer for the device is found
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EhciDelAsyncIntTransfer (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT8 DevAddr,
|
||||
IN UINT8 EpNum,
|
||||
OUT UINT8 *DataToggle
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Remove all the asynchronous interrutp transfers
|
||||
|
||||
@param Ehc The EHCI device
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhciDelAllAsyncIntTransfers (
|
||||
IN USB2_HC_DEV *Ehc
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Interrupt transfer periodic check handler
|
||||
|
||||
@param Event Interrupt event
|
||||
@param Context Pointer to USB2_HC_DEV
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcMoniteAsyncRequests (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,669 @@
|
|||
/** @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:
|
||||
|
||||
EhciUrb.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This file contains URB request, each request is warpped in a
|
||||
URB (Usb Request Block)
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
#include "Ehci.h"
|
||||
|
||||
|
||||
/**
|
||||
Create a single QTD to hold the data
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Data Current data not associated with a QTD
|
||||
@param DataLen The length of the data
|
||||
@param PktId Packet ID to use in the QTD
|
||||
@param Toggle Data toggle to use in the QTD
|
||||
@param MaxPacket Maximu packet length of the endpoint
|
||||
|
||||
@return Created QTD or NULL if failed to create one
|
||||
|
||||
**/
|
||||
EHC_QTD *
|
||||
EhcCreateQtd (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT8 *Data,
|
||||
IN UINTN DataLen,
|
||||
IN UINT8 PktId,
|
||||
IN UINT8 Toggle,
|
||||
IN UINTN MaxPacket
|
||||
)
|
||||
{
|
||||
EHC_QTD *Qtd;
|
||||
QTD_HW *QtdHw;
|
||||
UINTN Index;
|
||||
UINTN Len;
|
||||
UINTN ThisBufLen;
|
||||
|
||||
ASSERT (Ehc != NULL);
|
||||
|
||||
Qtd = UsbHcAllocateMem (Ehc->MemPool, sizeof (EHC_QTD));
|
||||
|
||||
if (Qtd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Qtd->Signature = EHC_QTD_SIG;
|
||||
Qtd->Data = Data;
|
||||
Qtd->DataLen = 0;
|
||||
|
||||
InitializeListHead (&Qtd->QtdList);
|
||||
|
||||
QtdHw = &Qtd->QtdHw;
|
||||
QtdHw->NextQtd = QTD_LINK (NULL, TRUE);
|
||||
QtdHw->AltNext = QTD_LINK (NULL, TRUE);
|
||||
QtdHw->Status = QTD_STAT_ACTIVE;
|
||||
QtdHw->Pid = PktId;
|
||||
QtdHw->ErrCnt = QTD_MAX_ERR;
|
||||
QtdHw->IOC = 0;
|
||||
QtdHw->TotalBytes = 0;
|
||||
QtdHw->DataToggle = Toggle;
|
||||
|
||||
//
|
||||
// Fill in the buffer points
|
||||
//
|
||||
if (Data != NULL) {
|
||||
Len = 0;
|
||||
|
||||
for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {
|
||||
//
|
||||
// Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
|
||||
// compute the offset and clear Reserved fields. This is already
|
||||
// done in the data point.
|
||||
//
|
||||
QtdHw->Page[Index] = EHC_LOW_32BIT (Data);
|
||||
QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (Data);
|
||||
|
||||
ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (Data) & QTD_BUF_MASK);
|
||||
|
||||
if (Len + ThisBufLen >= DataLen) {
|
||||
Len = DataLen;
|
||||
break;
|
||||
}
|
||||
|
||||
Len += ThisBufLen;
|
||||
Data += ThisBufLen;
|
||||
}
|
||||
|
||||
//
|
||||
// Need to fix the last pointer if the Qtd can't hold all the
|
||||
// user's data to make sure that the length is in the unit of
|
||||
// max packets. If it can hold all the data, there is no such
|
||||
// need.
|
||||
//
|
||||
if (Len < DataLen) {
|
||||
Len = Len - Len % MaxPacket;
|
||||
}
|
||||
|
||||
QtdHw->TotalBytes = (UINT32) Len;
|
||||
Qtd->DataLen = Len;
|
||||
}
|
||||
|
||||
return Qtd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Initialize the queue head for interrupt transfer,
|
||||
that is, initialize the following three fields:
|
||||
1. SplitXState in the Status field
|
||||
2. Microframe S-mask
|
||||
3. Microframe C-mask
|
||||
|
||||
@param Ep The queue head's related endpoint
|
||||
@param QhHw The queue head to initialize
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EhcInitIntQh (
|
||||
IN USB_ENDPOINT *Ep,
|
||||
IN QH_HW *QhHw
|
||||
)
|
||||
{
|
||||
//
|
||||
// Because UEFI interface can't utilitize an endpoint with
|
||||
// poll rate faster than 1ms, only need to set one bit in
|
||||
// the queue head. simple. But it may be changed later. If
|
||||
// sub-1ms interrupt is supported, need to update the S-Mask
|
||||
// here
|
||||
//
|
||||
if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
|
||||
QhHw->SMask = QH_MICROFRAME_0;
|
||||
return ;
|
||||
}
|
||||
|
||||
//
|
||||
// For low/full speed device, the transfer must go through
|
||||
// the split transaction. Need to update three fields
|
||||
// 1. SplitXState in the status
|
||||
// 2. Microframe S-Mask
|
||||
// 3. Microframe C-Mask
|
||||
// UEFI USB doesn't exercise admission control. It simplely
|
||||
// schedule the high speed transactions in microframe 0, and
|
||||
// full/low speed transactions at microframe 1. This also
|
||||
// avoid the use of FSTN.
|
||||
//
|
||||
QhHw->SMask = QH_MICROFRAME_1;
|
||||
QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Allocate and initialize a EHCI queue head
|
||||
|
||||
@param Ehci The EHCI device
|
||||
@param Ep The endpoint to create queue head for
|
||||
|
||||
@return Created queue head or NULL if failed to create one
|
||||
|
||||
**/
|
||||
EHC_QH *
|
||||
EhcCreateQh (
|
||||
IN USB2_HC_DEV *Ehci,
|
||||
IN USB_ENDPOINT *Ep
|
||||
)
|
||||
{
|
||||
EHC_QH *Qh;
|
||||
QH_HW *QhHw;
|
||||
|
||||
Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));
|
||||
|
||||
if (Qh == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Qh->Signature = EHC_QH_SIG;
|
||||
Qh->NextQh = NULL;
|
||||
Qh->Interval = Ep->PollRate;
|
||||
|
||||
InitializeListHead (&Qh->Qtds);
|
||||
|
||||
QhHw = &Qh->QhHw;
|
||||
QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);
|
||||
QhHw->DeviceAddr = Ep->DevAddr;
|
||||
QhHw->Inactive = 0;
|
||||
QhHw->EpNum = Ep->EpAddr;
|
||||
QhHw->EpSpeed = Ep->DevSpeed;
|
||||
QhHw->DtCtrl = 0;
|
||||
QhHw->ReclaimHead = 0;
|
||||
QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;
|
||||
QhHw->CtrlEp = 0;
|
||||
QhHw->NakReload = QH_NAK_RELOAD;
|
||||
QhHw->HubAddr = Ep->HubAddr;
|
||||
QhHw->PortNum = Ep->HubPort;
|
||||
QhHw->Multiplier = 1;
|
||||
QhHw->DataToggle = Ep->Toggle;
|
||||
|
||||
if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
|
||||
QhHw->Status |= QTD_STAT_DO_SS;
|
||||
}
|
||||
|
||||
switch (Ep->Type) {
|
||||
case EHC_CTRL_TRANSFER:
|
||||
//
|
||||
// Special initialization for the control transfer:
|
||||
// 1. Control transfer initialize data toggle from each QTD
|
||||
// 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
|
||||
//
|
||||
QhHw->DtCtrl = 1;
|
||||
|
||||
if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
|
||||
QhHw->CtrlEp = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EHC_INT_TRANSFER_ASYNC:
|
||||
case EHC_INT_TRANSFER_SYNC:
|
||||
//
|
||||
// Special initialization for the interrupt transfer
|
||||
// to set the S-Mask and C-Mask
|
||||
//
|
||||
QhHw->NakReload = 0;
|
||||
EhcInitIntQh (Ep, QhHw);
|
||||
break;
|
||||
|
||||
case EHC_BULK_TRANSFER:
|
||||
if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
|
||||
QhHw->Status |= QTD_STAT_DO_PING;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return Qh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Convert the poll interval from application to that
|
||||
be used by EHCI interface data structure. Only need
|
||||
to get the max 2^n that is less than interval. UEFI
|
||||
can't support high speed endpoint with a interval less
|
||||
than 8 microframe because interval is specified in
|
||||
the unit of ms (millisecond)
|
||||
|
||||
@param Interval The interval to convert
|
||||
|
||||
@return The converted interval
|
||||
|
||||
**/
|
||||
STATIC
|
||||
UINTN
|
||||
EhcConvertPollRate (
|
||||
IN UINTN Interval
|
||||
)
|
||||
{
|
||||
UINTN BitCount;
|
||||
|
||||
if (Interval == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Find the index (1 based) of the highest non-zero bit
|
||||
//
|
||||
BitCount = 0;
|
||||
|
||||
while (Interval != 0) {
|
||||
Interval >>= 1;
|
||||
BitCount++;
|
||||
}
|
||||
|
||||
return 1 << (BitCount - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Free a list of QTDs
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Qtds The list head of the QTD
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EhcFreeQtds (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN LIST_ENTRY *Qtds
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *Next;
|
||||
EHC_QTD *Qtd;
|
||||
|
||||
EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
|
||||
Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
|
||||
|
||||
RemoveEntryList (&Qtd->QtdList);
|
||||
UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Free an allocated URB. It is possible for it to be partially inited.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Urb The URB to free
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcFreeUrb (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN URB *Urb
|
||||
)
|
||||
{
|
||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||
|
||||
PciIo = Ehc->PciIo;
|
||||
|
||||
if (Urb->RequestPhy != NULL) {
|
||||
PciIo->Unmap (PciIo, Urb->RequestMap);
|
||||
}
|
||||
|
||||
if (Urb->DataMap != NULL) {
|
||||
PciIo->Unmap (PciIo, Urb->DataMap);
|
||||
}
|
||||
|
||||
if (Urb->Qh != NULL) {
|
||||
//
|
||||
// Ensure that this queue head has been unlinked from the
|
||||
// schedule data structures. Free all the associated QTDs
|
||||
//
|
||||
EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
|
||||
UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));
|
||||
}
|
||||
|
||||
gBS->FreePool (Urb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Create a list of QTDs for the URB
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Urb The URB to create QTDs for
|
||||
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD
|
||||
@retval EFI_SUCCESS The QTDs are allocated for the URB
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EhcCreateQtds (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN URB *Urb
|
||||
)
|
||||
{
|
||||
USB_ENDPOINT *Ep;
|
||||
EHC_QH *Qh;
|
||||
EHC_QTD *Qtd;
|
||||
EHC_QTD *StatusQtd;
|
||||
EHC_QTD *NextQtd;
|
||||
LIST_ENTRY *Entry;
|
||||
UINT32 AlterNext;
|
||||
UINT8 Toggle;
|
||||
UINTN Len;
|
||||
UINT8 Pid;
|
||||
|
||||
ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
|
||||
|
||||
//
|
||||
// EHCI follows the alternet next QTD pointer if it meets
|
||||
// a short read and the AlterNext pointer is valid. UEFI
|
||||
// EHCI driver should terminate the transfer except the
|
||||
// control transfer.
|
||||
//
|
||||
Toggle = 0;
|
||||
Qh = Urb->Qh;
|
||||
Ep = &Urb->Ep;
|
||||
StatusQtd = NULL;
|
||||
AlterNext = QTD_LINK (NULL, TRUE);
|
||||
|
||||
if (Ep->Direction == EfiUsbDataIn) {
|
||||
AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// Build the Setup and status packets for control transfer
|
||||
//
|
||||
if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
|
||||
Len = sizeof (EFI_USB_DEVICE_REQUEST);
|
||||
Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
|
||||
|
||||
if (Qtd == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
InsertTailList (&Qh->Qtds, &Qtd->QtdList);
|
||||
|
||||
//
|
||||
// Create the status packet now. Set the AlterNext to it. So, when
|
||||
// EHCI meets a short control read, it can resume at the status stage.
|
||||
// Use the opposite direction of the data stage, or IN if there is
|
||||
// no data stage.
|
||||
//
|
||||
if (Ep->Direction == EfiUsbDataIn) {
|
||||
Pid = QTD_PID_OUTPUT;
|
||||
} else {
|
||||
Pid = QTD_PID_INPUT;
|
||||
}
|
||||
|
||||
StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket);
|
||||
|
||||
if (StatusQtd == NULL) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
if (Ep->Direction == EfiUsbDataIn) {
|
||||
AlterNext = QTD_LINK (StatusQtd, FALSE);
|
||||
}
|
||||
|
||||
Toggle = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Build the data packets for all the transfers
|
||||
//
|
||||
if (Ep->Direction == EfiUsbDataIn) {
|
||||
Pid = QTD_PID_INPUT;
|
||||
} else {
|
||||
Pid = QTD_PID_OUTPUT;
|
||||
}
|
||||
|
||||
Qtd = NULL;
|
||||
Len = 0;
|
||||
|
||||
while (Len < Urb->DataLen) {
|
||||
Qtd = EhcCreateQtd (
|
||||
Ehc,
|
||||
(UINT8 *) Urb->DataPhy + Len,
|
||||
Urb->DataLen - Len,
|
||||
Pid,
|
||||
Toggle,
|
||||
Ep->MaxPacket
|
||||
);
|
||||
|
||||
if (Qtd == NULL) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
Qtd->QtdHw.AltNext = AlterNext;
|
||||
InsertTailList (&Qh->Qtds, &Qtd->QtdList);
|
||||
|
||||
//
|
||||
// Switch the Toggle bit if odd number of packets are included in the QTD.
|
||||
//
|
||||
if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
|
||||
Toggle = 1 - Toggle;
|
||||
}
|
||||
|
||||
Len += Qtd->DataLen;
|
||||
}
|
||||
|
||||
//
|
||||
// Insert the status packet for control transfer
|
||||
//
|
||||
if (Ep->Type == EHC_CTRL_TRANSFER) {
|
||||
InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
|
||||
}
|
||||
|
||||
//
|
||||
// OK, all the QTDs needed are created. Now, fix the NextQtd point
|
||||
//
|
||||
EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {
|
||||
Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
|
||||
|
||||
//
|
||||
// break if it is the last entry on the list
|
||||
//
|
||||
if (Entry->ForwardLink == &Qh->Qtds) {
|
||||
break;
|
||||
}
|
||||
|
||||
NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);
|
||||
Qtd->QtdHw.NextQtd = QTD_LINK (NextQtd, FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// Link the QTDs to the queue head
|
||||
//
|
||||
NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);
|
||||
Qh->QhHw.NextQtd = QTD_LINK (NextQtd, FALSE);
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_ERROR:
|
||||
EhcFreeQtds (Ehc, &Qh->Qtds);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create a new URB and its associated QTD
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param DevAddr The device address
|
||||
@param EpAddr Endpoint addrress & its direction
|
||||
@param DevSpeed The device speed
|
||||
@param Toggle Initial data toggle to use
|
||||
@param MaxPacket The max packet length of the endpoint
|
||||
@param Hub The transaction translator to use
|
||||
@param Type The transaction type
|
||||
@param Request The standard USB request for control transfer
|
||||
@param Data The user data to transfer
|
||||
@param DataLen The length of data buffer
|
||||
@param Callback The function to call when data is transferred
|
||||
@param Context The context to the callback
|
||||
@param Interval The interval for interrupt transfer
|
||||
|
||||
@return Created URB or NULL
|
||||
|
||||
**/
|
||||
URB *
|
||||
EhcCreateUrb (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT8 DevAddr,
|
||||
IN UINT8 EpAddr,
|
||||
IN UINT8 DevSpeed,
|
||||
IN UINT8 Toggle,
|
||||
IN UINTN MaxPacket,
|
||||
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
|
||||
IN UINTN Type,
|
||||
IN EFI_USB_DEVICE_REQUEST *Request,
|
||||
IN VOID *Data,
|
||||
IN UINTN DataLen,
|
||||
IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
|
||||
IN VOID *Context,
|
||||
IN UINTN Interval
|
||||
)
|
||||
{
|
||||
USB_ENDPOINT *Ep;
|
||||
EFI_PHYSICAL_ADDRESS PhyAddr;
|
||||
EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
|
||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||
EFI_STATUS Status;
|
||||
UINTN Len;
|
||||
URB *Urb;
|
||||
VOID *Map;
|
||||
|
||||
Urb = AllocateZeroPool (sizeof (URB));
|
||||
|
||||
if (Urb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Urb->Signature = EHC_URB_SIG;
|
||||
InitializeListHead (&Urb->UrbList);
|
||||
|
||||
Ep = &Urb->Ep;
|
||||
Ep->DevAddr = DevAddr;
|
||||
Ep->EpAddr = EpAddr & 0x0F;
|
||||
Ep->Direction = ((EpAddr & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
|
||||
Ep->DevSpeed = DevSpeed;
|
||||
Ep->MaxPacket = MaxPacket;
|
||||
|
||||
Ep->HubAddr = 0;
|
||||
Ep->HubPort = 0;
|
||||
|
||||
if (DevSpeed != EFI_USB_SPEED_HIGH) {
|
||||
ASSERT (Hub != NULL);
|
||||
|
||||
Ep->HubAddr = Hub->TranslatorHubAddress;
|
||||
Ep->HubPort = Hub->TranslatorPortNumber;
|
||||
}
|
||||
|
||||
Ep->Toggle = Toggle;
|
||||
Ep->Type = Type;
|
||||
Ep->PollRate = EhcConvertPollRate (Interval);
|
||||
|
||||
Urb->Request = Request;
|
||||
Urb->Data = Data;
|
||||
Urb->DataLen = DataLen;
|
||||
Urb->Callback = Callback;
|
||||
Urb->Context = Context;
|
||||
|
||||
PciIo = Ehc->PciIo;
|
||||
Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);
|
||||
|
||||
if (Urb->Qh == NULL) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Map the request and user data
|
||||
//
|
||||
if (Request != NULL) {
|
||||
Len = sizeof (EFI_USB_DEVICE_REQUEST);
|
||||
MapOp = EfiPciIoOperationBusMasterRead;
|
||||
Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);
|
||||
|
||||
if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);
|
||||
Urb->RequestMap = Map;
|
||||
}
|
||||
|
||||
if (Data != NULL) {
|
||||
Len = DataLen;
|
||||
|
||||
if (Ep->Direction == EfiUsbDataIn) {
|
||||
MapOp = EfiPciIoOperationBusMasterWrite;
|
||||
} else {
|
||||
MapOp = EfiPciIoOperationBusMasterRead;
|
||||
}
|
||||
|
||||
Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);
|
||||
|
||||
if (EFI_ERROR (Status) || (Len != DataLen)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
|
||||
Urb->DataMap = Map;
|
||||
}
|
||||
|
||||
Status = EhcCreateQtds (Ehc, Urb);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_ERROR;
|
||||
}
|
||||
|
||||
return Urb;
|
||||
|
||||
ON_ERROR:
|
||||
EhcFreeUrb (Ehc, Urb);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,350 @@
|
|||
/** @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:
|
||||
|
||||
EhciUrb.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This file contains URB request, each request is warpped in a
|
||||
URB (Usb Request Block)
|
||||
|
||||
Revision History
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _EFI_EHCI_URB_H_
|
||||
#define _EFI_EHCI_URB_H_
|
||||
|
||||
|
||||
typedef struct _EHC_QTD EHC_QTD;
|
||||
typedef struct _EHC_QH EHC_QH;
|
||||
typedef struct _URB URB;
|
||||
|
||||
enum {
|
||||
//
|
||||
// Transfer types, used in URB to identify the transfer type
|
||||
//
|
||||
EHC_CTRL_TRANSFER = 0x01,
|
||||
EHC_BULK_TRANSFER = 0x02,
|
||||
EHC_INT_TRANSFER_SYNC = 0x04,
|
||||
EHC_INT_TRANSFER_ASYNC = 0x08,
|
||||
|
||||
EHC_QTD_SIG = EFI_SIGNATURE_32 ('U', 'S', 'B', 'T'),
|
||||
EHC_QH_SIG = EFI_SIGNATURE_32 ('U', 'S', 'B', 'H'),
|
||||
EHC_URB_SIG = EFI_SIGNATURE_32 ('U', 'S', 'B', 'R'),
|
||||
|
||||
//
|
||||
// Hardware related bit definitions
|
||||
//
|
||||
EHC_TYPE_ITD = 0x00,
|
||||
EHC_TYPE_QH = 0x02,
|
||||
EHC_TYPE_SITD = 0x04,
|
||||
EHC_TYPE_FSTN = 0x06,
|
||||
|
||||
QH_NAK_RELOAD = 3,
|
||||
QH_HSHBW_MULTI = 1,
|
||||
|
||||
QTD_MAX_ERR = 3,
|
||||
QTD_PID_OUTPUT = 0x00,
|
||||
QTD_PID_INPUT = 0x01,
|
||||
QTD_PID_SETUP = 0x02,
|
||||
|
||||
QTD_STAT_DO_OUT = 0,
|
||||
QTD_STAT_DO_SS = 0,
|
||||
QTD_STAT_DO_PING = 0x01,
|
||||
QTD_STAT_DO_CS = 0x02,
|
||||
QTD_STAT_TRANS_ERR = 0x08,
|
||||
QTD_STAT_BABBLE_ERR = 0x10,
|
||||
QTD_STAT_BUFF_ERR = 0x20,
|
||||
QTD_STAT_HALTED = 0x40,
|
||||
QTD_STAT_ACTIVE = 0x80,
|
||||
QTD_STAT_ERR_MASK = QTD_STAT_TRANS_ERR | QTD_STAT_BABBLE_ERR | QTD_STAT_BUFF_ERR,
|
||||
|
||||
QTD_MAX_BUFFER = 4,
|
||||
QTD_BUF_LEN = 4096,
|
||||
QTD_BUF_MASK = 0x0FFF,
|
||||
|
||||
QH_MICROFRAME_0 = 0x01,
|
||||
QH_MICROFRAME_1 = 0x02,
|
||||
QH_MICROFRAME_2 = 0x04,
|
||||
QH_MICROFRAME_3 = 0x08,
|
||||
QH_MICROFRAME_4 = 0x10,
|
||||
QH_MICROFRAME_5 = 0x20,
|
||||
QH_MICROFRAME_6 = 0x40,
|
||||
QH_MICROFRAME_7 = 0x80,
|
||||
|
||||
USB_ERR_SHORT_PACKET = 0x200,
|
||||
};
|
||||
|
||||
//
|
||||
// Fill in the hardware link point: pass in a EHC_QH/QH_HW
|
||||
// pointer to QH_LINK; A EHC_QTD/QTD_HW pointer to QTD_LINK
|
||||
//
|
||||
#define QH_LINK(Addr, Type, Term) \
|
||||
((UINT32) ((EHC_LOW_32BIT (Addr) & 0xFFFFFFE0) | (Type) | ((Term) ? 1 : 0)))
|
||||
|
||||
#define QTD_LINK(Addr, Term) QH_LINK((Addr), 0, (Term))
|
||||
|
||||
//
|
||||
// The defination of EHCI hardware used data structure for
|
||||
// little endian architecture. The QTD and QH structures
|
||||
// are required to be 32 bytes aligned. Don't add members
|
||||
// to the head of the associated software strucuture.
|
||||
//
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
UINT32 NextQtd;
|
||||
UINT32 AltNext;
|
||||
|
||||
UINT32 Status : 8;
|
||||
UINT32 Pid : 2;
|
||||
UINT32 ErrCnt : 2;
|
||||
UINT32 CurPage : 3;
|
||||
UINT32 IOC : 1;
|
||||
UINT32 TotalBytes : 15;
|
||||
UINT32 DataToggle : 1;
|
||||
|
||||
UINT32 Page[5];
|
||||
UINT32 PageHigh[5];
|
||||
} QTD_HW;
|
||||
|
||||
typedef struct {
|
||||
UINT32 HorizonLink;
|
||||
//
|
||||
// Endpoint capabilities/Characteristics DWord 1 and DWord 2
|
||||
//
|
||||
UINT32 DeviceAddr : 7;
|
||||
UINT32 Inactive : 1;
|
||||
UINT32 EpNum : 4;
|
||||
UINT32 EpSpeed : 2;
|
||||
UINT32 DtCtrl : 1;
|
||||
UINT32 ReclaimHead : 1;
|
||||
UINT32 MaxPacketLen : 11;
|
||||
UINT32 CtrlEp : 1;
|
||||
UINT32 NakReload : 4;
|
||||
|
||||
UINT32 SMask : 8;
|
||||
UINT32 CMask : 8;
|
||||
UINT32 HubAddr : 7;
|
||||
UINT32 PortNum : 7;
|
||||
UINT32 Multiplier : 2;
|
||||
|
||||
//
|
||||
// Transaction execution overlay area
|
||||
//
|
||||
UINT32 CurQtd;
|
||||
UINT32 NextQtd;
|
||||
UINT32 AltQtd;
|
||||
|
||||
UINT32 Status : 8;
|
||||
UINT32 Pid : 2;
|
||||
UINT32 ErrCnt : 2;
|
||||
UINT32 CurPage : 3;
|
||||
UINT32 IOC : 1;
|
||||
UINT32 TotalBytes : 15;
|
||||
UINT32 DataToggle : 1;
|
||||
|
||||
UINT32 Page[5];
|
||||
UINT32 PageHigh[5];
|
||||
} QH_HW;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
//
|
||||
// Endpoint address and its capabilities
|
||||
//
|
||||
typedef struct _USB_ENDPOINT {
|
||||
UINT8 DevAddr;
|
||||
UINT8 EpAddr; // Endpoint address, no direction encoded in
|
||||
EFI_USB_DATA_DIRECTION Direction;
|
||||
UINT8 DevSpeed;
|
||||
UINTN MaxPacket;
|
||||
UINT8 HubAddr;
|
||||
UINT8 HubPort;
|
||||
UINT8 Toggle; // Data toggle, not used for control transfer
|
||||
UINTN Type;
|
||||
UINTN PollRate; // Polling interval used by EHCI
|
||||
} USB_ENDPOINT;
|
||||
|
||||
//
|
||||
// Software QTD strcture, this is used to manage all the
|
||||
// QTD generated from a URB. Don't add fields before QtdHw.
|
||||
//
|
||||
typedef struct _EHC_QTD {
|
||||
QTD_HW QtdHw;
|
||||
UINT32 Signature;
|
||||
LIST_ENTRY QtdList; // The list of QTDs to one end point
|
||||
UINT8 *Data; // Buffer of the original data
|
||||
UINTN DataLen; // Original amount of data in this QTD
|
||||
} EHC_QTD;
|
||||
|
||||
//
|
||||
// Software QH structure. All three different transaction types
|
||||
// supported by UEFI USB, that is the control/bulk/interrupt
|
||||
// transfers use the queue head and queue token strcuture.
|
||||
//
|
||||
// Interrupt QHs are linked to periodic frame list in the reversed
|
||||
// 2^N tree. Each interrupt QH is linked to the list starting at
|
||||
// frame 0. There is a dummy interrupt QH linked to each frame as
|
||||
// a sentinental whose polling interval is 1. Synchronous interrupt
|
||||
// transfer is linked after this dummy QH.
|
||||
//
|
||||
// For control/bulk transfer, only synchronous (in the sense of UEFI)
|
||||
// transfer is supported. A dummy QH is linked to EHCI AsyncListAddr
|
||||
// as the reclamation header. New transfer is inserted after this QH.
|
||||
//
|
||||
typedef struct _EHC_QH {
|
||||
QH_HW QhHw;
|
||||
UINT32 Signature;
|
||||
EHC_QH *NextQh; // The queue head pointed to by horizontal link
|
||||
LIST_ENTRY Qtds; // The list of QTDs to this queue head
|
||||
UINTN Interval;
|
||||
} EHC_QH;
|
||||
|
||||
//
|
||||
// URB (Usb Request Block) contains information for all kinds of
|
||||
// usb requests.
|
||||
//
|
||||
typedef struct _URB {
|
||||
UINT32 Signature;
|
||||
LIST_ENTRY UrbList;
|
||||
|
||||
//
|
||||
// Transaction information
|
||||
//
|
||||
USB_ENDPOINT Ep;
|
||||
EFI_USB_DEVICE_REQUEST *Request; // Control transfer only
|
||||
VOID *RequestPhy; // Address of the mapped request
|
||||
VOID *RequestMap;
|
||||
VOID *Data;
|
||||
UINTN DataLen;
|
||||
VOID *DataPhy; // Address of the mapped user data
|
||||
VOID *DataMap;
|
||||
EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
|
||||
VOID *Context;
|
||||
|
||||
//
|
||||
// Schedule data
|
||||
//
|
||||
EHC_QH *Qh;
|
||||
|
||||
//
|
||||
// Transaction result
|
||||
//
|
||||
UINT32 Result;
|
||||
UINTN Completed; // completed data length
|
||||
UINT8 DataToggle;
|
||||
} URB;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Create a single QTD to hold the data
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Data Current data not associated with a QTD
|
||||
@param DataLen The length of the data
|
||||
@param PktId Packet ID to use in the QTD
|
||||
@param Toggle Data toggle to use in the QTD
|
||||
@param MaxPacket Maximu packet length of the endpoint
|
||||
|
||||
@return Created QTD or NULL if failed to create one
|
||||
|
||||
**/
|
||||
EHC_QTD *
|
||||
EhcCreateQtd (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT8 *Data,
|
||||
IN UINTN DataLen,
|
||||
IN UINT8 PktId,
|
||||
IN UINT8 Toggle,
|
||||
IN UINTN MaxPacket
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Allocate and initialize a EHCI queue head
|
||||
|
||||
@param Ehci The EHCI device
|
||||
@param Ep The endpoint to create queue head for
|
||||
|
||||
@return Created queue head or NULL if failed to create one
|
||||
|
||||
**/
|
||||
EHC_QH *
|
||||
EhcCreateQh (
|
||||
IN USB2_HC_DEV *Ehci,
|
||||
IN USB_ENDPOINT *Ep
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Free an allocated URB. It is possible for it to be partially inited.
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param Urb The URB to free
|
||||
|
||||
@return None
|
||||
|
||||
**/
|
||||
VOID
|
||||
EhcFreeUrb (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN URB *Urb
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
Create a new URB and its associated QTD
|
||||
|
||||
@param Ehc The EHCI device
|
||||
@param DevAddr The device address
|
||||
@param EpAddr Endpoint addrress & its direction
|
||||
@param DevSpeed The device speed
|
||||
@param Toggle Initial data toggle to use
|
||||
@param MaxPacket The max packet length of the endpoint
|
||||
@param Hub The transaction translator to use
|
||||
@param Type The transaction type
|
||||
@param Request The standard USB request for control transfer
|
||||
@param Data The user data to transfer
|
||||
@param DataLen The length of data buffer
|
||||
@param Callback The function to call when data is transferred
|
||||
@param Context The context to the callback
|
||||
@param Interval The interval for interrupt transfer
|
||||
|
||||
@return Created URB or NULL
|
||||
|
||||
**/
|
||||
URB *
|
||||
EhcCreateUrb (
|
||||
IN USB2_HC_DEV *Ehc,
|
||||
IN UINT8 DevAddr,
|
||||
IN UINT8 EpAddr,
|
||||
IN UINT8 DevSpeed,
|
||||
IN UINT8 Toggle,
|
||||
IN UINTN MaxPacket,
|
||||
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
|
||||
IN UINTN Type,
|
||||
IN EFI_USB_DEVICE_REQUEST *Request,
|
||||
IN VOID *Data,
|
||||
IN UINTN DataLen,
|
||||
IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
|
||||
IN VOID *Context,
|
||||
IN UINTN Interval
|
||||
)
|
||||
;
|
||||
#endif
|
|
@ -0,0 +1,549 @@
|
|||
/** @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 "Ehci.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 ;
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/** @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
|
|
@ -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
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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>
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
);
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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 ;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue