git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1117 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			3073 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3073 lines
		
	
	
		
			68 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
 | |
|   //
 | |
|   gBS->SetMem (*QhPtrPtr, sizeof (EHCI_QH_ENTITY), 0);
 | |
| 
 | |
|   //
 | |
|   // 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
 | |
|   //
 | |
|   gBS->SetMem (*QtdPtrPtr, sizeof (EHCI_QTD_ENTITY), 0);
 | |
| 
 | |
|   //
 | |
|   // 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 *) (UINTN) 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 *) (UINTN) 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 *) (UINTN) 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 (((UINTN) &(FindQhPtr->Next->Qh)) >> 5);
 | |
|           QhPtr->Qh.SelectType          = QH_SELECT_TYPE;
 | |
|           QhPtr->Qh.QhTerminate         = FALSE;
 | |
|         }
 | |
| 
 | |
|         FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN)&(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 (((UINTN) &(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 (((UINTN) &(QhPtr->Qh)) >> 5);
 | |
|           FindQhPtr->Prev->Qh.SelectType          = QH_SELECT_TYPE;
 | |
|           FindQhPtr->Prev->Qh.QhTerminate         = FALSE;
 | |
|         }
 | |
| 
 | |
|         QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(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 (((UINTN) &(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 (((UINTN) &(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 (((UINTN) &(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 (((UINTN) &(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 *) (UINTN) 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 (((UINTN) &(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 (((UINTN) &(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 (((UINTN) &(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 (((UINTN) &(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);
 | |
| 
 | |
|   //
 | |
|   // 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->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->ExtBufferPointer0;
 | |
| 
 | |
|   //
 | |
|   // 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->ExtBufferPointer0;
 | |
| 
 | |
|   //
 | |
|   // 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->ExtBufferPointer0;
 | |
| 
 | |
| 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)++;
 | |
|     QtdHwPtr = GetQtdNextPointer (QtdHwPtr);
 | |
|     QtdPtr = (EHCI_QTD_ENTITY *) GET_QTD_ENTITY_ADDR (QtdHwPtr);
 | |
| 
 | |
|   }
 | |
| 
 | |
|   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 *) (UINTN) 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;
 | |
| }
 | |
| 
 |