summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Bus/Pci/Uhci
diff options
context:
space:
mode:
authorbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
committerbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
commit878ddf1fc3540a715f63594ed22b6929e881afb4 (patch)
treec56c44dac138137b510e1fba7c3efe5e4d84bea2 /EdkModulePkg/Bus/Pci/Uhci
downloadedk2-878ddf1fc3540a715f63594ed22b6929e881afb4.zip
edk2-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.gz
edk2-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.bz2
Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EdkModulePkg/Bus/Pci/Uhci')
-rw-r--r--EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c189
-rw-r--r--EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd42
-rw-r--r--EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa66
-rw-r--r--EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml47
-rw-r--r--EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c4237
-rw-r--r--EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c3498
-rw-r--r--EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h1187
7 files changed, 9266 insertions, 0 deletions
diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c b/EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c
new file mode 100644
index 0000000..71d9339
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/ComponentName.c
@@ -0,0 +1,189 @@
+/*++
+
+Copyright (c) 2006, 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", (CHAR16 *) 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;
+ }
+ //
+ // 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 = USB_HC_DEV_FROM_THIS (UsbHc);
+
+ return LookupUnicodeString (
+ Language,
+ gUhciComponentName.SupportedLanguages,
+ UhciDev->ControllerNameTable,
+ ControllerName
+ );
+
+}
diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd b/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd
new file mode 100644
index 0000000..76d35e7
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.mbd
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, 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.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>Uhci</BaseName>
+ <Guid>2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</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>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:18</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ </Libraries>
+</ModuleBuildDescription>
diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa b/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa
new file mode 100644
index 0000000..9e91154
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/Uhci.msa
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2006, 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.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>Uhci</BaseName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>2FB92EFA-2EE0-4bae-9EB6-7464125E1EF7</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for Uhci module</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</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>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:18</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>uhci.c</Filename>
+ <Filename>uhchlp.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>uhci.h</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="TO_START">PciIo</Protocol>
+ <Protocol Usage="BY_START">UsbHc</Protocol>
+ </Protocols>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gUhciDriverBinding</DriverBinding>
+ <ComponentName>gUhciComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml b/EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml
new file mode 100644
index 0000000..37bb3c3
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/build.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- Copyright (c) 2006, 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.-->
+<project basedir="." default="Uhci"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Bus\Pci\Uhci\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="Uhci">
+ <GenBuild baseName="Uhci" mbdFilename="${MODULE_DIR}\Uhci.mbd" msaFilename="${MODULE_DIR}\Uhci.msa"/>
+ </target>
+ <target depends="Uhci_clean" name="clean"/>
+ <target depends="Uhci_cleanall" name="cleanall"/>
+ <target name="Uhci_clean">
+ <OutputDirSetup baseName="Uhci" mbdFilename="${MODULE_DIR}\Uhci.mbd" msaFilename="${MODULE_DIR}\Uhci.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Uhci_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Uhci_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="Uhci_cleanall">
+ <OutputDirSetup baseName="Uhci" mbdFilename="${MODULE_DIR}\Uhci.mbd" msaFilename="${MODULE_DIR}\Uhci.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\Uhci_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\Uhci_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**Uhci*"/>
+ </delete>
+ </target>
+</project> \ No newline at end of file
diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c
new file mode 100644
index 0000000..62d58ee
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c
@@ -0,0 +1,4237 @@
+/*++
+
+Copyright (c) 2006, 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:
+
+ UhcHlp.c
+
+Abstract:
+
+
+Revision History
+--*/
+
+#include "uhci.h"
+
+EFI_STATUS
+USBReadPortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 PortOffset,
+ IN OUT UINT16 *Data
+ )
+/*++
+
+Routine Description:
+
+ USBReadPort Word
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ PortOffset - Port offset
+ Data - Data to reutrn
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Perform 16bit Read in PCI IO Space
+ //
+ return PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ USB_BAR_INDEX,
+ (UINT64) PortOffset,
+ 1,
+ Data
+ );
+}
+
+EFI_STATUS
+USBReadPortDW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 PortOffset,
+ IN OUT UINT32 *Data
+ )
+/*++
+
+Routine Description:
+
+ USBReadPort DWord
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ PortOffset - Port offset
+ Data - Data to reutrn
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Perform 32bit Read in PCI IO Space
+ //
+ return PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ USB_BAR_INDEX,
+ (UINT64) PortOffset,
+ 1,
+ Data
+ );
+}
+
+EFI_STATUS
+USBWritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 PortOffset,
+ IN UINT16 Data
+ )
+/*++
+
+Routine Description:
+
+ USB Write Port Word
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ PortOffset - Port offset
+ Data - Data to write
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Perform 16bit Write in PCI IO Space
+ //
+ return PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ USB_BAR_INDEX,
+ (UINT64) PortOffset,
+ 1,
+ &Data
+ );
+}
+
+EFI_STATUS
+USBWritePortDW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 PortOffset,
+ IN UINT32 Data
+ )
+/*++
+
+Routine Description:
+
+ USB Write Port DWord
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ PortOffset - Port offset
+ Data - Data to write
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Perform 32bit Write in PCI IO Space
+ //
+ return PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ USB_BAR_INDEX,
+ (UINT64) PortOffset,
+ 1,
+ &Data
+ );
+}
+//
+// USB register-base helper functions
+//
+EFI_STATUS
+WriteUHCCommandReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 CmdAddrOffset,
+ IN UINT16 UsbCmd
+ )
+/*++
+
+Routine Description:
+
+ Write UHCI Command Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ CmdAddrOffset - Command address offset
+ UsbCmd - Data to write
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Write to UHC's Command Register
+ //
+ return USBWritePortW (PciIo, CmdAddrOffset, UsbCmd);
+}
+
+EFI_STATUS
+ReadUHCCommandReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 CmdAddrOffset,
+ IN OUT UINT16 *Data
+ )
+/*++
+
+Routine Description:
+
+ Read UHCI Command Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ CmdAddrOffset - Command address offset
+ Data - Data to return
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Read from UHC's Command Register
+ //
+ return USBReadPortW (PciIo, CmdAddrOffset, Data);
+}
+
+EFI_STATUS
+WriteUHCStatusReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusAddrOffset,
+ IN UINT16 UsbSts
+ )
+/*++
+
+Routine Description:
+
+ Write UHCI Staus Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ StatusAddrOffset - Status address offset
+ UsbSts - Data to write
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Write to UHC's Status Register
+ //
+ return USBWritePortW (PciIo, StatusAddrOffset, UsbSts);
+}
+
+EFI_STATUS
+ReadUHCStatusReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusAddrOffset,
+ IN OUT UINT16 *Data
+ )
+/*++
+
+Routine Description:
+
+ Read UHCI Staus Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ StatusAddrOffset - Status address offset
+ UsbSts - Data to return
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Read from UHC's Status Register
+ //
+ return USBReadPortW (PciIo, StatusAddrOffset, Data);
+}
+
+
+EFI_STATUS
+ClearStatusReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusAddrOffset
+ )
+/*++
+
+Routine Description:
+
+ Clear the content of UHC's Status Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ StatusAddrOffset - Status address offset
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+
+ return WriteUHCStatusReg (PciIo, StatusAddrOffset, 0x003F);
+}
+
+EFI_STATUS
+ReadUHCFrameNumberReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FrameNumAddrOffset,
+ IN OUT UINT16 *Data
+ )
+/*++
+
+Routine Description:
+
+ Read from UHC's Frame Number Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ FrameNumAddrOffset - Frame number register offset
+ Data - Data to return
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+
+ return USBReadPortW (PciIo, FrameNumAddrOffset, Data);
+}
+
+EFI_STATUS
+WriteUHCFrameListBaseReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FlBaseAddrOffset,
+ IN UINT32 UsbFrameListBaseAddr
+ )
+/*++
+
+Routine Description:
+
+ Write to UHC's Frame List Base Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ FlBaseAddrOffset - Frame Base address register
+ UsbFrameListBaseAddr - Address to write
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+
+ return USBWritePortDW (PciIo, FlBaseAddrOffset, UsbFrameListBaseAddr);
+}
+
+EFI_STATUS
+ReadRootPortReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 PortAddrOffset,
+ IN OUT UINT16 *Data
+ )
+/*++
+
+Routine Description:
+
+ Read from UHC's Root Port Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ PortAddrOffset - Port Addrress Offset,
+ Data - Data to return
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+
+ return USBReadPortW (PciIo, PortAddrOffset, Data);
+}
+
+EFI_STATUS
+WriteRootPortReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 PortAddrOffset,
+ IN UINT16 ControlBits
+ )
+/*++
+
+Routine Description:
+
+ Write to UHC's Root Port Register
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ PortAddrOffset - Port Addrress Offset,
+ ControlBits - Data to write
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+
+ return USBWritePortW (PciIo, PortAddrOffset, ControlBits);
+}
+
+
+
+EFI_STATUS
+WaitForUHCHalt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusRegAddr,
+ IN UINTN Timeout
+ )
+/*++
+
+Routine Description:
+
+ Wait until UHCI halt or timeout
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ StatusRegAddr - Status Register Address
+ Timeout - Time out value in us
+
+Returns:
+
+ EFI_DEVICE_ERROR - Unable to read the status register
+ EFI_TIMEOUT - Time out
+ EFI_SUCCESS - Success
+
+--*/
+{
+ UINTN Delay;
+ EFI_STATUS Status;
+ UINT16 HcStatus;
+
+ //
+ // Timeout is in us unit
+ //
+ Delay = (Timeout / 50) + 1;
+ do {
+ Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((HcStatus & USBSTS_HCH) == USBSTS_HCH) {
+ break;
+ }
+ //
+ // Stall for 50 us
+ //
+ gBS->Stall (50);
+
+ } while (Delay--);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+IsStatusOK (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusRegAddr
+ )
+/*++
+
+Routine Description:
+
+ Judge whether the host controller operates well
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ StatusRegAddr - Status register address
+
+Returns:
+
+ TRUE - Status is good
+ FALSE - Status is bad
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT16 HcStatus;
+ //
+ // Detect whether the interrupt is caused by fatal error.
+ // see "UHCI Design Guid".
+ //
+ Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (HcStatus & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+
+}
+
+
+BOOLEAN
+IsHostSysOrProcessErr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusRegAddr
+ )
+/*++
+
+Routine Description:
+
+ Judge the status is HostSys,ProcessErr error or good
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ StatusRegAddr - Status register address
+
+Returns:
+
+ TRUE - Status is good
+ FALSE - Status is bad
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT16 HcStatus;
+ //
+ // Detect whether the interrupt is caused by serious error.
+ // see "UHCI Design Guid".
+ //
+ Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (HcStatus & (USBSTS_HSE | USBSTS_HCPE)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+UINT16
+GetCurrentFrameNumber (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FrameNumAddrOffset
+ )
+/*++
+
+Routine Description:
+
+ Get Current Frame Number
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ FrameNumAddrOffset - FrameNum register AddrOffset
+
+Returns:
+
+ Frame number
+
+--*/
+{
+ //
+ // Gets value in the USB frame number register.
+ //
+ UINT16 FrameNumber;
+
+ ReadUHCFrameNumberReg (PciIo, FrameNumAddrOffset, &FrameNumber);
+
+ return (UINT16) (FrameNumber & 0x03FF);
+}
+
+EFI_STATUS
+SetFrameListBaseAddress (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FlBaseAddrReg,
+ IN UINT32 Addr
+ )
+/*++
+
+Routine Description:
+
+ Set FrameListBase Address
+
+Arguments:
+
+ PciIo - EFI_PCI_IO_PROTOCOL
+ FlBaseAddrReg - FrameListBase register
+ Addr - Address to set
+
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ //
+ // Sets value in the USB Frame List Base Address register.
+ //
+ return WriteUHCFrameListBaseReg (PciIo, FlBaseAddrReg, (UINT32) (Addr & 0xFFFFF000));
+}
+
+VOID
+EnableMaxPacketSize (
+ IN USB_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Enable Max Packet Size
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+
+Returns:
+
+ VOID
+
+--*/
+{
+ UINT16 CommandContent;
+ EFI_STATUS Status;
+
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ (UINT32) (USBCMD),
+ &CommandContent
+ );
+
+ if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {
+ CommandContent |= USBCMD_MAXP;
+ WriteUHCCommandReg (
+ HcDev->PciIo,
+ (UINT32) (USBCMD),
+ CommandContent
+ );
+ }
+
+ return ;
+}
+
+EFI_STATUS
+CreateFrameList (
+ IN USB_HC_DEV *HcDev,
+ IN UINT32 FlBaseAddrReg
+ )
+/*++
+
+Routine Description:
+
+ CreateFrameList
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ FlBaseAddrReg - Frame List register
+
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate memory resources
+ EFI_UNSUPPORTED - Map memory fail
+ EFI_SUCCESS - Success
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *CommonBuffer;
+ EFI_PHYSICAL_ADDRESS MappedAddress;
+ VOID *Mapping;
+ UINTN BufferSizeInPages;
+ UINTN BufferSizeInBytes;
+
+ //
+ // The Frame List is a common buffer that will be
+ // accessed by both the cpu and the usb bus master
+ // at the same time.
+ // The Frame List ocupies 4K bytes,
+ // and must be aligned on 4-Kbyte boundaries.
+ //
+ BufferSizeInBytes = 4096;
+ BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);
+ Status = HcDev->PciIo->AllocateBuffer (
+ HcDev->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ BufferSizeInPages,
+ &CommonBuffer,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ CommonBuffer,
+ &BufferSizeInBytes,
+ &MappedAddress,
+ &Mapping
+ );
+ if (EFI_ERROR (Status) || (BufferSizeInBytes != 4096)) {
+ HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);
+ return EFI_UNSUPPORTED;
+ }
+
+ HcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) MappedAddress);
+
+ HcDev->FrameListMapping = Mapping;
+
+ InitFrameList (HcDev);
+
+ //
+ // Tell the Host Controller where the Frame List lies,
+ // by set the Frame List Base Address Register.
+ //
+ SetFrameListBaseAddress (
+ HcDev->PciIo,
+ FlBaseAddrReg,
+ (UINT32) ((UINTN) HcDev->FrameListEntry)
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FreeFrameListEntry (
+ IN USB_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Free FrameList buffer
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+
+Returns:
+
+ EFI_SUCCESS - success
+
+--*/
+{
+ //
+ // Unmap the common buffer for framelist entry,
+ // and free the common buffer.
+ // Uhci's frame list occupy 4k memory.
+ //
+ HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->FrameListMapping);
+ HcDev->PciIo->FreeBuffer (
+ HcDev->PciIo,
+ EFI_SIZE_TO_PAGES (4096),
+ (VOID *) (HcDev->FrameListEntry)
+ );
+ return EFI_SUCCESS;
+}
+
+VOID
+InitFrameList (
+ IN USB_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Initialize FrameList
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+
+Returns:
+ VOID
+
+--*/
+{
+ FRAMELIST_ENTRY *FrameListPtr;
+ UINTN Index;
+
+ //
+ // Validate each Frame List Entry
+ //
+ FrameListPtr = HcDev->FrameListEntry;
+ for (Index = 0; Index < 1024; Index++) {
+ FrameListPtr->FrameListPtrTerminate = 1;
+ FrameListPtr->FrameListPtr = 0;
+ FrameListPtr->FrameListPtrQSelect = 0;
+ FrameListPtr->FrameListRsvd = 0;
+ FrameListPtr++;
+ }
+}
+//
+// //////////////////////////////////////////////////////////////
+//
+// QH TD related Helper Functions
+//
+////////////////////////////////////////////////////////////////
+//
+// functions for QH
+//
+EFI_STATUS
+AllocateQHStruct (
+ IN USB_HC_DEV *HcDev,
+ OUT QH_STRUCT **ppQHStruct
+ )
+/*++
+
+Routine Description:
+
+ Allocate QH Struct
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ ppQHStruct - QH_STRUCT content to return
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ *ppQHStruct = NULL;
+
+ //
+ // QH must align on 16 bytes alignment,
+ // since the memory allocated by UhciAllocatePool ()
+ // is aligned on 32 bytes, it is no need to adjust
+ // the allocated memory returned.
+ //
+ return UhciAllocatePool (HcDev, (UINT8 **) ppQHStruct, sizeof (QH_STRUCT));
+}
+
+
+EFI_STATUS
+CreateQH (
+ IN USB_HC_DEV *HcDev,
+ OUT QH_STRUCT **pptrQH
+ )
+/*++
+
+Routine Description:
+
+ CreateQH
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ ppQHStruct - QH_STRUCT content to return
+Returns:
+
+ EFI_SUCCESS - Success
+ EFI_OUT_OF_RESOURCES - Can't allocate memory
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // allocate align memory for QH_STRUCT
+ //
+ Status = AllocateQHStruct (HcDev, pptrQH);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // init each field of the QH_STRUCT
+ //
+ //
+ // Make QH ready
+ //
+ SetQHHorizontalValidorInvalid (*pptrQH, FALSE);
+ SetQHVerticalValidorInvalid (*pptrQH, FALSE);
+
+ return EFI_SUCCESS;
+}
+
+VOID
+SetQHHorizontalLinkPtr (
+ IN QH_STRUCT *PtrQH,
+ IN VOID *ptrNext
+ )
+/*++
+
+Routine Description:
+
+ Set QH Horizontal Link Pointer
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+ ptrNext - Data to write
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // Since the QH_STRUCT is aligned on 16-byte boundaries,
+ // Only the highest 28bit of the address is valid
+ // (take 32bit address as an example).
+ //
+ PtrQH->QH.QHHorizontalPtr = (UINT32) ((UINTN) ptrNext >> 4);
+}
+
+VOID *
+GetQHHorizontalLinkPtr (
+ IN QH_STRUCT *PtrQH
+ )
+/*++
+
+Routine Description:
+
+ Get QH Horizontal Link Pointer
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+
+
+Returns:
+
+ Data to return
+
+--*/
+{
+ //
+ // Restore the 28bit address to 32bit address
+ // (take 32bit address as an example)
+ //
+ return (VOID *) ((UINTN) (PtrQH->QH.QHHorizontalPtr << 4));
+}
+
+VOID
+SetQHHorizontalQHorTDSelect (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN bQH
+ )
+/*++
+
+Routine Description:
+
+ Set QH Horizontal QH or TD
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+ bQH - TRUE is QH FALSE is TD
+
+Returns:
+ VOID
+
+--*/
+{
+ //
+ // if QH is connected, the specified bit is set,
+ // if TD is connected, the specified bit is cleared.
+ //
+ PtrQH->QH.QHHorizontalQSelect = bQH ? 1 : 0;
+}
+
+
+VOID
+SetQHHorizontalValidorInvalid (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN bValid
+ )
+/*++
+
+Routine Description:
+
+ Set QH Horizontal Valid or Invalid
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+ bValid - TRUE is Valid FALSE is Invalid
+
+Returns:
+ VOID
+
+--*/
+{
+ //
+ // Valid means the horizontal link pointer is valid,
+ // else, it's invalid.
+ //
+ PtrQH->QH.QHHorizontalTerminate = bValid ? 0 : 1;
+}
+
+VOID
+SetQHVerticalLinkPtr (
+ IN QH_STRUCT *PtrQH,
+ IN VOID *ptrNext
+ )
+/*++
+
+Routine Description:
+
+ Set QH Vertical Link Pointer
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+ ptrNext - Data to write
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // Since the QH_STRUCT is aligned on 16-byte boundaries,
+ // Only the highest 28bit of the address is valid
+ // (take 32bit address as an example).
+ //
+ PtrQH->QH.QHVerticalPtr = (UINT32) ((UINTN) ptrNext >> 4);
+}
+
+VOID *
+GetQHVerticalLinkPtr (
+ IN QH_STRUCT *PtrQH
+ )
+/*++
+
+Routine Description:
+
+ Get QH Vertical Link Pointer
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+
+Returns:
+
+ Data to return
+
+--*/
+{
+ //
+ // Restore the 28bit address to 32bit address
+ // (take 32bit address as an example)
+ //
+ return (VOID *) ((UINTN) (PtrQH->QH.QHVerticalPtr << 4));
+}
+
+VOID
+SetQHVerticalQHorTDSelect (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN bQH
+ )
+/*++
+
+Routine Description:
+
+ Set QH Vertical QH or TD
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+ bQH - TRUE is QH FALSE is TD
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // Set the specified bit if the Vertical Link Pointer pointing to a QH,
+ // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
+ //
+ PtrQH->QH.QHVerticalQSelect = bQH ? 1 : 0;
+}
+
+BOOLEAN
+IsQHHorizontalQHSelect (
+ IN QH_STRUCT *PtrQH
+ )
+/*++
+
+Routine Description:
+
+ Is QH Horizontal QH Select
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+
+Returns:
+
+ TRUE - QH
+ FALSE - TD
+
+--*/
+{
+ //
+ // Retrieve the information about whether the Horizontal Link Pointer
+ // pointing to a QH or TD.
+ //
+ return (BOOLEAN) (PtrQH->QH.QHHorizontalQSelect ? TRUE : FALSE);
+}
+
+VOID
+SetQHVerticalValidorInvalid (
+ IN QH_STRUCT *PtrQH,
+ IN BOOLEAN IsValid
+ )
+/*++
+
+Routine Description:
+
+ Set QH Vertical Valid or Invalid
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+ IsValid - TRUE is valid FALSE is invalid
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // If TRUE, indicates the Vertical Link Pointer field is valid,
+ // else, the field is invalid.
+ //
+ PtrQH->QH.QHVerticalTerminate = IsValid ? 0 : 1;
+}
+
+
+BOOLEAN
+GetQHVerticalValidorInvalid (
+ IN QH_STRUCT *PtrQH
+ )
+/*++
+
+Routine Description:
+
+ Get QH Vertical Valid or Invalid
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+
+Returns:
+
+ TRUE - Valid
+ FALSE - Invalid
+
+--*/
+{
+ //
+ // If TRUE, indicates the Vertical Link Pointer field is valid,
+ // else, the field is invalid.
+ //
+ return (BOOLEAN) (!(PtrQH->QH.QHVerticalTerminate));
+}
+
+BOOLEAN
+GetQHHorizontalValidorInvalid (
+ IN QH_STRUCT *PtrQH
+ )
+/*++
+
+Routine Description:
+
+ Get QH Horizontal Valid or Invalid
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+
+Returns:
+
+ TRUE - Valid
+ FALSE - Invalid
+
+--*/
+{
+ //
+ // If TRUE, meaning the Horizontal Link Pointer field is valid,
+ // else, the field is invalid.
+ //
+ return (BOOLEAN) (!(PtrQH->QH.QHHorizontalTerminate));
+}
+//
+// functions for TD
+//
+EFI_STATUS
+AllocateTDStruct (
+ IN USB_HC_DEV *HcDev,
+ OUT TD_STRUCT **ppTDStruct
+ )
+/*++
+
+Routine Description:
+
+ Allocate TD Struct
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ ppTDStruct - place to store TD_STRUCT pointer
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+{
+ *ppTDStruct = NULL;
+
+ //
+ // TD must align on 16 bytes alignment,
+ // since the memory allocated by UhciAllocatePool ()
+ // is aligned on 32 bytes, it is no need to adjust
+ // the allocated memory returned.
+ //
+ return UhciAllocatePool (
+ HcDev,
+ (UINT8 **) ppTDStruct,
+ sizeof (TD_STRUCT)
+ );
+}
+
+EFI_STATUS
+CreateTD (
+ IN USB_HC_DEV *HcDev,
+ OUT TD_STRUCT **pptrTD
+ )
+/*++
+
+Routine Description:
+
+ Create TD
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ pptrTD - TD_STRUCT pointer to store
+
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate resources
+ EFI_SUCCESS - Success
+
+--*/
+{
+ EFI_STATUS Status;
+ //
+ // create memory for TD_STRUCT, and align the memory.
+ //
+ Status = AllocateTDStruct (HcDev, pptrTD);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Make TD ready.
+ //
+ SetTDLinkPtrValidorInvalid (*pptrTD, FALSE);
+
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GenSetupStageTD (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN BOOLEAN bSlow,
+ IN UINT8 *pDevReq,
+ IN UINT8 RequestLen,
+ OUT TD_STRUCT **ppTD
+ )
+/*++
+
+Routine Description:
+
+ Generate Setup Stage TD
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ DevAddr - Device address
+ Endpoint - Endpoint number
+ bSlow - Full speed or low speed
+ pDevReq - Device request
+ RequestLen - Request length
+ ppTD - TD_STRUCT to return
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate memory
+ EFI_SUCCESS - Success
+
+--*/
+{
+ EFI_STATUS Status;
+ TD_STRUCT *pTDStruct;
+
+ Status = CreateTD (HcDev, &pTDStruct);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetTDLinkPtr (pTDStruct, NULL);
+
+ //
+ // Depth first fashion
+ //
+ SetTDLinkPtrDepthorBreadth (pTDStruct, TRUE);
+
+ //
+ // initialize as the last TD in the QH context,
+ // this field will be updated in the TD linkage process.
+ //
+ SetTDLinkPtrValidorInvalid (pTDStruct, FALSE);
+
+ //
+ // Disable Short Packet Detection by default
+ //
+ EnableorDisableTDShortPacket (pTDStruct, FALSE);
+
+ //
+ // Max error counter is 3, retry 3 times when error encountered.
+ //
+ SetTDControlErrorCounter (pTDStruct, 3);
+
+ //
+ // set device speed attribute
+ // (TRUE - Slow Device; FALSE - Full Speed Device)
+ //
+ SetTDLoworFullSpeedDevice (pTDStruct, bSlow);
+
+ //
+ // Non isochronous transfer TD
+ //
+ SetTDControlIsochronousorNot (pTDStruct, FALSE);
+
+ //
+ // Interrupt On Complete bit be set to zero,
+ // Disable IOC interrupt.
+ //
+ SetorClearTDControlIOC (pTDStruct, FALSE);
+
+ //
+ // Set TD Active bit
+ //
+ SetTDStatusActiveorInactive (pTDStruct, TRUE);
+
+ SetTDTokenMaxLength (pTDStruct, RequestLen);
+
+ SetTDTokenDataToggle0 (pTDStruct);
+
+ SetTDTokenEndPoint (pTDStruct, Endpoint);
+
+ SetTDTokenDeviceAddress (pTDStruct, DevAddr);
+
+ SetTDTokenPacketID (pTDStruct, SETUP_PACKET_ID);
+
+ pTDStruct->pTDBuffer = (UINT8 *) pDevReq;
+ pTDStruct->TDBufferLength = RequestLen;
+ SetTDDataBuffer (pTDStruct);
+
+ *ppTD = pTDStruct;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GenDataTD (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 *pData,
+ IN UINT8 Len,
+ IN UINT8 PktID,
+ IN UINT8 Toggle,
+ IN BOOLEAN bSlow,
+ OUT TD_STRUCT **ppTD
+ )
+/*++
+
+Routine Description:
+
+ Generate Data Stage TD
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ DevAddr - Device address
+ Endpoint - Endpoint number
+ pData - Data buffer
+ Len - Data length
+ PktID - Packet ID
+ Toggle - Data toggle value
+ bSlow - Full speed or low speed
+ ppTD - TD_STRUCT to return
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate memory
+ EFI_SUCCESS - Success
+
+--*/
+{
+ TD_STRUCT *pTDStruct;
+ EFI_STATUS Status;
+
+ Status = CreateTD (HcDev, &pTDStruct);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetTDLinkPtr (pTDStruct, NULL);
+
+ //
+ // Depth first fashion
+ //
+ SetTDLinkPtrDepthorBreadth (pTDStruct, TRUE);
+
+ //
+ // Link pointer pointing to TD struct
+ //
+ SetTDLinkPtrQHorTDSelect (pTDStruct, FALSE);
+
+ //
+ // initialize as the last TD in the QH context,
+ // this field will be updated in the TD linkage process.
+ //
+ SetTDLinkPtrValidorInvalid (pTDStruct, FALSE);
+
+ //
+ // Disable short packet detect
+ //
+ EnableorDisableTDShortPacket (pTDStruct, FALSE);
+ //
+ // Max error counter is 3
+ //
+ SetTDControlErrorCounter (pTDStruct, 3);
+
+ //
+ // set device speed attribute
+ // (TRUE - Slow Device; FALSE - Full Speed Device)
+ //
+ SetTDLoworFullSpeedDevice (pTDStruct, bSlow);
+
+ //
+ // Non isochronous transfer TD
+ //
+ SetTDControlIsochronousorNot (pTDStruct, FALSE);
+
+ //
+ // Disable Interrupt On Complete
+ // Disable IOC interrupt.
+ //
+ SetorClearTDControlIOC (pTDStruct, FALSE);
+
+ //
+ // Set Active bit
+ //
+ SetTDStatusActiveorInactive (pTDStruct, TRUE);
+
+ SetTDTokenMaxLength (pTDStruct, Len);
+
+ if (Toggle) {
+ SetTDTokenDataToggle1 (pTDStruct);
+ } else {
+ SetTDTokenDataToggle0 (pTDStruct);
+ }
+
+ SetTDTokenEndPoint (pTDStruct, Endpoint);
+
+ SetTDTokenDeviceAddress (pTDStruct, DevAddr);
+
+ SetTDTokenPacketID (pTDStruct, PktID);
+
+ pTDStruct->pTDBuffer = (UINT8 *) pData;
+ pTDStruct->TDBufferLength = Len;
+ SetTDDataBuffer (pTDStruct);
+ *ppTD = pTDStruct;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+CreateStatusTD (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 PktID,
+ IN BOOLEAN bSlow,
+ OUT TD_STRUCT **ppTD
+ )
+/*++
+
+Routine Description:
+
+ Generate Status Stage TD
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ DevAddr - Device address
+ Endpoint - Endpoint number
+ PktID - Packet ID
+ bSlow - Full speed or low speed
+ ppTD - TD_STRUCT to return
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate memory
+ EFI_SUCCESS - Success
+
+--*/
+{
+ TD_STRUCT *ptrTDStruct;
+ EFI_STATUS Status;
+
+ Status = CreateTD (HcDev, &ptrTDStruct);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetTDLinkPtr (ptrTDStruct, NULL);
+
+ //
+ // Depth first fashion
+ //
+ SetTDLinkPtrDepthorBreadth (ptrTDStruct, TRUE);
+
+ //
+ // initialize as the last TD in the QH context,
+ // this field will be updated in the TD linkage process.
+ //
+ SetTDLinkPtrValidorInvalid (ptrTDStruct, FALSE);
+
+ //
+ // Disable short packet detect
+ //
+ EnableorDisableTDShortPacket (ptrTDStruct, FALSE);
+
+ //
+ // Max error counter is 3
+ //
+ SetTDControlErrorCounter (ptrTDStruct, 3);
+
+ //
+ // set device speed attribute
+ // (TRUE - Slow Device; FALSE - Full Speed Device)
+ //
+ SetTDLoworFullSpeedDevice (ptrTDStruct, bSlow);
+
+ //
+ // Non isochronous transfer TD
+ //
+ SetTDControlIsochronousorNot (ptrTDStruct, FALSE);
+
+ //
+ // Disable Interrupt On Complete
+ // Disable IOC interrupt.
+ //
+ SetorClearTDControlIOC (ptrTDStruct, FALSE);
+
+ //
+ // Set TD Active bit
+ //
+ SetTDStatusActiveorInactive (ptrTDStruct, TRUE);
+
+ SetTDTokenMaxLength (ptrTDStruct, 0);
+
+ SetTDTokenDataToggle1 (ptrTDStruct);
+
+ SetTDTokenEndPoint (ptrTDStruct, Endpoint);
+
+ SetTDTokenDeviceAddress (ptrTDStruct, DevAddr);
+
+ SetTDTokenPacketID (ptrTDStruct, PktID);
+
+ ptrTDStruct->pTDBuffer = NULL;
+ ptrTDStruct->TDBufferLength = 0;
+ SetTDDataBuffer (ptrTDStruct);
+
+ *ppTD = ptrTDStruct;
+
+ return EFI_SUCCESS;
+}
+
+
+VOID
+SetTDLinkPtrValidorInvalid (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bValid
+ )
+/*++
+
+Routine Description:
+
+ Set TD Link Pointer Valid or Invalid
+
+Arguments:
+
+ ptrTDStruct - TD_STRUCT
+ bValid - TRUE is valid FALSE is invalid
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // Valid means the link pointer is valid,
+ // else, it's invalid.
+ //
+ ptrTDStruct->TDData.TDLinkPtrTerminate = (bValid ? 0 : 1);
+}
+
+VOID
+SetTDLinkPtrQHorTDSelect (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bQH
+ )
+/*++
+
+Routine Description:
+
+ Set TD Link Pointer QH or TD Select
+
+Arguments:
+
+ ptrTDStruct - TD_STRUCT
+ bQH - TRUE is QH FALSE is TD
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // Indicate whether the Link Pointer pointing to a QH or TD
+ //
+ ptrTDStruct->TDData.TDLinkPtrQSelect = (bQH ? 1 : 0);
+}
+
+VOID
+SetTDLinkPtrDepthorBreadth (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bDepth
+ )
+/*++
+
+Routine Description:
+
+ Set TD Link Pointer depth or bread priority
+
+Arguments:
+
+ ptrTDStruct - TD_STRUCT
+ bDepth - TRUE is Depth FALSE is Breadth
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // If TRUE, indicating the host controller should process in depth first
+ // fashion,
+ // else, the host controller should process in breadth first fashion
+ //
+ ptrTDStruct->TDData.TDLinkPtrDepthSelect = (bDepth ? 1 : 0);
+}
+
+VOID
+SetTDLinkPtr (
+ IN TD_STRUCT *ptrTDStruct,
+ IN VOID *ptrNext
+ )
+/*++
+
+Routine Description:
+
+ Set TD Link Pointer
+
+Arguments:
+
+ ptrTDStruct - TD_STRUCT
+ ptrNext - Pointer to set
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
+ // only the highest 28 bits are valid. (if take 32bit address as an example)
+ //
+ ptrTDStruct->TDData.TDLinkPtr = (UINT32) ((UINTN) ptrNext >> 4);
+}
+
+VOID *
+GetTDLinkPtr (
+ IN TD_STRUCT *ptrTDStruct
+ )
+/*++
+
+Routine Description:
+
+ Get TD Link Pointer
+
+Arguments:
+
+ ptrTDStruct - TD_STRUCT
+
+Returns:
+
+ Pointer to get
+
+--*/
+{
+ //
+ // Get TD Link Pointer. Restore it back to 32bit
+ // (if take 32bit address as an example)
+ //
+ return (VOID *) ((UINTN) (ptrTDStruct->TDData.TDLinkPtr << 4));
+}
+
+BOOLEAN
+IsTDLinkPtrQHOrTD (
+ IN TD_STRUCT *ptrTDStruct
+ )
+/*++
+
+Routine Description:
+
+ Is TD Link Pointer is QH Or TD
+
+Arguments:
+
+ ptrTDStruct - TODO: add argument description
+
+Returns:
+
+ TRUE - QH
+ FALSE - TD
+
+--*/
+{
+ //
+ // Get the information about whether the Link Pointer field pointing to
+ // a QH or a TD.
+ //
+ return (BOOLEAN) (ptrTDStruct->TDData.TDLinkPtrQSelect);
+}
+
+VOID
+EnableorDisableTDShortPacket (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bEnable
+ )
+/*++
+
+Routine Description:
+
+ Enable or Disable TD ShortPacket
+
+Arguments:
+
+ ptrTDStruct - TD_STRUCT
+ bEnable - TRUE is Enanble FALSE is Disable
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // TRUE means enable short packet detection mechanism.
+ //
+ ptrTDStruct->TDData.TDStatusSPD = (bEnable ? 1 : 0);
+}
+
+VOID
+SetTDControlErrorCounter (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINT8 nMaxErrors
+ )
+/*++
+
+Routine Description:
+
+ Set TD Control ErrorCounter
+
+Arguments:
+
+ ptrTDStruct - TD_STRUCT
+ nMaxErrors - Error counter number
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // valid value of nMaxErrors is 0,1,2,3
+ //
+ if (nMaxErrors > 3) {
+ nMaxErrors = 3;
+ }
+
+ ptrTDStruct->TDData.TDStatusErr = nMaxErrors;
+}
+
+
+VOID
+SetTDLoworFullSpeedDevice (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bLowSpeedDevice
+ )
+{
+ //
+ // TRUE means the TD is targeting at a Low-speed device
+ //
+ ptrTDStruct->TDData.TDStatusLS = (bLowSpeedDevice ? 1 : 0);
+}
+
+VOID
+SetTDControlIsochronousorNot (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN IsIsochronous
+ )
+{
+ //
+ // TRUE means the TD belongs to Isochronous transfer type.
+ //
+ ptrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);
+}
+
+VOID
+SetorClearTDControlIOC (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN IsSet
+ )
+{
+ //
+ // If this bit is set, it indicates that the host controller should issue
+ // an interrupt on completion of the frame in which this TD is executed.
+ //
+ ptrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;
+}
+
+VOID
+SetTDStatusActiveorInactive (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN IsActive
+ )
+{
+ //
+ // If this bit is set, it indicates that the TD is active and can be
+ // executed.
+ //
+ if (IsActive) {
+ ptrTDStruct->TDData.TDStatus |= 0x80;
+ } else {
+ ptrTDStruct->TDData.TDStatus &= 0x7F;
+ }
+}
+
+UINT16
+SetTDTokenMaxLength (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINT16 MaximumLength
+ )
+{
+ //
+ // Specifies the maximum number of data bytes allowed for the transfer.
+ // the legal value extent is 0 ~ 0x500.
+ //
+ if (MaximumLength > 0x500) {
+ MaximumLength = 0x500;
+ }
+ ptrTDStruct->TDData.TDTokenMaxLen = MaximumLength - 1;
+
+ return MaximumLength;
+}
+
+VOID
+SetTDTokenDataToggle1 (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Set the data toggle bit to DATA1
+ //
+ ptrTDStruct->TDData.TDTokenDataToggle = 1;
+}
+
+VOID
+SetTDTokenDataToggle0 (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Set the data toggle bit to DATA0
+ //
+ ptrTDStruct->TDData.TDTokenDataToggle = 0;
+}
+
+UINT8
+GetTDTokenDataToggle (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Get the data toggle value.
+ //
+ return (UINT8) (ptrTDStruct->TDData.TDTokenDataToggle);
+}
+
+VOID
+SetTDTokenEndPoint (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINTN EndPoint
+ )
+{
+ //
+ // Set EndPoint Number the TD is targeting at.
+ //
+ ptrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;
+}
+
+VOID
+SetTDTokenDeviceAddress (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINTN DeviceAddress
+ )
+{
+ //
+ // Set Device Address the TD is targeting at.
+ //
+ ptrTDStruct->TDData.TDTokenDevAddr = (UINT8) DeviceAddress;
+}
+
+VOID
+SetTDTokenPacketID (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINT8 PID
+ )
+{
+ //
+ // Set the Packet Identification to be used for this transaction.
+ //
+ ptrTDStruct->TDData.TDTokenPID = PID;
+}
+
+VOID
+SetTDDataBuffer (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Set the beginning address of the data buffer that will be used
+ // during the transaction.
+ //
+ ptrTDStruct->TDData.TDBufferPtr = (UINT32) ((UINTN) (ptrTDStruct->pTDBuffer));
+}
+
+BOOLEAN
+IsTDStatusActive (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether the TD is active.
+ //
+ TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x80);
+}
+
+BOOLEAN
+IsTDStatusStalled (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether the device/endpoint addressed by this TD is stalled.
+ //
+ TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x40);
+}
+
+BOOLEAN
+IsTDStatusBufferError (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ UINT8 TDStatus;
+ //
+ // Detect whether Data Buffer Error is happened.
+ //
+ TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x20);
+}
+
+BOOLEAN
+IsTDStatusBabbleError (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether Babble Error is happened.
+ //
+ TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x10);
+}
+
+BOOLEAN
+IsTDStatusNAKReceived (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether NAK is received.
+ //
+ TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x08);
+}
+
+BOOLEAN
+IsTDStatusCRCTimeOutError (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether CRC/Time Out Error is encountered.
+ //
+ TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x04);
+}
+
+BOOLEAN
+IsTDStatusBitStuffError (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ UINT8 TDStatus;
+
+ //
+ // Detect whether Bitstuff Error is received.
+ //
+ TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);
+ return (BOOLEAN) (TDStatus & 0x02);
+}
+
+UINT16
+GetTDStatusActualLength (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Retrieve the actual number of bytes that were tansferred.
+ // the value is encoded as n-1. so return the decoded value.
+ //
+ return (UINT16) ((ptrTDStruct->TDData.TDStatusActualLength) + 1);
+}
+
+UINT16
+GetTDTokenMaxLength (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Retrieve the maximum number of data bytes allowed for the trnasfer.
+ //
+ return (UINT16) ((ptrTDStruct->TDData.TDTokenMaxLen) + 1);
+}
+
+UINT8
+GetTDTokenEndPoint (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Retrieve the endpoint number the transaction is targeting at.
+ //
+ return (UINT8) (ptrTDStruct->TDData.TDTokenEndPt);
+}
+
+UINT8
+GetTDTokenDeviceAddress (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Retrieve the device address the transaction is targeting at.
+ //
+ return (UINT8) (ptrTDStruct->TDData.TDTokenDevAddr);
+}
+
+UINT8
+GetTDTokenPacketID (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Retrieve the Packet Identification information.
+ //
+ return (UINT8) (ptrTDStruct->TDData.TDTokenPID);
+}
+
+UINT8 *
+GetTDDataBuffer (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Retrieve the beginning address of the data buffer
+ // that involved in this transaction.
+ //
+ return ptrTDStruct->pTDBuffer;
+}
+
+BOOLEAN
+GetTDLinkPtrValidorInvalid (
+ IN TD_STRUCT *ptrTDStruct
+ )
+{
+ //
+ // Retrieve the information of whether the Link Pointer field
+ // is valid or not.
+ //
+ if (ptrTDStruct->TDData.TDLinkPtrTerminate) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+
+}
+
+UINTN
+CountTDsNumber (
+ IN TD_STRUCT *PtrFirstTD
+ )
+{
+ UINTN Number;
+ TD_STRUCT *ptr;
+ //
+ // Count the queued TDs number.
+ //
+ Number = 0;
+ ptr = PtrFirstTD;
+ while (ptr) {
+ ptr = (TD_STRUCT *) ptr->ptrNextTD;
+ Number++;
+ }
+
+ return Number;
+}
+
+
+
+VOID
+LinkTDToQH (
+ IN QH_STRUCT *PtrQH,
+ IN TD_STRUCT *PtrTD
+ )
+/*++
+
+Routine Description:
+
+ Link TD To QH
+
+Arguments:
+
+ PtrQH - QH_STRUCT
+ PtrTD - TD_STRUCT
+Returns:
+
+ VOID
+
+--*/
+{
+ if (PtrQH == NULL || PtrTD == NULL) {
+ return ;
+ }
+ //
+ // Validate QH Vertical Ptr field
+ //
+ SetQHVerticalValidorInvalid (PtrQH, TRUE);
+
+ //
+ // Vertical Ptr pointing to TD structure
+ //
+ SetQHVerticalQHorTDSelect (PtrQH, FALSE);
+
+ SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);
+
+ PtrQH->ptrDown = (VOID *) PtrTD;
+}
+
+VOID
+LinkTDToTD (
+ IN TD_STRUCT *ptrPreTD,
+ IN TD_STRUCT *PtrTD
+ )
+/*++
+
+Routine Description:
+
+ Link TD To TD
+
+Arguments:
+
+ ptrPreTD - Previous TD_STRUCT to be linked
+ PtrTD - TD_STRUCT to link
+Returns:
+
+ VOID
+
+--*/
+{
+ if (ptrPreTD == NULL || PtrTD == NULL) {
+ return ;
+ }
+ //
+ // Depth first fashion
+ //
+ SetTDLinkPtrDepthorBreadth (ptrPreTD, TRUE);
+
+ //
+ // Link pointer pointing to TD struct
+ //
+ SetTDLinkPtrQHorTDSelect (ptrPreTD, FALSE);
+
+ //
+ // Validate the link pointer valid bit
+ //
+ SetTDLinkPtrValidorInvalid (ptrPreTD, TRUE);
+
+ SetTDLinkPtr (ptrPreTD, PtrTD);
+
+ ptrPreTD->ptrNextTD = (VOID *) PtrTD;
+}
+//
+// Transfer Schedule related Helper Functions
+//
+VOID
+SetorClearCurFrameListTerminate (
+ IN FRAMELIST_ENTRY *pCurEntry,
+ IN BOOLEAN IsSet
+ )
+{
+ //
+ // If TRUE, empty the frame. If FALSE, indicate the Pointer field is valid.
+ //
+ pCurEntry->FrameListPtrTerminate = (IsSet ? 1 : 0);
+}
+
+VOID
+SetCurFrameListQHorTD (
+ IN FRAMELIST_ENTRY *pCurEntry,
+ IN BOOLEAN IsQH
+ )
+{
+ //
+ // This bit indicates to the hardware whether the item referenced by the
+ // link pointer is a TD or a QH.
+ //
+ pCurEntry->FrameListPtrQSelect = (IsQH ? 1 : 0);
+}
+
+BOOLEAN
+IsCurFrameListQHorTD (
+ IN FRAMELIST_ENTRY *pCurEntry
+ )
+{
+ //
+ // TRUE is QH
+ // FALSE is TD
+ //
+ return (BOOLEAN) (pCurEntry->FrameListPtrQSelect);
+}
+
+BOOLEAN
+GetCurFrameListTerminate (
+ IN FRAMELIST_ENTRY *pCurEntry
+ )
+{
+ //
+ // TRUE means the frame is empty,
+ // FALSE means the link pointer field is valid.
+ //
+ return (BOOLEAN) (pCurEntry->FrameListPtrTerminate);
+}
+
+VOID
+SetCurFrameListPointer (
+ IN FRAMELIST_ENTRY *pCurEntry,
+ IN UINT8 *ptr
+ )
+{
+ //
+ // Set the pointer field of the frame.
+ //
+ pCurEntry->FrameListPtr = (UINT32) ((UINTN) ptr >> 4);
+}
+
+VOID *
+GetCurFrameListPointer (
+ IN FRAMELIST_ENTRY *pCurEntry
+ )
+{
+ //
+ // Get the link pointer of the frame.
+ //
+ return (VOID *) ((UINTN) (pCurEntry->FrameListPtr << 4));
+
+}
+
+VOID
+LinkQHToFrameList (
+ IN FRAMELIST_ENTRY *pEntry,
+ IN UINT16 FrameListIndex,
+ IN QH_STRUCT *PtrQH
+ )
+/*++
+
+Routine Description:
+
+ Link QH To Frame List
+
+Arguments:
+
+ pEntry - FRAMELIST_ENTRY
+ FrameListIndex - Frame List Index
+ PtrQH - QH to link
+Returns:
+
+ VOID
+
+--*/
+{
+ FRAMELIST_ENTRY *pCurFrame;
+ QH_STRUCT *TempQH;
+ QH_STRUCT *NextTempQH;
+ TD_STRUCT *TempTD;
+ BOOLEAN LINK;
+
+ //
+ // Get frame list entry that the link process will begin from.
+ //
+ pCurFrame = pEntry + FrameListIndex;
+
+ //
+ // if current frame is empty
+ // then link the specified QH directly to the Frame List.
+ //
+ if (GetCurFrameListTerminate (pCurFrame)) {
+
+ //
+ // Link new QH to the frame list entry.
+ //
+ SetCurFrameListQHorTD (pCurFrame, TRUE);
+
+ SetCurFrameListPointer (pCurFrame, (UINT8 *) PtrQH);
+
+ //
+ // clear T bit in the Frame List, indicating that the frame list entry
+ // is no longer empty.
+ //
+ SetorClearCurFrameListTerminate (pCurFrame, FALSE);
+
+ return ;
+
+ } else {
+ //
+ // current frame list has link pointer
+ //
+ if (!IsCurFrameListQHorTD (pCurFrame)) {
+ //
+ // a TD is linked to the framelist entry
+ //
+ TempTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame);
+
+ while (GetTDLinkPtrValidorInvalid (TempTD)) {
+
+ if (IsTDLinkPtrQHOrTD (TempTD)) {
+ //
+ // QH linked next to the TD
+ //
+ break;
+ }
+
+ TempTD = (TD_STRUCT *) GetTDLinkPtr (TempTD);
+ }
+
+ //
+ // either no ptr linked next to the TD or QH is linked next to the TD
+ //
+ if (!GetTDLinkPtrValidorInvalid (TempTD)) {
+
+ //
+ // no ptr linked next to the TD
+ //
+ TempTD->ptrNextQH = PtrQH;
+ SetTDLinkPtrQHorTDSelect (TempTD, TRUE);
+ SetTDLinkPtr (TempTD, PtrQH);
+ SetTDLinkPtrValidorInvalid (TempTD, TRUE);
+ return ;
+
+ } else {
+ //
+ // QH is linked next to the TD
+ //
+ TempQH = (QH_STRUCT *) GetTDLinkPtr (TempTD);
+ }
+ } else {
+ //
+ // a QH is linked to the framelist entry
+ //
+ TempQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame);
+ }
+
+ //
+ // Set up Flag
+ //
+ LINK = TRUE;
+
+ //
+ // Avoid the same qh repeated linking in one frame entry
+ //
+ if (TempQH == PtrQH) {
+ LINK = FALSE;
+ return ;
+ }
+ //
+ // if current QH has next QH connected
+ //
+ while (GetQHHorizontalValidorInvalid (TempQH)) {
+ //
+ // Get next QH pointer
+ //
+ NextTempQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (TempQH);
+
+ //
+ // Bulk transfer qh may be self-linked,
+ // so, the code below is to aVOID dead-loop when meeting self-linked qh
+ //
+ if (NextTempQH == TempQH) {
+ LINK = FALSE;
+ break;
+ }
+
+ TempQH = NextTempQH;
+
+ //
+ // Avoid the same qh repeated linking in one frame entry
+ //
+ if (TempQH == PtrQH) {
+ LINK = FALSE;
+ }
+ }
+
+ if (LINK) {
+ TempQH->ptrNext = PtrQH;
+ SetQHHorizontalQHorTDSelect (TempQH, TRUE);
+ SetQHHorizontalLinkPtr (TempQH, PtrQH);
+ SetQHHorizontalValidorInvalid (TempQH, TRUE);
+ }
+
+ return ;
+ }
+}
+
+EFI_STATUS
+ExecuteControlTransfer (
+ IN USB_HC_DEV *HcDev,
+ IN TD_STRUCT *PtrTD,
+ IN UINT32 wIndex,
+ OUT UINTN *ActualLen,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+/*++
+
+Routine Description:
+
+ Execute Control Transfer
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrTD - TD_STRUCT
+ wIndex - No use
+ ActualLen - Actual transfered Len
+ TimeOut - TimeOut value in milliseconds
+ TransferResult - Transfer result
+Returns:
+
+ EFI_SUCCESS - Sucess
+ EFI_DEVICE_ERROR - Error
+
+
+--*/
+{
+ UINTN ErrTDPos;
+ UINTN Delay;
+ UINTN RequiredLen;
+ BOOLEAN TransferFinished;
+
+ ErrTDPos = 0;
+ *TransferResult = EFI_USB_NOERROR;
+ RequiredLen = *ActualLen;
+ *ActualLen = 0;
+
+ Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;
+
+ do {
+ TransferFinished = CheckTDsResults (
+ PtrTD,
+ RequiredLen,
+ TransferResult,
+ &ErrTDPos,
+ ActualLen
+ );
+
+ if (TransferFinished) {
+ break;
+ }
+
+ //
+ // TD is inactive, which means the control transfer is end.
+ //
+ if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
+ break;
+ }
+
+ gBS->Stall (50);
+
+ } while (Delay--);
+
+ if (*TransferResult != EFI_USB_NOERROR) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ExecBulkorSyncInterruptTransfer (
+ IN USB_HC_DEV *HcDev,
+ IN TD_STRUCT *PtrTD,
+ IN UINT32 wIndex,
+ OUT UINTN *ActualLen,
+ OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+/*++
+
+Routine Description:
+
+ Execute Bulk or SyncInterrupt Transfer
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrTD - TD_STRUCT
+ wIndex - No use
+ ActualLen - Actual transfered Len
+ DataToggle - Data Toggle
+ TimeOut - TimeOut value in milliseconds
+ TransferResult - Transfer result
+Returns:
+
+ EFI_SUCCESS - Sucess
+ EFI_DEVICE_ERROR - Error
+--*/
+{
+ UINTN ErrTDPos;
+ UINTN ScrollNum;
+ UINTN Delay;
+ UINTN RequiredLen;
+ BOOLEAN TransferFinished;
+
+ ErrTDPos = 0;
+ *TransferResult = EFI_USB_NOERROR;
+ RequiredLen = *ActualLen;
+ *ActualLen = 0;
+
+ Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;
+
+ do {
+
+ TransferFinished = CheckTDsResults (
+ PtrTD,
+ RequiredLen,
+ TransferResult,
+ &ErrTDPos,
+ ActualLen
+ );
+
+ if (TransferFinished) {
+ break;
+ }
+
+ //
+ // TD is inactive, which means bulk or interrupt transfer's end.
+ //
+ if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
+ break;
+ }
+
+ gBS->Stall (50);
+
+ } while (Delay--);
+
+ //
+ // has error
+ //
+ if (*TransferResult != EFI_USB_NOERROR) {
+
+ //
+ // scroll the Data Toggle back to the last success TD
+ //
+ ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;
+ if (ScrollNum & 0x1) {
+ *DataToggle ^= 1;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+DelLinkSingleQH (
+ IN USB_HC_DEV *HcDev,
+ IN QH_STRUCT *PtrQH,
+ IN UINT16 FrameListIndex,
+ IN BOOLEAN SearchOther,
+ IN BOOLEAN Delete
+ )
+/*++
+
+Routine Description:
+
+ Unlink from frame list and delete single QH
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrQH - QH_STRUCT
+ FrameListIndex - Frame List Index
+ SearchOther - Search Other QH
+ Delete - TRUE is to delete the QH
+Returns:
+ VOID
+--*/
+{
+ FRAMELIST_ENTRY *pCurFrame;
+ UINTN Index;
+ UINTN BeginFrame;
+ UINTN EndFrame;
+ QH_STRUCT *CurrentQH;
+ QH_STRUCT *NextQH;
+ TD_STRUCT *CurrentTD;
+ VOID *PtrPreQH;
+ BOOLEAN Found;
+
+ NextQH = NULL;
+ PtrPreQH = NULL;
+ Found = FALSE;
+
+ if (PtrQH == NULL) {
+ return ;
+ }
+
+ if (SearchOther) {
+ BeginFrame = 0;
+ EndFrame = 1024;
+ } else {
+ BeginFrame = FrameListIndex;
+ EndFrame = FrameListIndex + 1;
+ }
+
+ for (Index = BeginFrame; Index < EndFrame; Index++) {
+
+ pCurFrame = HcDev->FrameListEntry + (Index & 0x3FF);
+
+ if (GetCurFrameListTerminate (pCurFrame)) {
+ //
+ // current frame list is empty,search next frame list entry
+ //
+ continue;
+ }
+
+ if (!IsCurFrameListQHorTD (pCurFrame)) {
+ //
+ // TD linked to current framelist
+ //
+ CurrentTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame);
+
+ while (GetTDLinkPtrValidorInvalid (CurrentTD)) {
+
+ if (IsTDLinkPtrQHOrTD (CurrentTD)) {
+ //
+ // QH linked next to the TD,break while ()
+ //
+ break;
+ }
+
+ CurrentTD = (TD_STRUCT *) GetTDLinkPtr (CurrentTD);
+ }
+
+ if (!GetTDLinkPtrValidorInvalid (CurrentTD)) {
+ //
+ // no QH linked next to the last TD,
+ // search next frame list
+ //
+ continue;
+ }
+
+ //
+ // a QH linked next to the last TD
+ //
+ CurrentQH = (QH_STRUCT *) GetTDLinkPtr (CurrentTD);
+
+ PtrPreQH = CurrentTD;
+
+ } else {
+ //
+ // a QH linked to current framelist
+ //
+ CurrentQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame);
+
+ PtrPreQH = NULL;
+ }
+
+ if (CurrentQH == PtrQH) {
+
+ if (GetQHHorizontalValidorInvalid (PtrQH)) {
+ //
+ // there is QH connected after the QH found
+ //
+ //
+ // retrieve nex qh pointer of the qh found.
+ //
+ NextQH = GetQHHorizontalLinkPtr (PtrQH);
+ } else {
+ NextQH = NULL;
+ }
+
+ if (PtrPreQH) {
+ //
+ // QH linked to a TD struct
+ //
+ CurrentTD = (TD_STRUCT *) PtrPreQH;
+
+ SetTDLinkPtrValidorInvalid (CurrentTD, (BOOLEAN) ((NextQH == NULL) ? FALSE : TRUE));
+ SetTDLinkPtr (CurrentTD, NextQH);
+ CurrentTD->ptrNextQH = NextQH;
+
+ } else {
+ //
+ // QH linked directly to current framelist entry
+ //
+ SetorClearCurFrameListTerminate (pCurFrame, (BOOLEAN) ((NextQH == NULL) ? TRUE : FALSE));
+ SetCurFrameListPointer (pCurFrame, (UINT8 *) NextQH);
+ }
+
+ Found = TRUE;
+ //
+ // search next framelist entry
+ //
+ continue;
+ }
+
+ while (GetQHHorizontalValidorInvalid (CurrentQH)) {
+
+ PtrPreQH = CurrentQH;
+ //
+ // Get next horizontal linked QH
+ //
+ CurrentQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (CurrentQH);
+ //
+ // the qh is found
+ //
+ if (CurrentQH == PtrQH) {
+ break;
+ }
+ }
+
+ //
+ // search next frame list entry
+ //
+ if (CurrentQH != PtrQH) {
+ //
+ // Not find the QH
+ //
+ continue;
+ }
+ //
+ // find the specified qh, then delink it from
+ // the horizontal QH list in the frame entry.
+ //
+
+ if (GetQHHorizontalValidorInvalid (PtrQH)) {
+ //
+ // there is QH connected after the QH found
+ //
+ //
+ // retrieve nex qh pointer of the qh found.
+ //
+ NextQH = GetQHHorizontalLinkPtr (PtrQH);
+
+ } else {
+ //
+ // NO QH connected after the QH found
+ //
+ NextQH = NULL;
+ //
+ // NULL the previous QH's link ptr and set Terminate field.
+ //
+ SetQHHorizontalValidorInvalid ((QH_STRUCT *) PtrPreQH, FALSE);
+ }
+
+ SetQHHorizontalLinkPtr ((QH_STRUCT *) PtrPreQH, NextQH);
+ ((QH_STRUCT *) PtrPreQH)->ptrNext = NextQH;
+
+ Found = TRUE;
+ }
+
+ if (Found && Delete) {
+ //
+ // free memory once used by the specific QH
+ //
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ }
+
+ return ;
+}
+
+
+VOID
+DeleteQueuedTDs (
+ IN USB_HC_DEV *HcDev,
+ IN TD_STRUCT *PtrFirstTD
+ )
+/*++
+Routine Description:
+
+ Delete Queued TDs
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrFirstTD - TD link list head
+
+Returns:
+ VOID
+
+--*/
+{
+ TD_STRUCT *Tptr1;
+ TD_STRUCT *Tptr2;
+
+ Tptr1 = PtrFirstTD;
+ //
+ // Delete all the TDs in a queue.
+ //
+ while (Tptr1) {
+
+ Tptr2 = Tptr1;
+
+ if (!GetTDLinkPtrValidorInvalid (Tptr2)) {
+ Tptr1 = NULL;
+ } else {
+
+ Tptr1 = GetTDLinkPtr (Tptr2);
+
+ //
+ // TD link to itself
+ //
+ if (Tptr1 == Tptr2) {
+ Tptr1 = NULL;
+ }
+ }
+
+ UhciFreePool (HcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));
+ }
+
+ return ;
+}
+
+VOID
+InsertQHTDToINTList (
+ IN USB_HC_DEV *HcDev,
+ IN QH_STRUCT *PtrQH,
+ IN TD_STRUCT *PtrFirstTD,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DataToggle,
+ IN UINTN DataLength,
+ IN UINTN PollingInterval,
+ IN VOID *Mapping,
+ IN UINT8 *DataBuffer,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
+ IN VOID *Context
+ )
+/*++
+Routine Description:
+ Insert QH and TD To Interrupt List
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrQH - QH_STRUCT
+ PtrFirstTD - First TD_STRUCT
+ DeviceAddress - Device Address
+ EndPointAddress - EndPoint Address
+ DataToggle - Data Toggle
+ DataLength - Data length
+ PollingInterval - Polling Interval when inserted to frame list
+ Mapping - Mapping alue
+ DataBuffer - Data buffer
+ CallBackFunction- CallBackFunction after interrupt transfeer
+ Context - CallBackFunction Context passed as function parameter
+Returns:
+ EFI_SUCCESS - Sucess
+ EFI_INVALID_PARAMETER - Paremeter is error
+
+--*/
+{
+ INTERRUPT_LIST *Node;
+
+ Node = AllocatePool (sizeof (INTERRUPT_LIST));
+ if (Node == NULL) {
+ return ;
+ }
+
+ //
+ // Fill Node field
+ //
+ Node->Signature = INTERRUPT_LIST_SIGNATURE;
+ Node->DevAddr = DeviceAddress;
+ Node->EndPoint = EndPointAddress;
+ Node->PtrQH = PtrQH;
+ Node->PtrFirstTD = PtrFirstTD;
+ Node->DataToggle = DataToggle;
+ Node->DataLen = DataLength;
+ Node->PollInterval = PollingInterval;
+ Node->Mapping = Mapping;
+ //
+ // DataBuffer is allocated host memory, not mapped memory
+ //
+ Node->DataBuffer = DataBuffer;
+ Node->InterruptCallBack = CallBackFunction;
+ Node->InterruptContext = Context;
+
+ //
+ // insert the new interrupt transfer to the head of the list.
+ // The interrupt transfer's monitor function scans the whole list from head
+ // to tail. The new interrupt transfer MUST be added to the head of the list
+ // for the sake of error recovery.
+ //
+ InsertHeadList (&(HcDev->InterruptListHead), &(Node->Link));
+
+ return ;
+}
+
+
+EFI_STATUS
+DeleteAsyncINTQHTDs (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ OUT UINT8 *DataToggle
+ )
+/*++
+Routine Description:
+
+ Delete Async INT QH and TDs
+Arguments:
+
+ HcDev - USB_HC_DEV
+ DeviceAddress - Device Address
+ EndPointAddress - EndPoint Address
+ DataToggle - Data Toggle
+
+Returns:
+ EFI_SUCCESS - Sucess
+ EFI_INVALID_PARAMETER - Paremeter is error
+
+--*/
+{
+ QH_STRUCT *MatchQH;
+ QH_STRUCT *ptrNextQH;
+ TD_STRUCT *MatchTD;
+ LIST_ENTRY *Link;
+ INTERRUPT_LIST *MatchList;
+ INTERRUPT_LIST *PtrList;
+ BOOLEAN Found;
+
+ UINT32 Result;
+ UINTN ErrTDPos;
+ UINTN ActualLen;
+
+ MatchQH = NULL;
+ MatchTD = NULL;
+ MatchList = NULL;
+
+ //
+ // no interrupt transaction exists
+ //
+ if (IsListEmpty (&(HcDev->InterruptListHead))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // find the correct QH-TD that need to delete
+ // (by matching Device address and EndPoint number to match QH-TD )
+ //
+ Found = FALSE;
+ Link = &(HcDev->InterruptListHead);
+ do {
+
+ Link = Link->ForwardLink;
+ PtrList = INTERRUPT_LIST_FROM_LINK (Link);
+
+ if ((PtrList->DevAddr == DeviceAddress) && ((PtrList->EndPoint & 0x0f) == (EndPointAddress & 0x0f))) {
+ MatchList = PtrList;
+
+ Found = TRUE;
+ break;
+ }
+
+ } while (Link->ForwardLink != &(HcDev->InterruptListHead));
+
+ if (!Found) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // get current endpoint's data toggle bit and save.
+ //
+ ExecuteAsyncINTTDs (HcDev, MatchList, &Result, &ErrTDPos, &ActualLen);
+ UpdateAsyncINTQHTDs (MatchList, Result, (UINT32) ErrTDPos);
+ *DataToggle = MatchList->DataToggle;
+
+ MatchTD = MatchList->PtrFirstTD;
+ MatchQH = MatchList->PtrQH;
+ //
+ // find the first matching QH position in the FrameList
+ //
+ while (MatchQH) {
+
+ ptrNextQH = MatchQH->ptrNextIntQH;
+
+ //
+ // Search all the entries
+ //
+ DelLinkSingleQH (HcDev, MatchQH, 0, TRUE, TRUE);
+
+ MatchQH = ptrNextQH;
+ }
+
+ //
+ // Call PciIo->Unmap() to unmap the busmaster read/write
+ //
+ HcDev->PciIo->Unmap (HcDev->PciIo, MatchList->Mapping);
+
+ //
+ // free host data buffer allocated,
+ // mapped data buffer is freed by Unmap
+ //
+ if (MatchList->DataBuffer != NULL) {
+ gBS->FreePool (MatchList->DataBuffer);
+ }
+
+ //
+ // at last delete the TDs, to aVOID problems
+ //
+ DeleteQueuedTDs (HcDev, MatchTD);
+
+ //
+ // remove Match node from interrupt list
+ //
+ RemoveEntryList (&(MatchList->Link));
+ gBS->FreePool (MatchList);
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+CheckTDsResults (
+ IN TD_STRUCT *PtrTD,
+ IN UINTN RequiredLen,
+ OUT UINT32 *Result,
+ OUT UINTN *ErrTDPos,
+ OUT UINTN *ActualTransferSize
+ )
+/*++
+
+Routine Description:
+
+ Check TDs Results
+
+Arguments:
+
+ PtrTD - TD_STRUCT to check
+ RequiredLen - Required Len
+ Result - Transfer result
+ ErrTDPos - Error TD Position
+ ActualTransferSize - Actual Transfer Size
+
+Returns:
+
+ TRUE - Sucess
+ FALSE - Fail
+
+--*/
+{
+ UINTN Len;
+
+ *Result = EFI_USB_NOERROR;
+ *ErrTDPos = 0;
+
+ //
+ // Init to zero.
+ //
+ *ActualTransferSize = 0;
+
+ while (PtrTD) {
+
+ if (IsTDStatusActive (PtrTD)) {
+ *Result |= EFI_USB_ERR_NOTEXECUTE;
+ }
+
+ if (IsTDStatusStalled (PtrTD)) {
+ *Result |= EFI_USB_ERR_STALL;
+ }
+
+ if (IsTDStatusBufferError (PtrTD)) {
+ *Result |= EFI_USB_ERR_BUFFER;
+ }
+
+ if (IsTDStatusBabbleError (PtrTD)) {
+ *Result |= EFI_USB_ERR_BABBLE;
+ }
+
+ if (IsTDStatusNAKReceived (PtrTD)) {
+ *Result |= EFI_USB_ERR_NAK;
+ }
+
+ if (IsTDStatusCRCTimeOutError (PtrTD)) {
+ *Result |= EFI_USB_ERR_TIMEOUT;
+ }
+
+ if (IsTDStatusBitStuffError (PtrTD)) {
+ *Result |= EFI_USB_ERR_BITSTUFF;
+ }
+
+ //
+ // if any error encountered, stop processing the left TDs.
+ //
+ if (*Result) {
+ return FALSE;
+ }
+
+ Len = GetTDStatusActualLength (PtrTD) & 0x7FF;
+ *ActualTransferSize += Len;
+
+ if (*ActualTransferSize <= RequiredLen && Len < PtrTD->TDData.TDTokenMaxLen) {
+ //
+ // transter finished and actural length less than required length
+ //
+ goto Done;
+ }
+ //
+ // Accumulate actual transferred data length in each TD.
+ //
+ PtrTD = (TD_STRUCT *) (PtrTD->ptrNextTD);
+ //
+ // Record the first Error TD's position in the queue,
+ // this value is zero-based.
+ //
+ (*ErrTDPos)++;
+ }
+
+Done:
+ return TRUE;
+}
+
+
+VOID
+ExecuteAsyncINTTDs (
+ IN USB_HC_DEV *HcDev,
+ IN INTERRUPT_LIST *PtrList,
+ OUT UINT32 *Result,
+ OUT UINTN *ErrTDPos,
+ OUT UINTN *ActualLen
+ )
+/*++
+
+Routine Description:
+
+ Execute Async Interrupt TDs
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrList - INTERRUPT_LIST
+ Result - Transfer result
+ ErrTDPos - Error TD Position
+ ActualTransferSize - Actual Transfer Size
+
+Returns:
+
+ VOID
+
+--*/
+{
+ //
+ // *ErrTDPos is zero-based value, indicating the first error TD's position
+ // in the TDs' sequence.
+ // *ErrTDPos value is only valid when *Result is not equal NOERROR.
+ //
+ UINTN RequiredLen;
+
+ RequiredLen = *ActualLen;
+ CheckTDsResults (PtrList->PtrFirstTD, RequiredLen, Result, ErrTDPos, ActualLen);
+
+ return ;
+}
+
+
+VOID
+UpdateAsyncINTQHTDs (
+ IN INTERRUPT_LIST *PtrList,
+ IN UINT32 Result,
+ IN UINT32 ErrTDPos
+ )
+/*++
+
+Routine Description:
+
+ Update Async Interrupt QH and TDs
+
+Arguments:
+
+ PtrList - INTERRUPT_LIST
+ Result - Transfer reslut
+ ErrTDPos - Error TD Position
+
+Returns:
+
+ VOID
+
+--*/
+{
+ QH_STRUCT *PtrFirstQH;
+ QH_STRUCT *PtrQH;
+ TD_STRUCT *PtrFirstTD;
+ TD_STRUCT *PtrTD;
+ UINT8 DataToggle;
+ UINT32 Index;
+
+ PtrFirstQH = PtrList->PtrQH;
+ PtrFirstTD = PtrList->PtrFirstTD;
+
+ DataToggle = 0;
+
+ if (Result == EFI_USB_NOERROR) {
+
+ PtrTD = PtrFirstTD;
+ while (PtrTD) {
+ DataToggle = GetTDTokenDataToggle (PtrTD);
+ PtrTD = PtrTD->ptrNextTD;
+ }
+
+ //
+ // save current DataToggle value to interrupt list.
+ // this value is used for tracing the interrupt endpoint DataToggle.
+ // when this interrupt transfer is deleted, the last DataToggle is saved
+ //
+ PtrList->DataToggle = DataToggle;
+
+ PtrTD = PtrFirstTD;
+
+ //
+ // Since DataToggle bit should toggle after each success transaction,
+ // the First TD's DataToggle bit will be updated to XOR of Last TD's
+ // DataToggle bit. If the First TD's DataToggle bit is not equal Last
+ // TD's DataToggle bit, that means it already be the XOR of Last TD's,
+ // so no update is needed.
+ //
+ if (DataToggle == GetTDTokenDataToggle (PtrFirstTD)) {
+ PtrTD = PtrFirstTD;
+ while (PtrTD) {
+
+ DataToggle ^= 1;
+ if (DataToggle) {
+ SetTDTokenDataToggle1 (PtrTD);
+ } else {
+ SetTDTokenDataToggle0 (PtrTD);
+ }
+
+ PtrTD = PtrTD->ptrNextTD;
+ }
+ }
+ //
+ // restore Link Pointer of QH to First TD
+ // (because QH's Link Pointer will change during TD execution)
+ //
+ PtrQH = PtrFirstQH;
+ while (PtrQH) {
+
+ LinkTDToQH (PtrQH, PtrFirstTD);
+ PtrQH = PtrQH->ptrNextIntQH;
+ }
+
+ //
+ // set all the TDs active
+ //
+ PtrTD = PtrFirstTD;
+ while (PtrTD) {
+ SetTDStatusActiveorInactive (PtrTD, TRUE);
+ PtrTD = PtrTD->ptrNextTD;
+ }
+
+ } else if (((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE) ||
+ ((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK)
+ ) {
+ //
+ // no update
+ //
+ } else {
+ //
+ // Have Errors
+ //
+ PtrTD = PtrFirstTD;
+ //
+ // not first TD error
+ //
+ if (ErrTDPos != 0) {
+ //
+ // get the last success TD
+ //
+ for (Index = 1; Index < ErrTDPos; Index++) {
+ PtrTD = PtrTD->ptrNextTD;
+ }
+ //
+ // update Data Toggle in the interrupt list node
+ //
+ PtrList->DataToggle = GetTDTokenDataToggle (PtrTD);
+
+ //
+ // get the error TD
+ //
+ PtrTD = PtrTD->ptrNextTD;
+
+ } else {
+ PtrList->DataToggle = GetTDTokenDataToggle (PtrTD);
+ }
+ //
+ // do not restore the QH's vertical link pointer,
+ // let the callback function do the rest of error handling.
+ //
+ }
+
+ return ;
+}
+
+VOID
+ReleaseInterruptList (
+ IN USB_HC_DEV *HcDev,
+ IN LIST_ENTRY *ListHead
+ )
+/*++
+
+Routine Description:
+
+ Release Interrupt List
+Arguments:
+
+ HcDev - USB_HC_DEV
+ ListHead - List head
+
+Returns:
+
+ VOID
+
+--*/
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *SavedLink;
+ INTERRUPT_LIST *pNode;
+ TD_STRUCT *PtrTD;
+ TD_STRUCT *ptrNextTD;
+ QH_STRUCT *PtrQH;
+ QH_STRUCT *SavedQH;
+
+ if (ListHead == NULL) {
+ return ;
+ }
+
+ Link = ListHead;
+
+ //
+ // Free all the resources in the interrupt list
+ //
+ SavedLink = Link->ForwardLink;
+ while (!IsListEmpty (ListHead)) {
+
+ Link = SavedLink;
+
+ SavedLink = Link->ForwardLink;
+
+ pNode = INTERRUPT_LIST_FROM_LINK (Link);
+
+ RemoveEntryList (&pNode->Link);
+
+ SavedQH = pNode->PtrQH;
+ for (PtrQH = SavedQH; PtrQH != NULL; PtrQH = SavedQH) {
+ SavedQH = PtrQH->ptrNextIntQH;
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ }
+
+ PtrTD = pNode->PtrFirstTD;
+ while (PtrTD != NULL) {
+
+ ptrNextTD = PtrTD->ptrNextTD;
+ UhciFreePool (HcDev, (UINT8 *) PtrTD, sizeof (TD_STRUCT));
+ PtrTD = ptrNextTD;
+ }
+
+ gBS->FreePool (pNode);
+ }
+}
+
+
+EFI_STATUS
+InitializeMemoryManagement (
+ IN USB_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Initialize Memory Management
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+
+Returns:
+
+ EFI_SUCCESS - Success
+--*/
+{
+ MEMORY_MANAGE_HEADER *MemoryHeader;
+ EFI_STATUS Status;
+ UINTN MemPages;
+
+ MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
+ Status = CreateMemoryBlock (HcDev, &MemoryHeader, MemPages);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HcDev->MemoryHeader = MemoryHeader;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+CreateMemoryBlock (
+ IN USB_HC_DEV *HcDev,
+ OUT MEMORY_MANAGE_HEADER **MemoryHeader,
+ IN UINTN MemoryBlockSizeInPages
+ )
+/*++
+
+Routine Description:
+
+ Use PciIo->AllocateBuffer to allocate common buffer for the memory block,
+ and use PciIo->Map to map the common buffer for Bus Master Read/Write.
+
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ MemoryHeader - MEMORY_MANAGE_HEADER to output
+ MemoryBlockSizeInPages - MemoryBlockSizeInPages
+Returns:
+
+ EFI_SUCCESS - Success
+--*/
+{
+ EFI_STATUS Status;
+ VOID *CommonBuffer;
+ EFI_PHYSICAL_ADDRESS MappedAddress;
+ UINTN MemoryBlockSizeInBytes;
+ VOID *Mapping;
+
+ //
+ // Allocate memory for MemoryHeader
+ //
+ *MemoryHeader = AllocateZeroPool (sizeof (MEMORY_MANAGE_HEADER));
+ if (*MemoryHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ (*MemoryHeader)->Next = NULL;
+
+ //
+ // set Memory block size
+ //
+ (*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);
+
+ //
+ // each bit in Bit Array will manage 32 bytes memory in memory block
+ //
+ (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
+
+ //
+ // Allocate memory for BitArray
+ //
+ (*MemoryHeader)->BitArrayPtr = AllocateZeroPool ((*MemoryHeader)->BitArraySizeInBytes);
+ if ((*MemoryHeader)->BitArrayPtr == NULL) {
+ gBS->FreePool (*MemoryHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Memory Block uses MemoryBlockSizeInPages pages,
+ // and it is allocated as common buffer use.
+ //
+ Status = HcDev->PciIo->AllocateBuffer (
+ HcDev->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ MemoryBlockSizeInPages,
+ &CommonBuffer,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
+ gBS->FreePool (*MemoryHeader);
+ return Status;
+ }
+
+ MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ CommonBuffer,
+ &MemoryBlockSizeInBytes,
+ &MappedAddress,
+ &Mapping
+ );
+ //
+ // if returned Mapped size is less than the size we request,do not support.
+ //
+ if (EFI_ERROR (Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages))) {
+ HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);
+ gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
+ gBS->FreePool (*MemoryHeader);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Set Memory block initial address
+ //
+ (*MemoryHeader)->MemoryBlockPtr = (UINT8 *) ((UINTN) MappedAddress);
+ (*MemoryHeader)->Mapping = Mapping;
+
+ ZeroMem (
+ (*MemoryHeader)->MemoryBlockPtr,
+ EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages)
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FreeMemoryHeader (
+ IN USB_HC_DEV *HcDev,
+ IN MEMORY_MANAGE_HEADER *MemoryHeader
+ )
+/*++
+
+Routine Description:
+
+ Free Memory Header
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ MemoryHeader - MemoryHeader to be freed
+
+Returns:
+
+ EFI_INVALID_PARAMETER - Parameter is error
+ EFI_SUCCESS - Success
+
+--*/
+{
+ if ((MemoryHeader == NULL) || (HcDev == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // unmap the common buffer used by the memory block
+ //
+ HcDev->PciIo->Unmap (HcDev->PciIo, MemoryHeader->Mapping);
+
+ //
+ // free common buffer
+ //
+ HcDev->PciIo->FreeBuffer (
+ HcDev->PciIo,
+ EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes),
+ MemoryHeader->MemoryBlockPtr
+ );
+ //
+ // free bit array
+ //
+ gBS->FreePool (MemoryHeader->BitArrayPtr);
+ //
+ // free memory header
+ //
+ gBS->FreePool (MemoryHeader);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+UhciAllocatePool (
+ IN USB_HC_DEV *HcDev,
+ OUT UINT8 **Pool,
+ IN UINTN AllocSize
+ )
+/*++
+
+Routine Description:
+
+ Uhci Allocate Pool
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ Pool - Place to store pointer to the memory buffer
+ AllocSize - Alloc Size
+
+Returns:
+
+ EFI_SUCCESS - Success
+
+--*/
+{
+ MEMORY_MANAGE_HEADER *MemoryHeader;
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;
+ MEMORY_MANAGE_HEADER *NewMemoryHeader;
+ UINTN RealAllocSize;
+ UINTN MemoryBlockSizeInPages;
+ EFI_STATUS Status;
+
+ *Pool = NULL;
+
+ MemoryHeader = HcDev->MemoryHeader;
+ ASSERT (MemoryHeader != NULL);
+
+ //
+ // allocate unit is 32 bytes (align on 32 byte)
+ //
+ if (AllocSize & 0x1F) {
+ RealAllocSize = (AllocSize / 32 + 1) * 32;
+ } else {
+ RealAllocSize = AllocSize;
+ }
+
+ //
+ // There may be linked MemoryHeaders.
+ // To allocate a free pool in Memory blocks,
+ // must search in the MemoryHeader link list
+ // until enough free pool is found.
+ //
+ Status = EFI_NOT_FOUND;
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;
+ TempHeaderPtr = TempHeaderPtr->Next) {
+
+ Status = AllocMemInMemoryBlock (
+ TempHeaderPtr,
+ (VOID **) Pool,
+ RealAllocSize / 32
+ );
+ if (!EFI_ERROR (Status)) {
+ ZeroMem (*Pool, AllocSize);
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // There is no enough memory,
+ // Create a new Memory Block
+ //
+
+ //
+ // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
+ // just allocate a large enough memory block.
+ //
+ if (RealAllocSize > EFI_PAGES_TO_SIZE (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES)) {
+ MemoryBlockSizeInPages = EFI_SIZE_TO_PAGES (RealAllocSize) + 1;
+ } else {
+ MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
+ }
+
+ Status = CreateMemoryBlock (HcDev, &NewMemoryHeader, MemoryBlockSizeInPages);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Link the new Memory Block to the Memory Header list
+ //
+ InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);
+
+ Status = AllocMemInMemoryBlock (
+ NewMemoryHeader,
+ (VOID **) Pool,
+ RealAllocSize / 32
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ZeroMem (*Pool, AllocSize);
+ }
+
+ return Status;
+}
+
+VOID
+UhciFreePool (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 *Pool,
+ IN UINTN AllocSize
+ )
+/*++
+
+Routine Description:
+
+ Uhci Free Pool
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ Pool - Pool to free
+ AllocSize - Pool size
+
+Returns:
+
+ VOID
+
+--*/
+{
+ MEMORY_MANAGE_HEADER *MemoryHeader;
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;
+ UINTN StartBytePos;
+ UINTN Index;
+ UINT8 StartBitPos;
+ UINT8 Index2;
+ UINTN Count;
+ UINTN RealAllocSize;
+
+ MemoryHeader = HcDev->MemoryHeader;
+
+ //
+ // allocate unit is 32 byte (align on 32 byte)
+ //
+ if (AllocSize & 0x1F) {
+ RealAllocSize = (AllocSize / 32 + 1) * 32;
+ } else {
+ RealAllocSize = AllocSize;
+ }
+ //
+ // scan the memory header linked list for
+ // the asigned memory to free.
+ //
+ for (TempHeaderPtr = MemoryHeader;TempHeaderPtr != NULL;
+ TempHeaderPtr = TempHeaderPtr->Next) {
+
+ if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&
+ ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr + TempHeaderPtr->MemoryBlockSizeInBytes))
+ ) {
+ //
+ // Pool is in the Memory Block area,
+ // find the start byte and bit in the bit array
+ //
+ StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;
+ StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) & 0x7);
+
+ //
+ // reset associated bits in bit arry
+ //
+ for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {
+
+ TempHeaderPtr->BitArrayPtr[Index] ^= (UINT8) (bit (Index2));
+ Index2++;
+ if (Index2 == 8) {
+ Index += 1;
+ Index2 = 0;
+ }
+ }
+ //
+ // break the loop
+ //
+ break;
+ }
+ }
+
+ //
+ // Release emptied memory blocks (only if the memory block is not
+ // the first one in the memory header list
+ //
+ for (TempHeaderPtr = MemoryHeader->Next; TempHeaderPtr != NULL;) {
+ //
+ // Debug
+ //
+ ASSERT (MemoryHeader->Next != NULL);
+
+ if (IsMemoryBlockEmptied (TempHeaderPtr)) {
+
+ DelinkMemoryBlock (MemoryHeader, TempHeaderPtr);
+ //
+ // when the TempHeaderPtr is freed in FreeMemoryHeader(),
+ // the TempHeaderPtr is pointing to nonsense content.
+ //
+ FreeMemoryHeader (HcDev, TempHeaderPtr);
+ //
+ // reset the TempHeaderPtr, continue search for
+ // another empty memory block.
+ //
+ TempHeaderPtr = MemoryHeader->Next;
+ continue;
+ }
+
+ TempHeaderPtr = TempHeaderPtr->Next;
+ }
+}
+
+VOID
+InsertMemoryHeaderToList (
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,
+ IN MEMORY_MANAGE_HEADER *NewMemoryHeader
+ )
+/*++
+
+Routine Description:
+
+ Insert Memory Header To List
+
+Arguments:
+
+ MemoryHeader - MEMORY_MANAGE_HEADER
+ NewMemoryHeader - MEMORY_MANAGE_HEADER
+
+Returns:
+
+ VOID
+
+--*/
+{
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;
+
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;
+ TempHeaderPtr = TempHeaderPtr->Next) {
+ if (TempHeaderPtr->Next == NULL) {
+ TempHeaderPtr->Next = NewMemoryHeader;
+ break;
+ }
+ }
+}
+
+EFI_STATUS
+AllocMemInMemoryBlock (
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,
+ OUT VOID **Pool,
+ IN UINTN NumberOfMemoryUnit
+ )
+/*++
+
+Routine Description:
+
+ Alloc Memory In MemoryBlock
+
+Arguments:
+
+ MemoryHeader - MEMORY_MANAGE_HEADER
+ Pool - Place to store pointer to memory
+ NumberOfMemoryUnit - Number Of Memory Unit
+
+Returns:
+
+ EFI_NOT_FOUND - Can't find the free memory
+ EFI_SUCCESS - Success
+
+--*/
+{
+ UINTN TempBytePos;
+ UINTN FoundBytePos;
+ UINT8 Index;
+ UINT8 FoundBitPos;
+ UINT8 ByteValue;
+ UINT8 BitValue;
+ UINTN NumberOfZeros;
+ UINTN Count;
+
+ FoundBytePos = 0;
+ FoundBitPos = 0;
+ ByteValue = MemoryHeader->BitArrayPtr[0];
+ NumberOfZeros = 0;
+ Index = 0;
+
+ for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {
+
+ //
+ // Pop out BitValue from a byte in TempBytePos.
+ //
+ BitValue = (UINT8) (ByteValue & 0x1);
+ //
+ // right shift the byte
+ //
+ ByteValue /= 2;
+
+ if (BitValue == 0) {
+ //
+ // Found a free bit, the NumberOfZeros only record the number
+ // of those consecutive zeros
+ //
+ NumberOfZeros++;
+ //
+ // Found enough consecutive free space, break the loop
+ //
+ if (NumberOfZeros >= NumberOfMemoryUnit) {
+ break;
+ }
+ } else {
+ //
+ // Encountering a '1', meant the bit is ocupied.
+ //
+ if (NumberOfZeros >= NumberOfMemoryUnit) {
+ //
+ // Found enough consecutive free space,break the loop
+ //
+ break;
+ } else {
+ //
+ // the NumberOfZeros only record the number of those consecutive zeros,
+ // so reset the NumberOfZeros to 0 when encountering '1' before finding
+ // enough consecutive '0's
+ //
+ NumberOfZeros = 0;
+ //
+ // reset the (FoundBytePos,FoundBitPos) to the position of '1'
+ //
+ FoundBytePos = TempBytePos;
+ FoundBitPos = Index;
+ }
+ }
+ //
+ // step forward a bit
+ //
+ Index++;
+ if (Index == 8) {
+ //
+ // step forward a byte, getting the byte value,
+ // and reset the bit pos.
+ //
+ TempBytePos += 1;
+ ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];
+ Index = 0;
+ }
+ }
+
+ if (NumberOfZeros < NumberOfMemoryUnit) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Found enough free space.
+ //
+
+ //
+ // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
+ // 1)(FoundBytePos,FoundBitPos) record the position
+ // of the last '1' before the consecutive '0's, it must
+ // be adjusted to the start position of the consecutive '0's.
+ // 2)the start address of the consecutive '0's is just the start of
+ // the bitarray. so no need to adjust the values of
+ // (FoundBytePos,FoundBitPos).
+ //
+ if ((MemoryHeader->BitArrayPtr[0] & bit (0)) != 0) {
+ FoundBitPos += 1;
+ }
+
+ //
+ // Have the (FoundBytePos,FoundBitPos) make sense.
+ //
+ if (FoundBitPos > 7) {
+ FoundBytePos += 1;
+ FoundBitPos -= 8;
+ }
+
+ //
+ // Set the memory as allocated
+ //
+ for (TempBytePos = FoundBytePos, Index = FoundBitPos,Count = 0;
+ Count < NumberOfMemoryUnit; Count ++) {
+
+ MemoryHeader->BitArrayPtr[TempBytePos] |= bit (Index);
+ Index++;
+ if (Index == 8) {
+ TempBytePos += 1;
+ Index = 0;
+ }
+ }
+
+ *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+IsMemoryBlockEmptied (
+ IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr
+ )
+/*++
+
+Routine Description:
+
+ Is Memory Block Emptied
+
+Arguments:
+
+ MemoryHeaderPtr - MEMORY_MANAGE_HEADER
+
+Returns:
+
+ TRUE - Empty
+ FALSE - Not Empty
+
+--*/
+{
+ UINTN Index;
+
+ for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {
+ if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+DelinkMemoryBlock (
+ IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,
+ IN MEMORY_MANAGE_HEADER *NeedFreeMemoryHeader
+ )
+/*++
+
+Routine Description:
+
+ Delink Memory Block
+
+Arguments:
+
+ FirstMemoryHeader - MEMORY_MANAGE_HEADER
+ NeedFreeMemoryHeader - MEMORY_MANAGE_HEADER
+
+Returns:
+
+ VOID
+
+--*/
+{
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;
+
+ if ((FirstMemoryHeader == NULL) || (NeedFreeMemoryHeader == NULL)) {
+ return ;
+ }
+ for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL;
+ TempHeaderPtr = TempHeaderPtr->Next) {
+
+ if (TempHeaderPtr->Next == NeedFreeMemoryHeader) {
+ //
+ // Link the before and after
+ //
+ TempHeaderPtr->Next = NeedFreeMemoryHeader->Next;
+ break;
+ }
+ }
+}
+
+EFI_STATUS
+DelMemoryManagement (
+ IN USB_HC_DEV *HcDev
+ )
+/*++
+
+Routine Description:
+
+ Delete Memory Management
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+
+Returns:
+
+ EFI_SUCCESS - Success
+
+--*/
+{
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;
+
+ for (TempHeaderPtr = HcDev->MemoryHeader->Next; TempHeaderPtr != NULL;) {
+
+ DelinkMemoryBlock (HcDev->MemoryHeader, TempHeaderPtr);
+ //
+ // when the TempHeaderPtr is freed in FreeMemoryHeader(),
+ // the TempHeaderPtr is pointing to nonsense content.
+ //
+ FreeMemoryHeader (HcDev, TempHeaderPtr);
+ //
+ // reset the TempHeaderPtr,continue free another memory block.
+ //
+ TempHeaderPtr = HcDev->MemoryHeader->Next;
+ }
+
+ FreeMemoryHeader (HcDev, HcDev->MemoryHeader);
+
+ return EFI_SUCCESS;
+}
+
+
+VOID
+CleanUsbTransactions (
+ IN USB_HC_DEV *HcDev
+ )
+{
+ //
+ // only asynchronous interrupt transfers are always alive on the bus
+ //
+ ReleaseInterruptList (HcDev, &(HcDev->InterruptListHead));
+}
+
+VOID
+TurnOffUSBEmulation (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+/*++
+
+ Routine Description:
+ Disable USB Emulation
+ Arguments:
+ PciIo - EFI_PCI_IO_PROTOCOL
+ Returns:
+ VOID
+--*/
+{
+ UINT16 Command;
+
+ //
+ // Disable USB Emulation
+ //
+ Command = 0;
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ USB_EMULATION,
+ 1,
+ &Command
+ );
+
+ return ;
+}
diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c
new file mode 100644
index 0000000..1eba8be
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.c
@@ -0,0 +1,3498 @@
+/*++
+
+Copyright (c) 2006, 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.c
+
+Abstract:
+
+
+Revision History
+--*/
+
+#include "uhci.h"
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+
+EFI_STATUS
+EFIAPI
+UHCIDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// UHCI interface functions
+//
+
+EFI_STATUS
+EFIAPI
+UHCIReset (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT16 Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIGetState (
+ IN EFI_USB_HC_PROTOCOL *This,
+ OUT EFI_USB_HC_STATE *State
+ );
+
+EFI_STATUS
+EFIAPI
+UHCISetState (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN EFI_USB_HC_STATE State
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIControlTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data, OPTIONAL
+ IN OUT UINTN *DataLength, OPTIONAL
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIBulkTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIAsyncInterruptTransfer (
+ IN EFI_USB_HC_PROTOCOL * This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxiumPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN PollingInterval, OPTIONAL
+ IN UINTN DataLength, OPTIONAL
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, OPTIONAL
+ IN VOID *Context OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+UHCISyncInterruptTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIIsochronousTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ OUT UINT32 *TransferResult
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIAsyncIsochronousTransfer (
+ IN EFI_USB_HC_PROTOCOL * This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIGetRootHubPortNumber (
+ IN EFI_USB_HC_PROTOCOL *This,
+ OUT UINT8 *PortNumber
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIGetRootHubPortStatus (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ );
+
+EFI_STATUS
+EFIAPI
+UHCISetRootHubPortFeature (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+EFI_STATUS
+EFIAPI
+UHCIClearRootHubPortFeature (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ );
+
+//
+// Asynchronous interrupt transfer monitor function
+//
+VOID
+EFIAPI
+MonitorInterruptTrans (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// UHCI Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
+ UHCIDriverBindingSupported,
+ UHCIDriverBindingStart,
+ UHCIDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+EFI_STATUS
+EFIAPI
+UHCIDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+ Routine Description:
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ that has UsbHcProtocol installed will be supported.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Controller, - Handle of device to test
+ RemainingDevicePath - Not used
+
+ Returns:
+ EFI_SUCCESS - This driver supports this device.
+ EFI_UNSUPPORTED - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS OpenStatus;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_CLASSC UsbClassCReg;
+
+ //
+ // Test whether there is PCI IO Protocol attached on the controller handle.
+ //
+ OpenStatus = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (OpenStatus)) {
+ return OpenStatus;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ CLASSC,
+ sizeof (USB_CLASSC) / sizeof (UINT8),
+ &UsbClassCReg
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Test whether the controller belongs to UHCI type
+ //
+ if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
+ (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
+ (UsbClassCReg.PI != PCI_CLASSC_PI_UHCI)) {
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+EFIAPI
+UHCIDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+ Routine Description:
+ Starting the Usb UHCI Driver
+
+ Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to test
+ RemainingDevicePath - Not used
+
+ Returns:
+ EFI_SUCCESS - This driver supports this device.
+ EFI_UNSUPPORTED - This driver does not support this device.
+ EFI_DEVICE_ERROR - This driver cannot be started due to device
+ Error
+ EFI_OUT_OF_RESOURCES
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN FlBaseAddrReg;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ USB_HC_DEV *HcDev;
+
+ HcDev = NULL;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Turn off USB emulation
+ //
+ TurnOffUSBEmulation (PciIo);
+
+ //
+ // Enable the USB Host Controller
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // allocate memory for UHC private data structure
+ //
+ HcDev = AllocateZeroPool (sizeof (USB_HC_DEV));
+ if (HcDev == NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // init EFI_USB_HC_PROTOCOL protocol interface and install the protocol
+ //
+ HcDev->UsbHc.Reset = UHCIReset;
+ HcDev->UsbHc.GetState = UHCIGetState;
+ HcDev->UsbHc.SetState = UHCISetState;
+ HcDev->UsbHc.ControlTransfer = UHCIControlTransfer;
+ HcDev->UsbHc.BulkTransfer = UHCIBulkTransfer;
+ HcDev->UsbHc.AsyncInterruptTransfer = UHCIAsyncInterruptTransfer;
+ HcDev->UsbHc.SyncInterruptTransfer = UHCISyncInterruptTransfer;
+ HcDev->UsbHc.IsochronousTransfer = UHCIIsochronousTransfer;
+ HcDev->UsbHc.AsyncIsochronousTransfer = UHCIAsyncIsochronousTransfer;
+ HcDev->UsbHc.GetRootHubPortNumber = UHCIGetRootHubPortNumber;
+ HcDev->UsbHc.GetRootHubPortStatus = UHCIGetRootHubPortStatus;
+ HcDev->UsbHc.SetRootHubPortFeature = UHCISetRootHubPortFeature;
+ HcDev->UsbHc.ClearRootHubPortFeature = UHCIClearRootHubPortFeature;
+
+ HcDev->UsbHc.MajorRevision = 0x1;
+ HcDev->UsbHc.MinorRevision = 0x1;
+
+ //
+ // Init UHCI private data structures
+ //
+ HcDev->Signature = USB_HC_DEV_SIGNATURE;
+ HcDev->PciIo = PciIo;
+
+ FlBaseAddrReg = USBFLBASEADD;
+
+ //
+ // Allocate and Init Host Controller's Frame List Entry
+ //
+ Status = CreateFrameList (HcDev, (UINT32) FlBaseAddrReg);
+ if (EFI_ERROR (Status)) {
+
+ if (HcDev != NULL) {
+ gBS->FreePool (HcDev);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Init interrupt list head in the HcDev structure.
+ //
+ InitializeListHead (&(HcDev->InterruptListHead));
+
+ //
+ // Create timer for interrupt transfer result polling
+ //
+ Status = gBS->CreateEvent (
+ EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
+ EFI_TPL_NOTIFY,
+ MonitorInterruptTrans,
+ HcDev,
+ &HcDev->InterruptTransTimer
+ );
+ if (EFI_ERROR (Status)) {
+
+ FreeFrameListEntry (HcDev);
+
+ if (HcDev != NULL) {
+ gBS->FreePool (HcDev);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Here set interrupt transfer polling timer in 50ms unit.
+ //
+ Status = gBS->SetTimer (
+ HcDev->InterruptTransTimer,
+ TimerPeriodic,
+ INTERRUPT_POLLING_TIME
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (HcDev->InterruptTransTimer);
+
+ FreeFrameListEntry (HcDev);
+
+ if (HcDev != NULL) {
+ gBS->FreePool (HcDev);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // QH,TD structures must in common buffer that will be
+ // accessed by both cpu and usb bus master at the same time.
+ // so, there must has memory management for QH,TD structures.
+ //
+ Status = InitializeMemoryManagement (HcDev);
+ if (EFI_ERROR (Status)) {
+
+ gBS->CloseEvent (HcDev->InterruptTransTimer);
+
+ FreeFrameListEntry (HcDev);
+
+ if (HcDev != NULL) {
+ gBS->FreePool (HcDev);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ //
+ // Install Host Controller Protocol
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiUsbHcProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &HcDev->UsbHc
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (HcDev->InterruptTransTimer);
+ FreeFrameListEntry (HcDev);
+ DelMemoryManagement (HcDev);
+
+ if (HcDev != NULL) {
+ gBS->FreePool (HcDev);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ //
+ // component name protocol.
+ //
+ HcDev->ControllerNameTable = NULL;
+ AddUnicodeString (
+ "eng",
+ gUhciComponentName.SupportedLanguages,
+ &HcDev->ControllerNameTable,
+ (CHAR16 *) L"Usb Universal Host Controller"
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+UnInstallUHCInterface (
+ IN EFI_HANDLE Controller,
+ IN EFI_USB_HC_PROTOCOL *This
+ )
+/*++
+ Routine Description:
+ UnInstall UHCInterface
+ Arguments:
+ Controller - Controller handle
+ This - Protocol instance pointer.
+ Returns:
+ EFI_SUCCESS
+ others
+--*/
+{
+ USB_HC_DEV *HcDev;
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ &HcDev->UsbHc
+ );
+
+ //
+ // first stop USB Host Controller
+ //
+ This->SetState (This, EfiUsbHcStateHalt);
+
+ //
+ // Delete interrupt transfer polling timer
+ //
+ gBS->CloseEvent (HcDev->InterruptTransTimer);
+
+ //
+ // Delete all the asynchronous interrupt transfers in the interrupt list
+ // and free associated memory
+ //
+ ReleaseInterruptList (HcDev, &(HcDev->InterruptListHead));
+
+ //
+ // free Frame List Entry.
+ //
+ FreeFrameListEntry (HcDev);
+
+ //
+ // Free common buffer allocated for QH,TD structures
+ //
+ DelMemoryManagement (HcDev);
+
+ if (HcDev->ControllerNameTable) {
+ FreeUnicodeStringTable (HcDev->ControllerNameTable);
+ }
+ //
+ // Disable the USB Host Controller
+ //
+ HcDev->PciIo->Attributes (
+ HcDev->PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+
+ gBS->FreePool (HcDev);
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+UHCIDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+ Routine Description:
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to stop driver on
+ NumberOfChildren - Number of Children in the ChildHandleBuffer
+ ChildHandleBuffer - List of handles for the children we need to stop.
+
+ Returns:
+ EFI_SUCCESS
+ others
+
+--*/
+{
+ EFI_USB_HC_PROTOCOL *UsbHc;
+ EFI_STATUS OpenStatus;
+
+ OpenStatus = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ (VOID **) &UsbHc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ //
+ // Test whether the Controller handler passed in is a valid
+ // Usb controller handle that should be supported, if not,
+ // return the error status directly
+ //
+ if (EFI_ERROR (OpenStatus)) {
+ return OpenStatus;
+ }
+ //
+ // free all the controller related memory and uninstall UHCI Protocol.
+ //
+ UnInstallUHCInterface (Controller, UsbHc);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+
+}
+
+
+EFI_STATUS
+EFIAPI
+UHCIReset (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT16 Attributes
+ )
+/*++
+
+ Routine Description:
+ Provides software reset for the USB host controller.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ Attributes A bit mask of the reset operation to perform.
+ See below for a list of the supported bit mask values.
+
+ #define EFI_USB_HC_RESET_GLOBAL 0x0001
+ #define EFI_USB_HC_RESET_HOST_CONTROLLER 0x0002
+
+ EFI_USB_HC_RESET_GLOBAL
+ If this bit is set, a global reset signal will be sent to the USB bus.
+ This resets all of the USB bus logic, including the USB host
+ controller hardware and all the devices attached on the USB bus.
+ EFI_USB_HC_RESET_HOST_CONTROLLER
+ If this bit is set, the USB host controller hardware will be reset.
+ No reset signal will be sent to the USB bus.
+
+ Returns:
+ EFI_SUCCESS
+ The reset operation succeeded.
+ EFI_INVALID_PARAMETER
+ Attributes is not valid.
+ EFI_DEVICE_ERROR
+ An error was encountered while attempting to perform
+ the reset operation.
+--*/
+{
+ BOOLEAN Match;
+ USB_HC_DEV *HcDev;
+ UINT32 CommandRegAddr;
+ UINT32 FlBaseAddrReg;
+ UINT16 Command;
+ EFI_STATUS Status;
+
+ Match = FALSE;
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+
+ CommandRegAddr = (UINT32) (USBCMD);
+ FlBaseAddrReg = (UINT32) (USBFLBASEADD);
+
+ if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) {
+ Match = TRUE;
+ //
+ // set the Global Reset bit in the command register
+ //
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ &Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Command |= USBCMD_GRESET;
+ Status = WriteUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Wait 50ms for root port to let reset complete
+ // See UHCI spec page122 Reset signaling
+ //
+ gBS->Stall (ROOT_PORT_REST_TIME);
+
+ //
+ // Clear the Global Reset bit to zero.
+ //
+ Command &= ~USBCMD_GRESET;
+ Status = WriteUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // UHCI spec page120 reset recovery time
+ //
+ gBS->Stall (PORT_RESET_RECOVERY_TIME);
+ }
+
+ if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {
+ Match = TRUE;
+ //
+ // set Host Controller Reset bit to 1
+ //
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ &Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Command |= USBCMD_HCRESET;
+ Status = WriteUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // this bit will be reset by Host Controller when reset is completed.
+ // wait 10ms to let reset complete
+ //
+ gBS->Stall (PORT_RESET_RECOVERY_TIME);
+ }
+
+ if (!Match) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete all old transactions on the USB bus
+ //
+ CleanUsbTransactions (HcDev);
+
+ //
+ // Initialize Universal Host Controller's Frame List Data Structure
+ //
+ InitFrameList (HcDev);
+
+ //
+ // Reset may cause Frame List Base Address Register reset to zero,
+ // so set the original value back again.
+ //
+ SetFrameListBaseAddress (
+ HcDev->PciIo,
+ FlBaseAddrReg,
+ (UINT32) ((UINTN) HcDev->FrameListEntry)
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UHCIGetState (
+ IN EFI_USB_HC_PROTOCOL *This,
+ OUT EFI_USB_HC_STATE *State
+ )
+/*++
+
+ Routine Description:
+ Retrieves current state of the USB host controller.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ State A pointer to the EFI_USB_HC_STATE data structure that
+ indicates current state of the USB host controller.
+ Type EFI_USB_HC_STATE is defined below.
+
+ typedef enum {
+ EfiUsbHcStateHalt,
+ EfiUsbHcStateOperational,
+ EfiUsbHcStateSuspend,
+ EfiUsbHcStateMaximum
+ } EFI_USB_HC_STATE;
+
+ Returns:
+ EFI_SUCCESS
+ The state information of the host controller was returned in State.
+ EFI_INVALID_PARAMETER
+ State is NULL.
+ EFI_DEVICE_ERROR
+ An error was encountered while attempting to retrieve the
+ host controller's current state.
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 CommandRegAddr;
+ UINT32 StatusRegAddr;
+ UINT16 UhcCommand;
+ UINT16 UhcStatus;
+ EFI_STATUS Status;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+
+ CommandRegAddr = (UINT32) (USBCMD);
+ StatusRegAddr = (UINT32) (USBSTS);
+
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ &UhcCommand
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ StatusRegAddr,
+ &UhcStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (UhcCommand & USBCMD_EGSM) {
+ *State = EfiUsbHcStateSuspend;
+ return EFI_SUCCESS;
+ }
+
+ if ((UhcStatus & USBSTS_HCH) == 0) {
+ *State = EfiUsbHcStateOperational;
+ } else {
+ *State = EfiUsbHcStateHalt;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+UHCISetState (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN EFI_USB_HC_STATE State
+ )
+/*++
+
+ Routine Description:
+ Sets the USB host controller to a specific state.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ State Indicates the state of the host controller that will be set.
+
+ Returns:
+ EFI_SUCCESS
+ The USB host controller was successfully placed in the state
+ specified by State.
+ EFI_INVALID_PARAMETER
+ State is invalid.
+ EFI_DEVICE_ERROR
+ Failed to set the state specified by State due to device error.
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 CommandRegAddr;
+ UINT32 StatusRegAddr;
+ UINT16 Command;
+ EFI_USB_HC_STATE CurrentState;
+ EFI_STATUS Status;
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+
+ CommandRegAddr = (UINT32) (USBCMD);
+ StatusRegAddr = (UINT32) (USBSTS);
+
+ Status = UHCIGetState (This, &CurrentState);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (State) {
+
+ case EfiUsbHcStateHalt:
+ if (CurrentState == EfiUsbHcStateHalt) {
+ return EFI_SUCCESS;
+ }
+
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ &Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Command &= ~USBCMD_RS;
+
+ Status = WriteUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ StatusRegAddr = (UINT32) (USBSTS);
+ //
+ // ensure the HC is in halt status after send the stop command
+ //
+ if (WaitForUHCHalt (HcDev->PciIo, StatusRegAddr, STALL_1_SECOND) == EFI_TIMEOUT) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ case EfiUsbHcStateOperational:
+ if (IsHostSysOrProcessErr (HcDev->PciIo, StatusRegAddr)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (CurrentState) {
+
+ case EfiUsbHcStateOperational:
+ return EFI_SUCCESS;
+
+ case EfiUsbHcStateHalt:
+ //
+ // Set Run/Stop bit to 1.
+ //
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ &Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Command |= USBCMD_RS | USBCMD_MAXP;
+ Status = WriteUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ break;
+
+ case EfiUsbHcStateSuspend:
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ &Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // FGR(Force Global Resume) bit is 0
+ //
+ if ((Command | (~USBCMD_FGR)) != 0xFF) {
+ //
+ // Write FGR bit to 1
+ //
+ Command |= USBCMD_FGR;
+ WriteUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ Command
+ );
+ }
+
+ //
+ // wait 20ms to let resume complete
+ // (20ms is specified by UHCI spec)
+ //
+ gBS->Stall (FORCE_GLOBAL_RESUME_TIME);
+
+ //
+ // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0
+ //
+ Command &= ~USBCMD_FGR;
+ Command &= ~USBCMD_EGSM;
+ Command |= USBCMD_RS;
+ WriteUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ Command
+ );
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EfiUsbHcStateSuspend:
+ if (CurrentState == EfiUsbHcStateSuspend) {
+ return EFI_SUCCESS;
+ }
+
+ Status = UHCISetState (This, EfiUsbHcStateHalt);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set Enter Global Suspend Mode bit to 1.
+ //
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ &Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Command |= USBCMD_EGSM;
+ Status = WriteUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UHCIGetRootHubPortNumber (
+ IN EFI_USB_HC_PROTOCOL *This,
+ OUT UINT8 *PortNumber
+ )
+/*++
+
+ Routine Description:
+ Retrieves the number of root hub ports.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ PortNumber A pointer to the number of the root hub ports.
+
+ Returns:
+ EFI_SUCCESS
+ The port number was retrieved successfully.
+ EFI_INVALID_PARAMETER
+ PortNumber is NULL.
+ EFI_DEVICE_ERROR
+ An error was encountered while attempting to
+ retrieve the port number.
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 PSAddr;
+ UINT16 RHPortControl;
+ UINT32 Index;
+ EFI_STATUS Status;
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+
+ if (PortNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *PortNumber = 0;
+
+ for (Index = 0; Index < 2; Index++) {
+ PSAddr = (UINT32) (USBPORTSC1 + Index * 2);
+ Status = ReadRootPortReg (
+ HcDev->PciIo,
+ PSAddr,
+ &RHPortControl
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Port Register content is valid
+ //
+ if (RHPortControl != 0xff) {
+ (*PortNumber)++;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UHCIGetRootHubPortStatus (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ OUT EFI_USB_PORT_STATUS *PortStatus
+ )
+/*++
+
+ Routine Description:
+ Retrieves the current status of a USB root hub port.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL.
+
+ PortNumber Specifies the root hub port from which the status
+ is to be retrieved. This value is zero-based. For example,
+ if a root hub has two ports, then the first port is numbered 0,
+ and the second port is numbered 1.
+
+ PortStatus A pointer to the current port status bits and
+ port status change bits.
+
+ Returns:
+ EFI_SUCCESS
+ The status of the USB root hub port specified by PortNumber
+ was returned in PortStatus.
+ EFI_INVALID_PARAMETER
+ PortNumber is invalid.
+ EFI_DEVICE_ERROR - Can't read register
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 PSAddr;
+ UINT16 RHPortStatus;
+ UINT8 TotalPortNumber;
+ EFI_STATUS Status;
+
+ if (PortStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UHCIGetRootHubPortNumber (This, &TotalPortNumber);
+ if (PortNumber >= TotalPortNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+ PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2);
+
+ //
+ // Clear port status
+ //
+ PortStatus->PortStatus = 0;
+ PortStatus->PortChangeStatus = 0;
+
+ Status = ReadRootPortReg (
+ HcDev->PciIo,
+ PSAddr,
+ &RHPortStatus
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Fill Port Status bits
+ //
+
+ //
+ // Current Connect Status
+ //
+ if (RHPortStatus & USBPORTSC_CCS) {
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
+ }
+ //
+ // Port Enabled/Disabled
+ //
+ if (RHPortStatus & USBPORTSC_PED) {
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
+ }
+
+ //
+ // Port Suspend
+ //
+ if (RHPortStatus & USBPORTSC_SUSP) {
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
+ }
+
+ //
+ // Port Reset
+ //
+ if (RHPortStatus & USBPORTSC_PR) {
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;
+ }
+
+ //
+ // Low Speed Device Attached
+ //
+ if (RHPortStatus & USBPORTSC_LSDA) {
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
+ }
+ //
+ // Fill Port Status Change bits
+ //
+
+ //
+ // Connect Status Change
+ //
+ if (RHPortStatus & USBPORTSC_CSC) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
+ }
+
+ //
+ // Port Enabled/Disabled Change
+ //
+ if (RHPortStatus & USBPORTSC_PEDC) {
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UHCISetRootHubPortFeature (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+/*++
+
+ Routine Description:
+ Sets a feature for the specified root hub port.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL.
+
+ PortNumber Specifies the root hub port whose feature
+ is requested to be set.
+
+ PortFeature Indicates the feature selector associated
+ with the feature set request.
+
+ Returns:
+ EFI_SUCCESS
+ The feature specified by PortFeature was set for the
+ USB root hub port specified by PortNumber.
+ EFI_INVALID_PARAMETER
+ PortNumber is invalid or PortFeature is invalid.
+ EFI_DEVICE_ERROR
+ Can't read register
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 PSAddr;
+ UINT32 CommandRegAddr;
+ //
+ // root hub port status
+ //
+ UINT16 RHPortControl;
+ UINT16 Command;
+ UINT8 TotalPortNumber;
+ EFI_STATUS Status;
+
+ UHCIGetRootHubPortNumber (This, &TotalPortNumber);
+ if (PortNumber >= TotalPortNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+
+ PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2);
+ CommandRegAddr = (UINT32) (USBCMD);
+
+ Status = ReadRootPortReg (
+ HcDev->PciIo,
+ PSAddr,
+ &RHPortControl
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (PortFeature) {
+
+ case EfiUsbPortSuspend:
+ Status = ReadUHCCommandReg (
+ HcDev->PciIo,
+ CommandRegAddr,
+ &Command
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (!(Command & USBCMD_EGSM)) {
+ //
+ // if global suspend is not active, can set port suspend
+ //
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_SUSP;
+ }
+ break;
+
+ case EfiUsbPortReset:
+ RHPortControl &= 0xfff5;
+ //
+ // Set the reset bit
+ //
+ RHPortControl |= USBPORTSC_PR;
+ break;
+
+ case EfiUsbPortPower:
+ break;
+
+ case EfiUsbPortEnable:
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_PED;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WriteRootPortReg (
+ HcDev->PciIo,
+ PSAddr,
+ RHPortControl
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UHCIClearRootHubPortFeature (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 PortNumber,
+ IN EFI_USB_PORT_FEATURE PortFeature
+ )
+/*++
+
+ Routine Description:
+ Clears a feature for the specified root hub port.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ PortNumber Specifies the root hub port whose feature
+ is requested to be cleared.
+
+ PortFeature Indicates the feature selector associated with the
+ feature clear request.
+
+ Returns:
+ EFI_SUCCESS
+ The feature specified by PortFeature was cleared for the
+ USB root hub port specified by PortNumber.
+ EFI_INVALID_PARAMETER
+ PortNumber is invalid or PortFeature is invalid.
+ EFI_DEVICE_ERROR
+ Can't read register
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 PSAddr;
+ UINT16 RHPortControl;
+ UINT8 TotalPortNumber;
+ EFI_STATUS Status;
+
+ UHCIGetRootHubPortNumber (This, &TotalPortNumber);
+
+ if (PortNumber >= TotalPortNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+ PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2);
+
+ Status = ReadRootPortReg (
+ HcDev->PciIo,
+ PSAddr,
+ &RHPortControl
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (PortFeature) {
+ //
+ // clear PORT_ENABLE feature means disable port.
+ //
+ case EfiUsbPortEnable:
+ RHPortControl &= 0xfff5;
+ RHPortControl &= ~USBPORTSC_PED;
+ break;
+
+ //
+ // clear PORT_SUSPEND feature means resume the port.
+ // (cause a resume on the specified port if in suspend mode)
+ //
+ case EfiUsbPortSuspend:
+ RHPortControl &= 0xfff5;
+ RHPortControl &= ~USBPORTSC_SUSP;
+ break;
+
+ //
+ // no operation
+ //
+ case EfiUsbPortPower:
+ break;
+
+ //
+ // clear PORT_RESET means clear the reset signal.
+ //
+ case EfiUsbPortReset:
+ RHPortControl &= 0xfff5;
+ RHPortControl &= ~USBPORTSC_PR;
+ break;
+
+ //
+ // clear connect status change
+ //
+ case EfiUsbPortConnectChange:
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_CSC;
+ break;
+
+ //
+ // clear enable/disable status change
+ //
+ case EfiUsbPortEnableChange:
+ RHPortControl &= 0xfff5;
+ RHPortControl |= USBPORTSC_PEDC;
+ break;
+
+ //
+ // root hub does not support this request
+ //
+ case EfiUsbPortSuspendChange:
+ break;
+
+ //
+ // root hub does not support this request
+ //
+ case EfiUsbPortOverCurrentChange:
+ break;
+
+ //
+ // root hub does not support this request
+ //
+ case EfiUsbPortResetChange:
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WriteRootPortReg (
+ HcDev->PciIo,
+ PSAddr,
+ RHPortControl
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UHCIControlTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaximumPacketLength,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION TransferDirection,
+ IN OUT VOID *Data, OPTIONAL
+ IN OUT UINTN *DataLength, OPTIONAL
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+/*++
+
+ Routine Description:
+ Submits control transfer to a target USB device.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+
+ IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+
+ MaximumPacketLength Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+
+ Request A pointer to the USB device request that will be sent
+ to the USB device.
+
+ TransferDirection Specifies the data direction for the transfer.
+ There are three values available, DataIn, DataOut
+ and NoData.
+
+ Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+
+ DataLength Indicates the size, in bytes, of the data buffer
+ specified by Data.
+
+ TimeOut Indicates the maximum time, in microseconds,
+ which the transfer is allowed to complete.
+
+ TransferResult A pointer to the detailed result information generated
+ by this control transfer.
+
+ Returns:
+ EFI_SUCCESS
+ The control transfer was completed successfully.
+ EFI_OUT_OF_RESOURCES
+ The control transfer could not be completed due to a lack of resources.
+ EFI_INVALID_PARAMETER
+ Some parameters are invalid.
+ EFI_TIMEOUT
+ The control transfer failed due to timeout.
+ EFI_DEVICE_ERROR
+ The control transfer failed due to host controller or device error.
+ Caller should check TranferResult for detailed error information.
+
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 StatusReg;
+ UINT32 FrameNumReg;
+ UINT8 PktID;
+ QH_STRUCT *PtrQH;
+ TD_STRUCT *PtrTD;
+ TD_STRUCT *PtrPreTD;
+ TD_STRUCT *PtrSetupTD;
+ TD_STRUCT *PtrStatusTD;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN DataLen;
+ UINT8 *PtrDataSource;
+ UINT8 *Ptr;
+ UINT8 DataToggle;
+ UINT16 LoadFrameListIndex;
+ UINT8 PktSize;
+
+ UINT8 *RequestMappedAddress;
+ VOID *RequestMapping;
+ UINTN RequestLen;
+
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ VOID *Mapping;
+
+ TD_STRUCT *PtrFirstDataTD;
+ TD_STRUCT *ptrLastDataTD;
+ BOOLEAN FirstTD;
+
+ FirstTD = FALSE;
+ RequestMappedAddress = NULL;
+ RequestMapping = NULL;
+ Mapping = NULL;
+ PtrFirstDataTD = NULL;
+ ptrLastDataTD = NULL;
+ PktID = INPUT_PACKET_ID;
+ Mapping = NULL;
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+ StatusReg = (UINT32) (USBSTS);
+ FrameNumReg = (UINT32) (USBFRNUM);
+ PtrPreTD = NULL;
+ PtrTD = NULL;
+
+ //
+ // Parameters Checking
+ //
+ if (Request == NULL || TransferResult == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // if errors exist that cause host controller halt,
+ // then return EFI_DEVICE_ERROR.
+ //
+ if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // low speed usb devices are limited to only an eight-byte
+ // maximum data payload size
+ //
+ if (IsSlowDevice && (MaximumPacketLength != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MaximumPacketLength != 8 &&
+ MaximumPacketLength != 16 &&
+ MaximumPacketLength != 32 &&
+ MaximumPacketLength != 64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((TransferDirection != EfiUsbNoData) && (DataLength == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (TransferDirection) {
+
+ case EfiUsbDataIn:
+ PktID = INPUT_PACKET_ID;
+ PtrDataSource = Data;
+ DataLen = *DataLength;
+
+ //
+ // map the source data buffer for bus master access.
+ // BusMasterWrite means cpu read
+ //
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterWrite,
+ PtrDataSource,
+ &DataLen,
+ &TempPtr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ptr = (UINT8 *) ((UINTN) TempPtr);
+ break;
+
+ case EfiUsbDataOut:
+ PktID = OUTPUT_PACKET_ID;
+ PtrDataSource = Data;
+ DataLen = *DataLength;
+
+ //
+ // map the source data buffer for bus master access.
+ // BusMasterRead means cpu write
+ //
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterRead,
+ PtrDataSource,
+ &DataLen,
+ &TempPtr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ptr = (UINT8 *) ((UINTN) TempPtr);
+ break;
+
+ //
+ // no data stage
+ //
+ case EfiUsbNoData:
+ if ((DataLength != NULL) && (*DataLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PktID = OUTPUT_PACKET_ID;
+ PtrDataSource = NULL;
+ DataLen = 0;
+ Ptr = NULL;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ClearStatusReg (HcDev->PciIo, StatusReg);
+ if (EFI_ERROR (Status)) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // create QH structure and init
+ //
+ Status = CreateQH (HcDev, &PtrQH);
+ if (EFI_ERROR (Status)) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ return Status;
+ }
+
+ //
+ // map the Request for bus master access.
+ // BusMasterRead means cpu write
+ //
+ RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterRead,
+ (UINT8 *) Request,
+ &RequestLen,
+ &TempPtr,
+ &RequestMapping
+ );
+
+ if (EFI_ERROR (Status)) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ return Status;
+ }
+
+ RequestMappedAddress = (UINT8 *) ((UINTN) TempPtr);
+
+ //
+ // generate Setup Stage TD
+ //
+ Status = GenSetupStageTD (
+ HcDev,
+ DeviceAddress,
+ 0,
+ IsSlowDevice,
+ (UINT8 *) RequestMappedAddress,
+ sizeof (EFI_USB_DEVICE_REQUEST),
+ &PtrSetupTD
+ );
+
+ if (EFI_ERROR (Status)) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping);
+ return Status;
+ }
+
+ //
+ // Data Stage of Control Transfer
+ //
+ DataToggle = 1;
+ FirstTD = TRUE;
+ while (DataLen > 0) {
+ //
+ // create TD structures and link together
+ //
+
+ //
+ // PktSize is the data load size that each TD carries.
+ //
+ PktSize = (UINT8) DataLen;
+ if (DataLen > MaximumPacketLength) {
+ PktSize = MaximumPacketLength;
+ }
+
+ Status = GenDataTD (
+ HcDev,
+ DeviceAddress,
+ 0,
+ Ptr,
+ PktSize,
+ PktID,
+ DataToggle,
+ IsSlowDevice,
+ &PtrTD
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // free all resources occupied
+ //
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping);
+ DeleteQueuedTDs (HcDev, PtrSetupTD);
+ DeleteQueuedTDs (HcDev, PtrFirstDataTD);
+ return Status;
+ }
+
+ //
+ // Link two TDs in vertical depth
+ //
+ if (FirstTD) {
+ PtrFirstDataTD = PtrTD;
+ PtrFirstDataTD->ptrNextTD = NULL;
+ FirstTD = FALSE;
+ } else {
+ LinkTDToTD (PtrPreTD, PtrTD);
+ }
+
+ PtrPreTD = PtrTD;
+
+ DataToggle ^= 1;
+ Ptr += PktSize;
+ DataLen -= PktSize;
+ }
+
+ ptrLastDataTD = PtrTD;
+
+ //
+ // Status Stage of Control Transfer
+ //
+ if (PktID == OUTPUT_PACKET_ID) {
+ PktID = INPUT_PACKET_ID;
+ } else {
+ PktID = OUTPUT_PACKET_ID;
+ }
+
+ //
+ // create Status Stage TD structure
+ //
+ Status = CreateStatusTD (
+ HcDev,
+ DeviceAddress,
+ 0,
+ PktID,
+ IsSlowDevice,
+ &PtrStatusTD
+ );
+
+ if (EFI_ERROR (Status)) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping);
+ DeleteQueuedTDs (HcDev, PtrSetupTD);
+ DeleteQueuedTDs (HcDev, PtrFirstDataTD);
+ return Status;
+ }
+
+ if (IsSlowDevice) {
+ //
+ // link setup TD structures to QH structure
+ //
+ LinkTDToQH (PtrQH, PtrSetupTD);
+
+ LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
+
+ //
+ // link QH-TDs to total 100 frame list entry to speed up the execution.
+ //
+ for (Index = 0; Index < 100; Index++) {
+ LinkQHToFrameList (
+ HcDev->FrameListEntry,
+ (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
+ PtrQH
+ );
+ }
+ //
+ // Poll QH-TDs execution and get result.
+ // detail status is returned
+ //
+ Status = ExecuteControlTransfer (
+ HcDev,
+ PtrSetupTD,
+ LoadFrameListIndex,
+ DataLength,
+ TimeOut,
+ TransferResult
+ );
+ //
+ // Remove Control Transfer QH-TDs structure from the frame list
+ // and update the pointers in the Frame List
+ // and other pointers in other related QH structures.
+ //
+ for (Index = 0; Index < 100; Index++) {
+ DelLinkSingleQH (
+ HcDev,
+ PtrQH,
+ (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
+ FALSE,
+ FALSE
+ );
+ }
+ //
+ // delete setup stage TD; the QH is reserved for the next stages.
+ //
+ DeleteQueuedTDs (HcDev, PtrSetupTD);
+
+ //
+ // if setup stage error, return error
+ //
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // some control transfers do not have Data Stage
+ //
+ if (PtrFirstDataTD != NULL) {
+
+ LinkTDToQH (PtrQH, PtrFirstDataTD);
+ LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
+
+ for (Index = 0; Index < 500; Index++) {
+ LinkQHToFrameList (
+ HcDev->FrameListEntry,
+ (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
+ PtrQH
+ );
+ }
+
+ Status = ExecuteControlTransfer (
+ HcDev,
+ PtrFirstDataTD,
+ LoadFrameListIndex,
+ DataLength,
+ TimeOut,
+ TransferResult
+ );
+
+ for (Index = 0; Index < 500; Index++) {
+ DelLinkSingleQH (
+ HcDev,
+ PtrQH,
+ (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
+ FALSE,
+ FALSE
+ );
+ }
+ //
+ // delete data stage TD; the QH is reserved for the next stage.
+ //
+ DeleteQueuedTDs (HcDev, PtrFirstDataTD);
+ }
+ //
+ // if data stage error, goto done and return error
+ //
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ LinkTDToQH (PtrQH, PtrStatusTD);
+ //
+ // get the frame list index that the QH-TDs will be linked to.
+ //
+ LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
+
+ for (Index = 0; Index < 100; Index++) {
+ //
+ // put the QH-TDs directly or indirectly into the proper place
+ // in the Frame List
+ //
+ LinkQHToFrameList (
+ HcDev->FrameListEntry,
+ (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
+ PtrQH
+ );
+ }
+ //
+ // Poll QH-TDs execution and get result.
+ // detail status is returned
+ //
+ Status = ExecuteControlTransfer (
+ HcDev,
+ PtrStatusTD,
+ LoadFrameListIndex,
+ DataLength,
+ TimeOut,
+ TransferResult
+ );
+
+ //
+ // Delete Control Transfer QH-TDs structure
+ // and update the pointers in the Frame List
+ // and other pointers in other related QH structures.
+ //
+ // TRUE means must search other framelistindex
+ //
+ for (Index = 0; Index < 100; Index++) {
+ DelLinkSingleQH (
+ HcDev,
+ PtrQH,
+ (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
+ FALSE,
+ FALSE
+ );
+ }
+
+ DeleteQueuedTDs (HcDev, PtrStatusTD);
+
+ } else {
+ //
+ // link setup stage TD with data stage TD
+ //
+ PtrPreTD = PtrSetupTD;
+ if (PtrFirstDataTD != NULL) {
+ LinkTDToTD (PtrSetupTD, PtrFirstDataTD);
+ PtrPreTD = ptrLastDataTD;
+ }
+ //
+ // link status TD with previous TD
+ //
+ LinkTDToTD (PtrPreTD, PtrStatusTD);
+
+ //
+ // link QH with TD
+ //
+ LinkTDToQH (PtrQH, PtrSetupTD);
+
+ LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
+ for (Index = 0; Index < 500; Index++) {
+ //
+ // put the QH-TDs directly or indirectly into the proper place
+ // in the Frame List
+ //
+ LinkQHToFrameList (
+ HcDev->FrameListEntry,
+ (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
+ PtrQH
+ );
+ }
+ //
+ // Poll QH-TDs execution and get result.
+ // detail status is returned
+ //
+ Status = ExecuteControlTransfer (
+ HcDev,
+ PtrSetupTD,
+ LoadFrameListIndex,
+ DataLength,
+ TimeOut,
+ TransferResult
+ );
+ //
+ // Remove Control Transfer QH-TDs structure from the frame list
+ // and update the pointers in the Frame List
+ // and other pointers in other related QH structures.
+ //
+ for (Index = 0; Index < 500; Index++) {
+ DelLinkSingleQH (
+ HcDev,
+ PtrQH,
+ (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
+ FALSE,
+ FALSE
+ );
+ }
+
+ DeleteQueuedTDs (HcDev, PtrSetupTD);
+ }
+
+Done:
+
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+
+ if (Mapping != NULL) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ }
+
+ if (RequestMapping != NULL) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping);
+ }
+ //
+ // if has errors that cause host controller halt,
+ // then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+ *TransferResult |= EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+ HcDev->PciIo->Flush (HcDev->PciIo);
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UHCIBulkTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+/*++
+
+ Routine Description:
+ Submits bulk transfer to a bulk endpoint of a USB device.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ EndPointAddress The combination of an endpoint number and an
+ endpoint direction of the target USB device.
+ Each endpoint address supports data transfer in
+ one direction except the control endpoint
+ (whose default endpoint address is 0).
+ It is the caller's responsibility to make sure that
+ the EndPointAddress represents a bulk endpoint.
+
+ MaximumPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+
+ Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ DataLength When input, indicates the size, in bytes, of the data buffer
+ specified by Data. When output, indicates the actually
+ transferred data size.
+
+ DataToggle A pointer to the data toggle value. On input, it indicates
+ the initial data toggle value the bulk transfer should adopt;
+ on output, it is updated to indicate the data toggle value
+ of the subsequent bulk transfer.
+
+ TimeOut Indicates the maximum time, in microseconds, which the
+ transfer is allowed to complete.
+
+ TransferResult A pointer to the detailed result information of the
+ bulk transfer.
+
+ Returns:
+ EFI_SUCCESS
+ The bulk transfer was completed successfully.
+ EFI_OUT_OF_RESOURCES
+ The bulk transfer could not be submitted due to lack of resource.
+ EFI_INVALID_PARAMETER
+ Some parameters are invalid.
+ EFI_TIMEOUT
+ The bulk transfer failed due to timeout.
+ EFI_DEVICE_ERROR
+ The bulk transfer failed due to host controller or device error.
+ Caller should check TranferResult for detailed error information.
+
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 StatusReg;
+ UINT32 FrameNumReg;
+ UINTN DataLen;
+ QH_STRUCT *PtrQH;
+ TD_STRUCT *PtrFirstTD;
+ TD_STRUCT *PtrTD;
+ TD_STRUCT *PtrPreTD;
+ UINT16 LoadFrameListIndex;
+ UINT16 SavedFrameListIndex;
+ UINT8 PktID;
+ UINT8 *PtrDataSource;
+ UINT8 *Ptr;
+ BOOLEAN IsFirstTD;
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT8 PktSize;
+
+ EFI_USB_DATA_DIRECTION TransferDirection;
+ //
+ // Used to calculate how many entries are linked to the
+ // specified bulk transfer QH-TDs
+ //
+ UINT32 LinkTimes;
+
+ BOOLEAN ShortPacketEnable;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ VOID *Mapping;
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+ StatusReg = (UINT32) (USBSTS);
+ FrameNumReg = (UINT32) (USBFRNUM);
+ PktID = INPUT_PACKET_ID;
+ PtrTD = NULL;
+ PtrFirstTD = NULL;
+ PtrPreTD = NULL;
+ LinkTimes = 1;
+ DataLen = 0;
+ Ptr = NULL;
+ ShortPacketEnable = FALSE;
+ Mapping = NULL;
+
+ //
+ // Parameters Checking
+ //
+
+ if ((DataLength == NULL) ||
+ (Data == NULL) ||
+ (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // if has errors that cause host controller halt,
+ // then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (*DataLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MaximumPacketLength != 8 &&
+ MaximumPacketLength != 16 &&
+ MaximumPacketLength != 32 &&
+ MaximumPacketLength != 64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Enable the maximum packet size (64bytes)
+ // that can be used for full speed bandwidth reclamation
+ // at the end of a frame.
+ //
+ EnableMaxPacketSize (HcDev);
+
+ Status = ClearStatusReg (HcDev->PciIo, StatusReg);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // construct QH and TD data structures,
+ // and link them together
+ //
+ if (EndPointAddress & 0x80) {
+ TransferDirection = EfiUsbDataIn;
+ } else {
+ TransferDirection = EfiUsbDataOut;
+ }
+
+ switch (TransferDirection) {
+
+ case EfiUsbDataIn:
+ ShortPacketEnable = TRUE;
+ PktID = INPUT_PACKET_ID;
+ PtrDataSource = Data;
+ DataLen = *DataLength;
+
+ //
+ // BusMasterWrite means cpu read
+ //
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterWrite,
+ PtrDataSource,
+ &DataLen,
+ &TempPtr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ptr = (UINT8 *) ((UINTN) TempPtr);
+ break;
+
+ case EfiUsbDataOut:
+ PktID = OUTPUT_PACKET_ID;
+ PtrDataSource = Data;
+ DataLen = *DataLength;
+
+ //
+ // BusMasterRead means cpu write
+ //
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterRead,
+ PtrDataSource,
+ &DataLen,
+ &TempPtr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ptr = (UINT8 *) ((UINTN) TempPtr);
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // create QH structure and init
+ //
+ Status = CreateQH (HcDev, &PtrQH);
+ if (EFI_ERROR (Status)) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ return Status;
+ }
+
+ //
+ // i is used to calculate the total number of TDs.
+ //
+ Index = 0;
+
+ IsFirstTD = TRUE;
+ while (DataLen > 0) {
+
+ //
+ // create TD structures and link together
+ //
+
+ PktSize = (UINT8) DataLen;
+ if (DataLen > MaximumPacketLength) {
+ PktSize = MaximumPacketLength;
+ }
+
+ Status = GenDataTD (
+ HcDev,
+ DeviceAddress,
+ EndPointAddress,
+ Ptr,
+ PktSize,
+ PktID,
+ *DataToggle,
+ FALSE,
+ &PtrTD
+ );
+
+ if (EFI_ERROR (Status)) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ DeleteQueuedTDs (HcDev, PtrFirstTD);
+ return Status;
+ }
+
+ //
+ // Enable short packet detection.
+ // (default action is disabling short packet detection)
+ //
+ if (ShortPacketEnable) {
+ EnableorDisableTDShortPacket (PtrTD, TRUE);
+ }
+
+ if (IsFirstTD) {
+ PtrFirstTD = PtrTD;
+ PtrFirstTD->ptrNextTD = NULL;
+ IsFirstTD = FALSE;
+ } else {
+ //
+ // Link two TDs in vertical depth
+ //
+ LinkTDToTD (PtrPreTD, PtrTD);
+ }
+
+ Index++;
+
+ PtrPreTD = PtrTD;
+
+ *DataToggle ^= 1;
+ Ptr += PktSize;
+ DataLen -= PktSize;
+ }
+
+ //
+ // link TD structures to QH structure
+ //
+ LinkTDToQH (PtrQH, PtrFirstTD);
+
+ //
+ // calculate how many entries are linked to the specified bulk transfer QH-TDs
+ // the below values are referred to the USB spec revision1.1.
+ //
+ switch (MaximumPacketLength) {
+ case 8:
+ LinkTimes = Index / 71 + 1;
+ break;
+
+ case 16:
+ LinkTimes = Index / 51 + 1;
+ break;
+
+ case 32:
+ LinkTimes = Index / 33 + 1;
+ break;
+
+ case 64:
+ LinkTimes = Index / 19 + 1;
+ break;
+ }
+
+ LinkTimes += 500;
+
+ //
+ // put QH-TDs into Frame list
+ //
+ LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
+ SavedFrameListIndex = LoadFrameListIndex;
+
+ for (Index = 0; Index <= LinkTimes; Index++) {
+
+ //
+ // put the QH-TD directly or indirectly into the proper place
+ // in the Frame List
+ //
+ LinkQHToFrameList (HcDev->FrameListEntry, LoadFrameListIndex, PtrQH);
+
+ LoadFrameListIndex += 1;
+ LoadFrameListIndex &= 0x3FF;
+ }
+
+ LoadFrameListIndex = SavedFrameListIndex;
+
+ //
+ // Execute QH-TD and get result
+ //
+ //
+ // detail status is put into the Result field in the pIRP
+ // the Data Toggle value is also re-updated to the value
+ // of the last successful TD
+ //
+ Status = ExecBulkorSyncInterruptTransfer (
+ HcDev,
+ PtrFirstTD,
+ LoadFrameListIndex,
+ DataLength,
+ DataToggle,
+ TimeOut,
+ TransferResult
+ );
+
+ //
+ // Delete Bulk transfer QH-TD structure
+ // and maitain the pointers in the Frame List
+ // and other pointers in related QH structure
+ //
+ // TRUE means must search other framelistindex
+ //
+ for (Index = 0; Index <= LinkTimes; Index++) {
+ DelLinkSingleQH (
+ HcDev,
+ PtrQH,
+ LoadFrameListIndex,
+ FALSE,
+ FALSE
+ );
+ LoadFrameListIndex += 1;
+ LoadFrameListIndex &= 0x3FF;
+ }
+
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+
+ DeleteQueuedTDs (HcDev, PtrFirstTD);
+
+ if (Mapping != NULL) {
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ }
+
+ //
+ // if has errors that cause host controller halt,
+ // then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+ *TransferResult |= EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+
+ HcDev->PciIo->Flush (HcDev->PciIo);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UHCIAsyncInterruptTransfer (
+ IN EFI_USB_HC_PROTOCOL * This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaxiumPacketLength,
+ IN BOOLEAN IsNewTransfer,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN PollingInterval, OPTIONAL
+ IN UINTN DataLength, OPTIONAL
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, OPTIONAL
+ IN VOID *Context OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ Submits an asynchronous interrupt transfer to an
+ interrupt endpoint of a USB device.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+
+ EndPointAddress The combination of an endpoint number and an endpoint
+ direction of the target USB device. Each endpoint address
+ supports data transfer in one direction except the
+ control endpoint (whose default endpoint address is 0).
+ It is the caller's responsibility to make sure that
+ the EndPointAddress represents an interrupt endpoint.
+
+ IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+
+ MaxiumPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+
+ IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
+ the host and the target interrupt endpoint.
+ If FALSE, the specified asynchronous interrupt pipe
+ is canceled.
+
+ DataToggle A pointer to the data toggle value. On input, it is valid
+ when IsNewTransfer is TRUE, and it indicates the initial
+ data toggle value the asynchronous interrupt transfer
+ should adopt.
+ On output, it is valid when IsNewTransfer is FALSE,
+ and it is updated to indicate the data toggle value of
+ the subsequent asynchronous interrupt transfer.
+
+ PollingInterval Indicates the interval, in milliseconds, that the
+ asynchronous interrupt transfer is polled.
+ This parameter is required when IsNewTransfer is TRUE.
+
+ DataLength Indicates the length of data to be received at the
+ rate specified by PollingInterval from the target
+ asynchronous interrupt endpoint. This parameter
+ is only required when IsNewTransfer is TRUE.
+
+ CallBackFunction The Callback function.This function is called at the
+ rate specified by PollingInterval.This parameter is
+ only required when IsNewTransfer is TRUE.
+
+ Context The context that is passed to the CallBackFunction.
+ This is an optional parameter and may be NULL.
+
+ Returns:
+ EFI_SUCCESS
+ The asynchronous interrupt transfer request has been successfully
+ submitted or canceled.
+ EFI_INVALID_PARAMETER
+ Some parameters are invalid.
+ EFI_OUT_OF_RESOURCES
+ The request could not be completed due to a lack of resources.
+ EFI_DEVICE_ERROR
+ Can't read register
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 StatusReg;
+ UINT32 FrameNumReg;
+ UINTN DataLen;
+ QH_STRUCT *ptrFirstQH;
+ QH_STRUCT *PtrQH;
+ QH_STRUCT *ptrPreQH;
+ TD_STRUCT *PtrFirstTD;
+ TD_STRUCT *PtrTD;
+ TD_STRUCT *PtrPreTD;
+ UINT16 LoadFrameListIndex;
+ UINT16 Index;
+ UINT8 PktID;
+ UINT8 *Ptr;
+ UINT8 *MappedPtr;
+ BOOLEAN IsFirstTD;
+ BOOLEAN IsFirstQH;
+ EFI_STATUS Status;
+ BOOLEAN ShortPacketEnable;
+ UINT8 CurrentDataToggle;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ VOID *Mapping;
+ UINT8 PktSize;
+ QH_STRUCT *TempQH;
+ EFI_TPL OldTpl;
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+ StatusReg = (UINT32) (USBSTS);
+ FrameNumReg = (UINT32) (USBFRNUM);
+ Mapping = NULL;
+ ShortPacketEnable = FALSE;
+
+ PktID = INPUT_PACKET_ID;
+ PtrTD = NULL;
+ PtrFirstTD = NULL;
+ PtrPreTD = NULL;
+ Ptr = NULL;
+ PtrQH = NULL;
+ ptrPreQH = NULL;
+ ptrFirstQH = NULL;
+
+ if ((EndPointAddress & 0x80) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // delete Async interrupt transfer request
+ //
+ if (!IsNewTransfer) {
+
+ OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
+
+ Status = DeleteAsyncINTQHTDs (
+ HcDev,
+ DeviceAddress,
+ EndPointAddress,
+ DataToggle
+ );
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+ }
+ //
+ // if has errors that cause host controller halt,
+ // then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+ return EFI_DEVICE_ERROR;
+ }
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+
+ //
+ // submit Async interrupt transfer request
+ //
+ if (PollingInterval < 1 || PollingInterval > 255) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ShortPacketEnable = TRUE;
+ PktID = INPUT_PACKET_ID;
+ DataLen = DataLength;
+ Ptr = AllocatePool (DataLen);
+ if (Ptr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // BusMasterWrite means cpu read
+ //
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterWrite,
+ Ptr,
+ &DataLen,
+ &TempPtr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (Ptr);
+ return Status;
+ }
+
+ MappedPtr = (UINT8 *) ((UINTN) TempPtr);
+
+ CurrentDataToggle = *DataToggle;
+
+ IsFirstTD = TRUE;
+
+ while (DataLen > 0) {
+ //
+ // create TD structures and link together
+ //
+
+ PktSize = (UINT8) DataLen;
+ if (DataLen > MaxiumPacketLength) {
+ PktSize = MaxiumPacketLength;
+ }
+
+ Status = GenDataTD (
+ HcDev,
+ DeviceAddress,
+ EndPointAddress,
+ MappedPtr,
+ PktSize,
+ PktID,
+ CurrentDataToggle,
+ IsSlowDevice,
+ &PtrTD
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (Ptr);
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ DeleteQueuedTDs (HcDev, PtrFirstTD);
+ return Status;
+ }
+ //
+ // Enable short packet detection.
+ //
+ if (ShortPacketEnable) {
+ EnableorDisableTDShortPacket (PtrTD, TRUE);
+ }
+
+ if (IsFirstTD) {
+ PtrFirstTD = PtrTD;
+ PtrFirstTD->ptrNextTD = NULL;
+ IsFirstTD = FALSE;
+ } else {
+ //
+ // Link two TDs in vertical depth
+ //
+ LinkTDToTD (PtrPreTD, PtrTD);
+ }
+
+ PtrPreTD = PtrTD;
+
+ CurrentDataToggle ^= 1;
+ MappedPtr += PktSize;
+ DataLen -= PktSize;
+ }
+
+ //
+ // roll one value back
+ //
+ CurrentDataToggle ^= 1;
+
+ //
+ // create a list of QH structures and init,
+ // link TDs to all the QHs, and link all the QHs together using internal
+ // defined pointer of the QH_STRUCT.
+ //
+ IsFirstQH = TRUE;
+ ptrPreQH = NULL;
+ for (Index = 0; Index < 1024;) {
+
+ Status = CreateQH (HcDev, &PtrQH);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (Ptr);
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ DeleteQueuedTDs (HcDev, PtrFirstTD);
+ PtrQH = ptrFirstQH;
+ while (PtrQH) {
+ TempQH = PtrQH;
+ PtrQH = TempQH->ptrNextIntQH;
+ UhciFreePool (HcDev, (UINT8 *) TempQH, sizeof (QH_STRUCT));
+ }
+
+ return Status;
+ }
+
+ //
+ // link TD structures to QH structure
+ //
+ LinkTDToQH (PtrQH, PtrFirstTD);
+
+ if (IsFirstQH) {
+ ptrFirstQH = PtrQH;
+ ptrFirstQH->ptrNextIntQH = NULL;
+ IsFirstQH = FALSE;
+ } else {
+ //
+ // link neighbor QH structures together
+ //
+ ptrPreQH->ptrNextIntQH = PtrQH;
+ }
+
+ ptrPreQH = PtrQH;
+
+ Index = (UINT16) (PollingInterval + Index);
+ }
+ //
+ // last QH in QH list should set its next QH pointer to NULL.
+ //
+ PtrQH->ptrNextIntQH = NULL;
+
+ //
+ // Save QH-TD structures in Interrupt transfer list,
+ // for monitor interrupt transfer execution routine use.
+ //
+ InsertQHTDToINTList (
+ HcDev,
+ ptrFirstQH,
+ PtrFirstTD,
+ DeviceAddress,
+ EndPointAddress,
+ CurrentDataToggle,
+ DataLength,
+ PollingInterval,
+ Mapping,
+ Ptr,
+ CallBackFunction,
+ Context
+ );
+
+ //
+ // put QHs-TDs into Frame list
+ //
+ LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
+
+ PtrQH = ptrFirstQH;
+
+ for (Index = LoadFrameListIndex; Index < (1024 + LoadFrameListIndex);) {
+
+ //
+ // put the QH-TD directly or indirectly into the proper place
+ // in the Frame List
+ //
+ LinkQHToFrameList (HcDev->FrameListEntry, (UINT16) (Index & 0x3FF), PtrQH);
+
+ Index = (UINT16) (PollingInterval + Index);
+
+ PtrQH = PtrQH->ptrNextIntQH;
+ }
+
+ HcDev->PciIo->Flush (HcDev->PciIo);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UHCISyncInterruptTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN BOOLEAN IsSlowDevice,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ )
+/*++
+
+ Routine Description:
+ Submits synchronous interrupt transfer to an interrupt endpoint
+ of a USB device.
+
+ Arguments:
+
+ This A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ DeviceAddress Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+
+ EndPointAddress The combination of an endpoint number and an endpoint
+ direction of the target USB device. Each endpoint
+ address supports data transfer in one direction
+ except the control endpoint (whose default
+ endpoint address is 0). It is the caller's responsibility
+ to make sure that the EndPointAddress represents
+ an interrupt endpoint.
+
+ IsSlowDevice Indicates whether the target device is slow device
+ or full-speed device.
+
+ MaximumPacketLength Indicates the maximum packet size the target endpoint
+ is capable of sending or receiving.
+
+ Data A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+
+ DataLength On input, the size, in bytes, of the data buffer specified
+ by Data. On output, the number of bytes transferred.
+
+ DataToggle A pointer to the data toggle value. On input, it indicates
+ the initial data toggle value the synchronous interrupt
+ transfer should adopt;
+ on output, it is updated to indicate the data toggle value
+ of the subsequent synchronous interrupt transfer.
+
+ TimeOut Indicates the maximum time, in microseconds, which the
+ transfer is allowed to complete.
+
+ TransferResult A pointer to the detailed result information from
+ the synchronous interrupt transfer.
+
+ Returns:
+ EFI_SUCCESS
+ The synchronous interrupt transfer was completed successfully.
+ EFI_OUT_OF_RESOURCES
+ The synchronous interrupt transfer could not be submitted due
+ to lack of resource.
+ EFI_INVALID_PARAMETER
+ Some parameters are invalid.
+ EFI_TIMEOUT
+ The synchronous interrupt transfer failed due to timeout.
+ EFI_DEVICE_ERROR
+ The synchronous interrupt transfer failed due to host controller
+ or device error. Caller should check TranferResult for detailed
+ error information.
+--*/
+{
+ USB_HC_DEV *HcDev;
+ UINT32 StatusReg;
+ UINT32 FrameNumReg;
+ UINTN DataLen;
+ QH_STRUCT *PtrQH;
+ TD_STRUCT *PtrFirstTD;
+ TD_STRUCT *PtrTD;
+ TD_STRUCT *PtrPreTD;
+ UINT16 LoadFrameListIndex;
+ UINT16 SavedFrameListIndex;
+ UINT32 Index;
+ UINT32 LinkTimes;
+ UINT8 PktID;
+ UINT8 *PtrDataSource;
+ UINT8 *Ptr;
+ BOOLEAN IsFirstTD;
+ EFI_STATUS Status;
+ BOOLEAN ShortPacketEnable;
+ EFI_PHYSICAL_ADDRESS TempPtr;
+ VOID *Mapping;
+ UINT8 PktSize;
+
+ HcDev = USB_HC_DEV_FROM_THIS (This);
+ StatusReg = (UINT32) (USBSTS);
+ FrameNumReg = (UINT32) (USBFRNUM);
+ ShortPacketEnable = FALSE;
+ Mapping = NULL;
+ PktID = INPUT_PACKET_ID;
+ PtrTD = NULL;
+ PtrFirstTD = NULL;
+ PtrPreTD = NULL;
+ DataLen = 0;
+ Ptr = NULL;
+ Index = 0;
+ LinkTimes = 0;
+
+ //
+ // Parameters Checking
+ //
+
+ if ((DataLength == NULL) ||
+ (Data == NULL) ||
+ (TransferResult == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // if has errors that cause host controller halt,
+ // then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+ *TransferResult = EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((EndPointAddress & 0x80) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*DataLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MaximumPacketLength > 64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsSlowDevice && (MaximumPacketLength > 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+
+ //
+ // submit Sync interrupt transfer request
+ //
+ ShortPacketEnable = TRUE;
+ PktID = INPUT_PACKET_ID;
+ DataLen = *DataLength;
+ PtrDataSource = Data;
+
+ //
+ // create QH structure and init
+ //
+ Status = CreateQH (HcDev, &PtrQH);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // BusMasterWrite means cpu read
+ //
+ Status = HcDev->PciIo->Map (
+ HcDev->PciIo,
+ EfiPciIoOperationBusMasterWrite,
+ PtrDataSource,
+ &DataLen,
+ &TempPtr,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ return Status;
+ }
+
+ Ptr = (UINT8 *) ((UINTN) TempPtr);
+
+ IsFirstTD = TRUE;
+ while (DataLen > 0) {
+ //
+ // create TD structures and link together
+ //
+ PktSize = (UINT8) DataLen;
+ if (DataLen > MaximumPacketLength) {
+ PktSize = MaximumPacketLength;
+ }
+
+ Status = GenDataTD (
+ HcDev,
+ DeviceAddress,
+ EndPointAddress,
+ Ptr,
+ PktSize,
+ PktID,
+ *DataToggle,
+ IsSlowDevice,
+ &PtrTD
+ );
+ if (EFI_ERROR (Status)) {
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+ DeleteQueuedTDs (HcDev, PtrFirstTD);
+ return Status;
+ }
+ //
+ // Enable short packet detection.
+ //
+ if (ShortPacketEnable) {
+ EnableorDisableTDShortPacket (PtrTD, TRUE);
+ }
+
+ if (IsFirstTD) {
+ PtrFirstTD = PtrTD;
+ PtrFirstTD->ptrNextTD = NULL;
+ IsFirstTD = FALSE;
+ } else {
+ //
+ // Link two TDs in vertical depth
+ //
+ LinkTDToTD (PtrPreTD, PtrTD);
+ }
+
+ Index++;
+
+ PtrPreTD = PtrTD;
+
+ *DataToggle ^= 1;
+ Ptr += PktSize;
+ DataLen -= PktSize;
+ }
+
+ //
+ // link TD structures to QH structure
+ //
+ LinkTDToQH (PtrQH, PtrFirstTD);
+
+ switch (MaximumPacketLength) {
+ case 8:
+ LinkTimes = Index / 71 + 1;
+ break;
+
+ case 16:
+ LinkTimes = Index / 51 + 1;
+ break;
+
+ case 32:
+ LinkTimes = Index / 33 + 1;
+ break;
+
+ case 64:
+ LinkTimes = Index / 19 + 1;
+ break;
+ }
+
+ LinkTimes += 100;
+
+ LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
+ SavedFrameListIndex = LoadFrameListIndex;
+
+ for (Index = 0; Index < LinkTimes; Index++) {
+
+ //
+ // put the QH-TD directly or indirectly into the proper place
+ // in the Frame List
+ //
+ LinkQHToFrameList (HcDev->FrameListEntry, LoadFrameListIndex, PtrQH);
+
+ LoadFrameListIndex += 1;
+ LoadFrameListIndex &= 0x3FF;
+ }
+
+ LoadFrameListIndex = SavedFrameListIndex;
+ //
+ // detail status is put into the Result field in the pIRP
+ // the Data Toggle value is also re-updated to the value
+ // of the last successful TD
+ //
+ Status = ExecBulkorSyncInterruptTransfer (
+ HcDev,
+ PtrFirstTD,
+ LoadFrameListIndex,
+ DataLength,
+ DataToggle,
+ TimeOut,
+ TransferResult
+ );
+ //
+ // Delete Sync Interrupt transfer QH-TD structure
+ // and maintain the pointers in the Frame List
+ // and other pointers in related QH structure
+ //
+ // TRUE means must search other framelistindex
+ //
+ for (Index = 0; Index <= LinkTimes; Index++) {
+ DelLinkSingleQH (
+ HcDev,
+ PtrQH,
+ LoadFrameListIndex,
+ FALSE,
+ FALSE
+ );
+ LoadFrameListIndex += 1;
+ LoadFrameListIndex &= 0x3FF;
+ }
+
+ UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
+
+ DeleteQueuedTDs (HcDev, PtrFirstTD);
+
+ HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
+
+ //
+ // if has errors that cause host controller halt,
+ // then return EFI_DEVICE_ERROR directly.
+ //
+ if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+ *TransferResult |= EFI_USB_ERR_SYSTEM;
+ return EFI_DEVICE_ERROR;
+ }
+
+ ClearStatusReg (HcDev->PciIo, StatusReg);
+
+ HcDev->PciIo->Flush (HcDev->PciIo);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UHCIIsochronousTransfer (
+ IN EFI_USB_HC_PROTOCOL *This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ OUT UINT32 *TransferResult
+ )
+/*++
+
+ Routine Description:
+ Submits isochronous transfer to a target USB device.
+
+ Arguments:
+
+ This - A pointer to the EFI_USB_HC_PROTOCOL instance.
+ DeviceAddress - Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+ EndPointAddress - End point address
+ MaximumPacketLength - Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+ Data - A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+ DataLength - Indicates the size, in bytes, of the data buffer
+ specified by Data.
+ TransferResult - A pointer to the detailed result information generated
+ by this control transfer.
+ Returns:
+ EFI_UNSUPPORTED
+
+--*/
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+EFI_STATUS
+EFIAPI
+UHCIAsyncIsochronousTransfer (
+ IN EFI_USB_HC_PROTOCOL * This,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 MaximumPacketLength,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ Submits Async isochronous transfer to a target USB device.
+
+ Arguments:
+
+ This - A pointer to the EFI_USB_HC_PROTOCOL instance.
+
+ DeviceAddress - Represents the address of the target device on the USB,
+ which is assigned during USB enumeration.
+
+ EndPointAddress - End point address
+
+ MaximumPacketLength - Indicates the maximum packet size that the
+ default control transfer endpoint is capable of
+ sending or receiving.
+
+ Data - A pointer to the buffer of data that will be transmitted
+ to USB device or received from USB device.
+
+ IsochronousCallBack - When the transfer complete, the call back function will be called
+
+ Context - Pass to the call back function as parameter
+
+ Returns:
+ EFI_UNSUPPORTED
+
+--*/
+{
+ return EFI_UNSUPPORTED;
+}
+
+VOID
+EFIAPI
+MonitorInterruptTrans (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+ Routine Description:
+ Interrupt transfer periodic check handler
+ Arguments:
+ Event - Interrupt event
+ Contex - Pointer to USB_HC_DEV
+ Returns:
+ None
+--*/
+{
+
+ USB_HC_DEV *HcDev;
+ INTERRUPT_LIST *PtrList;
+ LIST_ENTRY *Link;
+ UINT32 Result;
+ VOID *DataBuffer;
+ UINTN DataLen;
+ UINTN ActualLen;
+ UINTN ErrTDPos;
+ UINT32 StatusAddr;
+ LIST_ENTRY *NextLink;
+
+ HcDev = (USB_HC_DEV *) Context;
+ StatusAddr = (UINT32) (USBSTS);
+
+ //
+ // interrupt transfer list is empty, means that no interrupt transfer
+ // is submitted by far.
+ //
+ if (IsListEmpty (&(HcDev->InterruptListHead))) {
+ return ;
+ }
+
+ NextLink = HcDev->InterruptListHead.ForwardLink;
+ do {
+
+ Link = NextLink;
+ NextLink = Link->ForwardLink;
+
+ PtrList = INTERRUPT_LIST_FROM_LINK (Link);
+
+ //
+ // get TD execution results.
+ // ErrTDPos is zero-based value indicating the first error TD's position
+ // in the TDs' list.
+ // This value is only valid when Result not equal NOERROR.
+ //
+ ExecuteAsyncINTTDs (
+ HcDev,
+ PtrList,
+ &Result,
+ &ErrTDPos,
+ &ActualLen
+ );
+
+ //
+ // interrupt transfer has not been executed yet.
+ //
+ if (((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK) ||
+ ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) {
+ continue;
+ }
+ //
+ // get actual data length transferred data and its data length.
+ //
+ DataLen = ActualLen;
+ DataBuffer = AllocatePool (DataLen);
+ if (DataBuffer == NULL) {
+ return ;
+ }
+
+ CopyMem (
+ DataBuffer,
+ PtrList->PtrFirstTD->pTDBuffer,
+ DataLen
+ );
+
+ //
+ // only if interrupt endpoint responds
+ // and the interrupt transfer stops because of completion
+ // or error, then we will call callback function.
+ //
+ if (Result == EFI_USB_NOERROR) {
+ //
+ // add for real platform debug
+ //
+ if (PtrList->InterruptCallBack != NULL) {
+ (PtrList->InterruptCallBack) (
+ DataBuffer,
+ DataLen,
+ PtrList->InterruptContext,
+ Result
+ );
+ }
+
+ if (DataBuffer) {
+ gBS->FreePool (DataBuffer);
+ }
+
+ //
+ // update should done after data buffer got.
+ //
+ UpdateAsyncINTQHTDs (PtrList, Result, (UINT32) ErrTDPos);
+
+ } else {
+
+ DEBUG ((EFI_D_ERROR, "interrupt transfer error code is %x\n", Result));
+
+ if (DataBuffer) {
+ gBS->FreePool (DataBuffer);
+ }
+ //
+ // leave error recovery to its related device driver.
+ // A common case of the error recovery is to re-submit the interrupt
+ // transfer.
+ // When an interrupt transfer is re-submitted, its position in the linked
+ // list is changed. It is inserted to the head of the linked list, while
+ // this function scans the whole list from head to tail. Thus, the
+ // re-submitted interrupt transfer's callback function will not be called
+ // again in this round.
+ //
+ if (PtrList->InterruptCallBack != NULL) {
+ (PtrList->InterruptCallBack) (
+ NULL,
+ 0,
+ PtrList->InterruptContext,
+ Result
+ );
+ }
+ }
+ } while (NextLink != &(HcDev->InterruptListHead));
+
+}
diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h
new file mode 100644
index 0000000..93da46c
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhci.h
@@ -0,0 +1,1187 @@
+/*++
+
+Copyright (c) 2006, 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:
+
+
+Revision History
+--*/
+
+#ifndef _UHCI_H
+#define _UHCI_H
+
+/*
+ * Universal Host Controller Interface data structures and defines
+ */
+
+#include <IndustryStandard/Pci22.h>
+
+#define EFI_D_UHCI EFI_D_INFO
+
+//
+// stall time
+//
+#define STALL_1_MILLI_SECOND 1000
+#define STALL_1_SECOND 1000 * STALL_1_MILLI_SECOND
+
+#define FORCE_GLOBAL_RESUME_TIME 20 * STALL_1_MILLI_SECOND
+
+#define ROOT_PORT_REST_TIME 50 * STALL_1_MILLI_SECOND
+
+#define PORT_RESET_RECOVERY_TIME 10 * STALL_1_MILLI_SECOND
+
+//
+// 50 ms
+//
+#define INTERRUPT_POLLING_TIME 50 * 1000 * 10
+
+//
+// UHCI IO Space Address Register Register locates at
+// offset 20 ~ 23h of PCI Configuration Space (UHCI spec, Revision 1.1),
+// so, its BAR Index is 4.
+//
+#define USB_BAR_INDEX 4
+
+//
+// One memory block uses 1 page (common buffer for QH,TD use.)
+//
+#define NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES 1
+
+
+#define bit(a) 1 << (a)
+
+//
+// ////////////////////////////////////////////////////////////////////////
+//
+// Universal Host Controller Registers Definitions
+//
+//////////////////////////////////////////////////////////////////////////
+extern UINT16 USBBaseAddr;
+
+/* Command register */
+#define USBCMD 0 /* Command Register Offset 00-01h */
+#define USBCMD_RS bit (0) /* Run/Stop */
+#define USBCMD_HCRESET bit (1) /* Host reset */
+#define USBCMD_GRESET bit (2) /* Global reset */
+#define USBCMD_EGSM bit (3) /* Global Suspend Mode */
+#define USBCMD_FGR bit (4) /* Force Global Resume */
+#define USBCMD_SWDBG bit (5) /* SW Debug mode */
+#define USBCMD_CF bit (6) /* Config Flag (sw only) */
+#define USBCMD_MAXP bit (7) /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS 2 /* Status Register Offset 02-03h */
+#define USBSTS_USBINT bit (0) /* Interrupt due to IOC */
+#define USBSTS_ERROR bit (1) /* Interrupt due to error */
+#define USBSTS_RD bit (2) /* Resume Detect */
+#define USBSTS_HSE bit (3) /* Host System Error*/
+#define USBSTS_HCPE bit (4) /* Host Controller Process Error*/
+#define USBSTS_HCH bit (5) /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR 4 /* Interrupt Enable Register 04-05h */
+#define USBINTR_TIMEOUT bit (0) /* Timeout/CRC error enable */
+#define USBINTR_RESUME bit (1) /* Resume interrupt enable */
+#define USBINTR_IOC bit (2) /* Interrupt On Complete enable */
+#define USBINTR_SP bit (3) /* Short packet interrupt enable */
+
+/* Frame Number Register Offset 06-08h */
+#define USBFRNUM 6
+
+/* Frame List Base Address Register Offset 08-0Bh */
+#define USBFLBASEADD 8
+
+/* Start of Frame Modify Register Offset 0Ch */
+#define USBSOF 0x0c
+
+/* USB port status and control registers */
+#define USBPORTSC1 0x10 /*Port 1 offset 10-11h */
+#define USBPORTSC2 0x12 /*Port 2 offset 12-13h */
+
+#define USBPORTSC_CCS bit (0) /* Current Connect Status*/
+#define USBPORTSC_CSC bit (1) /* Connect Status Change */
+#define USBPORTSC_PED bit (2) /* Port Enable / Disable */
+#define USBPORTSC_PEDC bit (3) /* Port Enable / Disable Change */
+#define USBPORTSC_LSL bit (4) /* Line Status Low bit*/
+#define USBPORTSC_LSH bit (5) /* Line Status High bit*/
+#define USBPORTSC_RD bit (6) /* Resume Detect */
+#define USBPORTSC_LSDA bit (8) /* Low Speed Device Attached */
+#define USBPORTSC_PR bit (9) /* Port Reset */
+#define USBPORTSC_SUSP bit (12) /* Suspend */
+
+/* PCI Configuration Registers for USB */
+
+//
+// Class Code Register offset
+//
+#define CLASSC 0x09
+//
+// USB IO Space Base Address Register offset
+//
+#define USBBASE 0x20
+
+//
+// USB legacy Support
+//
+#define USB_EMULATION 0xc0
+
+//
+// USB Base Class Code,Sub-Class Code and Programming Interface.
+//
+#define PCI_CLASSC_PI_UHCI 0x00
+
+#define SETUP_PACKET_ID 0x2D
+#define INPUT_PACKET_ID 0x69
+#define OUTPUT_PACKET_ID 0xE1
+#define ERROR_PACKET_ID 0x55
+
+//
+// ////////////////////////////////////////////////////////////////////////
+//
+// USB Transfer Mechanism Data Structures
+//
+//////////////////////////////////////////////////////////////////////////
+#pragma pack(1)
+//
+// USB Class Code structure
+//
+typedef struct {
+ UINT8 PI;
+ UINT8 SubClassCode;
+ UINT8 BaseCode;
+} USB_CLASSC;
+
+typedef struct {
+ UINT32 QHHorizontalTerminate : 1;
+ UINT32 QHHorizontalQSelect : 1;
+ UINT32 QHHorizontalRsvd : 2;
+ UINT32 QHHorizontalPtr : 28;
+ UINT32 QHVerticalTerminate : 1;
+ UINT32 QHVerticalQSelect : 1;
+ UINT32 QHVerticalRsvd : 2;
+ UINT32 QHVerticalPtr : 28;
+} QUEUE_HEAD;
+
+typedef struct {
+ UINT32 TDLinkPtrTerminate : 1;
+ UINT32 TDLinkPtrQSelect : 1;
+ UINT32 TDLinkPtrDepthSelect : 1;
+ UINT32 TDLinkPtrRsvd : 1;
+ UINT32 TDLinkPtr : 28;
+ UINT32 TDStatusActualLength : 11;
+ UINT32 TDStatusRsvd : 5;
+ UINT32 TDStatus : 8;
+ UINT32 TDStatusIOC : 1;
+ UINT32 TDStatusIOS : 1;
+ UINT32 TDStatusLS : 1;
+ UINT32 TDStatusErr : 2;
+ UINT32 TDStatusSPD : 1;
+ UINT32 TDStatusRsvd2 : 2;
+ UINT32 TDTokenPID : 8;
+ UINT32 TDTokenDevAddr : 7;
+ UINT32 TDTokenEndPt : 4;
+ UINT32 TDTokenDataToggle : 1;
+ UINT32 TDTokenRsvd : 1;
+ UINT32 TDTokenMaxLen : 11;
+ UINT32 TDBufferPtr;
+} TD;
+
+#pragma pack()
+
+typedef struct {
+ QUEUE_HEAD QH;
+ VOID *ptrNext;
+ VOID *ptrDown;
+ VOID *ptrNextIntQH; // for interrupt transfer's special use
+ VOID *LoopPtr;
+} QH_STRUCT;
+
+typedef struct {
+ TD TDData;
+ UINT8 *pTDBuffer;
+ VOID *ptrNextTD;
+ VOID *ptrNextQH;
+ UINT16 TDBufferLength;
+ UINT16 reserved;
+} TD_STRUCT;
+
+//
+// ////////////////////////////////////////////////////////////////////////
+//
+// Universal Host Controller Device Data Structure
+//
+//////////////////////////////////////////////////////////////////////////
+#define USB_HC_DEV_FROM_THIS(a) CR (a, USB_HC_DEV, UsbHc, USB_HC_DEV_SIGNATURE)
+
+#define USB_HC_DEV_SIGNATURE EFI_SIGNATURE_32 ('u', 'h', 'c', 'i')
+#define INTERRUPT_LIST_SIGNATURE EFI_SIGNATURE_32 ('i', 'n', 't', 's')
+typedef struct {
+ UINTN Signature;
+
+ LIST_ENTRY Link;
+ UINT8 DevAddr;
+ UINT8 EndPoint;
+ UINT8 DataToggle;
+ UINT8 Reserved[5];
+ TD_STRUCT *PtrFirstTD;
+ QH_STRUCT *PtrQH;
+ UINTN DataLen;
+ UINTN PollInterval;
+ VOID *Mapping;
+ UINT8 *DataBuffer; // allocated host memory, not mapped memory
+ EFI_ASYNC_USB_TRANSFER_CALLBACK InterruptCallBack;
+ VOID *InterruptContext;
+} INTERRUPT_LIST;
+
+#define INTERRUPT_LIST_FROM_LINK(a) CR (a, INTERRUPT_LIST, Link, INTERRUPT_LIST_SIGNATURE)
+
+typedef struct {
+ UINT32 FrameListPtrTerminate : 1;
+ UINT32 FrameListPtrQSelect : 1;
+ UINT32 FrameListRsvd : 2;
+ UINT32 FrameListPtr : 28;
+
+} FRAMELIST_ENTRY;
+
+typedef struct _MEMORY_MANAGE_HEADER {
+ UINT8 *BitArrayPtr;
+ UINTN BitArraySizeInBytes;
+ UINT8 *MemoryBlockPtr;
+ UINTN MemoryBlockSizeInBytes;
+ VOID *Mapping;
+ struct _MEMORY_MANAGE_HEADER *Next;
+} MEMORY_MANAGE_HEADER;
+
+typedef struct {
+ UINTN Signature;
+ EFI_USB_HC_PROTOCOL UsbHc;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // local data
+ //
+ LIST_ENTRY InterruptListHead;
+ FRAMELIST_ENTRY *FrameListEntry;
+ VOID *FrameListMapping;
+ MEMORY_MANAGE_HEADER *MemoryHeader;
+ EFI_EVENT InterruptTransTimer;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+} USB_HC_DEV;
+
+extern EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gUhciComponentName;
+
+EFI_STATUS
+WriteUHCCommandReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 CmdAddrOffset,
+ IN UINT16 UsbCmd
+ );
+
+EFI_STATUS
+ReadUHCCommandReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 CmdAddrOffset,
+ IN OUT UINT16 *Data
+ );
+
+EFI_STATUS
+WriteUHCStatusReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusAddrOffset,
+ IN UINT16 UsbSts
+ );
+
+EFI_STATUS
+ReadUHCStatusReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusAddrOffset,
+ IN OUT UINT16 *Data
+ );
+
+EFI_STATUS
+ClearStatusReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusAddrOffset
+ );
+
+EFI_STATUS
+ReadUHCFrameNumberReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FrameNumAddrOffset,
+ IN OUT UINT16 *Data
+ );
+
+EFI_STATUS
+WriteUHCFrameListBaseReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FlBaseAddrOffset,
+ IN UINT32 UsbFrameListBaseAddr
+ );
+
+EFI_STATUS
+ReadRootPortReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 PortAddrOffset,
+ IN OUT UINT16 *Data
+ );
+
+EFI_STATUS
+WriteRootPortReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 PortAddrOffset,
+ IN UINT16 ControlBits
+ );
+
+EFI_STATUS
+WaitForUHCHalt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusRegAddr,
+ IN UINTN Timeout
+ );
+
+BOOLEAN
+IsStatusOK (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusRegAddr
+ );
+
+BOOLEAN
+IsHostSysOrProcessErr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 StatusRegAddr
+ );
+
+//
+// This routine programs the USB frame number register. We assume that the
+// HC schedule execution is stopped.
+//
+EFI_STATUS
+SetFrameNumberReg (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FRNUMAddr,
+ IN UINT16 Index
+ );
+
+UINT16
+GetCurrentFrameNumber (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FRNUMAddr
+ );
+
+EFI_STATUS
+SetFrameListBaseAddress (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FLBASEADDRReg,
+ IN UINT32 Addr
+ );
+
+UINT32
+GetFrameListBaseAddress (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 FLBAddr
+ );
+
+EFI_STATUS
+CreateFrameList (
+ IN USB_HC_DEV *HcDev,
+ IN UINT32 FLBASEADDRReg
+ );
+
+EFI_STATUS
+FreeFrameListEntry (
+ IN USB_HC_DEV *UhcDev
+ );
+
+VOID
+InitFrameList (
+ IN USB_HC_DEV *HcDev
+ );
+
+
+EFI_STATUS
+CreateQH (
+ IN USB_HC_DEV *HcDev,
+ OUT QH_STRUCT **pptrQH
+ );
+
+VOID
+SetQHHorizontalLinkPtr (
+ IN QH_STRUCT *ptrQH,
+ IN VOID *ptrNext
+ );
+
+VOID *
+GetQHHorizontalLinkPtr (
+ IN QH_STRUCT *ptrQH
+ );
+
+VOID
+SetQHHorizontalQHorTDSelect (
+ IN QH_STRUCT *ptrQH,
+ IN BOOLEAN bQH
+ );
+
+VOID
+SetQHHorizontalValidorInvalid (
+ IN QH_STRUCT *ptrQH,
+ IN BOOLEAN bValid
+ );
+
+VOID
+SetQHVerticalLinkPtr (
+ IN QH_STRUCT *ptrQH,
+ IN VOID *ptrNext
+ );
+
+VOID *
+GetQHVerticalLinkPtr (
+ IN QH_STRUCT *ptrQH
+ );
+
+VOID
+SetQHVerticalQHorTDSelect (
+ IN QH_STRUCT *ptrQH,
+ IN BOOLEAN bQH
+ );
+
+BOOLEAN
+IsQHHorizontalQHSelect (
+ IN QH_STRUCT *ptrQH
+ );
+
+VOID
+SetQHVerticalValidorInvalid (
+ IN QH_STRUCT *ptrQH,
+ IN BOOLEAN bValid
+ );
+
+BOOLEAN
+GetQHVerticalValidorInvalid (
+ IN QH_STRUCT *ptrQH
+ );
+
+EFI_STATUS
+AllocateTDStruct (
+ IN USB_HC_DEV *HcDev,
+ OUT TD_STRUCT **ppTDStruct
+ );
+/*++
+
+Routine Description:
+
+ Allocate TD Struct
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ ppTDStruct - place to store TD_STRUCT pointer
+Returns:
+
+ EFI_SUCCESS
+
+--*/
+
+EFI_STATUS
+CreateTD (
+ IN USB_HC_DEV *HcDev,
+ OUT TD_STRUCT **pptrTD
+ );
+/*++
+
+Routine Description:
+
+ Create TD
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ pptrTD - TD_STRUCT pointer to store
+
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate resources
+ EFI_SUCCESS - Success
+
+--*/
+
+
+EFI_STATUS
+GenSetupStageTD (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN BOOLEAN bSlow,
+ IN UINT8 *pDevReq,
+ IN UINT8 RequestLen,
+ OUT TD_STRUCT **ppTD
+ );
+/*++
+
+Routine Description:
+
+ Generate Setup Stage TD
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ DevAddr - Device address
+ Endpoint - Endpoint number
+ bSlow - Full speed or low speed
+ pDevReq - Device request
+ RequestLen - Request length
+ ppTD - TD_STRUCT to return
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate memory
+ EFI_SUCCESS - Success
+
+--*/
+
+EFI_STATUS
+GenDataTD (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 *pData,
+ IN UINT8 Len,
+ IN UINT8 PktID,
+ IN UINT8 Toggle,
+ IN BOOLEAN bSlow,
+ OUT TD_STRUCT **ppTD
+ );
+/*++
+
+Routine Description:
+
+ Generate Data Stage TD
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ DevAddr - Device address
+ Endpoint - Endpoint number
+ pData - Data buffer
+ Len - Data length
+ PktID - Packet ID
+ Toggle - Data toggle value
+ bSlow - Full speed or low speed
+ ppTD - TD_STRUCT to return
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate memory
+ EFI_SUCCESS - Success
+
+--*/
+
+EFI_STATUS
+CreateStatusTD (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 DevAddr,
+ IN UINT8 Endpoint,
+ IN UINT8 PktID,
+ IN BOOLEAN bSlow,
+ OUT TD_STRUCT **ppTD
+ );
+/*++
+
+Routine Description:
+
+ Generate Setup Stage TD
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ DevAddr - Device address
+ Endpoint - Endpoint number
+ bSlow - Full speed or low speed
+ pDevReq - Device request
+ RequestLen - Request length
+ ppTD - TD_STRUCT to return
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can't allocate memory
+ EFI_SUCCESS - Success
+
+--*/
+
+VOID
+SetTDLinkPtrValidorInvalid (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bValid
+ );
+
+VOID
+SetTDLinkPtrQHorTDSelect (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bQH
+ );
+
+VOID
+SetTDLinkPtrDepthorBreadth (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bDepth
+ );
+
+VOID
+SetTDLinkPtr (
+ IN TD_STRUCT *ptrTDStruct,
+ IN VOID *ptrNext
+ );
+
+VOID *
+GetTDLinkPtr (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+VOID
+EnableorDisableTDShortPacket (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bEnable
+ );
+
+VOID
+SetTDControlErrorCounter (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINT8 nMaxErrors
+ );
+
+VOID
+SetTDLoworFullSpeedDevice (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bLowSpeedDevice
+ );
+
+VOID
+SetTDControlIsochronousorNot (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bIsochronous
+ );
+
+VOID
+SetorClearTDControlIOC (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bSet
+ );
+
+VOID
+SetTDStatusActiveorInactive (
+ IN TD_STRUCT *ptrTDStruct,
+ IN BOOLEAN bActive
+ );
+
+UINT16
+SetTDTokenMaxLength (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINT16 nMaxLen
+ );
+
+VOID
+SetTDTokenDataToggle1 (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+VOID
+SetTDTokenDataToggle0 (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+UINT8
+GetTDTokenDataToggle (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+VOID
+SetTDTokenEndPoint (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINTN nEndPoint
+ );
+
+VOID
+SetTDTokenDeviceAddress (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINTN nDevAddr
+ );
+
+VOID
+SetTDTokenPacketID (
+ IN TD_STRUCT *ptrTDStruct,
+ IN UINT8 nPID
+ );
+
+VOID
+SetTDDataBuffer (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+BOOLEAN
+IsTDStatusActive (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+BOOLEAN
+IsTDStatusStalled (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+BOOLEAN
+IsTDStatusBufferError (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+BOOLEAN
+IsTDStatusBabbleError (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+BOOLEAN
+IsTDStatusNAKReceived (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+BOOLEAN
+IsTDStatusCRCTimeOutError (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+BOOLEAN
+IsTDStatusBitStuffError (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+UINT16
+GetTDStatusActualLength (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+UINT16
+GetTDTokenMaxLength (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+UINT8
+GetTDTokenEndPoint (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+UINT8
+GetTDTokenDeviceAddress (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+UINT8
+GetTDTokenPacketID (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+UINT8 *
+GetTDDataBuffer (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+BOOLEAN
+GetTDLinkPtrValidorInvalid (
+ IN TD_STRUCT *ptrTDStruct
+ );
+
+UINTN
+CountTDsNumber (
+ IN TD_STRUCT *ptrFirstTD
+ );
+
+VOID
+LinkTDToQH (
+ IN QH_STRUCT *ptrQH,
+ IN TD_STRUCT *ptrTD
+ );
+
+VOID
+LinkTDToTD (
+ IN TD_STRUCT *ptrPreTD,
+ IN TD_STRUCT *ptrTD
+ );
+
+VOID
+SetorClearCurFrameListTerminate (
+ IN FRAMELIST_ENTRY *pCurEntry,
+ IN BOOLEAN bSet
+ );
+
+VOID
+SetCurFrameListQHorTD (
+ IN FRAMELIST_ENTRY *pCurEntry,
+ IN BOOLEAN bQH
+ );
+
+BOOLEAN
+GetCurFrameListTerminate (
+ IN FRAMELIST_ENTRY *pCurEntry
+ );
+
+VOID
+SetCurFrameListPointer (
+ IN FRAMELIST_ENTRY *pCurEntry,
+ IN UINT8 *ptr
+ );
+
+VOID *
+GetCurFrameListPointer (
+ IN FRAMELIST_ENTRY *pCurEntry
+ );
+
+VOID
+LinkQHToFrameList (
+ IN FRAMELIST_ENTRY *pEntry,
+ IN UINT16 FrameListIndex,
+ IN QH_STRUCT *ptrQH
+ );
+/*++
+
+Routine Description:
+
+ Link QH To Frame List
+
+Arguments:
+
+ pEntry - FRAMELIST_ENTRY
+ FrameListIndex - Frame List Index
+ PtrQH - QH to link
+Returns:
+
+ VOID
+
+--*/
+VOID
+DeleteQHTDs (
+ IN FRAMELIST_ENTRY *pEntry,
+ IN QH_STRUCT *ptrQH,
+ IN TD_STRUCT *ptrFirstTD,
+ IN UINT16 FrameListIndex,
+ IN BOOLEAN SearchOther
+ );
+
+VOID
+DelLinkSingleQH (
+ IN USB_HC_DEV *HcDev,
+ IN QH_STRUCT *ptrQH,
+ IN UINT16 FrameListIndex,
+ IN BOOLEAN SearchOther,
+ IN BOOLEAN Delete
+ );
+
+VOID
+DeleteQueuedTDs (
+ IN USB_HC_DEV *HcDev,
+ IN TD_STRUCT *ptrFirstTD
+ );
+
+VOID
+InsertQHTDToINTList (
+ IN USB_HC_DEV *HcDev,
+ IN QH_STRUCT *ptrQH,
+ IN TD_STRUCT *ptrFirstTD,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ IN UINT8 DataToggle,
+ IN UINTN DataLength,
+ IN UINTN PollingInterval,
+ IN VOID *Mapping,
+ IN UINT8 *DataBuffer,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
+ IN VOID *Context
+ );
+/*++
+Routine Description:
+ Insert QH and TD To Interrupt List
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrQH - QH_STRUCT
+ PtrFirstTD - First TD_STRUCT
+ DeviceAddress - Device Address
+ EndPointAddress - EndPoint Address
+ DataToggle - Data Toggle
+ DataLength - Data length
+ PollingInterval - Polling Interval when inserted to frame list
+ Mapping - Mapping alue
+ DataBuffer - Data buffer
+ CallBackFunction- CallBackFunction after interrupt transfeer
+ Context - CallBackFunction Context passed as function parameter
+Returns:
+ EFI_SUCCESS - Sucess
+ EFI_INVALID_PARAMETER - Paremeter is error
+
+--*/
+
+EFI_STATUS
+DeleteAsyncINTQHTDs (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 DeviceAddress,
+ IN UINT8 EndPointAddress,
+ OUT UINT8 *DataToggle
+ );
+/*++
+Routine Description:
+
+ Delete Async INT QH and TDs
+Arguments:
+
+ HcDev - USB_HC_DEV
+ DeviceAddress - Device Address
+ EndPointAddress - EndPoint Address
+ DataToggle - Data Toggle
+
+Returns:
+ EFI_SUCCESS - Sucess
+ EFI_INVALID_PARAMETER - Paremeter is error
+
+--*/
+BOOLEAN
+CheckTDsResults (
+ IN TD_STRUCT *ptrTD,
+ IN UINTN RequiredLen,
+ OUT UINT32 *Result,
+ OUT UINTN *ErrTDPos,
+ OUT UINTN *ActualTransferSize
+ );
+/*++
+
+Routine Description:
+
+ Check TDs Results
+
+Arguments:
+
+ PtrTD - TD_STRUCT to check
+ RequiredLen - Required Len
+ Result - Transfer result
+ ErrTDPos - Error TD Position
+ ActualTransferSize - Actual Transfer Size
+
+Returns:
+
+ TRUE - Sucess
+ FALSE - Fail
+
+--*/
+VOID
+ExecuteAsyncINTTDs (
+ IN USB_HC_DEV *HcDev,
+ IN INTERRUPT_LIST *ptrList,
+ OUT UINT32 *Result,
+ OUT UINTN *ErrTDPos,
+ OUT UINTN *ActualLen
+ ) ;
+/*++
+
+Routine Description:
+
+ Execute Async Interrupt TDs
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrList - INTERRUPT_LIST
+ Result - Transfer result
+ ErrTDPos - Error TD Position
+ ActualTransferSize - Actual Transfer Size
+
+Returns:
+
+ VOID
+
+--*/
+VOID
+UpdateAsyncINTQHTDs (
+ IN INTERRUPT_LIST *ptrList,
+ IN UINT32 Result,
+ IN UINT32 ErrTDPos
+ );
+/*++
+
+Routine Description:
+
+ Update Async Interrupt QH and TDs
+
+Arguments:
+
+ PtrList - INTERRUPT_LIST
+ Result - Transfer reslut
+ ErrTDPos - Error TD Position
+
+Returns:
+
+ VOID
+
+--*/
+VOID
+ReleaseInterruptList (
+ IN USB_HC_DEV *HcDev,
+ IN LIST_ENTRY *ListHead
+ );
+/*++
+
+Routine Description:
+
+ Release Interrupt List
+Arguments:
+
+ HcDev - USB_HC_DEV
+ ListHead - List head
+
+Returns:
+
+ VOID
+
+--*/
+EFI_STATUS
+ExecuteControlTransfer (
+ IN USB_HC_DEV *HcDev,
+ IN TD_STRUCT *ptrTD,
+ IN UINT32 wIndex,
+ OUT UINTN *ActualLen,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+/*++
+
+Routine Description:
+
+ Execute Control Transfer
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrTD - TD_STRUCT
+ wIndex - No use
+ ActualLen - Actual transfered Len
+ TimeOut - TimeOut value in milliseconds
+ TransferResult - Transfer result
+Returns:
+
+ EFI_SUCCESS - Sucess
+ EFI_DEVICE_ERROR - Error
+
+
+--*/
+EFI_STATUS
+ExecBulkorSyncInterruptTransfer (
+ IN USB_HC_DEV *HcDev,
+ IN TD_STRUCT *ptrTD,
+ IN UINT32 wIndex,
+ OUT UINTN *ActualLen,
+ OUT UINT8 *DataToggle,
+ IN UINTN TimeOut,
+ OUT UINT32 *TransferResult
+ );
+/*++
+
+Routine Description:
+
+ Execute Bulk or SyncInterrupt Transfer
+
+Arguments:
+
+ HcDev - USB_HC_DEV
+ PtrTD - TD_STRUCT
+ wIndex - No use
+ ActualLen - Actual transfered Len
+ DataToggle - Data Toggle
+ TimeOut - TimeOut value in milliseconds
+ TransferResult - Transfer result
+Returns:
+
+ EFI_SUCCESS - Sucess
+ EFI_DEVICE_ERROR - Error
+--*/
+
+EFI_STATUS
+InitializeMemoryManagement (
+ IN USB_HC_DEV *HcDev
+ );
+
+EFI_STATUS
+CreateMemoryBlock (
+ IN USB_HC_DEV *HcDev,
+ IN MEMORY_MANAGE_HEADER **MemoryHeader,
+ IN UINTN MemoryBlockSizeInPages
+ );
+
+EFI_STATUS
+FreeMemoryHeader (
+ IN USB_HC_DEV *HcDev,
+ IN MEMORY_MANAGE_HEADER *MemoryHeader
+ );
+
+EFI_STATUS
+UhciAllocatePool (
+ IN USB_HC_DEV *UhcDev,
+ IN UINT8 **Pool,
+ IN UINTN AllocSize
+ );
+
+VOID
+UhciFreePool (
+ IN USB_HC_DEV *HcDev,
+ IN UINT8 *Pool,
+ IN UINTN AllocSize
+ );
+
+VOID
+InsertMemoryHeaderToList (
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,
+ IN MEMORY_MANAGE_HEADER *NewMemoryHeader
+ );
+
+EFI_STATUS
+AllocMemInMemoryBlock (
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,
+ IN VOID **Pool,
+ IN UINTN NumberOfMemoryUnit
+ );
+
+BOOLEAN
+IsMemoryBlockEmptied (
+ IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr
+ );
+
+VOID
+DelinkMemoryBlock (
+ IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,
+ IN MEMORY_MANAGE_HEADER *FreeMemoryHeader
+ );
+
+EFI_STATUS
+DelMemoryManagement (
+ IN USB_HC_DEV *HcDev
+ );
+
+VOID
+EnableMaxPacketSize (
+ IN USB_HC_DEV *HcDev
+ );
+
+VOID
+CleanUsbTransactions (
+ IN USB_HC_DEV *HcDev
+ );
+
+VOID
+TurnOffUSBEmulation (
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ );
+
+#endif