diff options
Diffstat (limited to 'EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c')
-rw-r--r-- | EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c | 4237 |
1 files changed, 4237 insertions, 0 deletions
diff --git a/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c b/EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c new file mode 100644 index 0000000000..62d58eed78 --- /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 ;
+}
|