2. Use ZeroMem to replace gBS->SetMem; 3. Remove marked code; 4. Add IsHub judgement in UsbPortReset function to following EFI1.1 spec; 5. Add brackets for macro definition git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1740 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			3080 lines
		
	
	
		
			69 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3080 lines
		
	
	
		
			69 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
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:
 | 
						|
 | 
						|
    EhciSched.c
 | 
						|
    
 | 
						|
Abstract: 
 | 
						|
    
 | 
						|
 | 
						|
Revision History
 | 
						|
--*/
 | 
						|
 | 
						|
#include "Ehci.h"
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
InitialPeriodicFrameList (
 | 
						|
  IN  USB2_HC_DEV     *HcDev,
 | 
						|
  IN  UINTN           Length
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Initialize Periodic Schedule Frame List
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev   - USB2_HC_DEV
 | 
						|
  Length  - Frame List Length
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  VOID                  *CommonBuffer;
 | 
						|
  EFI_PHYSICAL_ADDRESS  FrameBuffer;
 | 
						|
  VOID                  *Map;
 | 
						|
  UINTN                 BufferSizeInPages;
 | 
						|
  UINTN                 BufferSizeInBytes;
 | 
						|
  UINTN                 FrameIndex;
 | 
						|
  FRAME_LIST_ENTRY      *FrameEntryPtr;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // 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.
 | 
						|
  //
 | 
						|
  if (EHCI_MAX_FRAME_LIST_LENGTH != Length && IsFrameListProgrammable (HcDev)) {
 | 
						|
    Status = SetFrameListLen (HcDev, Length);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  BufferSizeInBytes = EFI_PAGE_SIZE;
 | 
						|
  BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);
 | 
						|
  Status = HcDev->PciIo->AllocateBuffer (
 | 
						|
                          HcDev->PciIo,
 | 
						|
                          AllocateAnyPages,
 | 
						|
                          EfiBootServicesData,
 | 
						|
                          BufferSizeInPages,
 | 
						|
                          &CommonBuffer,
 | 
						|
                          0
 | 
						|
                          );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((gEHCErrorLevel, "PciIo->AllocateBuffer Failed\n"));
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = HcDev->PciIo->Map (
 | 
						|
                          HcDev->PciIo,
 | 
						|
                          EfiPciIoOperationBusMasterCommonBuffer,
 | 
						|
                          CommonBuffer,
 | 
						|
                          &BufferSizeInBytes,
 | 
						|
                          &FrameBuffer,
 | 
						|
                          &Map
 | 
						|
                          );
 | 
						|
  if (EFI_ERROR (Status) || (BufferSizeInBytes != EFI_PAGE_SIZE)) {
 | 
						|
    DEBUG ((gEHCErrorLevel, "PciIo->MapBuffer Failed\n"));
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto free_buffer;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Put high 32bit into CtrlDataStructSeg reg 
 | 
						|
  // when 64bit addressing range capability
 | 
						|
  //
 | 
						|
  if (HcDev->Is64BitCapable != 0) {
 | 
						|
  	HcDev->High32BitAddr = (UINT32) GET_32B_TO_63B (FrameBuffer);
 | 
						|
	
 | 
						|
  	Status = SetCtrlDataStructSeg (HcDev);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((gEHCErrorLevel, "SetCtrlDataStructSeg Failed\n"));
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto unmap_buffer;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Tell the Host Controller where the Frame List lies,
 | 
						|
  // by set the Frame List Base Address Register.
 | 
						|
  //
 | 
						|
  Status = SetFrameListBaseAddr (HcDev, (UINT32) FrameBuffer);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto unmap_buffer;
 | 
						|
  }
 | 
						|
 | 
						|
  HcDev->PeriodicFrameListLength  = Length;
 | 
						|
  HcDev->PeriodicFrameListBuffer  = (VOID *) ((UINTN) FrameBuffer);
 | 
						|
  HcDev->PeriodicFrameListMap     = Map;
 | 
						|
 | 
						|
  //
 | 
						|
  // Init Frame List Array fields
 | 
						|
  //
 | 
						|
  FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
 | 
						|
  for (FrameIndex = 0; FrameIndex < HcDev->PeriodicFrameListLength; FrameIndex++) {
 | 
						|
    FrameEntryPtr->LinkPointer    = 0;
 | 
						|
    FrameEntryPtr->Rsvd           = 0;
 | 
						|
    FrameEntryPtr->SelectType     = 0;
 | 
						|
    FrameEntryPtr->LinkTerminate  = TRUE;
 | 
						|
    FrameEntryPtr++;
 | 
						|
  }
 | 
						|
 | 
						|
  goto exit;
 | 
						|
 | 
						|
unmap_buffer:
 | 
						|
  HcDev->PciIo->Unmap (HcDev->PciIo, Map);
 | 
						|
free_buffer:
 | 
						|
  HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
DeinitialPeriodicFrameList (
 | 
						|
  IN  USB2_HC_DEV     *HcDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Deinitialize Periodic Schedule Frame List
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev - USB2_HC_DEV
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->PeriodicFrameListMap);
 | 
						|
  HcDev->PciIo->FreeBuffer (HcDev->PciIo, EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE), HcDev->PeriodicFrameListBuffer);
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreatePollingTimer (
 | 
						|
  IN  USB2_HC_DEV      *HcDev,
 | 
						|
  IN  EFI_EVENT_NOTIFY NotifyFunction
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Async Request Polling Timer
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev          - USB2_HC_DEV
 | 
						|
  NotifyFunction - Timer Notify Function
 | 
						|
  
 | 
						|
Returns:
 | 
						|
  
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return gBS->CreateEvent (
 | 
						|
                EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                EFI_TPL_NOTIFY,
 | 
						|
                NotifyFunction,
 | 
						|
                HcDev,
 | 
						|
                &HcDev->AsyncRequestEvent
 | 
						|
                );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
DestoryPollingTimer (
 | 
						|
  IN  USB2_HC_DEV *HcDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Destory Async Request Polling Timer
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev - USB2_HC_DEV
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return gBS->CloseEvent (HcDev->AsyncRequestEvent);
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
StartPollingTimer (
 | 
						|
  IN  USB2_HC_DEV *HcDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Start Async Request Polling Timer
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev - USB2_HC_DEV
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return gBS->SetTimer (
 | 
						|
                HcDev->AsyncRequestEvent,
 | 
						|
                TimerPeriodic,
 | 
						|
                EHCI_ASYNC_REQUEST_POLLING_TIME
 | 
						|
                );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
StopPollingTimer (
 | 
						|
  IN  USB2_HC_DEV *HcDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Stop Async Request Polling Timer
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev - USB2_HC_DEV
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return gBS->SetTimer (
 | 
						|
                HcDev->AsyncRequestEvent,
 | 
						|
                TimerCancel,
 | 
						|
                EHCI_ASYNC_REQUEST_POLLING_TIME
 | 
						|
                );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateQh (
 | 
						|
  IN  USB2_HC_DEV         *HcDev,
 | 
						|
  IN  UINT8               DeviceAddr,
 | 
						|
  IN  UINT8               Endpoint,
 | 
						|
  IN  UINT8               DeviceSpeed,
 | 
						|
  IN  UINTN               MaxPacketLen,
 | 
						|
  OUT EHCI_QH_ENTITY      **QhPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qh Structure and Pre-Initialize
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev        - USB2_HC_DEV 
 | 
						|
  DeviceAddr   - Address of Device
 | 
						|
  Endpoint     - Endpoint Number
 | 
						|
  DeviceSpeed  - Device Speed
 | 
						|
  MaxPacketLen - Max Length of one Packet
 | 
						|
  QhPtrPtr     - A pointer of pointer to Qh for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EHCI_QH_HW  *QhHwPtr;
 | 
						|
 | 
						|
  ASSERT (HcDev);
 | 
						|
  ASSERT (QhPtrPtr);
 | 
						|
 | 
						|
  *QhPtrPtr = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate  memory for Qh structure
 | 
						|
  //
 | 
						|
  Status = EhciAllocatePool (
 | 
						|
             HcDev,
 | 
						|
             (UINT8 **) QhPtrPtr,
 | 
						|
             sizeof (EHCI_QH_ENTITY)
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Init fields in Qh
 | 
						|
  //
 | 
						|
  ZeroMem (*QhPtrPtr, sizeof (EHCI_QH_ENTITY));
 | 
						|
 | 
						|
  //
 | 
						|
  // Software field
 | 
						|
  //
 | 
						|
  (*QhPtrPtr)->Next         = NULL;
 | 
						|
  (*QhPtrPtr)->Prev         = NULL;
 | 
						|
  (*QhPtrPtr)->FirstQtdPtr  = NULL;
 | 
						|
  (*QhPtrPtr)->AltQtdPtr    = NULL;
 | 
						|
  (*QhPtrPtr)->LastQtdPtr   = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Hardware field
 | 
						|
  //
 | 
						|
  QhHwPtr                       = &((*QhPtrPtr)->Qh);
 | 
						|
  QhHwPtr->QhHorizontalPointer  = 0;
 | 
						|
  QhHwPtr->SelectType           = 0;
 | 
						|
  QhHwPtr->MaxPacketLen         = (UINT32) MaxPacketLen;
 | 
						|
  QhHwPtr->EndpointSpeed        = (DeviceSpeed & 0x3);
 | 
						|
  QhHwPtr->EndpointNum          = (Endpoint & 0x0f);
 | 
						|
  QhHwPtr->DeviceAddr           = (DeviceAddr & 0x7f);
 | 
						|
  QhHwPtr->Multiplier           = HIGH_BANDWIDTH_PIPE_MULTIPLIER;
 | 
						|
  QhHwPtr->Rsvd1                = 0;
 | 
						|
  QhHwPtr->Rsvd2                = 0;
 | 
						|
  QhHwPtr->Rsvd3                = 0;
 | 
						|
  QhHwPtr->Rsvd4                = 0;
 | 
						|
  QhHwPtr->Rsvd5                = 0;
 | 
						|
  QhHwPtr->Rsvd6                = 0;
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
DestoryQh (
 | 
						|
  IN USB2_HC_DEV         *HcDev,
 | 
						|
  IN EHCI_QH_ENTITY      *QhPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Destory Qh Structure 
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev - USB2_HC_DEV 
 | 
						|
  QhPtr - A pointer to Qh
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  ASSERT (HcDev);
 | 
						|
  ASSERT (QhPtr);
 | 
						|
 | 
						|
  EhciFreePool (HcDev, (UINT8 *) QhPtr, sizeof (EHCI_QH_ENTITY));
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateControlQh (
 | 
						|
  IN  USB2_HC_DEV                         *HcDev,
 | 
						|
  IN  UINT8                               DeviceAddr,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINTN                               MaxPacketLen,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT EHCI_QH_ENTITY                      **QhPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qh for Control Transfer
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev        - USB2_HC_DEV 
 | 
						|
  DeviceAddr   - Address of Device
 | 
						|
  DeviceSpeed  - Device Speed
 | 
						|
  MaxPacketLen - Max Length of one Packet
 | 
						|
  Translator   - Translator Transaction for SplitX
 | 
						|
  QhPtrPtr     - A pointer of pointer to Qh for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create and init Control Qh
 | 
						|
  //
 | 
						|
  Status = CreateQh (
 | 
						|
             HcDev,
 | 
						|
             DeviceAddr,
 | 
						|
             0,
 | 
						|
             DeviceSpeed,
 | 
						|
             MaxPacketLen,
 | 
						|
             QhPtrPtr
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Software field
 | 
						|
  //
 | 
						|
  (*QhPtrPtr)->Next         = (*QhPtrPtr);
 | 
						|
  (*QhPtrPtr)->Prev         = (*QhPtrPtr);
 | 
						|
  (*QhPtrPtr)->TransferType = CONTROL_TRANSFER;
 | 
						|
 | 
						|
  //
 | 
						|
  // Hardware field
 | 
						|
  //
 | 
						|
  // Control Transfer use DataToggleControl
 | 
						|
  //
 | 
						|
  (*QhPtrPtr)->Qh.DataToggleControl   = TRUE;
 | 
						|
  (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);
 | 
						|
  (*QhPtrPtr)->Qh.SelectType          = QH_SELECT_TYPE;
 | 
						|
  (*QhPtrPtr)->Qh.QhTerminate         = FALSE;
 | 
						|
  (*QhPtrPtr)->Qh.ControlEndpointFlag = TRUE;
 | 
						|
  (*QhPtrPtr)->Qh.NakCountReload      = NAK_COUNT_RELOAD;
 | 
						|
  if (NULL != Translator) {
 | 
						|
    (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
 | 
						|
    (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
 | 
						|
    (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
 | 
						|
  }
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateBulkQh (
 | 
						|
  IN  USB2_HC_DEV                         *HcDev,
 | 
						|
  IN  UINT8                               DeviceAddr,
 | 
						|
  IN  UINT8                               EndPointAddr,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINT8                               DataToggle,
 | 
						|
  IN  UINTN                               MaxPacketLen,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT EHCI_QH_ENTITY                      **QhPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qh for Bulk Transfer
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev        - USB2_HC_DEV 
 | 
						|
  DeviceAddr   - Address of Device
 | 
						|
  EndPointAddr - Address of Endpoint
 | 
						|
  DeviceSpeed  - Device Speed
 | 
						|
  MaxPacketLen - Max Length of one Packet
 | 
						|
  Translator   - Translator Transaction for SplitX
 | 
						|
  QhPtrPtr     - A pointer of pointer to Qh for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create and init Bulk Qh
 | 
						|
  //
 | 
						|
  Status = CreateQh (
 | 
						|
             HcDev,
 | 
						|
             DeviceAddr,
 | 
						|
             EndPointAddr,
 | 
						|
             DeviceSpeed,
 | 
						|
             MaxPacketLen,
 | 
						|
             QhPtrPtr
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Software fields
 | 
						|
  //
 | 
						|
  (*QhPtrPtr)->Next         = (*QhPtrPtr);
 | 
						|
  (*QhPtrPtr)->Prev         = (*QhPtrPtr);
 | 
						|
  (*QhPtrPtr)->TransferType = BULK_TRANSFER;
 | 
						|
 | 
						|
  //
 | 
						|
  // Hardware fields
 | 
						|
  //
 | 
						|
  // BulkTransfer don't use DataToggleControl
 | 
						|
  //
 | 
						|
  (*QhPtrPtr)->Qh.DataToggleControl   = FALSE;  
 | 
						|
  (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);
 | 
						|
  (*QhPtrPtr)->Qh.SelectType          = QH_SELECT_TYPE;
 | 
						|
  (*QhPtrPtr)->Qh.QhTerminate         = FALSE;
 | 
						|
  (*QhPtrPtr)->Qh.NakCountReload      = NAK_COUNT_RELOAD;
 | 
						|
  (*QhPtrPtr)->Qh.DataToggle          = DataToggle;
 | 
						|
  if (NULL != Translator) {
 | 
						|
    (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
 | 
						|
    (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
 | 
						|
    (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
 | 
						|
  }
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateInterruptQh (
 | 
						|
  IN  USB2_HC_DEV                         *HcDev,
 | 
						|
  IN  UINT8                               DeviceAddr,
 | 
						|
  IN  UINT8                               EndPointAddr,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINT8                               DataToggle,
 | 
						|
  IN  UINTN                               MaxPacketLen,
 | 
						|
  IN  UINTN                               Interval,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT EHCI_QH_ENTITY                      **QhPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qh for Control Transfer
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev        - USB2_HC_DEV 
 | 
						|
  DeviceAddr   - Address of Device
 | 
						|
  EndPointAddr - Address of Endpoint
 | 
						|
  DeviceSpeed  - Device Speed
 | 
						|
  MaxPacketLen - Max Length of one Packet
 | 
						|
  Interval     - value of interval
 | 
						|
  Translator   - Translator Transaction for SplitX
 | 
						|
  QhPtrPtr     - A pointer of pointer to Qh for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create and init InterruptQh
 | 
						|
  //
 | 
						|
  Status = CreateQh (
 | 
						|
             HcDev,
 | 
						|
             DeviceAddr,
 | 
						|
             EndPointAddr,
 | 
						|
             DeviceSpeed,
 | 
						|
             MaxPacketLen,
 | 
						|
             QhPtrPtr
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Software fields
 | 
						|
  //
 | 
						|
  if (Interval == 0) {
 | 
						|
    (*QhPtrPtr)->TransferType = SYNC_INTERRUPT_TRANSFER;
 | 
						|
  } else {
 | 
						|
    (*QhPtrPtr)->TransferType = ASYNC_INTERRUPT_TRANSFER;
 | 
						|
  }
 | 
						|
  (*QhPtrPtr)->Interval = GetApproxiOfInterval (Interval);
 | 
						|
 | 
						|
  //
 | 
						|
  // Hardware fields
 | 
						|
  //
 | 
						|
  // InterruptTranfer don't use DataToggleControl
 | 
						|
  //
 | 
						|
  (*QhPtrPtr)->Qh.DataToggleControl     = FALSE;
 | 
						|
  (*QhPtrPtr)->Qh.QhHorizontalPointer   = 0;
 | 
						|
  (*QhPtrPtr)->Qh.QhTerminate           = TRUE;
 | 
						|
  (*QhPtrPtr)->Qh.NakCountReload        = 0;
 | 
						|
  (*QhPtrPtr)->Qh.InerruptScheduleMask  = MICRO_FRAME_0_CHANNEL;
 | 
						|
  (*QhPtrPtr)->Qh.SplitComletionMask    = (MICRO_FRAME_2_CHANNEL | MICRO_FRAME_3_CHANNEL | MICRO_FRAME_4_CHANNEL);
 | 
						|
  (*QhPtrPtr)->Qh.DataToggle            = DataToggle;
 | 
						|
  if (NULL != Translator) {
 | 
						|
    (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
 | 
						|
    (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
 | 
						|
    (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
 | 
						|
  }
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateQtd (
 | 
						|
  IN  USB2_HC_DEV          *HcDev,
 | 
						|
  IN  UINT8                *DataPtr,
 | 
						|
  IN  UINTN                DataLen,
 | 
						|
  IN  UINT8                PktId,
 | 
						|
  IN  UINT8                Toggle,
 | 
						|
  IN  UINT8                QtdStatus,
 | 
						|
  OUT EHCI_QTD_ENTITY      **QtdPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qtd Structure and Pre-Initialize it
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev       - USB2_HC_DEV 
 | 
						|
  DataPtr     - A pointer to user data buffer to transfer
 | 
						|
  DataLen     - Length of user data to transfer
 | 
						|
  PktId       - Packet Identification of this Qtd
 | 
						|
  Toggle      - Data Toggle of this Qtd
 | 
						|
  QtdStatus   - Default value of status of this Qtd
 | 
						|
  QtdPtrPtr   - A pointer of pointer to Qtd for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EHCI_QTD_HW *QtdHwPtr;
 | 
						|
 | 
						|
  ASSERT (HcDev);
 | 
						|
  ASSERT (QtdPtrPtr);
 | 
						|
 | 
						|
  //
 | 
						|
  // Create memory for Qtd structure
 | 
						|
  //
 | 
						|
  Status = EhciAllocatePool (
 | 
						|
             HcDev,
 | 
						|
             (UINT8 **) QtdPtrPtr,
 | 
						|
             sizeof (EHCI_QTD_ENTITY)
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Init fields in Qtd
 | 
						|
  //
 | 
						|
 | 
						|
  ZeroMem (*QtdPtrPtr, sizeof (EHCI_QTD_ENTITY));
 | 
						|
 | 
						|
  //
 | 
						|
  // Software field
 | 
						|
  //
 | 
						|
  (*QtdPtrPtr)->TotalBytes        = (UINT32) DataLen;
 | 
						|
  (*QtdPtrPtr)->StaticTotalBytes  = (UINT32) DataLen;
 | 
						|
  (*QtdPtrPtr)->Prev              = NULL;
 | 
						|
  (*QtdPtrPtr)->Next              = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Hardware field
 | 
						|
  //
 | 
						|
  QtdHwPtr                      = &((*QtdPtrPtr)->Qtd);
 | 
						|
  QtdHwPtr->NextQtdPointer      = 0;
 | 
						|
  QtdHwPtr->NextQtdTerminate    = TRUE;
 | 
						|
  QtdHwPtr->AltNextQtdPointer   = 0;
 | 
						|
  QtdHwPtr->AltNextQtdTerminate = TRUE;
 | 
						|
  QtdHwPtr->DataToggle          = Toggle;
 | 
						|
  QtdHwPtr->TotalBytes          = (UINT32) DataLen;
 | 
						|
  QtdHwPtr->CurrentPage         = 0;
 | 
						|
  QtdHwPtr->ErrorCount          = QTD_ERROR_COUNTER;
 | 
						|
  QtdHwPtr->Status              = QtdStatus;
 | 
						|
  QtdHwPtr->Rsvd1               = 0;
 | 
						|
  QtdHwPtr->Rsvd2               = 0;
 | 
						|
  QtdHwPtr->Rsvd3               = 0;
 | 
						|
  QtdHwPtr->Rsvd4               = 0;
 | 
						|
  QtdHwPtr->Rsvd5               = 0;
 | 
						|
  QtdHwPtr->Rsvd6               = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set PacketID [Setup/Data/Status]
 | 
						|
  //
 | 
						|
  switch (PktId) {
 | 
						|
  case SETUP_PACKET_ID:
 | 
						|
    QtdHwPtr->PidCode = SETUP_PACKET_PID_CODE;
 | 
						|
    break;
 | 
						|
 | 
						|
  case INPUT_PACKET_ID:
 | 
						|
    QtdHwPtr->PidCode = INPUT_PACKET_PID_CODE;
 | 
						|
    break;
 | 
						|
 | 
						|
  case OUTPUT_PACKET_ID:
 | 
						|
    QtdHwPtr->PidCode = OUTPUT_PACKET_PID_CODE;
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Set Data Buffer Pointers
 | 
						|
  //
 | 
						|
  if (NULL != DataPtr) {
 | 
						|
    SetQtdBufferPointer (
 | 
						|
      QtdHwPtr,
 | 
						|
      DataPtr,
 | 
						|
      DataLen
 | 
						|
      );
 | 
						|
    (*QtdPtrPtr)->StaticCurrentOffset = QtdHwPtr->CurrentOffset;
 | 
						|
  }
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateSetupQtd (
 | 
						|
  IN  USB2_HC_DEV          *HcDev,
 | 
						|
  IN  UINT8                *DevReqPtr,
 | 
						|
  OUT EHCI_QTD_ENTITY      **QtdPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qtd Structure for Setup 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev      - USB2_HC_DEV 
 | 
						|
  DevReqPtr  - A pointer to Device Request Data
 | 
						|
  QtdPtrPtr  - A pointer of pointer to Qtd for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return CreateQtd (
 | 
						|
           HcDev,
 | 
						|
           DevReqPtr,
 | 
						|
           sizeof (EFI_USB_DEVICE_REQUEST),
 | 
						|
           SETUP_PACKET_ID,
 | 
						|
           DATA0,
 | 
						|
           QTD_STATUS_ACTIVE,
 | 
						|
           QtdPtrPtr
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateDataQtd (
 | 
						|
  IN  USB2_HC_DEV           *HcDev,
 | 
						|
  IN  UINT8                 *DataPtr,
 | 
						|
  IN  UINTN                 DataLen,
 | 
						|
  IN  UINT8                 PktId,
 | 
						|
  IN  UINT8                 Toggle,
 | 
						|
  OUT EHCI_QTD_ENTITY       **QtdPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qtd Structure for data 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev       - USB2_HC_DEV 
 | 
						|
  DataPtr     - A pointer to user data buffer to transfer
 | 
						|
  DataLen     - Length of user data to transfer
 | 
						|
  PktId       - Packet Identification of this Qtd
 | 
						|
  Toggle      - Data Toggle of this Qtd
 | 
						|
  QtdPtrPtr   - A pointer of pointer to Qtd for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return CreateQtd (
 | 
						|
           HcDev,
 | 
						|
           DataPtr,
 | 
						|
           DataLen,
 | 
						|
           PktId,
 | 
						|
           Toggle,
 | 
						|
           QTD_STATUS_ACTIVE,
 | 
						|
           QtdPtrPtr
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateAltQtd (
 | 
						|
  IN  USB2_HC_DEV           *HcDev,
 | 
						|
  IN  UINT8                 PktId,
 | 
						|
  OUT EHCI_QTD_ENTITY       **QtdPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qtd Structure for Alternative 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev      - USB2_HC_DEV 
 | 
						|
  PktId      - Packet Identification of this Qtd
 | 
						|
  QtdPtrPtr  - A pointer of pointer to Qtd for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return CreateQtd (
 | 
						|
           HcDev,
 | 
						|
           NULL,
 | 
						|
           0,
 | 
						|
           PktId,
 | 
						|
           0,
 | 
						|
           QTD_STATUS_ACTIVE,
 | 
						|
           QtdPtrPtr
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateStatusQtd (
 | 
						|
  IN  USB2_HC_DEV           *HcDev,
 | 
						|
  IN  UINT8                 PktId,
 | 
						|
  OUT EHCI_QTD_ENTITY       **QtdPtrPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qtd Structure for status 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev       - USB2_HC_DEV 
 | 
						|
  PktId       - Packet Identification of this Qtd
 | 
						|
  QtdPtrPtr   - A pointer of pointer to Qtd for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return CreateQtd (
 | 
						|
           HcDev,
 | 
						|
           NULL,
 | 
						|
           0,
 | 
						|
           PktId,
 | 
						|
           DATA1,
 | 
						|
           QTD_STATUS_ACTIVE,
 | 
						|
           QtdPtrPtr
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateControlQtds (
 | 
						|
  IN  USB2_HC_DEV                         *HcDev,
 | 
						|
  IN UINT8                                DataPktId,
 | 
						|
  IN UINT8                                *RequestCursor,
 | 
						|
  IN UINT8                                *DataCursor,
 | 
						|
  IN UINTN                                DataLen,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT EHCI_QTD_ENTITY                     **ControlQtdsHead
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qtds list for Control Transfer 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev           - USB2_HC_DEV 
 | 
						|
  DataPktId       - Packet Identification of Data Qtds
 | 
						|
  RequestCursor   - A pointer to request structure buffer to transfer
 | 
						|
  DataCursor      - A pointer to user data buffer to transfer
 | 
						|
  DataLen         - Length of user data to transfer
 | 
						|
  ControlQtdsHead - A pointer of pointer to first Qtd for control tranfer for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  EHCI_QTD_ENTITY *QtdPtr;
 | 
						|
  EHCI_QTD_ENTITY *PreQtdPtr;
 | 
						|
  EHCI_QTD_ENTITY *SetupQtdPtr;
 | 
						|
  EHCI_QTD_ENTITY *FirstDataQtdPtr;
 | 
						|
  EHCI_QTD_ENTITY *LastDataQtdPtr;
 | 
						|
  EHCI_QTD_ENTITY *StatusQtdPtr;
 | 
						|
  UINT8           DataToggle;
 | 
						|
  UINT8           StatusPktId;
 | 
						|
  UINTN           CapacityOfQtd;
 | 
						|
  UINTN           SizePerQtd;
 | 
						|
  UINTN           DataCount;
 | 
						|
  UINTN           Xnum;
 | 
						|
  
 | 
						|
  QtdPtr          = NULL;
 | 
						|
  PreQtdPtr       = NULL;
 | 
						|
  SetupQtdPtr     = NULL;
 | 
						|
  FirstDataQtdPtr = NULL;
 | 
						|
  LastDataQtdPtr  = NULL;
 | 
						|
  StatusQtdPtr    = NULL;
 | 
						|
  CapacityOfQtd = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Setup Stage of Control Transfer
 | 
						|
  //
 | 
						|
  Status = CreateSetupQtd (
 | 
						|
             HcDev,
 | 
						|
             RequestCursor,
 | 
						|
             &SetupQtdPtr
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  //  Data Stage of Control Transfer
 | 
						|
  //
 | 
						|
  DataToggle  = 1;
 | 
						|
  DataCount   = DataLen;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create Qtd structure and link together
 | 
						|
  //
 | 
						|
  while (DataCount > 0) {
 | 
						|
    //
 | 
						|
    // PktSize is the data load size that each Qtd.
 | 
						|
    //
 | 
						|
    CapacityOfQtd = GetCapacityOfQtd (DataCursor);
 | 
						|
    SizePerQtd    = DataCount;
 | 
						|
    if (DataCount > CapacityOfQtd) {
 | 
						|
      SizePerQtd = CapacityOfQtd;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = CreateDataQtd (
 | 
						|
               HcDev,
 | 
						|
               DataCursor,
 | 
						|
               SizePerQtd,
 | 
						|
               DataPktId,
 | 
						|
               DataToggle,
 | 
						|
               &QtdPtr
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      if (NULL == FirstDataQtdPtr) {
 | 
						|
        goto destory_setup_qtd;
 | 
						|
      } else {
 | 
						|
        goto destory_qtds;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (NULL == FirstDataQtdPtr) {
 | 
						|
      FirstDataQtdPtr = QtdPtr;
 | 
						|
    } else {
 | 
						|
      LinkQtdToQtd (PreQtdPtr, QtdPtr);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Reverse Data Toggle or not determined by parity of transactions of one qtd
 | 
						|
    //
 | 
						|
    Xnum = Translator ? GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE_WITH_TT) : GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE);
 | 
						|
    if (Xnum % 2 != 0) {
 | 
						|
      DataToggle ^= 1;
 | 
						|
    }
 | 
						|
    
 | 
						|
    PreQtdPtr = QtdPtr;
 | 
						|
    DataCursor += SizePerQtd;
 | 
						|
    DataCount -= SizePerQtd;
 | 
						|
  }
 | 
						|
 | 
						|
  LastDataQtdPtr = QtdPtr;
 | 
						|
 | 
						|
  //
 | 
						|
  // Status Stage of Control Transfer
 | 
						|
  //
 | 
						|
  if (OUTPUT_PACKET_ID == DataPktId) {
 | 
						|
    StatusPktId = INPUT_PACKET_ID;
 | 
						|
  } else {
 | 
						|
    StatusPktId = OUTPUT_PACKET_ID;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = CreateStatusQtd (
 | 
						|
            HcDev,
 | 
						|
            StatusPktId,
 | 
						|
            &StatusQtdPtr
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto destory_qtds;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Link setup Qtd -> data Qtds -> status Qtd
 | 
						|
  //
 | 
						|
  if (FirstDataQtdPtr != NULL) {
 | 
						|
    LinkQtdToQtd (SetupQtdPtr, FirstDataQtdPtr);
 | 
						|
    LinkQtdToQtd (LastDataQtdPtr, StatusQtdPtr);
 | 
						|
  } else {
 | 
						|
    LinkQtdToQtd (SetupQtdPtr, StatusQtdPtr);
 | 
						|
  }
 | 
						|
 | 
						|
  *ControlQtdsHead = SetupQtdPtr;
 | 
						|
 | 
						|
  goto exit;
 | 
						|
 | 
						|
destory_qtds:
 | 
						|
  DestoryQtds (HcDev, FirstDataQtdPtr);
 | 
						|
destory_setup_qtd:
 | 
						|
  DestoryQtds (HcDev, SetupQtdPtr);
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CreateBulkOrInterruptQtds (
 | 
						|
  IN  USB2_HC_DEV                         *HcDev,
 | 
						|
  IN  UINT8                               PktId,
 | 
						|
  IN  UINT8                               *DataCursor,
 | 
						|
  IN  UINTN                               DataLen,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT EHCI_QTD_ENTITY                     **QtdsHead
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create Qtds list for Bulk or Interrupt Transfer 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev        - USB2_HC_DEV 
 | 
						|
  PktId        - Packet Identification of Qtds
 | 
						|
  DataCursor   - A pointer to user data buffer to transfer
 | 
						|
  DataLen      - Length of user data to transfer
 | 
						|
  DataToggle   - Data Toggle to start
 | 
						|
  Translator   - Translator Transaction for SplitX
 | 
						|
  QtdsHead     - A pointer of pointer to first Qtd for control tranfer for return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS            Success
 | 
						|
  EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  EHCI_QTD_ENTITY *QtdPtr;
 | 
						|
  EHCI_QTD_ENTITY *PreQtdPtr;
 | 
						|
  EHCI_QTD_ENTITY *FirstQtdPtr;
 | 
						|
  EHCI_QTD_ENTITY *AltQtdPtr;
 | 
						|
  UINTN           DataCount;
 | 
						|
  UINTN           CapacityOfQtd;
 | 
						|
  UINTN           SizePerQtd;
 | 
						|
 | 
						|
  Status        = EFI_SUCCESS;
 | 
						|
  QtdPtr        = NULL;
 | 
						|
  PreQtdPtr     = NULL;
 | 
						|
  FirstQtdPtr   = NULL;
 | 
						|
  AltQtdPtr     = NULL;
 | 
						|
  CapacityOfQtd = 0;
 | 
						|
 | 
						|
  DataCount   = DataLen;
 | 
						|
  while (DataCount > 0) {
 | 
						|
 | 
						|
    CapacityOfQtd = GetCapacityOfQtd (DataCursor);
 | 
						|
    SizePerQtd    = DataCount;
 | 
						|
    if (DataCount > CapacityOfQtd) {
 | 
						|
      SizePerQtd = CapacityOfQtd;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = CreateDataQtd (
 | 
						|
              HcDev,
 | 
						|
              DataCursor,
 | 
						|
              SizePerQtd,
 | 
						|
              PktId,
 | 
						|
              0,
 | 
						|
              &QtdPtr
 | 
						|
              );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      if (NULL == FirstQtdPtr) {
 | 
						|
        goto exit;
 | 
						|
      } else {
 | 
						|
        goto destory_qtds;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (NULL == FirstQtdPtr) {
 | 
						|
      FirstQtdPtr = QtdPtr;
 | 
						|
    } else {
 | 
						|
      LinkQtdToQtd (PreQtdPtr, QtdPtr);
 | 
						|
    }
 | 
						|
 | 
						|
    PreQtdPtr = QtdPtr;
 | 
						|
    DataCursor += SizePerQtd;
 | 
						|
    DataCount -= SizePerQtd;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Set Alternate Qtd
 | 
						|
  //
 | 
						|
  if (INPUT_PACKET_ID == PktId && 1 < GetNumberOfQtd (FirstQtdPtr)) {
 | 
						|
    Status = CreateAltQtd (
 | 
						|
              HcDev,
 | 
						|
              PktId,
 | 
						|
              &AltQtdPtr
 | 
						|
              );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto destory_qtds;
 | 
						|
    }
 | 
						|
 | 
						|
    LinkQtdsToAltQtd (FirstQtdPtr, AltQtdPtr);
 | 
						|
  }
 | 
						|
 | 
						|
  *QtdsHead = FirstQtdPtr;
 | 
						|
  goto exit;
 | 
						|
 | 
						|
destory_qtds:
 | 
						|
  DestoryQtds (HcDev, FirstQtdPtr);
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
DestoryQtds (
 | 
						|
  IN USB2_HC_DEV          *HcDev,
 | 
						|
  IN EHCI_QTD_ENTITY      *FirstQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Destory all Qtds in the list
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev         - USB2_HC_DEV 
 | 
						|
  FirstQtdPtr   - A pointer to first Qtd in the list 
 | 
						|
    
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_QTD_ENTITY *PrevQtd;
 | 
						|
  EHCI_QTD_ENTITY *NextQtd;
 | 
						|
 | 
						|
  if (!FirstQtdPtr) {
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  PrevQtd = FirstQtdPtr;
 | 
						|
 | 
						|
  //
 | 
						|
  // Delete all the Qtds.
 | 
						|
  //
 | 
						|
  do {
 | 
						|
    NextQtd = PrevQtd->Next;
 | 
						|
    EhciFreePool (HcDev, (UINT8 *) PrevQtd, sizeof (EHCI_QTD_ENTITY));
 | 
						|
    PrevQtd = NextQtd;
 | 
						|
  } while (NULL != PrevQtd);
 | 
						|
 | 
						|
exit:
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
UINTN
 | 
						|
GetNumberOfQtd (
 | 
						|
  IN EHCI_QTD_ENTITY    *FirstQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Number of Qtds in the list
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  FirstQtdPtr - A pointer to first Qtd in the list
 | 
						|
    
 | 
						|
Returns:
 | 
						|
 | 
						|
  Number of Qtds in the list
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINTN           Count;
 | 
						|
  EHCI_QTD_ENTITY *QtdPtr;
 | 
						|
  Count   = 0;
 | 
						|
  QtdPtr  = FirstQtdPtr;
 | 
						|
 | 
						|
  ;
 | 
						|
 | 
						|
  while (NULL != QtdPtr) {
 | 
						|
    Count++;
 | 
						|
    QtdPtr = QtdPtr->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  return Count;
 | 
						|
}
 | 
						|
 | 
						|
UINTN
 | 
						|
GetNumberOfTransaction (
 | 
						|
  IN UINTN    SizeOfData,
 | 
						|
  IN UINTN    SizeOfTransaction
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Number of Transactions in one Qtd
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  SizeOfData           - Size of one Qtd
 | 
						|
  SizeOfTransaction    - Size of one Transaction
 | 
						|
   
 | 
						|
Returns:
 | 
						|
 | 
						|
  Number of Transactions in this Qtd
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
 | 
						|
  return ((SizeOfData & (SizeOfTransaction - 1)) ? SizeOfData / SizeOfTransaction + 1 : SizeOfData / SizeOfTransaction);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
UINTN
 | 
						|
GetCapacityOfQtd (
 | 
						|
  IN UINT8    *BufferCursor
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Get Size of First Qtd
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  BufferCursor       - BufferCursor of the Qtd
 | 
						|
   
 | 
						|
Returns:
 | 
						|
 | 
						|
  Size of First Qtd
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
 | 
						|
  return (EHCI_MAX_QTD_CAPACITY - (EHCI_BLOCK_SIZE * GetNumberOfTransaction (EFI_PAGE_MASK & GET_0B_TO_31B (BufferCursor), EHCI_BLOCK_SIZE)));
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
UINTN
 | 
						|
GetApproxiOfInterval (
 | 
						|
  IN UINTN  Interval
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Get the approximate value in the 2 index sequence
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Interval  - the value of interval
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  approximate value of interval in the 2 index sequence
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINTN Orignate;
 | 
						|
  UINTN Approxi;
 | 
						|
 | 
						|
  Orignate  = Interval;
 | 
						|
  Approxi   = 1;
 | 
						|
 | 
						|
  while (Orignate != 1 && Orignate != 0) {
 | 
						|
    Orignate  = Orignate >> 1;
 | 
						|
    Approxi   = Approxi << 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Interval & (Approxi >> 1)) {
 | 
						|
    Approxi = Approxi << 1;
 | 
						|
  }
 | 
						|
 | 
						|
  return Approxi;
 | 
						|
}
 | 
						|
 | 
						|
EHCI_QTD_HW *
 | 
						|
GetQtdAlternateNextPointer (
 | 
						|
  IN EHCI_QTD_HW  *HwQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Get Qtd alternate next pointer field
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HwQtdPtr - A pointer to hardware Qtd structure
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  A pointer to hardware alternate Qtd
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_QTD_HW *Value;
 | 
						|
 | 
						|
  Value = NULL;
 | 
						|
 | 
						|
  if (!HwQtdPtr->AltNextQtdTerminate) {
 | 
						|
    Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->AltNextQtdPointer << 5);
 | 
						|
  }
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
EHCI_QTD_HW *
 | 
						|
GetQtdNextPointer (
 | 
						|
  IN EHCI_QTD_HW  *HwQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Get Qtd next pointer field
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HwQtdPtr - A pointer to hardware Qtd structure
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  A pointer to next hardware Qtd structure
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_QTD_HW *Value;
 | 
						|
 | 
						|
  Value = NULL;
 | 
						|
 | 
						|
  if (!HwQtdPtr->NextQtdTerminate) {
 | 
						|
    Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->NextQtdPointer << 5);
 | 
						|
  }
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
VOID LinkQtdToQtd (
 | 
						|
  IN EHCI_QTD_ENTITY * PreQtdPtr, 
 | 
						|
  IN EHCI_QTD_ENTITY * QtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Link Qtds together
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  PreQtdPtr   - A pointer to pre Qtd
 | 
						|
  QtdPtr      - A pointer to next Qtd
 | 
						|
    
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_QTD_HW *QtdHwPtr;
 | 
						|
 | 
						|
  ASSERT(PreQtdPtr);
 | 
						|
  ASSERT(QtdPtr);
 | 
						|
 | 
						|
  //
 | 
						|
  // Software link
 | 
						|
  //
 | 
						|
  PreQtdPtr->Next = QtdPtr;
 | 
						|
  QtdPtr->Prev    = PreQtdPtr;
 | 
						|
 | 
						|
  //
 | 
						|
  // Hardware link
 | 
						|
  //
 | 
						|
  QtdHwPtr                        = &(QtdPtr->Qtd);
 | 
						|
  PreQtdPtr->Qtd.NextQtdPointer   = (UINT32) (GET_0B_TO_31B(QtdHwPtr) >> 5);
 | 
						|
  PreQtdPtr->Qtd.NextQtdTerminate = FALSE;
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
VOID LinkQtdsToAltQtd (
 | 
						|
  IN EHCI_QTD_ENTITY  * FirstQtdPtr, 
 | 
						|
  IN EHCI_QTD_ENTITY  * AltQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Link AlterQtds together
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  FirstQtdPtr  - A pointer to first Qtd in the list
 | 
						|
  AltQtdPtr    - A pointer to alternative Qtd
 | 
						|
    
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_QTD_ENTITY *QtdPtr;
 | 
						|
  EHCI_QTD_HW     *AltQtdHwPtr;
 | 
						|
 | 
						|
  ASSERT(FirstQtdPtr);
 | 
						|
  ASSERT(AltQtdPtr);
 | 
						|
 | 
						|
  AltQtdHwPtr = &(AltQtdPtr->Qtd);
 | 
						|
  QtdPtr      = FirstQtdPtr;
 | 
						|
  
 | 
						|
  while (NULL != QtdPtr) {
 | 
						|
    //
 | 
						|
    // Software link
 | 
						|
    //
 | 
						|
    QtdPtr->AltNext = AltQtdPtr;
 | 
						|
    //
 | 
						|
    // Hardware link
 | 
						|
    //
 | 
						|
    QtdPtr->Qtd.AltNextQtdPointer   = (UINT32) (GET_0B_TO_31B(AltQtdHwPtr) >> 5);
 | 
						|
    QtdPtr->Qtd.AltNextQtdTerminate = FALSE;
 | 
						|
    QtdPtr                          = QtdPtr->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
LinkQtdToQh (
 | 
						|
  IN EHCI_QH_ENTITY      *QhPtr,
 | 
						|
  IN EHCI_QTD_ENTITY     *QtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Link Qtds list to Qh
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  QhPtr    - A pointer to Qh
 | 
						|
  QtdPtr   - A pointer to first Qtd in the list
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_QTD_ENTITY *Cursor;
 | 
						|
  EHCI_QTD_HW     *QtdHwPtr;
 | 
						|
 | 
						|
  ASSERT (QhPtr);
 | 
						|
  ASSERT (QtdPtr);
 | 
						|
 | 
						|
  QhPtr->FirstQtdPtr = QtdPtr;
 | 
						|
  if (NULL != QtdPtr->AltNext) {
 | 
						|
    QhPtr->AltQtdPtr = QtdPtr->AltNext;
 | 
						|
  }
 | 
						|
 | 
						|
  Cursor = QtdPtr;
 | 
						|
  while (NULL != Cursor) {
 | 
						|
    Cursor->SelfQh = QhPtr;
 | 
						|
    if (NULL == Cursor->Next) {
 | 
						|
      QhPtr->LastQtdPtr = Cursor;
 | 
						|
    }
 | 
						|
 | 
						|
    Cursor = Cursor->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  QtdHwPtr                    = &(QtdPtr->Qtd);
 | 
						|
  QhPtr->Qh.NextQtdPointer    = (UINT32) (GET_0B_TO_31B (QtdHwPtr) >> 5);
 | 
						|
  QhPtr->Qh.NextQtdTerminate  = FALSE;
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
LinkQhToAsyncList (
 | 
						|
  IN  USB2_HC_DEV       *HcDev,
 | 
						|
  IN EHCI_QH_ENTITY     *QhPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Link Qh to Async Schedule List
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev  - USB2_HC_DEV 
 | 
						|
  QhPtr  - A pointer to Qh
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS       Success
 | 
						|
  EFI_DEVICE_ERROR  Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  ASSERT (HcDev);
 | 
						|
  ASSERT (QhPtr);
 | 
						|
 | 
						|
  QhPtr->Qh.HeadReclamationFlag = TRUE;
 | 
						|
 | 
						|
  Status                        = SetAsyncListAddr (HcDev, QhPtr);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsAsyncScheduleEnabled (HcDev)) {
 | 
						|
 | 
						|
    Status = EnableAsynchronousSchedule (HcDev);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = WaitForAsyncScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((gEHCDebugLevel, "WaitForAsyncScheduleEnable TimeOut"));
 | 
						|
      Status = EFI_TIMEOUT;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsEhcHalted (HcDev)) {
 | 
						|
      Status = StartScheduleExecution (HcDev);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        Status = EFI_DEVICE_ERROR;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
UnlinkQhFromAsyncList (
 | 
						|
  IN USB2_HC_DEV        *HcDev,
 | 
						|
  IN EHCI_QH_ENTITY     *QhPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Unlink Qh from Async Schedule List
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev  - USB2_HC_DEV 
 | 
						|
  QhPtr  - A pointer to Qh
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS       Success
 | 
						|
  EFI_DEVICE_ERROR  Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  ASSERT (HcDev);
 | 
						|
  ASSERT (QhPtr);
 | 
						|
 | 
						|
  if (QhPtr == QhPtr->Next) {
 | 
						|
 | 
						|
    Status = DisableAsynchronousSchedule (HcDev);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = WaitForAsyncScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((gEHCErrorLevel, "WaitForAsyncScheduleDisable TimeOut\n"));
 | 
						|
      Status = EFI_TIMEOUT;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
LinkQhToPeriodicList (
 | 
						|
  IN USB2_HC_DEV        *HcDev,
 | 
						|
  IN EHCI_QH_ENTITY     *QhPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Link Qh to Periodic Schedule List
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev  - USB2_HC_DEV 
 | 
						|
  QhPtr  - A pointer to Qh
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  FRAME_LIST_ENTRY  *FrameEntryPtr;
 | 
						|
  EHCI_QH_ENTITY    *FindQhPtr;
 | 
						|
  EHCI_QH_HW        *FindQhHwPtr;
 | 
						|
  UINTN             FrameIndex;
 | 
						|
 | 
						|
  ASSERT (HcDev);
 | 
						|
  ASSERT (QhPtr);
 | 
						|
 | 
						|
  FindQhPtr                     = NULL;
 | 
						|
  FindQhHwPtr                   = NULL;
 | 
						|
  FrameIndex                    = 0;
 | 
						|
  FrameEntryPtr                 = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
 | 
						|
 | 
						|
  QhPtr->Qh.HeadReclamationFlag = FALSE;
 | 
						|
 | 
						|
  if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {
 | 
						|
  	
 | 
						|
    //
 | 
						|
    // AsyncInterruptTransfer Qh
 | 
						|
    //
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Link to Frame[0] List
 | 
						|
    //
 | 
						|
    if (!FrameEntryPtr->LinkTerminate) {
 | 
						|
      //
 | 
						|
      // Not Null FrameList
 | 
						|
      //
 | 
						|
      FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);
 | 
						|
      FindQhPtr   = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);
 | 
						|
      //
 | 
						|
      // FindQh is Left/Right to Qh
 | 
						|
      //
 | 
						|
      while ((NULL != FindQhPtr->Next) && (FindQhPtr->Interval > QhPtr->Interval)) {
 | 
						|
        FindQhPtr = FindQhPtr->Next;
 | 
						|
      }
 | 
						|
 | 
						|
      if (FindQhPtr->Interval == QhPtr->Interval) {
 | 
						|
        //
 | 
						|
        // Link Qh after FindQh
 | 
						|
        //
 | 
						|
        if (NULL != FindQhPtr->Next) {
 | 
						|
          FindQhPtr->Next->Prev         = QhPtr;
 | 
						|
          QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Next->Qh) >> 5);
 | 
						|
          QhPtr->Qh.SelectType          = QH_SELECT_TYPE;
 | 
						|
          QhPtr->Qh.QhTerminate         = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
        FindQhPtr->Qh.SelectType          = QH_SELECT_TYPE;
 | 
						|
        FindQhPtr->Qh.QhTerminate         = FALSE;
 | 
						|
 | 
						|
        QhPtr->Prev                       = FindQhPtr;
 | 
						|
        QhPtr->Next                       = FindQhPtr->Next;
 | 
						|
        FindQhPtr->Next                   = QhPtr;
 | 
						|
      } else if (FindQhPtr->Interval < QhPtr->Interval) {
 | 
						|
        //
 | 
						|
        // Link Qh before FindQh
 | 
						|
        //
 | 
						|
        if (NULL == FindQhPtr->Prev) {
 | 
						|
          //
 | 
						|
          // Qh is the First one in Frame[0] List
 | 
						|
          //
 | 
						|
          FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
          FrameEntryPtr->SelectType     = QH_SELECT_TYPE;
 | 
						|
          FrameEntryPtr->LinkTerminate  = FALSE;
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // Qh is not the First one in Frame[0] List
 | 
						|
          //
 | 
						|
          FindQhPtr->Prev->Next                   = QhPtr;
 | 
						|
          FindQhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
          FindQhPtr->Prev->Qh.SelectType          = QH_SELECT_TYPE;
 | 
						|
          FindQhPtr->Prev->Qh.QhTerminate         = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Qh) >> 5);
 | 
						|
        QhPtr->Qh.SelectType          = QH_SELECT_TYPE;
 | 
						|
        QhPtr->Qh.QhTerminate         = FALSE;
 | 
						|
 | 
						|
        QhPtr->Next                   = FindQhPtr;
 | 
						|
        QhPtr->Prev                   = FindQhPtr->Prev;
 | 
						|
        FindQhPtr->Prev               = QhPtr;
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Link Qh after FindQh, Qh is the Last one
 | 
						|
        //
 | 
						|
        FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
        FindQhPtr->Prev->Qh.SelectType    = QH_SELECT_TYPE;
 | 
						|
        FindQhPtr->Qh.QhTerminate         = FALSE;
 | 
						|
 | 
						|
        QhPtr->Prev                       = FindQhPtr;
 | 
						|
        QhPtr->Next                       = NULL;
 | 
						|
        FindQhPtr->Next                   = QhPtr;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Null FrameList
 | 
						|
      //
 | 
						|
      FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
      FrameEntryPtr->SelectType     = QH_SELECT_TYPE;
 | 
						|
      FrameEntryPtr->LinkTerminate  = FALSE;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Other Frame[X]
 | 
						|
    //
 | 
						|
    if (NULL == QhPtr->Prev) {
 | 
						|
      //
 | 
						|
      // Qh is the First one in Frame[0] List
 | 
						|
      //
 | 
						|
      FrameIndex += QhPtr->Interval;
 | 
						|
      while (FrameIndex < HcDev->PeriodicFrameListLength) {
 | 
						|
        FrameEntryPtr                 = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);
 | 
						|
        FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
        FrameEntryPtr->SelectType     = QH_SELECT_TYPE;
 | 
						|
        FrameEntryPtr->LinkTerminate  = FALSE;
 | 
						|
        FrameIndex += QhPtr->Interval;
 | 
						|
      }
 | 
						|
    } else if (QhPtr->Interval < QhPtr->Prev->Interval) {
 | 
						|
      //
 | 
						|
      // Qh is not the First one in Frame[0] List, and Prev.interval > Qh.interval
 | 
						|
      //
 | 
						|
      FrameIndex += QhPtr->Interval;
 | 
						|
      while (FrameIndex < HcDev->PeriodicFrameListLength) {
 | 
						|
        FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);
 | 
						|
        if ((FrameIndex % QhPtr->Prev->Interval) != 0) {
 | 
						|
          FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
          FrameEntryPtr->SelectType     = QH_SELECT_TYPE;
 | 
						|
          FrameEntryPtr->LinkTerminate  = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        FrameIndex += QhPtr->Interval;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
  
 | 
						|
    //
 | 
						|
    // SyncInterruptTransfer Qh
 | 
						|
    //
 | 
						|
    
 | 
						|
    if (!FrameEntryPtr->LinkTerminate) {
 | 
						|
      //
 | 
						|
      // Not Null FrameList
 | 
						|
      //
 | 
						|
      FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);
 | 
						|
      FindQhPtr   = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);
 | 
						|
      //
 | 
						|
      // FindQh is Last Qh in the Asynchronous List, Link Qh after FindQh
 | 
						|
      //
 | 
						|
      while (NULL != FindQhPtr->Next) {
 | 
						|
        FindQhPtr = FindQhPtr->Next;
 | 
						|
      }
 | 
						|
 | 
						|
      FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
      FindQhPtr->Qh.SelectType          = QH_SELECT_TYPE;
 | 
						|
      FindQhPtr->Qh.QhTerminate         = FALSE;
 | 
						|
 | 
						|
      FindQhPtr->Next                   = QhPtr;
 | 
						|
      QhPtr->Prev                       = FindQhPtr;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Null FrameList
 | 
						|
      //
 | 
						|
      FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
 | 
						|
      FrameEntryPtr->SelectType     = QH_SELECT_TYPE;
 | 
						|
      FrameEntryPtr->LinkTerminate  = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
UnlinkQhFromPeriodicList (
 | 
						|
  IN USB2_HC_DEV        *HcDev,
 | 
						|
  IN EHCI_QH_ENTITY     *QhPtr,
 | 
						|
  IN UINTN              Interval
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Unlink Qh from Periodic Schedule List
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev     - USB2_HC_DEV 
 | 
						|
  QhPtr     - A pointer to Qh
 | 
						|
  Interval  - Interval of this periodic transfer
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  FRAME_LIST_ENTRY  *FrameEntryPtr;
 | 
						|
  UINTN             FrameIndex;
 | 
						|
 | 
						|
  FrameIndex = 0;
 | 
						|
 | 
						|
  ASSERT (HcDev);
 | 
						|
  ASSERT (QhPtr);
 | 
						|
 | 
						|
  FrameIndex    = 0;
 | 
						|
  FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
 | 
						|
 | 
						|
  if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {
 | 
						|
  
 | 
						|
    //
 | 
						|
    // AsyncInterruptTransfer Qh
 | 
						|
    //
 | 
						|
    
 | 
						|
    if (NULL == QhPtr->Prev) {
 | 
						|
      //
 | 
						|
      // Qh is the First one on  Frame[0] List
 | 
						|
      //
 | 
						|
      if (NULL == QhPtr->Next) {
 | 
						|
        //
 | 
						|
        // Only one on  Frame[0] List
 | 
						|
        //
 | 
						|
        while (FrameIndex < HcDev->PeriodicFrameListLength) {
 | 
						|
          FrameEntryPtr->LinkPointer    = 0;
 | 
						|
          FrameEntryPtr->SelectType     = 0;
 | 
						|
          FrameEntryPtr->LinkTerminate  = TRUE;
 | 
						|
          FrameEntryPtr                += Interval;
 | 
						|
          FrameIndex                   += Interval;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        while (FrameIndex < HcDev->PeriodicFrameListLength) {
 | 
						|
          FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);
 | 
						|
          FrameEntryPtr->SelectType     = QH_SELECT_TYPE;
 | 
						|
          FrameEntryPtr->LinkTerminate  = FALSE;
 | 
						|
          FrameEntryPtr += Interval;
 | 
						|
          FrameIndex += Interval;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
    
 | 
						|
      //
 | 
						|
      // Not First one on  Frame[0] List
 | 
						|
      //
 | 
						|
      if (NULL == QhPtr->Next) {
 | 
						|
        //
 | 
						|
        // Qh is the Last one on  Frame[0] List
 | 
						|
        //
 | 
						|
        QhPtr->Prev->Qh.QhHorizontalPointer = 0;
 | 
						|
        QhPtr->Prev->Qh.SelectType          = 0;
 | 
						|
        QhPtr->Prev->Qh.QhTerminate         = TRUE;
 | 
						|
      } else {
 | 
						|
        QhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);
 | 
						|
        QhPtr->Prev->Qh.SelectType          = QH_SELECT_TYPE;
 | 
						|
        QhPtr->Prev->Qh.QhTerminate         = FALSE;
 | 
						|
      }
 | 
						|
 | 
						|
      if (Interval == QhPtr->Prev->Interval) {
 | 
						|
        //
 | 
						|
        // Interval is the same as Prev
 | 
						|
        // Not involed Frame[X]
 | 
						|
        //
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Other Frame[X]
 | 
						|
        //
 | 
						|
        while (FrameIndex < HcDev->PeriodicFrameListLength) {
 | 
						|
          if ((FrameIndex % QhPtr->Prev->Interval) != 0) {
 | 
						|
            FrameEntryPtr->LinkPointer    = QhPtr->Prev->Qh.QhHorizontalPointer;
 | 
						|
            FrameEntryPtr->SelectType     = QhPtr->Prev->Qh.SelectType;
 | 
						|
            FrameEntryPtr->LinkTerminate  = QhPtr->Prev->Qh.QhTerminate;
 | 
						|
          }
 | 
						|
          FrameEntryPtr += Interval;
 | 
						|
          FrameIndex += Interval;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (NULL != QhPtr->Next) {
 | 
						|
      QhPtr->Next->Prev = QhPtr->Prev;
 | 
						|
    }
 | 
						|
 | 
						|
    if (NULL != QhPtr->Prev) {
 | 
						|
      QhPtr->Prev->Next = QhPtr->Next;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // SyncInterruptTransfer Qh
 | 
						|
    //
 | 
						|
    if (NULL == QhPtr->Prev) {
 | 
						|
      //
 | 
						|
      // Qh is the only one Qh on  Frame[0] List
 | 
						|
      //
 | 
						|
      FrameEntryPtr->LinkPointer    = 0;
 | 
						|
      FrameEntryPtr->SelectType     = 0;
 | 
						|
      FrameEntryPtr->LinkTerminate  = TRUE;
 | 
						|
    } else {
 | 
						|
      QhPtr->Prev->Qh.QhHorizontalPointer = 0;
 | 
						|
      QhPtr->Prev->Qh.SelectType          = 0;
 | 
						|
      QhPtr->Prev->Qh.QhTerminate         = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (NULL != QhPtr->Prev) {
 | 
						|
      QhPtr->Prev->Next = NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
LinkToAsyncReqeust (
 | 
						|
  IN  USB2_HC_DEV        *HcDev,
 | 
						|
  IN  EHCI_ASYNC_REQUEST *AsyncRequestPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Llink AsyncRequest Entry to Async Request List
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev             - USB2_HC_DEV 
 | 
						|
  AsyncRequestPtr   - A pointer to Async Request Entry
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_ASYNC_REQUEST  *CurrentPtr;
 | 
						|
 | 
						|
  CurrentPtr              = HcDev->AsyncRequestList;
 | 
						|
  HcDev->AsyncRequestList = AsyncRequestPtr;
 | 
						|
  AsyncRequestPtr->Prev   = NULL;
 | 
						|
  AsyncRequestPtr->Next   = CurrentPtr;
 | 
						|
 | 
						|
  if (NULL != CurrentPtr) {
 | 
						|
    CurrentPtr->Prev = AsyncRequestPtr;
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
UnlinkFromAsyncReqeust (
 | 
						|
  IN  USB2_HC_DEV        *HcDev,
 | 
						|
  IN  EHCI_ASYNC_REQUEST *AsyncRequestPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Unlink AsyncRequest Entry from Async Request List
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev            - USB2_HC_DEV 
 | 
						|
  AsyncRequestPtr  - A pointer to Async Request Entry
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  if (NULL == AsyncRequestPtr->Prev) {
 | 
						|
    HcDev->AsyncRequestList = AsyncRequestPtr->Next;
 | 
						|
    if (NULL != AsyncRequestPtr->Next) {
 | 
						|
      AsyncRequestPtr->Next->Prev = NULL;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    AsyncRequestPtr->Prev->Next = AsyncRequestPtr->Next;
 | 
						|
    if (NULL != AsyncRequestPtr->Next) {
 | 
						|
      AsyncRequestPtr->Next->Prev = AsyncRequestPtr->Prev;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
SetQtdBufferPointer (
 | 
						|
  IN EHCI_QTD_HW  *QtdHwPtr,
 | 
						|
  IN VOID         *DataPtr,
 | 
						|
  IN UINTN        DataLen
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Set data buffer pointers in Qtd
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  QtdHwPtr  - A pointer to Qtd hardware structure 
 | 
						|
  DataPtr   - A pointer to user data buffer
 | 
						|
  DataLen   - Length of the user data buffer
 | 
						|
    
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINTN RemainLen;
 | 
						|
 | 
						|
  RemainLen = DataLen;
 | 
						|
  ASSERT (QtdHwPtr);
 | 
						|
 | 
						|
  //
 | 
						|
  // Allow buffer address range across 4G.
 | 
						|
  // But EFI_USB_MAX_BULK_BUFFER_NUM = 1, so don't allow
 | 
						|
  // seperate buffer array.
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Set BufferPointer0, ExtBufferPointer0 and Offset
 | 
						|
  //
 | 
						|
  QtdHwPtr->BufferPointer0    = (UINT32) (GET_0B_TO_31B (DataPtr) >> 12);
 | 
						|
  QtdHwPtr->CurrentOffset     = (UINT32) (GET_0B_TO_31B (DataPtr) & EFI_PAGE_MASK);
 | 
						|
  QtdHwPtr->ExtBufferPointer0 = (UINT32) GET_32B_TO_63B (DataPtr);
 | 
						|
 | 
						|
  //
 | 
						|
  // Set BufferPointer1 and ExtBufferPointer1
 | 
						|
  //
 | 
						|
  RemainLen = RemainLen > (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset) ? (RemainLen - (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset)) : 0;
 | 
						|
  if (RemainLen == 0) {
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  QtdHwPtr->BufferPointer1    = QtdHwPtr->BufferPointer0 + 1;
 | 
						|
  QtdHwPtr->ExtBufferPointer1 = (QtdHwPtr->BufferPointer1 == 0) ? (QtdHwPtr->ExtBufferPointer0 + 1) : QtdHwPtr->ExtBufferPointer0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set BufferPointer2 and ExtBufferPointer2
 | 
						|
  //
 | 
						|
  RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
 | 
						|
  if (RemainLen == 0) {
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  QtdHwPtr->BufferPointer2    = QtdHwPtr->BufferPointer1 + 1;
 | 
						|
  QtdHwPtr->ExtBufferPointer2 = (QtdHwPtr->BufferPointer2 == 0) ? (QtdHwPtr->ExtBufferPointer1 + 1) : QtdHwPtr->ExtBufferPointer1;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set BufferPointer3 and ExtBufferPointer3
 | 
						|
  //
 | 
						|
  RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
 | 
						|
  if (RemainLen == 0) {
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  QtdHwPtr->BufferPointer3    = QtdHwPtr->BufferPointer2 + 1;
 | 
						|
  QtdHwPtr->ExtBufferPointer3 = (QtdHwPtr->BufferPointer2 == 0) ? (QtdHwPtr->ExtBufferPointer2 + 1) : QtdHwPtr->ExtBufferPointer2;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set BufferPointer4 and ExtBufferPointer4
 | 
						|
  //
 | 
						|
  RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
 | 
						|
  if (RemainLen == 0) {
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  QtdHwPtr->BufferPointer4    = QtdHwPtr->BufferPointer3 + 1;
 | 
						|
  QtdHwPtr->ExtBufferPointer4 = (QtdHwPtr->BufferPointer3 == 0) ? (QtdHwPtr->ExtBufferPointer3 + 1) : QtdHwPtr->ExtBufferPointer3;
 | 
						|
 | 
						|
exit:
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsQtdStatusActive (
 | 
						|
  IN EHCI_QTD_HW  *HwQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Whether Qtd status is active or not
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HwQtdPtr - A pointer to hardware Qtd structure
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  TRUE    Active
 | 
						|
  FALSE   Inactive
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8   QtdStatus;
 | 
						|
  BOOLEAN Value;
 | 
						|
 | 
						|
  QtdStatus = (UINT8) (HwQtdPtr->Status);
 | 
						|
  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_ACTIVE);
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsQtdStatusHalted (
 | 
						|
  IN EHCI_QTD_HW  *HwQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Whether Qtd status is halted or not
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HwQtdPtr - A pointer to hardware Qtd structure
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  TRUE    Halted
 | 
						|
  FALSE   Not halted
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8   QtdStatus;
 | 
						|
  BOOLEAN Value;
 | 
						|
 | 
						|
  QtdStatus = (UINT8) (HwQtdPtr->Status);
 | 
						|
  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_HALTED);
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsQtdStatusBufferError (
 | 
						|
  IN EHCI_QTD_HW  *HwQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Whether Qtd status is buffer error or not
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HwQtdPtr - A pointer to hardware Qtd structure
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  TRUE    Buffer error
 | 
						|
  FALSE   No buffer error
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8   QtdStatus;
 | 
						|
  BOOLEAN Value;
 | 
						|
 | 
						|
  QtdStatus = (UINT8) (HwQtdPtr->Status);
 | 
						|
  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_BUFFER_ERR);
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsQtdStatusBabbleError (
 | 
						|
  IN EHCI_QTD_HW  *HwQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Whether Qtd status is babble error or not
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HwQtdPtr - A pointer to hardware Qtd structure
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  TRUE    Babble error
 | 
						|
  FALSE   No babble error
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8   QtdStatus;
 | 
						|
  BOOLEAN Value;
 | 
						|
 | 
						|
  QtdStatus = (UINT8) (HwQtdPtr->Status);
 | 
						|
  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_BABBLE_ERR);
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsQtdStatusTransactionError (
 | 
						|
  IN EHCI_QTD_HW  *HwQtdPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Whether Qtd status is transaction error or not
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HwQtdPtr - A pointer to hardware Qtd structure
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  TRUE    Transaction error
 | 
						|
  FALSE   No transaction error
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8   QtdStatus;
 | 
						|
  BOOLEAN Value;
 | 
						|
 | 
						|
  QtdStatus = (UINT8) (HwQtdPtr->Status);
 | 
						|
  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_TRANSACTION_ERR);
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
IsDataInTransfer (
 | 
						|
  IN UINT8     EndPointAddress
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Whether is a DataIn direction transfer
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  EndPointAddress - address of the endpoint 
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  TRUE    DataIn
 | 
						|
  FALSE   DataOut
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  BOOLEAN Value;
 | 
						|
 | 
						|
  if (EndPointAddress & 0x80) {
 | 
						|
    Value = TRUE;
 | 
						|
  } else {
 | 
						|
    Value = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
MapDataBuffer (
 | 
						|
  IN  USB2_HC_DEV             *HcDev,
 | 
						|
  IN  EFI_USB_DATA_DIRECTION  TransferDirection,
 | 
						|
  IN  VOID                    *Data,
 | 
						|
  IN  OUT UINTN               *DataLength,
 | 
						|
  OUT UINT8                   *PktId,
 | 
						|
  OUT UINT8                   **DataCursor,
 | 
						|
  OUT VOID                    **DataMap
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Map address of user data buffer
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev              - USB2_HC_DEV 
 | 
						|
  TransferDirection  - direction of transfer
 | 
						|
  Data               - A pointer to user data buffer 
 | 
						|
  DataLength         - length of user data
 | 
						|
  PktId              - Packte Identificaion
 | 
						|
  DataCursor         - mapped address to return
 | 
						|
  DataMap            - identificaion of this mapping to return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  EFI_PHYSICAL_ADDRESS  TempPhysicalAddr;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  switch (TransferDirection) {
 | 
						|
 | 
						|
  case EfiUsbDataIn:
 | 
						|
 | 
						|
    *PktId = INPUT_PACKET_ID;
 | 
						|
    //
 | 
						|
    // BusMasterWrite means cpu read
 | 
						|
    //
 | 
						|
    Status = HcDev->PciIo->Map (
 | 
						|
                            HcDev->PciIo,
 | 
						|
                            EfiPciIoOperationBusMasterWrite,
 | 
						|
                            Data,
 | 
						|
                            DataLength,
 | 
						|
                            &TempPhysicalAddr,
 | 
						|
                            DataMap
 | 
						|
                            );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((gEHCDebugLevel, "MapDataBuffer Failed\n"));
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiUsbDataOut:
 | 
						|
 | 
						|
    *PktId = OUTPUT_PACKET_ID;
 | 
						|
    //
 | 
						|
    // BusMasterRead means cpu write
 | 
						|
    //
 | 
						|
    Status = HcDev->PciIo->Map (
 | 
						|
                            HcDev->PciIo,
 | 
						|
                            EfiPciIoOperationBusMasterRead,
 | 
						|
                            Data,
 | 
						|
                            DataLength,
 | 
						|
                            &TempPhysicalAddr,
 | 
						|
                            DataMap
 | 
						|
                            );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiUsbNoData:
 | 
						|
 | 
						|
    *PktId      = OUTPUT_PACKET_ID;
 | 
						|
    Data        = NULL;
 | 
						|
    *DataLength = 0;
 | 
						|
    *DataCursor = NULL;
 | 
						|
    *DataMap    = NULL;
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
  	
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
MapRequestBuffer (
 | 
						|
  IN  USB2_HC_DEV             *HcDev,
 | 
						|
  IN  OUT VOID                *Request,
 | 
						|
  OUT UINT8                   **RequestCursor,
 | 
						|
  OUT VOID                    **RequestMap
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Map address of request structure buffer
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev           - USB2_HC_DEV 
 | 
						|
  Request         - A pointer to request structure
 | 
						|
  RequestCursor   - Mapped address of request structure to return
 | 
						|
  RequestMap      - Identificaion of this mapping to return
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINTN                 RequestLen;
 | 
						|
  EFI_PHYSICAL_ADDRESS  TempPhysicalAddr;
 | 
						|
 | 
						|
  RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);
 | 
						|
  Status = HcDev->PciIo->Map (
 | 
						|
                           HcDev->PciIo,
 | 
						|
                           EfiPciIoOperationBusMasterRead,
 | 
						|
                           (UINT8 *) Request,
 | 
						|
                           (UINTN *) &RequestLen,
 | 
						|
                           &TempPhysicalAddr,
 | 
						|
                           RequestMap
 | 
						|
                           );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  *RequestCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
DeleteAsyncRequestTransfer (
 | 
						|
  IN  USB2_HC_DEV     *HcDev,
 | 
						|
  IN  UINT8           DeviceAddress,
 | 
						|
  IN  UINT8           EndPointAddress,
 | 
						|
  OUT UINT8           *DataToggle
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Delete all asynchronous request transfer
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev           - USB2_HC_DEV 
 | 
						|
  DeviceAddress   - address of usb device
 | 
						|
  EndPointAddress - address of endpoint
 | 
						|
  DataToggle      - stored data toggle
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  EHCI_ASYNC_REQUEST  *AsyncRequestPtr;
 | 
						|
  EHCI_ASYNC_REQUEST  *MatchPtr;
 | 
						|
  EHCI_QH_HW          *QhHwPtr;
 | 
						|
  UINT8               EndPointNum;
 | 
						|
 | 
						|
  if (NULL == HcDev->AsyncRequestList) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  MatchPtr        = NULL;
 | 
						|
  QhHwPtr         = NULL;
 | 
						|
  EndPointNum     = EndPointAddress & 0x0f;
 | 
						|
  AsyncRequestPtr = HcDev->AsyncRequestList;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find QH of AsyncRequest by DeviceAddress and EndPointNum
 | 
						|
  //
 | 
						|
  do {
 | 
						|
 | 
						|
    QhHwPtr = &(AsyncRequestPtr->QhPtr->Qh);
 | 
						|
    if (QhHwPtr->DeviceAddr == DeviceAddress && QhHwPtr->EndpointNum == EndPointNum) {
 | 
						|
      MatchPtr = AsyncRequestPtr;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    AsyncRequestPtr = AsyncRequestPtr->Next;
 | 
						|
 | 
						|
  } while (NULL != AsyncRequestPtr);
 | 
						|
 | 
						|
  if (NULL == MatchPtr) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = DisablePeriodicSchedule (HcDev);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleDisable TimeOut\n"));
 | 
						|
    Status = EFI_TIMEOUT;
 | 
						|
    goto exit;
 | 
						|
  }
 | 
						|
 | 
						|
  *DataToggle = (UINT8) MatchPtr->QhPtr->Qh.DataToggle;
 | 
						|
  UnlinkQhFromPeriodicList (HcDev, MatchPtr->QhPtr, MatchPtr->QhPtr->Interval);
 | 
						|
  UnlinkFromAsyncReqeust (HcDev, MatchPtr);
 | 
						|
 | 
						|
  if (NULL == HcDev->AsyncRequestList) {
 | 
						|
 | 
						|
    Status = StopPollingTimer (HcDev);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
 | 
						|
    Status = EnablePeriodicSchedule (HcDev);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleEnable TimeOut\n"));
 | 
						|
      Status = EFI_TIMEOUT;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsEhcHalted (HcDev)) {
 | 
						|
      Status = StartScheduleExecution (HcDev);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        Status = EFI_DEVICE_ERROR;
 | 
						|
        goto exit;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  DestoryQtds (HcDev, MatchPtr->QhPtr->FirstQtdPtr);
 | 
						|
  DestoryQh (HcDev, MatchPtr->QhPtr);
 | 
						|
  EhciFreePool (HcDev, (UINT8 *) MatchPtr, sizeof (EHCI_ASYNC_REQUEST));
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
CleanUpAllAsyncRequestTransfer (
 | 
						|
  IN USB2_HC_DEV  *HcDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Clean up all asynchronous request transfer
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev - USB2_HC_DEV 
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_ASYNC_REQUEST  *AsyncRequestPtr;
 | 
						|
  EHCI_ASYNC_REQUEST  *FreePtr;
 | 
						|
 | 
						|
  AsyncRequestPtr = NULL;
 | 
						|
  FreePtr         = NULL;
 | 
						|
 | 
						|
  StopPollingTimer (HcDev);
 | 
						|
 | 
						|
  AsyncRequestPtr = HcDev->AsyncRequestList;
 | 
						|
  while (NULL != AsyncRequestPtr) {
 | 
						|
 | 
						|
    FreePtr         = AsyncRequestPtr;
 | 
						|
    AsyncRequestPtr = AsyncRequestPtr->Next;
 | 
						|
    UnlinkFromAsyncReqeust (HcDev, FreePtr);
 | 
						|
    UnlinkQhFromPeriodicList (HcDev, FreePtr->QhPtr, FreePtr->QhPtr->Interval);
 | 
						|
    DestoryQtds (HcDev, FreePtr->QhPtr->FirstQtdPtr);
 | 
						|
    DestoryQh (HcDev, FreePtr->QhPtr);
 | 
						|
    EhciFreePool (HcDev, (UINT8 *) FreePtr, sizeof (EHCI_ASYNC_REQUEST));
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
ZeroOutQhOverlay (
 | 
						|
  IN EHCI_QH_ENTITY  *QhPtr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Zero out the fields in Qh structure
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  QhPtr - A pointer to Qh structure
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  QhPtr->Qh.CurrentQtdPointer   = 0;
 | 
						|
  QhPtr->Qh.AltNextQtdPointer   = 0;
 | 
						|
  QhPtr->Qh.NakCount            = 0;
 | 
						|
  QhPtr->Qh.AltNextQtdTerminate = 0;
 | 
						|
  QhPtr->Qh.TotalBytes          = 0;
 | 
						|
  QhPtr->Qh.InterruptOnComplete = 0;
 | 
						|
  QhPtr->Qh.CurrentPage         = 0;
 | 
						|
  QhPtr->Qh.ErrorCount          = 0;
 | 
						|
  QhPtr->Qh.PidCode             = 0;
 | 
						|
  QhPtr->Qh.Status              = 0;
 | 
						|
  QhPtr->Qh.BufferPointer0      = 0;
 | 
						|
  QhPtr->Qh.CurrentOffset       = 0;
 | 
						|
  QhPtr->Qh.BufferPointer1      = 0;
 | 
						|
  QhPtr->Qh.CompleteSplitMask   = 0;
 | 
						|
  QhPtr->Qh.BufferPointer2      = 0;
 | 
						|
  QhPtr->Qh.SplitBytes          = 0;
 | 
						|
  QhPtr->Qh.FrameTag            = 0;
 | 
						|
  QhPtr->Qh.BufferPointer3      = 0;
 | 
						|
  QhPtr->Qh.BufferPointer4      = 0;
 | 
						|
  QhPtr->Qh.ExtBufferPointer0   = 0;
 | 
						|
  QhPtr->Qh.ExtBufferPointer1   = 0;
 | 
						|
  QhPtr->Qh.ExtBufferPointer2   = 0;
 | 
						|
  QhPtr->Qh.ExtBufferPointer3   = 0;
 | 
						|
  QhPtr->Qh.ExtBufferPointer4   = 0;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
UpdateAsyncRequestTransfer (
 | 
						|
  IN EHCI_ASYNC_REQUEST *AsyncRequestPtr,
 | 
						|
  IN UINT32             TransferResult,
 | 
						|
  IN UINTN              ErrQtdPos
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Update asynchronous request transfer
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
  AsyncRequestPtr  - A pointer to async request  
 | 
						|
  TransferResult   - transfer result 
 | 
						|
  ErrQtdPos        - postion of error Qtd
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EHCI_QTD_ENTITY *QtdPtr;
 | 
						|
 | 
						|
  QtdPtr      = NULL;
 | 
						|
 | 
						|
  if (EFI_USB_NOERROR == TransferResult) {
 | 
						|
  
 | 
						|
    //
 | 
						|
    // Update Qh for next trigger
 | 
						|
    //
 | 
						|
 | 
						|
    QtdPtr = AsyncRequestPtr->QhPtr->FirstQtdPtr;
 | 
						|
 | 
						|
    //
 | 
						|
    // Update fields in Qh
 | 
						|
    //
 | 
						|
 | 
						|
    //
 | 
						|
    // Get DataToggle from Overlay in Qh
 | 
						|
    //
 | 
						|
    // ZeroOut Overlay in Qh except DataToggle, HostController will update this field
 | 
						|
    //
 | 
						|
    ZeroOutQhOverlay (AsyncRequestPtr->QhPtr);
 | 
						|
    AsyncRequestPtr->QhPtr->Qh.NextQtdPointer   = (UINT32) (GET_0B_TO_31B (&(QtdPtr->Qtd)) >> 5);
 | 
						|
    AsyncRequestPtr->QhPtr->Qh.NextQtdTerminate = FALSE;
 | 
						|
 | 
						|
    //
 | 
						|
    // Update fields in Qtd
 | 
						|
    //
 | 
						|
    while (NULL != QtdPtr) {
 | 
						|
      QtdPtr->Qtd.TotalBytes    = QtdPtr->StaticTotalBytes;
 | 
						|
      QtdPtr->Qtd.CurrentOffset = QtdPtr->StaticCurrentOffset;
 | 
						|
      QtdPtr->Qtd.CurrentPage   = 0;
 | 
						|
      QtdPtr->Qtd.ErrorCount    = QTD_ERROR_COUNTER;
 | 
						|
      QtdPtr->Qtd.Status        = QTD_STATUS_ACTIVE;
 | 
						|
 | 
						|
      QtdPtr->TotalBytes        = QtdPtr->StaticTotalBytes;
 | 
						|
      QtdPtr                    = QtdPtr->Next;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
CheckQtdsTransferResult (
 | 
						|
  IN  BOOLEAN            IsControl,
 | 
						|
  IN  EHCI_QH_ENTITY     *QhPtr,
 | 
						|
  OUT UINT32             *Result,
 | 
						|
  OUT UINTN              *ErrQtdPos,
 | 
						|
  OUT UINTN              *ActualLen
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Check transfer result of Qtds
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  IsControl    - Is control transfer or not
 | 
						|
  QhPtr        - A pointer to Qh
 | 
						|
  Result       - Transfer result
 | 
						|
  ErrQtdPos    - Error TD Position
 | 
						|
  ActualLen    - Actual Transfer Size
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  TRUE    Qtds finished
 | 
						|
  FALSE   Not finish
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINTN           ActualLenPerQtd;
 | 
						|
  EHCI_QTD_ENTITY *QtdPtr;
 | 
						|
  EHCI_QTD_HW     *QtdHwPtr;
 | 
						|
  BOOLEAN         Value;
 | 
						|
 | 
						|
  ASSERT (QhPtr);
 | 
						|
  ASSERT (Result);
 | 
						|
  ASSERT (ErrQtdPos);
 | 
						|
  ASSERT (ActualLen);
 | 
						|
 | 
						|
  Value     = TRUE;
 | 
						|
  QtdPtr    = QhPtr->FirstQtdPtr;
 | 
						|
  QtdHwPtr  = &(QtdPtr->Qtd);
 | 
						|
 | 
						|
  while (NULL != QtdHwPtr) {
 | 
						|
 | 
						|
    if (IsQtdStatusActive (QtdHwPtr)) {
 | 
						|
      *Result |= EFI_USB_ERR_NOTEXECUTE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsQtdStatusHalted (QtdHwPtr)) {
 | 
						|
      *Result |= EFI_USB_ERR_STALL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsQtdStatusBufferError (QtdHwPtr)) {
 | 
						|
      *Result |= EFI_USB_ERR_BUFFER;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsQtdStatusBabbleError (QtdHwPtr)) {
 | 
						|
      *Result |= EFI_USB_ERR_BABBLE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsQtdStatusTransactionError (QtdHwPtr)) {
 | 
						|
      *Result |= EFI_USB_ERR_TIMEOUT;
 | 
						|
    }
 | 
						|
 | 
						|
    ActualLenPerQtd     = QtdPtr->TotalBytes - QtdHwPtr->TotalBytes;
 | 
						|
    QtdPtr->TotalBytes  = QtdHwPtr->TotalBytes;
 | 
						|
    //
 | 
						|
    // Accumulate actual transferred data length in each DataQtd.
 | 
						|
 | 
						|
    //
 | 
						|
    if (SETUP_PACKET_PID_CODE != QtdHwPtr->PidCode) {
 | 
						|
      *ActualLen += ActualLenPerQtd;
 | 
						|
    }
 | 
						|
 | 
						|
    if (*Result) {
 | 
						|
      Value = FALSE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((!IsControl) && (QtdPtr->TotalBytes > 0)) {
 | 
						|
      //
 | 
						|
      // Did something, but isn't full workload
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    (*ErrQtdPos)++;
 | 
						|
    QtdPtr   = QtdPtr->Next;
 | 
						|
    QtdHwPtr = &(QtdPtr->Qtd);
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return Value;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
ExecuteTransfer (
 | 
						|
  IN  USB2_HC_DEV         *HcDev,
 | 
						|
  IN  BOOLEAN             IsControl,
 | 
						|
  IN  EHCI_QH_ENTITY      *QhPtr,
 | 
						|
  IN  OUT UINTN           *ActualLen,
 | 
						|
  OUT UINT8               *DataToggle,
 | 
						|
  IN  UINTN               TimeOut,
 | 
						|
  OUT UINT32              *TransferResult
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Execute Bulk or SyncInterrupt Transfer
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  HcDev            - USB2_HC_DEV
 | 
						|
  IsControl        - Is control transfer or not
 | 
						|
  QhPtr            - A pointer to Qh
 | 
						|
  ActualLen        - Actual transfered Len 
 | 
						|
  DataToggle       - Data Toggle
 | 
						|
  TimeOut          - TimeOut threshold
 | 
						|
  TransferResult   - Transfer result
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS      Sucess
 | 
						|
  EFI_DEVICE_ERROR Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINTN       ErrQtdPos;
 | 
						|
  UINTN       Delay;
 | 
						|
  UINTN       RequireLen;
 | 
						|
  BOOLEAN     Finished;
 | 
						|
 | 
						|
  Status          = EFI_SUCCESS;
 | 
						|
  ErrQtdPos       = 0;
 | 
						|
  *TransferResult = EFI_USB_NOERROR;
 | 
						|
  RequireLen      = *ActualLen;
 | 
						|
  *ActualLen      = 0;
 | 
						|
  Finished        = FALSE;
 | 
						|
 | 
						|
  Delay           = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;
 | 
						|
 | 
						|
  do {
 | 
						|
    *TransferResult = 0;
 | 
						|
    Finished = CheckQtdsTransferResult (
 | 
						|
                 IsControl,
 | 
						|
                 QhPtr,
 | 
						|
                 TransferResult,
 | 
						|
                 &ErrQtdPos,
 | 
						|
                 ActualLen
 | 
						|
                 );
 | 
						|
    if (Finished) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Qtd is inactive, which means bulk or interrupt transfer's end.
 | 
						|
    //
 | 
						|
    if (!(*TransferResult & EFI_USB_ERR_NOTEXECUTE)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->Stall (EHCI_SYNC_REQUEST_POLLING_TIME);
 | 
						|
 | 
						|
  } while (--Delay);
 | 
						|
 | 
						|
  if (EFI_USB_NOERROR != *TransferResult) {
 | 
						|
    if (0 == Delay) {
 | 
						|
      Status = EFI_TIMEOUT;
 | 
						|
    } else {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Special for Bulk and Interrupt Transfer
 | 
						|
  //
 | 
						|
  *DataToggle = (UINT8) QhPtr->Qh.DataToggle;
 | 
						|
  
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
AsyncRequestMoniter (
 | 
						|
  IN EFI_EVENT     Event,
 | 
						|
  IN VOID          *Context
 | 
						|
  )
 | 
						|
/*++
 | 
						|
Routine Description:
 | 
						|
  
 | 
						|
  Interrupt transfer periodic check handler
 | 
						|
    
 | 
						|
Arguments:
 | 
						|
  Event    - Interrupt event
 | 
						|
  Context  - Pointer to USB2_HC_DEV
 | 
						|
    
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS        Success
 | 
						|
  EFI_DEVICE_ERROR   Fail
 | 
						|
  
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  USB2_HC_DEV         *HcDev;
 | 
						|
  EHCI_ASYNC_REQUEST  *AsyncRequestPtr;
 | 
						|
  EHCI_QTD_HW         *QtdHwPtr;
 | 
						|
  UINTN               ErrQtdPos;
 | 
						|
  UINTN               ActualLen;
 | 
						|
  UINT32              TransferResult;
 | 
						|
  UINT8               *ReceiveBuffer;
 | 
						|
  UINT8               *ProcessBuffer;
 | 
						|
 | 
						|
  Status          = EFI_SUCCESS;
 | 
						|
  QtdHwPtr        = NULL;
 | 
						|
  ReceiveBuffer   = NULL;
 | 
						|
  ProcessBuffer   = NULL;
 | 
						|
  HcDev           = (USB2_HC_DEV *) Context;
 | 
						|
  AsyncRequestPtr = HcDev->AsyncRequestList;
 | 
						|
 | 
						|
  while (NULL != AsyncRequestPtr) {
 | 
						|
 | 
						|
    TransferResult  = 0;
 | 
						|
    ErrQtdPos       = 0;
 | 
						|
    ActualLen       = 0;
 | 
						|
 | 
						|
    CheckQtdsTransferResult (
 | 
						|
      FALSE, 
 | 
						|
      AsyncRequestPtr->QhPtr, 
 | 
						|
      &TransferResult, 
 | 
						|
      &ErrQtdPos, 
 | 
						|
      &ActualLen
 | 
						|
      );
 | 
						|
 | 
						|
    if ((TransferResult & EFI_USB_ERR_NAK) || (TransferResult & EFI_USB_ERR_NOTEXECUTE)) {
 | 
						|
      AsyncRequestPtr = AsyncRequestPtr->Next;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Allocate memory for EHC private data structure
 | 
						|
    //
 | 
						|
    ProcessBuffer = AllocateZeroPool (ActualLen);
 | 
						|
    if (NULL == ProcessBuffer) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto exit;
 | 
						|
    }
 | 
						|
 | 
						|
    QtdHwPtr = &(AsyncRequestPtr->QhPtr->FirstQtdPtr->Qtd);
 | 
						|
    ReceiveBuffer = (UINT8 *) GET_0B_TO_31B ((QtdHwPtr->BufferPointer0 << 12) | AsyncRequestPtr->QhPtr->FirstQtdPtr->StaticCurrentOffset);
 | 
						|
    CopyMem (
 | 
						|
      ProcessBuffer,
 | 
						|
      ReceiveBuffer,
 | 
						|
      ActualLen
 | 
						|
      );
 | 
						|
 | 
						|
    UpdateAsyncRequestTransfer (AsyncRequestPtr, TransferResult, ErrQtdPos);
 | 
						|
 | 
						|
    if (EFI_USB_NOERROR == TransferResult) {
 | 
						|
 | 
						|
      if (AsyncRequestPtr->CallBackFunc != NULL) {
 | 
						|
        (AsyncRequestPtr->CallBackFunc) (ProcessBuffer, ActualLen, AsyncRequestPtr->Context, TransferResult);
 | 
						|
      }
 | 
						|
 | 
						|
    } else {
 | 
						|
 | 
						|
      //
 | 
						|
      // 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 (AsyncRequestPtr->CallBackFunc != NULL) {
 | 
						|
        (AsyncRequestPtr->CallBackFunc) (NULL, 0, AsyncRequestPtr->Context, TransferResult);
 | 
						|
      }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    if (NULL != ProcessBuffer) {
 | 
						|
      gBS->FreePool (ProcessBuffer);
 | 
						|
    }
 | 
						|
 | 
						|
    AsyncRequestPtr = AsyncRequestPtr->Next;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
exit:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 |