]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c
Add DevicePathUtilities DevicePathToText DevciePathFromText USB2HostController protocols
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Ehci / Dxe / EhciSched.c
diff --git a/EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c b/EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c
new file mode 100644 (file)
index 0000000..3dc1ff7
--- /dev/null
@@ -0,0 +1,3072 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation                                                     \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+    EhciSched.c\r
+    \r
+Abstract: \r
+    \r
+\r
+Revision History\r
+--*/\r
+\r
+#include "Ehci.h"\r
+\r
+EFI_STATUS\r
+InitialPeriodicFrameList (\r
+  IN  USB2_HC_DEV     *HcDev,\r
+  IN  UINTN           Length\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize Periodic Schedule Frame List\r
+\r
+Arguments:\r
+\r
+  HcDev   - USB2_HC_DEV\r
+  Length  - Frame List Length\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  VOID                  *CommonBuffer;\r
+  EFI_PHYSICAL_ADDRESS  FrameBuffer;\r
+  VOID                  *Map;\r
+  UINTN                 BufferSizeInPages;\r
+  UINTN                 BufferSizeInBytes;\r
+  UINTN                 FrameIndex;\r
+  FRAME_LIST_ENTRY      *FrameEntryPtr;\r
+  \r
+  //\r
+  // The Frame List is a common buffer that will be\r
+  // accessed by both the cpu and the usb bus master\r
+  // at the same time.\r
+  // The Frame List ocupies 4K bytes,\r
+  // and must be aligned on 4-Kbyte boundaries.\r
+  //\r
+  if (EHCI_MAX_FRAME_LIST_LENGTH != Length && IsFrameListProgrammable (HcDev)) {\r
+    Status = SetFrameListLen (HcDev, Length);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto exit;\r
+    }\r
+  }\r
+\r
+  BufferSizeInBytes = EFI_PAGE_SIZE;\r
+  BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);\r
+  Status = HcDev->PciIo->AllocateBuffer (\r
+                          HcDev->PciIo,\r
+                          AllocateAnyPages,\r
+                          EfiBootServicesData,\r
+                          BufferSizeInPages,\r
+                          &CommonBuffer,\r
+                          0\r
+                          );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((gEHCErrorLevel, "PciIo->AllocateBuffer Failed\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto exit;\r
+  }\r
+\r
+  Status = HcDev->PciIo->Map (\r
+                          HcDev->PciIo,\r
+                          EfiPciIoOperationBusMasterCommonBuffer,\r
+                          CommonBuffer,\r
+                          &BufferSizeInBytes,\r
+                          &FrameBuffer,\r
+                          &Map\r
+                          );\r
+  if (EFI_ERROR (Status) || (BufferSizeInBytes != EFI_PAGE_SIZE)) {\r
+    DEBUG ((gEHCErrorLevel, "PciIo->MapBuffer Failed\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto free_buffer;\r
+  }\r
+\r
+  //\r
+  // Put high 32bit into CtrlDataStructSeg reg \r
+  // when 64bit addressing range capability\r
+  //\r
+  if (HcDev->Is64BitCapable != 0) {\r
+       HcDev->High32BitAddr = (UINT32) GET_32B_TO_63B (FrameBuffer);\r
+       \r
+       Status = SetCtrlDataStructSeg (HcDev);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((gEHCErrorLevel, "SetCtrlDataStructSeg Failed\n"));\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto unmap_buffer;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Tell the Host Controller where the Frame List lies,\r
+  // by set the Frame List Base Address Register.\r
+  //\r
+  Status = SetFrameListBaseAddr (HcDev, (UINT32) FrameBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto unmap_buffer;\r
+  }\r
+\r
+  HcDev->PeriodicFrameListLength  = Length;\r
+  HcDev->PeriodicFrameListBuffer  = (VOID *) ((UINTN) FrameBuffer);\r
+  HcDev->PeriodicFrameListMap     = Map;\r
+\r
+  //\r
+  // Init Frame List Array fields\r
+  //\r
+  FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
+  for (FrameIndex = 0; FrameIndex < HcDev->PeriodicFrameListLength; FrameIndex++) {\r
+    FrameEntryPtr->LinkPointer    = 0;\r
+    FrameEntryPtr->Rsvd           = 0;\r
+    FrameEntryPtr->SelectType     = 0;\r
+    FrameEntryPtr->LinkTerminate  = TRUE;\r
+    FrameEntryPtr++;\r
+  }\r
+\r
+  goto exit;\r
+\r
+unmap_buffer:\r
+  HcDev->PciIo->Unmap (HcDev->PciIo, Map);\r
+free_buffer:\r
+  HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);\r
+exit:\r
+  return Status;\r
+}\r
+\r
+VOID\r
+DeinitialPeriodicFrameList (\r
+  IN  USB2_HC_DEV     *HcDev\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Deinitialize Periodic Schedule Frame List\r
+\r
+Arguments:\r
+\r
+  HcDev - USB2_HC_DEV\r
+\r
+Returns:\r
+\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->PeriodicFrameListMap);\r
+  HcDev->PciIo->FreeBuffer (HcDev->PciIo, EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE), HcDev->PeriodicFrameListBuffer);\r
+  return ;\r
+}\r
+\r
+EFI_STATUS\r
+CreatePollingTimer (\r
+  IN  USB2_HC_DEV      *HcDev,\r
+  IN  EFI_EVENT_NOTIFY NotifyFunction\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Async Request Polling Timer\r
+\r
+Arguments:\r
+\r
+  HcDev          - USB2_HC_DEV\r
+  NotifyFunction - Timer Notify Function\r
+  \r
+Returns:\r
+  \r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+  \r
+--*/\r
+{\r
+  return gBS->CreateEvent (\r
+                EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,\r
+                EFI_TPL_NOTIFY,\r
+                NotifyFunction,\r
+                HcDev,\r
+                &HcDev->AsyncRequestEvent\r
+                );\r
+}\r
+\r
+EFI_STATUS\r
+DestoryPollingTimer (\r
+  IN  USB2_HC_DEV *HcDev\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destory Async Request Polling Timer\r
+\r
+Arguments:\r
+\r
+  HcDev - USB2_HC_DEV\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+  \r
+--*/\r
+{\r
+  return gBS->CloseEvent (HcDev->AsyncRequestEvent);\r
+}\r
+\r
+EFI_STATUS\r
+StartPollingTimer (\r
+  IN  USB2_HC_DEV *HcDev\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Start Async Request Polling Timer\r
+\r
+Arguments:\r
+\r
+  HcDev - USB2_HC_DEV\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+  \r
+--*/\r
+{\r
+  return gBS->SetTimer (\r
+                HcDev->AsyncRequestEvent,\r
+                TimerPeriodic,\r
+                EHCI_ASYNC_REQUEST_POLLING_TIME\r
+                );\r
+}\r
+\r
+EFI_STATUS\r
+StopPollingTimer (\r
+  IN  USB2_HC_DEV *HcDev\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Stop Async Request Polling Timer\r
+\r
+Arguments:\r
+\r
+  HcDev - USB2_HC_DEV\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+  \r
+--*/\r
+{\r
+  return gBS->SetTimer (\r
+                HcDev->AsyncRequestEvent,\r
+                TimerCancel,\r
+                EHCI_ASYNC_REQUEST_POLLING_TIME\r
+                );\r
+}\r
+\r
+EFI_STATUS\r
+CreateQh (\r
+  IN  USB2_HC_DEV         *HcDev,\r
+  IN  UINT8               DeviceAddr,\r
+  IN  UINT8               Endpoint,\r
+  IN  UINT8               DeviceSpeed,\r
+  IN  UINTN               MaxPacketLen,\r
+  OUT EHCI_QH_ENTITY      **QhPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qh Structure and Pre-Initialize\r
+\r
+Arguments:\r
+\r
+  HcDev        - USB2_HC_DEV \r
+  DeviceAddr   - Address of Device\r
+  Endpoint     - Endpoint Number\r
+  DeviceSpeed  - Device Speed\r
+  MaxPacketLen - Max Length of one Packet\r
+  QhPtrPtr     - A pointer of pointer to Qh for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  EHCI_QH_HW  *QhHwPtr;\r
+\r
+  ASSERT (HcDev);\r
+  ASSERT (QhPtrPtr);\r
+\r
+  *QhPtrPtr = NULL;\r
+\r
+  //\r
+  // Allocate  memory for Qh structure\r
+  //\r
+  Status = EhciAllocatePool (\r
+             HcDev,\r
+             (UINT8 **) QhPtrPtr,\r
+             sizeof (EHCI_QH_ENTITY)\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto exit;\r
+  }\r
+  //\r
+  // Init fields in Qh\r
+  //\r
+  gBS->SetMem (*QhPtrPtr, sizeof (EHCI_QH_ENTITY), 0);\r
+\r
+  //\r
+  // Software field\r
+  //\r
+  (*QhPtrPtr)->Next         = NULL;\r
+  (*QhPtrPtr)->Prev         = NULL;\r
+  (*QhPtrPtr)->FirstQtdPtr  = NULL;\r
+  (*QhPtrPtr)->AltQtdPtr    = NULL;\r
+  (*QhPtrPtr)->LastQtdPtr   = NULL;\r
+\r
+  //\r
+  // Hardware field\r
+  //\r
+  QhHwPtr                       = &((*QhPtrPtr)->Qh);\r
+  QhHwPtr->QhHorizontalPointer  = 0;\r
+  QhHwPtr->SelectType           = 0;\r
+  QhHwPtr->MaxPacketLen         = (UINT32) MaxPacketLen;\r
+  QhHwPtr->EndpointSpeed        = (DeviceSpeed & 0x3);\r
+  QhHwPtr->EndpointNum          = (Endpoint & 0x0f);\r
+  QhHwPtr->DeviceAddr           = (DeviceAddr & 0x7f);\r
+  QhHwPtr->Multiplier           = HIGH_BANDWIDTH_PIPE_MULTIPLIER;\r
+  QhHwPtr->Rsvd1                = 0;\r
+  QhHwPtr->Rsvd2                = 0;\r
+  QhHwPtr->Rsvd3                = 0;\r
+  QhHwPtr->Rsvd4                = 0;\r
+  QhHwPtr->Rsvd5                = 0;\r
+  QhHwPtr->Rsvd6                = 0;\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+VOID\r
+DestoryQh (\r
+  IN USB2_HC_DEV         *HcDev,\r
+  IN EHCI_QH_ENTITY      *QhPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destory Qh Structure \r
+  \r
+Arguments:\r
+\r
+  HcDev - USB2_HC_DEV \r
+  QhPtr - A pointer to Qh\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+  \r
+--*/\r
+{\r
+  ASSERT (HcDev);\r
+  ASSERT (QhPtr);\r
+\r
+  EhciFreePool (HcDev, (UINT8 *) QhPtr, sizeof (EHCI_QH_ENTITY));\r
+  return ;\r
+}\r
+\r
+EFI_STATUS\r
+CreateControlQh (\r
+  IN  USB2_HC_DEV                         *HcDev,\r
+  IN  UINT8                               DeviceAddr,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINTN                               MaxPacketLen,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT EHCI_QH_ENTITY                      **QhPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qh for Control Transfer\r
+\r
+Arguments:\r
+\r
+  HcDev        - USB2_HC_DEV \r
+  DeviceAddr   - Address of Device\r
+  DeviceSpeed  - Device Speed\r
+  MaxPacketLen - Max Length of one Packet\r
+  Translator   - Translator Transaction for SplitX\r
+  QhPtrPtr     - A pointer of pointer to Qh for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Create and init Control Qh\r
+  //\r
+  Status = CreateQh (\r
+             HcDev,\r
+             DeviceAddr,\r
+             0,\r
+             DeviceSpeed,\r
+             MaxPacketLen,\r
+             QhPtrPtr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto exit;\r
+  }\r
+  //\r
+  // Software field\r
+  //\r
+  (*QhPtrPtr)->Next         = (*QhPtrPtr);\r
+  (*QhPtrPtr)->Prev         = (*QhPtrPtr);\r
+  (*QhPtrPtr)->TransferType = CONTROL_TRANSFER;\r
+\r
+  //\r
+  // Hardware field\r
+  //\r
+  // Control Transfer use DataToggleControl\r
+  //\r
+  (*QhPtrPtr)->Qh.DataToggleControl   = TRUE;\r
+  (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);\r
+  (*QhPtrPtr)->Qh.SelectType          = QH_SELECT_TYPE;\r
+  (*QhPtrPtr)->Qh.QhTerminate         = FALSE;\r
+  (*QhPtrPtr)->Qh.ControlEndpointFlag = TRUE;\r
+  (*QhPtrPtr)->Qh.NakCountReload      = NAK_COUNT_RELOAD;\r
+  if (NULL != Translator) {\r
+    (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;\r
+    (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;\r
+    (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;\r
+  }\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CreateBulkQh (\r
+  IN  USB2_HC_DEV                         *HcDev,\r
+  IN  UINT8                               DeviceAddr,\r
+  IN  UINT8                               EndPointAddr,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINT8                               DataToggle,\r
+  IN  UINTN                               MaxPacketLen,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT EHCI_QH_ENTITY                      **QhPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qh for Bulk Transfer\r
+\r
+Arguments:\r
+\r
+  HcDev        - USB2_HC_DEV \r
+  DeviceAddr   - Address of Device\r
+  EndPointAddr - Address of Endpoint\r
+  DeviceSpeed  - Device Speed\r
+  MaxPacketLen - Max Length of one Packet\r
+  Translator   - Translator Transaction for SplitX\r
+  QhPtrPtr     - A pointer of pointer to Qh for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Create and init Bulk Qh\r
+  //\r
+  Status = CreateQh (\r
+             HcDev,\r
+             DeviceAddr,\r
+             EndPointAddr,\r
+             DeviceSpeed,\r
+             MaxPacketLen,\r
+             QhPtrPtr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto exit;\r
+  }\r
+  \r
+  //\r
+  // Software fields\r
+  //\r
+  (*QhPtrPtr)->Next         = (*QhPtrPtr);\r
+  (*QhPtrPtr)->Prev         = (*QhPtrPtr);\r
+  (*QhPtrPtr)->TransferType = BULK_TRANSFER;\r
+\r
+  //\r
+  // Hardware fields\r
+  //\r
+  // BulkTransfer don't use DataToggleControl\r
+  //\r
+  (*QhPtrPtr)->Qh.DataToggleControl   = FALSE;  \r
+  (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);\r
+  (*QhPtrPtr)->Qh.SelectType          = QH_SELECT_TYPE;\r
+  (*QhPtrPtr)->Qh.QhTerminate         = FALSE;\r
+  (*QhPtrPtr)->Qh.NakCountReload      = NAK_COUNT_RELOAD;\r
+  (*QhPtrPtr)->Qh.DataToggle          = DataToggle;\r
+  if (NULL != Translator) {\r
+    (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;\r
+    (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;\r
+    (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;\r
+  }\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CreateInterruptQh (\r
+  IN  USB2_HC_DEV                         *HcDev,\r
+  IN  UINT8                               DeviceAddr,\r
+  IN  UINT8                               EndPointAddr,\r
+  IN  UINT8                               DeviceSpeed,\r
+  IN  UINT8                               DataToggle,\r
+  IN  UINTN                               MaxPacketLen,\r
+  IN  UINTN                               Interval,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT EHCI_QH_ENTITY                      **QhPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qh for Control Transfer\r
+\r
+Arguments:\r
+\r
+  HcDev        - USB2_HC_DEV \r
+  DeviceAddr   - Address of Device\r
+  EndPointAddr - Address of Endpoint\r
+  DeviceSpeed  - Device Speed\r
+  MaxPacketLen - Max Length of one Packet\r
+  Interval     - value of interval\r
+  Translator   - Translator Transaction for SplitX\r
+  QhPtrPtr     - A pointer of pointer to Qh for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Create and init InterruptQh\r
+  //\r
+  Status = CreateQh (\r
+             HcDev,\r
+             DeviceAddr,\r
+             EndPointAddr,\r
+             DeviceSpeed,\r
+             MaxPacketLen,\r
+             QhPtrPtr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto exit;\r
+  }\r
+  \r
+  //\r
+  // Software fields\r
+  //\r
+  if (Interval == 0) {\r
+    (*QhPtrPtr)->TransferType = SYNC_INTERRUPT_TRANSFER;\r
+  } else {\r
+    (*QhPtrPtr)->TransferType = ASYNC_INTERRUPT_TRANSFER;\r
+  }\r
+  (*QhPtrPtr)->Interval = GetApproxiOfInterval (Interval);\r
+\r
+  //\r
+  // Hardware fields\r
+  //\r
+  // InterruptTranfer don't use DataToggleControl\r
+  //\r
+  (*QhPtrPtr)->Qh.DataToggleControl     = FALSE;\r
+  (*QhPtrPtr)->Qh.QhHorizontalPointer   = 0;\r
+  (*QhPtrPtr)->Qh.QhTerminate           = TRUE;\r
+  (*QhPtrPtr)->Qh.NakCountReload        = 0;\r
+  (*QhPtrPtr)->Qh.InerruptScheduleMask  = MICRO_FRAME_0_CHANNEL;\r
+  (*QhPtrPtr)->Qh.SplitComletionMask    = (MICRO_FRAME_2_CHANNEL | MICRO_FRAME_3_CHANNEL | MICRO_FRAME_4_CHANNEL);\r
+  (*QhPtrPtr)->Qh.DataToggle            = DataToggle;\r
+  if (NULL != Translator) {\r
+    (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;\r
+    (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;\r
+    (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;\r
+  }\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CreateQtd (\r
+  IN  USB2_HC_DEV          *HcDev,\r
+  IN  UINT8                *DataPtr,\r
+  IN  UINTN                DataLen,\r
+  IN  UINT8                PktId,\r
+  IN  UINT8                Toggle,\r
+  IN  UINT8                QtdStatus,\r
+  OUT EHCI_QTD_ENTITY      **QtdPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qtd Structure and Pre-Initialize it\r
+\r
+Arguments:\r
+\r
+  HcDev       - USB2_HC_DEV \r
+  DataPtr     - A pointer to user data buffer to transfer\r
+  DataLen     - Length of user data to transfer\r
+  PktId       - Packet Identification of this Qtd\r
+  Toggle      - Data Toggle of this Qtd\r
+  QtdStatus   - Default value of status of this Qtd\r
+  QtdPtrPtr   - A pointer of pointer to Qtd for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  EHCI_QTD_HW *QtdHwPtr;\r
+\r
+  ASSERT (HcDev);\r
+  ASSERT (QtdPtrPtr);\r
+\r
+  //\r
+  // Create memory for Qtd structure\r
+  //\r
+  Status = EhciAllocatePool (\r
+             HcDev,\r
+             (UINT8 **) QtdPtrPtr,\r
+             sizeof (EHCI_QTD_ENTITY)\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto exit;\r
+  }\r
+  //\r
+  // Init fields in Qtd\r
+  //\r
+  gBS->SetMem (*QtdPtrPtr, sizeof (EHCI_QTD_ENTITY), 0);\r
+\r
+  //\r
+  // Software field\r
+  //\r
+  (*QtdPtrPtr)->TotalBytes        = (UINT32) DataLen;\r
+  (*QtdPtrPtr)->StaticTotalBytes  = (UINT32) DataLen;\r
+  (*QtdPtrPtr)->Prev              = NULL;\r
+  (*QtdPtrPtr)->Next              = NULL;\r
+\r
+  //\r
+  // Hardware field\r
+  //\r
+  QtdHwPtr                      = &((*QtdPtrPtr)->Qtd);\r
+  QtdHwPtr->NextQtdPointer      = 0;\r
+  QtdHwPtr->NextQtdTerminate    = TRUE;\r
+  QtdHwPtr->AltNextQtdPointer   = 0;\r
+  QtdHwPtr->AltNextQtdTerminate = TRUE;\r
+  QtdHwPtr->DataToggle          = Toggle;\r
+  QtdHwPtr->TotalBytes          = (UINT32) DataLen;\r
+  QtdHwPtr->CurrentPage         = 0;\r
+  QtdHwPtr->ErrorCount          = QTD_ERROR_COUNTER;\r
+  QtdHwPtr->Status              = QtdStatus;\r
+  QtdHwPtr->Rsvd1               = 0;\r
+  QtdHwPtr->Rsvd2               = 0;\r
+  QtdHwPtr->Rsvd3               = 0;\r
+  QtdHwPtr->Rsvd4               = 0;\r
+  QtdHwPtr->Rsvd5               = 0;\r
+  QtdHwPtr->Rsvd6               = 0;\r
+\r
+  //\r
+  // Set PacketID [Setup/Data/Status]\r
+  //\r
+  switch (PktId) {\r
+  case SETUP_PACKET_ID:\r
+    QtdHwPtr->PidCode = SETUP_PACKET_PID_CODE;\r
+    break;\r
+\r
+  case INPUT_PACKET_ID:\r
+    QtdHwPtr->PidCode = INPUT_PACKET_PID_CODE;\r
+    break;\r
+\r
+  case OUTPUT_PACKET_ID:\r
+    QtdHwPtr->PidCode = OUTPUT_PACKET_PID_CODE;\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto exit;\r
+  }\r
+  \r
+  //\r
+  // Set Data Buffer Pointers\r
+  //\r
+  if (NULL != DataPtr) {\r
+    SetQtdBufferPointer (\r
+      QtdHwPtr,\r
+      DataPtr,\r
+      DataLen\r
+      );\r
+    (*QtdPtrPtr)->StaticCurrentOffset = QtdHwPtr->CurrentOffset;\r
+  }\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CreateSetupQtd (\r
+  IN  USB2_HC_DEV          *HcDev,\r
+  IN  UINT8                *DevReqPtr,\r
+  OUT EHCI_QTD_ENTITY      **QtdPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qtd Structure for Setup \r
+\r
+Arguments:\r
+\r
+  HcDev      - USB2_HC_DEV \r
+  DevReqPtr  - A pointer to Device Request Data\r
+  QtdPtrPtr  - A pointer of pointer to Qtd for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  return CreateQtd (\r
+           HcDev,\r
+           DevReqPtr,\r
+           sizeof (EFI_USB_DEVICE_REQUEST),\r
+           SETUP_PACKET_ID,\r
+           DATA0,\r
+           QTD_STATUS_ACTIVE,\r
+           QtdPtrPtr\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+CreateDataQtd (\r
+  IN  USB2_HC_DEV           *HcDev,\r
+  IN  UINT8                 *DataPtr,\r
+  IN  UINTN                 DataLen,\r
+  IN  UINT8                 PktId,\r
+  IN  UINT8                 Toggle,\r
+  OUT EHCI_QTD_ENTITY       **QtdPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qtd Structure for data \r
+\r
+Arguments:\r
+\r
+  HcDev       - USB2_HC_DEV \r
+  DataPtr     - A pointer to user data buffer to transfer\r
+  DataLen     - Length of user data to transfer\r
+  PktId       - Packet Identification of this Qtd\r
+  Toggle      - Data Toggle of this Qtd\r
+  QtdPtrPtr   - A pointer of pointer to Qtd for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  return CreateQtd (\r
+           HcDev,\r
+           DataPtr,\r
+           DataLen,\r
+           PktId,\r
+           Toggle,\r
+           QTD_STATUS_ACTIVE,\r
+           QtdPtrPtr\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+CreateAltQtd (\r
+  IN  USB2_HC_DEV           *HcDev,\r
+  IN  UINT8                 PktId,\r
+  OUT EHCI_QTD_ENTITY       **QtdPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qtd Structure for Alternative \r
+\r
+Arguments:\r
+\r
+  HcDev      - USB2_HC_DEV \r
+  PktId      - Packet Identification of this Qtd\r
+  QtdPtrPtr  - A pointer of pointer to Qtd for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  return CreateQtd (\r
+           HcDev,\r
+           NULL,\r
+           0,\r
+           PktId,\r
+           0,\r
+           QTD_STATUS_ACTIVE,\r
+           QtdPtrPtr\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+CreateStatusQtd (\r
+  IN  USB2_HC_DEV           *HcDev,\r
+  IN  UINT8                 PktId,\r
+  OUT EHCI_QTD_ENTITY       **QtdPtrPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qtd Structure for status \r
+\r
+Arguments:\r
+\r
+  HcDev       - USB2_HC_DEV \r
+  PktId       - Packet Identification of this Qtd\r
+  QtdPtrPtr   - A pointer of pointer to Qtd for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  return CreateQtd (\r
+           HcDev,\r
+           NULL,\r
+           0,\r
+           PktId,\r
+           DATA1,\r
+           QTD_STATUS_ACTIVE,\r
+           QtdPtrPtr\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+CreateControlQtds (\r
+  IN  USB2_HC_DEV                         *HcDev,\r
+  IN UINT8                                DataPktId,\r
+  IN UINT8                                *RequestCursor,\r
+  IN UINT8                                *DataCursor,\r
+  IN UINTN                                DataLen,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT EHCI_QTD_ENTITY                     **ControlQtdsHead\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qtds list for Control Transfer \r
+\r
+Arguments:\r
+\r
+  HcDev           - USB2_HC_DEV \r
+  DataPktId       - Packet Identification of Data Qtds\r
+  RequestCursor   - A pointer to request structure buffer to transfer\r
+  DataCursor      - A pointer to user data buffer to transfer\r
+  DataLen         - Length of user data to transfer\r
+  ControlQtdsHead - A pointer of pointer to first Qtd for control tranfer for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS      Status;\r
+  EHCI_QTD_ENTITY *QtdPtr;\r
+  EHCI_QTD_ENTITY *PreQtdPtr;\r
+  EHCI_QTD_ENTITY *SetupQtdPtr;\r
+  EHCI_QTD_ENTITY *FirstDataQtdPtr;\r
+  EHCI_QTD_ENTITY *LastDataQtdPtr;\r
+  EHCI_QTD_ENTITY *StatusQtdPtr;\r
+  UINT8           DataToggle;\r
+  UINT8           StatusPktId;\r
+  UINTN           CapacityOfQtd;\r
+  UINTN           SizePerQtd;\r
+  UINTN           DataCount;\r
+  UINTN           Xnum;\r
+  \r
+  QtdPtr          = NULL;\r
+  PreQtdPtr       = NULL;\r
+  SetupQtdPtr     = NULL;\r
+  FirstDataQtdPtr = NULL;\r
+  LastDataQtdPtr  = NULL;\r
+  StatusQtdPtr    = NULL;\r
+  CapacityOfQtd = 0;\r
+\r
+  //\r
+  //  Setup Stage of Control Transfer\r
+  //\r
+  Status = CreateSetupQtd (\r
+             HcDev,\r
+             RequestCursor,\r
+             &SetupQtdPtr\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto exit;\r
+  }\r
+  \r
+  //\r
+  //  Data Stage of Control Transfer\r
+  //\r
+  DataToggle  = 1;\r
+  DataCount   = DataLen;\r
+\r
+  //\r
+  // Create Qtd structure and link together\r
+  //\r
+  while (DataCount > 0) {\r
+    //\r
+    // PktSize is the data load size that each Qtd.\r
+    //\r
+    CapacityOfQtd = GetCapacityOfQtd (DataCursor);\r
+    SizePerQtd    = DataCount;\r
+    if (DataCount > CapacityOfQtd) {\r
+      SizePerQtd = CapacityOfQtd;\r
+    }\r
+\r
+    Status = CreateDataQtd (\r
+               HcDev,\r
+               DataCursor,\r
+               SizePerQtd,\r
+               DataPktId,\r
+               DataToggle,\r
+               &QtdPtr\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      if (NULL == FirstDataQtdPtr) {\r
+        goto destory_setup_qtd;\r
+      } else {\r
+        goto destory_qtds;\r
+      }\r
+    }\r
+\r
+    if (NULL == FirstDataQtdPtr) {\r
+      FirstDataQtdPtr = QtdPtr;\r
+    } else {\r
+      LinkQtdToQtd (PreQtdPtr, QtdPtr);\r
+    }\r
+\r
+    //\r
+    // Reverse Data Toggle or not determined by parity of transactions of one qtd\r
+    //\r
+    Xnum = Translator ? GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE_WITH_TT) : GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE);\r
+    if (Xnum % 2 != 0) {\r
+      DataToggle ^= 1;\r
+    }\r
+    \r
+    PreQtdPtr = QtdPtr;\r
+    DataCursor += SizePerQtd;\r
+    DataCount -= SizePerQtd;\r
+  }\r
+\r
+  LastDataQtdPtr = QtdPtr;\r
+\r
+  //\r
+  // Status Stage of Control Transfer\r
+  //\r
+  if (OUTPUT_PACKET_ID == DataPktId) {\r
+    StatusPktId = INPUT_PACKET_ID;\r
+  } else {\r
+    StatusPktId = OUTPUT_PACKET_ID;\r
+  }\r
+\r
+  Status = CreateStatusQtd (\r
+            HcDev,\r
+            StatusPktId,\r
+            &StatusQtdPtr\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto destory_qtds;\r
+  }\r
+  \r
+  //\r
+  // Link setup Qtd -> data Qtds -> status Qtd\r
+  //\r
+  if (FirstDataQtdPtr != NULL) {\r
+    LinkQtdToQtd (SetupQtdPtr, FirstDataQtdPtr);\r
+    LinkQtdToQtd (LastDataQtdPtr, StatusQtdPtr);\r
+  } else {\r
+    LinkQtdToQtd (SetupQtdPtr, StatusQtdPtr);\r
+  }\r
+\r
+  *ControlQtdsHead = SetupQtdPtr;\r
+\r
+  goto exit;\r
+\r
+destory_qtds:\r
+  DestoryQtds (HcDev, FirstDataQtdPtr);\r
+destory_setup_qtd:\r
+  DestoryQtds (HcDev, SetupQtdPtr);\r
+exit:\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CreateBulkOrInterruptQtds (\r
+  IN  USB2_HC_DEV                         *HcDev,\r
+  IN  UINT8                               PktId,\r
+  IN  UINT8                               *DataCursor,\r
+  IN  UINTN                               DataLen,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT EHCI_QTD_ENTITY                     **QtdsHead\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create Qtds list for Bulk or Interrupt Transfer \r
+\r
+Arguments:\r
+\r
+  HcDev        - USB2_HC_DEV \r
+  PktId        - Packet Identification of Qtds\r
+  DataCursor   - A pointer to user data buffer to transfer\r
+  DataLen      - Length of user data to transfer\r
+  DataToggle   - Data Toggle to start\r
+  Translator   - Translator Transaction for SplitX\r
+  QtdsHead     - A pointer of pointer to first Qtd for control tranfer for return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS            Success\r
+  EFI_OUT_OF_RESOURCES   Cannot allocate resources\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS      Status;\r
+  EHCI_QTD_ENTITY *QtdPtr;\r
+  EHCI_QTD_ENTITY *PreQtdPtr;\r
+  EHCI_QTD_ENTITY *FirstQtdPtr;\r
+  EHCI_QTD_ENTITY *AltQtdPtr;\r
+  UINTN           DataCount;\r
+  UINTN           CapacityOfQtd;\r
+  UINTN           SizePerQtd;\r
+\r
+  Status        = EFI_SUCCESS;\r
+  QtdPtr        = NULL;\r
+  PreQtdPtr     = NULL;\r
+  FirstQtdPtr   = NULL;\r
+  AltQtdPtr     = NULL;\r
+  CapacityOfQtd = 0;\r
+\r
+  DataCount   = DataLen;\r
+  while (DataCount > 0) {\r
+\r
+    CapacityOfQtd = GetCapacityOfQtd (DataCursor);\r
+    SizePerQtd    = DataCount;\r
+    if (DataCount > CapacityOfQtd) {\r
+      SizePerQtd = CapacityOfQtd;\r
+    }\r
+\r
+    Status = CreateDataQtd (\r
+              HcDev,\r
+              DataCursor,\r
+              SizePerQtd,\r
+              PktId,\r
+              0,\r
+              &QtdPtr\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      if (NULL == FirstQtdPtr) {\r
+        goto exit;\r
+      } else {\r
+        goto destory_qtds;\r
+      }\r
+    }\r
+\r
+    if (NULL == FirstQtdPtr) {\r
+      FirstQtdPtr = QtdPtr;\r
+    } else {\r
+      LinkQtdToQtd (PreQtdPtr, QtdPtr);\r
+    }\r
+\r
+    PreQtdPtr = QtdPtr;\r
+    DataCursor += SizePerQtd;\r
+    DataCount -= SizePerQtd;\r
+  }\r
+  \r
+  //\r
+  // Set Alternate Qtd\r
+  //\r
+  if (INPUT_PACKET_ID == PktId && 1 < GetNumberOfQtd (FirstQtdPtr)) {\r
+    Status = CreateAltQtd (\r
+              HcDev,\r
+              PktId,\r
+              &AltQtdPtr\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto destory_qtds;\r
+    }\r
+\r
+    LinkQtdsToAltQtd (FirstQtdPtr, AltQtdPtr);\r
+  }\r
+\r
+  *QtdsHead = FirstQtdPtr;\r
+  goto exit;\r
+\r
+destory_qtds:\r
+  DestoryQtds (HcDev, FirstQtdPtr);\r
+exit:\r
+  return Status;\r
+}\r
+\r
+VOID\r
+DestoryQtds (\r
+  IN USB2_HC_DEV          *HcDev,\r
+  IN EHCI_QTD_ENTITY      *FirstQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destory all Qtds in the list\r
+\r
+Arguments:\r
+\r
+  HcDev         - USB2_HC_DEV \r
+  FirstQtdPtr   - A pointer to first Qtd in the list \r
+    \r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  EHCI_QTD_ENTITY *PrevQtd;\r
+  EHCI_QTD_ENTITY *NextQtd;\r
+\r
+  if (!FirstQtdPtr) {\r
+    goto exit;\r
+  }\r
+\r
+  PrevQtd = FirstQtdPtr;\r
+\r
+  //\r
+  // Delete all the Qtds.\r
+  //\r
+  do {\r
+    NextQtd = PrevQtd->Next;\r
+    EhciFreePool (HcDev, (UINT8 *) PrevQtd, sizeof (EHCI_QTD_ENTITY));\r
+    PrevQtd = NextQtd;\r
+  } while (NULL != PrevQtd);\r
+\r
+exit:\r
+  return ;\r
+}\r
+\r
+UINTN\r
+GetNumberOfQtd (\r
+  IN EHCI_QTD_ENTITY    *FirstQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Number of Qtds in the list\r
+  \r
+Arguments:\r
+\r
+  FirstQtdPtr - A pointer to first Qtd in the list\r
+    \r
+Returns:\r
+\r
+  Number of Qtds in the list\r
+\r
+--*/\r
+{\r
+  UINTN           Count;\r
+  EHCI_QTD_ENTITY *QtdPtr;\r
+  Count   = 0;\r
+  QtdPtr  = FirstQtdPtr;\r
+\r
+  ;\r
+\r
+  while (NULL != QtdPtr) {\r
+    Count++;\r
+    QtdPtr = QtdPtr->Next;\r
+  }\r
+\r
+  return Count;\r
+}\r
+\r
+UINTN\r
+GetNumberOfTransaction (\r
+  IN UINTN    SizeOfData,\r
+  IN UINTN    SizeOfTransaction\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Number of Transactions in one Qtd\r
+  \r
+Arguments:\r
+\r
+  SizeOfData           - Size of one Qtd\r
+  SizeOfTransaction    - Size of one Transaction\r
+   \r
+Returns:\r
+\r
+  Number of Transactions in this Qtd\r
+\r
+--*/\r
+{\r
+\r
+  return ((SizeOfData & (SizeOfTransaction - 1)) ? SizeOfData / SizeOfTransaction + 1 : SizeOfData / SizeOfTransaction);\r
+\r
+}\r
+\r
+UINTN\r
+GetCapacityOfQtd (\r
+  IN UINT8    *BufferCursor\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get Size of First Qtd\r
+  \r
+Arguments:\r
+\r
+  BufferCursor       - BufferCursor of the Qtd\r
+   \r
+Returns:\r
+\r
+  Size of First Qtd\r
+\r
+--*/\r
+{\r
+\r
+  return (EHCI_MAX_QTD_CAPACITY - (EHCI_BLOCK_SIZE * GetNumberOfTransaction (EFI_PAGE_MASK & GET_0B_TO_31B (BufferCursor), EHCI_BLOCK_SIZE)));\r
+\r
+}\r
+\r
+UINTN\r
+GetApproxiOfInterval (\r
+  IN UINTN  Interval\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the approximate value in the 2 index sequence\r
+  \r
+Arguments:\r
+\r
+  Interval  - the value of interval\r
+  \r
+Returns:\r
+\r
+  approximate value of interval in the 2 index sequence\r
+  \r
+--*/\r
+{\r
+  UINTN Orignate;\r
+  UINTN Approxi;\r
+\r
+  Orignate  = Interval;\r
+  Approxi   = 1;\r
+\r
+  while (Orignate != 1 && Orignate != 0) {\r
+    Orignate  = Orignate >> 1;\r
+    Approxi   = Approxi << 1;\r
+  }\r
+\r
+  if (Interval & (Approxi >> 1)) {\r
+    Approxi = Approxi << 1;\r
+  }\r
+\r
+  return Approxi;\r
+}\r
+\r
+EHCI_QTD_HW *\r
+GetQtdAlternateNextPointer (\r
+  IN EHCI_QTD_HW  *HwQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get Qtd alternate next pointer field\r
+  \r
+Arguments:\r
+\r
+  HwQtdPtr - A pointer to hardware Qtd structure\r
+  \r
+Returns:\r
+\r
+  A pointer to hardware alternate Qtd\r
+  \r
+--*/\r
+{\r
+  EHCI_QTD_HW *Value;\r
+\r
+  Value = NULL;\r
+\r
+  if (!HwQtdPtr->AltNextQtdTerminate) {\r
+    Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->AltNextQtdPointer << 5);\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+EHCI_QTD_HW *\r
+GetQtdNextPointer (\r
+  IN EHCI_QTD_HW  *HwQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get Qtd next pointer field\r
+  \r
+Arguments:\r
+\r
+  HwQtdPtr - A pointer to hardware Qtd structure\r
+  \r
+Returns:\r
+\r
+  A pointer to next hardware Qtd structure\r
+  \r
+--*/\r
+{\r
+  EHCI_QTD_HW *Value;\r
+\r
+  Value = NULL;\r
+\r
+  if (!HwQtdPtr->NextQtdTerminate) {\r
+    Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->NextQtdPointer << 5);\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+VOID LinkQtdToQtd (\r
+  IN EHCI_QTD_ENTITY * PreQtdPtr, \r
+  IN EHCI_QTD_ENTITY * QtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Link Qtds together\r
+  \r
+Arguments:\r
+\r
+  PreQtdPtr   - A pointer to pre Qtd\r
+  QtdPtr      - A pointer to next Qtd\r
+    \r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  EHCI_QTD_HW *QtdHwPtr;\r
+\r
+  ASSERT(PreQtdPtr);\r
+  ASSERT(QtdPtr);\r
+\r
+  //\r
+  // Software link\r
+  //\r
+  PreQtdPtr->Next = QtdPtr;\r
+  QtdPtr->Prev    = PreQtdPtr;\r
+\r
+  //\r
+  // Hardware link\r
+  //\r
+  QtdHwPtr                        = &(QtdPtr->Qtd);\r
+  PreQtdPtr->Qtd.NextQtdPointer   = (UINT32) (GET_0B_TO_31B(QtdHwPtr) >> 5);\r
+  PreQtdPtr->Qtd.NextQtdTerminate = FALSE;\r
+\r
+  return ;\r
+}\r
+\r\r
+\r
+VOID LinkQtdsToAltQtd (\r
+  IN EHCI_QTD_ENTITY  * FirstQtdPtr, \r
+  IN EHCI_QTD_ENTITY  * AltQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Link AlterQtds together\r
+  \r
+Arguments:\r
+\r
+  FirstQtdPtr  - A pointer to first Qtd in the list\r
+  AltQtdPtr    - A pointer to alternative Qtd\r
+    \r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  EHCI_QTD_ENTITY *QtdPtr;\r
+  EHCI_QTD_HW     *AltQtdHwPtr;\r
+\r
+  ASSERT(FirstQtdPtr);\r
+  ASSERT(AltQtdPtr);\r
+\r
+  AltQtdHwPtr = &(AltQtdPtr->Qtd);\r
+  QtdPtr      = FirstQtdPtr;\r
+  \r
+  while (NULL != QtdPtr) {\r
+    //\r
+    // Software link\r
+    //\r
+    QtdPtr->AltNext = AltQtdPtr;\r
+    //\r
+    // Hardware link\r
+    //\r
+    QtdPtr->Qtd.AltNextQtdPointer   = (UINT32) (GET_0B_TO_31B(AltQtdHwPtr) >> 5);\r
+    QtdPtr->Qtd.AltNextQtdTerminate = FALSE;\r
+    QtdPtr                          = QtdPtr->Next;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+VOID\r
+LinkQtdToQh (\r
+  IN EHCI_QH_ENTITY      *QhPtr,\r
+  IN EHCI_QTD_ENTITY     *QtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Link Qtds list to Qh\r
+  \r
+Arguments:\r
+\r
+  QhPtr    - A pointer to Qh\r
+  QtdPtr   - A pointer to first Qtd in the list\r
+  \r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  EHCI_QTD_ENTITY *Cursor;\r
+  EHCI_QTD_HW     *QtdHwPtr;\r
+\r
+  ASSERT (QhPtr);\r
+  ASSERT (QtdPtr);\r
+\r
+  QhPtr->FirstQtdPtr = QtdPtr;\r
+  if (NULL != QtdPtr->AltNext) {\r
+    QhPtr->AltQtdPtr = QtdPtr->AltNext;\r
+  }\r
+\r
+  Cursor = QtdPtr;\r
+  while (NULL != Cursor) {\r
+    Cursor->SelfQh = QhPtr;\r
+    if (NULL == Cursor->Next) {\r
+      QhPtr->LastQtdPtr = Cursor;\r
+    }\r
+\r
+    Cursor = Cursor->Next;\r
+  }\r
+\r
+  QtdHwPtr                    = &(QtdPtr->Qtd);\r
+  QhPtr->Qh.NextQtdPointer    = (UINT32) (GET_0B_TO_31B (QtdHwPtr) >> 5);\r
+  QhPtr->Qh.NextQtdTerminate  = FALSE;\r
+\r
+  return ;\r
+}\r
+\r
+EFI_STATUS\r
+LinkQhToAsyncList (\r
+  IN  USB2_HC_DEV       *HcDev,\r
+  IN EHCI_QH_ENTITY     *QhPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Link Qh to Async Schedule List\r
+  \r
+Arguments:\r
+\r
+  HcDev  - USB2_HC_DEV \r
+  QhPtr  - A pointer to Qh\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS       Success\r
+  EFI_DEVICE_ERROR  Fail\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (HcDev);\r
+  ASSERT (QhPtr);\r
+\r
+  QhPtr->Qh.HeadReclamationFlag = TRUE;\r
+\r
+  Status                        = SetAsyncListAddr (HcDev, QhPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto exit;\r
+  }\r
+\r
+  if (!IsAsyncScheduleEnabled (HcDev)) {\r
+\r
+    Status = EnableAsynchronousSchedule (HcDev);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto exit;\r
+    }\r
+\r
+    Status = WaitForAsyncScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((gEHCDebugLevel, "WaitForAsyncScheduleEnable TimeOut"));\r
+      Status = EFI_TIMEOUT;\r
+      goto exit;\r
+    }\r
+\r
+    if (IsEhcHalted (HcDev)) {\r
+      Status = StartScheduleExecution (HcDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+      }\r
+    }\r
+\r
+  }\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+UnlinkQhFromAsyncList (\r
+  IN USB2_HC_DEV        *HcDev,\r
+  IN EHCI_QH_ENTITY     *QhPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Unlink Qh from Async Schedule List\r
+  \r
+Arguments:\r
+\r
+  HcDev  - USB2_HC_DEV \r
+  QhPtr  - A pointer to Qh\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS       Success\r
+  EFI_DEVICE_ERROR  Fail\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  ASSERT (HcDev);\r
+  ASSERT (QhPtr);\r
+\r
+  if (QhPtr == QhPtr->Next) {\r
+\r
+    Status = DisableAsynchronousSchedule (HcDev);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto exit;\r
+    }\r
+\r
+    Status = WaitForAsyncScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((gEHCErrorLevel, "WaitForAsyncScheduleDisable TimeOut\n"));\r
+      Status = EFI_TIMEOUT;\r
+      goto exit;\r
+    }\r
+\r
+  }\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+VOID\r
+LinkQhToPeriodicList (\r
+  IN USB2_HC_DEV        *HcDev,\r
+  IN EHCI_QH_ENTITY     *QhPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Link Qh to Periodic Schedule List\r
+  \r
+Arguments:\r
+\r
+  HcDev  - USB2_HC_DEV \r
+  QhPtr  - A pointer to Qh\r
+  \r
+Returns:\r
+\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  FRAME_LIST_ENTRY  *FrameEntryPtr;\r
+  EHCI_QH_ENTITY    *FindQhPtr;\r
+  EHCI_QH_HW        *FindQhHwPtr;\r
+  UINTN             FrameIndex;\r
+\r
+  ASSERT (HcDev);\r
+  ASSERT (QhPtr);\r
+\r
+  FindQhPtr                     = NULL;\r
+  FindQhHwPtr                   = NULL;\r
+  FrameIndex                    = 0;\r
+  FrameEntryPtr                 = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
+\r
+  QhPtr->Qh.HeadReclamationFlag = FALSE;\r
+\r
+  if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {\r
+       \r
+    //\r
+    // AsyncInterruptTransfer Qh\r
+    //\r
+    \r
+    //\r
+    // Link to Frame[0] List\r
+    //\r
+    if (!FrameEntryPtr->LinkTerminate) {\r
+      //\r
+      // Not Null FrameList\r
+      //\r
+      FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);\r
+      FindQhPtr   = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);\r
+      //\r
+      // FindQh is Left/Right to Qh\r
+      //\r
+      while ((NULL != FindQhPtr->Next) && (FindQhPtr->Interval > QhPtr->Interval)) {\r
+        FindQhPtr = FindQhPtr->Next;\r
+      }\r
+\r
+      if (FindQhPtr->Interval == QhPtr->Interval) {\r
+        //\r
+        // Link Qh after FindQh\r
+        //\r
+        if (NULL != FindQhPtr->Next) {\r
+          FindQhPtr->Next->Prev         = QhPtr;\r
+          QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Next->Qh) >> 5);\r
+          QhPtr->Qh.SelectType          = QH_SELECT_TYPE;\r
+          QhPtr->Qh.QhTerminate         = FALSE;\r
+        }\r
+\r
+        FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+        FindQhPtr->Qh.SelectType          = QH_SELECT_TYPE;\r
+        FindQhPtr->Qh.QhTerminate         = FALSE;\r
+\r
+        QhPtr->Prev                       = FindQhPtr;\r
+        QhPtr->Next                       = FindQhPtr->Next;\r
+        FindQhPtr->Next                   = QhPtr;\r
+      } else if (FindQhPtr->Interval < QhPtr->Interval) {\r
+        //\r
+        // Link Qh before FindQh\r
+        //\r
+        if (NULL == FindQhPtr->Prev) {\r
+          //\r
+          // Qh is the First one in Frame[0] List\r
+          //\r
+          FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+          FrameEntryPtr->SelectType     = QH_SELECT_TYPE;\r
+          FrameEntryPtr->LinkTerminate  = FALSE;\r
+        } else {\r
+          //\r
+          // Qh is not the First one in Frame[0] List\r
+          //\r
+          FindQhPtr->Prev->Next                   = QhPtr;\r
+          FindQhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+          FindQhPtr->Prev->Qh.SelectType          = QH_SELECT_TYPE;\r
+          FindQhPtr->Prev->Qh.QhTerminate         = FALSE;\r
+        }\r
+\r
+        QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Qh) >> 5);\r
+        QhPtr->Qh.SelectType          = QH_SELECT_TYPE;\r
+        QhPtr->Qh.QhTerminate         = FALSE;\r
+\r
+        QhPtr->Next                   = FindQhPtr;\r
+        QhPtr->Prev                   = FindQhPtr->Prev;\r
+        FindQhPtr->Prev               = QhPtr;\r
+      } else {\r
+        //\r
+        // Link Qh after FindQh, Qh is the Last one\r
+        //\r
+        FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+        FindQhPtr->Prev->Qh.SelectType    = QH_SELECT_TYPE;\r
+        FindQhPtr->Qh.QhTerminate         = FALSE;\r
+\r
+        QhPtr->Prev                       = FindQhPtr;\r
+        QhPtr->Next                       = NULL;\r
+        FindQhPtr->Next                   = QhPtr;\r
+      }\r
+    } else {\r
+      //\r
+      // Null FrameList\r
+      //\r
+      FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+      FrameEntryPtr->SelectType     = QH_SELECT_TYPE;\r
+      FrameEntryPtr->LinkTerminate  = FALSE;\r
+    }\r
+    //\r
+    // Other Frame[X]\r
+    //\r
+    if (NULL == QhPtr->Prev) {\r
+      //\r
+      // Qh is the First one in Frame[0] List\r
+      //\r
+      FrameIndex += QhPtr->Interval;\r
+      while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
+        FrameEntryPtr                 = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);\r
+        FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+        FrameEntryPtr->SelectType     = QH_SELECT_TYPE;\r
+        FrameEntryPtr->LinkTerminate  = FALSE;\r
+        FrameIndex += QhPtr->Interval;\r
+      }\r
+    } else if (QhPtr->Interval < QhPtr->Prev->Interval) {\r
+      //\r
+      // Qh is not the First one in Frame[0] List, and Prev.interval > Qh.interval\r
+      //\r
+      FrameIndex += QhPtr->Interval;\r
+      while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
+        FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);\r
+        if ((FrameIndex % QhPtr->Prev->Interval) != 0) {\r
+          FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+          FrameEntryPtr->SelectType     = QH_SELECT_TYPE;\r
+          FrameEntryPtr->LinkTerminate  = FALSE;\r
+        }\r
+\r
+        FrameIndex += QhPtr->Interval;\r
+      }\r
+    }\r
+  } else {\r
+  \r
+    //\r
+    // SyncInterruptTransfer Qh\r
+    //\r
+    \r
+    if (!FrameEntryPtr->LinkTerminate) {\r
+      //\r
+      // Not Null FrameList\r
+      //\r
+      FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);\r
+      FindQhPtr   = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);\r
+      //\r
+      // FindQh is Last Qh in the Asynchronous List, Link Qh after FindQh\r
+      //\r
+      while (NULL != FindQhPtr->Next) {\r
+        FindQhPtr = FindQhPtr->Next;\r
+      }\r
+\r
+      FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+      FindQhPtr->Qh.SelectType          = QH_SELECT_TYPE;\r
+      FindQhPtr->Qh.QhTerminate         = FALSE;\r
+\r
+      FindQhPtr->Next                   = QhPtr;\r
+      QhPtr->Prev                       = FindQhPtr;\r
+    } else {\r
+      //\r
+      // Null FrameList\r
+      //\r
+      FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
+      FrameEntryPtr->SelectType     = QH_SELECT_TYPE;\r
+      FrameEntryPtr->LinkTerminate  = FALSE;\r
+    }\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+VOID\r
+UnlinkQhFromPeriodicList (\r
+  IN USB2_HC_DEV        *HcDev,\r
+  IN EHCI_QH_ENTITY     *QhPtr,\r
+  IN UINTN              Interval\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Unlink Qh from Periodic Schedule List\r
+  \r
+Arguments:\r
+\r
+  HcDev     - USB2_HC_DEV \r
+  QhPtr     - A pointer to Qh\r
+  Interval  - Interval of this periodic transfer\r
+  \r
+Returns:\r
+\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  FRAME_LIST_ENTRY  *FrameEntryPtr;\r
+  UINTN             FrameIndex;\r
+\r
+  FrameIndex = 0;\r
+\r
+  ASSERT (HcDev);\r
+  ASSERT (QhPtr);\r
+\r
+  FrameIndex    = 0;\r
+  FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
+\r
+  if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {\r
+  \r
+    //\r
+    // AsyncInterruptTransfer Qh\r
+    //\r
+    \r
+    if (NULL == QhPtr->Prev) {\r
+      //\r
+      // Qh is the First one on  Frame[0] List\r
+      //\r
+      if (NULL == QhPtr->Next) {\r
+        //\r
+        // Only one on  Frame[0] List\r
+        //\r
+        while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
+          FrameEntryPtr->LinkPointer    = 0;\r
+          FrameEntryPtr->SelectType     = 0;\r
+          FrameEntryPtr->LinkTerminate  = TRUE;\r
+          FrameEntryPtr                += Interval;\r
+          FrameIndex                   += Interval;\r
+        }\r
+      } else {\r
+        while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
+          FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);\r
+          FrameEntryPtr->SelectType     = QH_SELECT_TYPE;\r
+          FrameEntryPtr->LinkTerminate  = FALSE;\r
+          FrameEntryPtr += Interval;\r
+          FrameIndex += Interval;\r
+        }\r
+      }\r
+    } else {\r
+    \r
+      //\r
+      // Not First one on  Frame[0] List\r
+      //\r
+      if (NULL == QhPtr->Next) {\r
+        //\r
+        // Qh is the Last one on  Frame[0] List\r
+        //\r
+        QhPtr->Prev->Qh.QhHorizontalPointer = 0;\r
+        QhPtr->Prev->Qh.SelectType          = 0;\r
+        QhPtr->Prev->Qh.QhTerminate         = TRUE;\r
+      } else {\r
+        QhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);\r
+        QhPtr->Prev->Qh.SelectType          = QH_SELECT_TYPE;\r
+        QhPtr->Prev->Qh.QhTerminate         = FALSE;\r
+      }\r
+\r
+      if (Interval == QhPtr->Prev->Interval) {\r
+        //\r
+        // Interval is the same as Prev\r
+        // Not involed Frame[X]\r
+        //\r
+      } else {\r
+        //\r
+        // Other Frame[X]\r
+        //\r
+        while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
+          if ((FrameIndex % QhPtr->Prev->Interval) != 0) {\r
+            FrameEntryPtr->LinkPointer    = QhPtr->Prev->Qh.QhHorizontalPointer;\r
+            FrameEntryPtr->SelectType     = QhPtr->Prev->Qh.SelectType;\r
+            FrameEntryPtr->LinkTerminate  = QhPtr->Prev->Qh.QhTerminate;\r
+          }\r
+          FrameEntryPtr += Interval;\r
+          FrameIndex += Interval;\r
+        }\r
+      }\r
+    }\r
+\r
+    if (NULL != QhPtr->Next) {\r
+      QhPtr->Next->Prev = QhPtr->Prev;\r
+    }\r
+\r
+    if (NULL != QhPtr->Prev) {\r
+      QhPtr->Prev->Next = QhPtr->Next;\r
+    }\r
+  } else {\r
+    //\r
+    // SyncInterruptTransfer Qh\r
+    //\r
+    if (NULL == QhPtr->Prev) {\r
+      //\r
+      // Qh is the only one Qh on  Frame[0] List\r
+      //\r
+      FrameEntryPtr->LinkPointer    = 0;\r
+      FrameEntryPtr->SelectType     = 0;\r
+      FrameEntryPtr->LinkTerminate  = TRUE;\r
+    } else {\r
+      QhPtr->Prev->Qh.QhHorizontalPointer = 0;\r
+      QhPtr->Prev->Qh.SelectType          = 0;\r
+      QhPtr->Prev->Qh.QhTerminate         = TRUE;\r
+    }\r
+\r
+    if (NULL != QhPtr->Prev) {\r
+      QhPtr->Prev->Next = NULL;\r
+    }\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+VOID\r
+LinkToAsyncReqeust (\r
+  IN  USB2_HC_DEV        *HcDev,\r
+  IN  EHCI_ASYNC_REQUEST *AsyncRequestPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Llink AsyncRequest Entry to Async Request List\r
+  \r
+Arguments:\r
+\r
+  HcDev             - USB2_HC_DEV \r
+  AsyncRequestPtr   - A pointer to Async Request Entry\r
+  \r
+Returns:\r
+\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  EHCI_ASYNC_REQUEST  *CurrentPtr;\r
+\r
+  CurrentPtr              = HcDev->AsyncRequestList;\r
+  HcDev->AsyncRequestList = AsyncRequestPtr;\r
+  AsyncRequestPtr->Prev   = NULL;\r
+  AsyncRequestPtr->Next   = CurrentPtr;\r
+\r
+  if (NULL != CurrentPtr) {\r
+    CurrentPtr->Prev = AsyncRequestPtr;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+VOID\r
+UnlinkFromAsyncReqeust (\r
+  IN  USB2_HC_DEV        *HcDev,\r
+  IN  EHCI_ASYNC_REQUEST *AsyncRequestPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Unlink AsyncRequest Entry from Async Request List\r
+  \r
+Arguments:\r
+\r
+  HcDev            - USB2_HC_DEV \r
+  AsyncRequestPtr  - A pointer to Async Request Entry\r
+  \r
+Returns:\r
+\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  if (NULL == AsyncRequestPtr->Prev) {\r
+    HcDev->AsyncRequestList = AsyncRequestPtr->Next;\r
+    if (NULL != AsyncRequestPtr->Next) {\r
+      AsyncRequestPtr->Next->Prev = NULL;\r
+    }\r
+  } else {\r
+    AsyncRequestPtr->Prev->Next = AsyncRequestPtr->Next;\r
+    if (NULL != AsyncRequestPtr->Next) {\r
+      AsyncRequestPtr->Next->Prev = AsyncRequestPtr->Prev;\r
+    }\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+VOID\r
+SetQtdBufferPointer (\r
+  IN EHCI_QTD_HW  *QtdHwPtr,\r
+  IN VOID         *DataPtr,\r
+  IN UINTN        DataLen\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set data buffer pointers in Qtd\r
+\r
+Arguments:\r
+\r
+  QtdHwPtr  - A pointer to Qtd hardware structure \r
+  DataPtr   - A pointer to user data buffer\r
+  DataLen   - Length of the user data buffer\r
+    \r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  UINTN RemainLen;\r
+\r
+  RemainLen = DataLen;\r
+  ASSERT (QtdHwPtr);\r
+\r
+  //\r
+  // Set BufferPointer0, ExtBufferPointer0 and Offset\r
+  //\r
+  QtdHwPtr->BufferPointer0    = (UINT32) (GET_0B_TO_31B (DataPtr) >> 12);\r
+  QtdHwPtr->CurrentOffset     = (UINT32) (GET_0B_TO_31B (DataPtr) & EFI_PAGE_MASK);\r
+  QtdHwPtr->ExtBufferPointer0 = (UINT32) GET_32B_TO_63B (DataPtr);\r
+\r
+  //\r
+  // Set BufferPointer1 and ExtBufferPointer1\r
+  //\r
+  RemainLen = RemainLen > (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset) ? (RemainLen - (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset)) : 0;\r
+  if (RemainLen == 0) {\r
+    goto exit;\r
+  }\r
+\r
+  QtdHwPtr->BufferPointer1    = QtdHwPtr->BufferPointer0 + 1;\r
+  QtdHwPtr->ExtBufferPointer1 = QtdHwPtr->ExtBufferPointer0;\r
+\r
+  //\r
+  // Set BufferPointer2 and ExtBufferPointer2\r
+  //\r
+  RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
+  if (RemainLen == 0) {\r
+    goto exit;\r
+  }\r
+\r
+  QtdHwPtr->BufferPointer2    = QtdHwPtr->BufferPointer1 + 1;\r
+  QtdHwPtr->ExtBufferPointer2 = QtdHwPtr->ExtBufferPointer0;\r
+\r
+  //\r
+  // Set BufferPointer3 and ExtBufferPointer3\r
+  //\r
+  RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
+  if (RemainLen == 0) {\r
+    goto exit;\r
+  }\r
+\r
+  QtdHwPtr->BufferPointer3    = QtdHwPtr->BufferPointer2 + 1;\r
+  QtdHwPtr->ExtBufferPointer3 = QtdHwPtr->ExtBufferPointer0;\r
+\r
+  //\r
+  // Set BufferPointer4 and ExtBufferPointer4\r
+  //\r
+  RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
+  if (RemainLen == 0) {\r
+    goto exit;\r
+  }\r
+\r
+  QtdHwPtr->BufferPointer4    = QtdHwPtr->BufferPointer3 + 1;\r
+  QtdHwPtr->ExtBufferPointer4 = QtdHwPtr->ExtBufferPointer0;\r
+\r
+exit:\r
+  return ;\r
+}\r
+\r
+BOOLEAN\r
+IsQtdStatusActive (\r
+  IN EHCI_QTD_HW  *HwQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Whether Qtd status is active or not\r
+  \r
+Arguments:\r
+\r
+  HwQtdPtr - A pointer to hardware Qtd structure\r
+  \r
+Returns:\r
+\r
+  TRUE    Active\r
+  FALSE   Inactive\r
+  \r
+--*/\r
+{\r
+  UINT8   QtdStatus;\r
+  BOOLEAN Value;\r
+\r
+  QtdStatus = (UINT8) (HwQtdPtr->Status);\r
+  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_ACTIVE);\r
+\r
+  return Value;\r
+}\r
+\r
+BOOLEAN\r
+IsQtdStatusHalted (\r
+  IN EHCI_QTD_HW  *HwQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Whether Qtd status is halted or not\r
+  \r
+Arguments:\r
+\r
+  HwQtdPtr - A pointer to hardware Qtd structure\r
+  \r
+Returns:\r
+\r
+  TRUE    Halted\r
+  FALSE   Not halted\r
+  \r
+--*/\r
+{\r
+  UINT8   QtdStatus;\r
+  BOOLEAN Value;\r
+\r
+  QtdStatus = (UINT8) (HwQtdPtr->Status);\r
+  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_HALTED);\r
+\r
+  return Value;\r
+}\r
+\r
+BOOLEAN\r
+IsQtdStatusBufferError (\r
+  IN EHCI_QTD_HW  *HwQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Whether Qtd status is buffer error or not\r
+  \r
+Arguments:\r
+\r
+  HwQtdPtr - A pointer to hardware Qtd structure\r
+  \r
+Returns:\r
+\r
+  TRUE    Buffer error\r
+  FALSE   No buffer error\r
+  \r
+--*/\r
+{\r
+  UINT8   QtdStatus;\r
+  BOOLEAN Value;\r
+\r
+  QtdStatus = (UINT8) (HwQtdPtr->Status);\r
+  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_BUFFER_ERR);\r
+\r
+  return Value;\r
+}\r
+\r
+BOOLEAN\r
+IsQtdStatusBabbleError (\r
+  IN EHCI_QTD_HW  *HwQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Whether Qtd status is babble error or not\r
+  \r
+Arguments:\r
+\r
+  HwQtdPtr - A pointer to hardware Qtd structure\r
+  \r
+Returns:\r
+\r
+  TRUE    Babble error\r
+  FALSE   No babble error\r
+  \r
+--*/\r
+{\r
+  UINT8   QtdStatus;\r
+  BOOLEAN Value;\r
+\r
+  QtdStatus = (UINT8) (HwQtdPtr->Status);\r
+  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_BABBLE_ERR);\r
+\r
+  return Value;\r
+}\r
+\r
+BOOLEAN\r
+IsQtdStatusTransactionError (\r
+  IN EHCI_QTD_HW  *HwQtdPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Whether Qtd status is transaction error or not\r
+  \r
+Arguments:\r
+\r
+  HwQtdPtr - A pointer to hardware Qtd structure\r
+  \r
+Returns:\r
+\r
+  TRUE    Transaction error\r
+  FALSE   No transaction error\r
+  \r
+--*/\r
+{\r
+  UINT8   QtdStatus;\r
+  BOOLEAN Value;\r
+\r
+  QtdStatus = (UINT8) (HwQtdPtr->Status);\r
+  Value     = (BOOLEAN) (QtdStatus & QTD_STATUS_TRANSACTION_ERR);\r
+\r
+  return Value;\r
+}\r
+\r
+BOOLEAN\r
+IsDataInTransfer (\r
+  IN UINT8     EndPointAddress\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Whether is a DataIn direction transfer\r
+  \r
+Arguments:\r
+\r
+  EndPointAddress - address of the endpoint \r
+  \r
+Returns:\r
+\r
+  TRUE    DataIn\r
+  FALSE   DataOut\r
+  \r
+--*/\r
+{\r
+  BOOLEAN Value;\r
+\r
+  if (EndPointAddress & 0x80) {\r
+    Value = TRUE;\r
+  } else {\r
+    Value = FALSE;\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+EFI_STATUS\r
+MapDataBuffer (\r
+  IN  USB2_HC_DEV             *HcDev,\r
+  IN  EFI_USB_DATA_DIRECTION  TransferDirection,\r
+  IN  VOID                    *Data,\r
+  IN  OUT UINTN               *DataLength,\r
+  OUT UINT8                   *PktId,\r
+  OUT UINT8                   **DataCursor,\r
+  OUT VOID                    **DataMap\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Map address of user data buffer\r
+  \r
+Arguments:\r
+\r
+  HcDev              - USB2_HC_DEV \r
+  TransferDirection  - direction of transfer\r
+  Data               - A pointer to user data buffer \r
+  DataLength         - length of user data\r
+  PktId              - Packte Identificaion\r
+  DataCursor         - mapped address to return\r
+  DataMap            - identificaion of this mapping to return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+    \r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  TempPhysicalAddr;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (TransferDirection) {\r
+\r
+  case EfiUsbDataIn:\r
+\r
+    *PktId = INPUT_PACKET_ID;\r
+    //\r
+    // BusMasterWrite means cpu read\r
+    //\r
+    Status = HcDev->PciIo->Map (\r
+                            HcDev->PciIo,\r
+                            EfiPciIoOperationBusMasterWrite,\r
+                            Data,\r
+                            DataLength,\r
+                            &TempPhysicalAddr,\r
+                            DataMap\r
+                            );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((gEHCDebugLevel, "MapDataBuffer Failed\n"));\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto exit;\r
+    }\r
+\r
+    *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
+    break;\r
+\r
+  case EfiUsbDataOut:\r
+\r
+    *PktId = OUTPUT_PACKET_ID;\r
+    //\r
+    // BusMasterRead means cpu write\r
+    //\r
+    Status = HcDev->PciIo->Map (\r
+                            HcDev->PciIo,\r
+                            EfiPciIoOperationBusMasterRead,\r
+                            Data,\r
+                            DataLength,\r
+                            &TempPhysicalAddr,\r
+                            DataMap\r
+                            );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto exit;\r
+    }\r
+\r
+    *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
+    break;\r
+\r
+  case EfiUsbNoData:\r
+\r
+    *PktId      = OUTPUT_PACKET_ID;\r
+    Data        = NULL;\r
+    *DataLength = 0;\r
+    *DataCursor = NULL;\r
+    *DataMap    = NULL;\r
+    break;\r
+\r
+  default:\r
+       \r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+MapRequestBuffer (\r
+  IN  USB2_HC_DEV             *HcDev,\r
+  IN  OUT VOID                *Request,\r
+  OUT UINT8                   **RequestCursor,\r
+  OUT VOID                    **RequestMap\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Map address of request structure buffer\r
+  \r
+Arguments:\r
+\r
+  HcDev           - USB2_HC_DEV \r
+  Request         - A pointer to request structure\r
+  RequestCursor   - Mapped address of request structure to return\r
+  RequestMap      - Identificaion of this mapping to return\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+    \r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 RequestLen;\r
+  EFI_PHYSICAL_ADDRESS  TempPhysicalAddr;\r
+\r
+  RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);\r
+  Status = HcDev->PciIo->Map (\r
+                           HcDev->PciIo,\r
+                           EfiPciIoOperationBusMasterRead,\r
+                           (UINT8 *) Request,\r
+                           (UINTN *) &RequestLen,\r
+                           &TempPhysicalAddr,\r
+                           RequestMap\r
+                           );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto exit;\r
+  }\r
+\r
+  *RequestCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+DeleteAsyncRequestTransfer (\r
+  IN  USB2_HC_DEV     *HcDev,\r
+  IN  UINT8           DeviceAddress,\r
+  IN  UINT8           EndPointAddress,\r
+  OUT UINT8           *DataToggle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Delete all asynchronous request transfer\r
+  \r
+Arguments:\r
+\r
+  HcDev           - USB2_HC_DEV \r
+  DeviceAddress   - address of usb device\r
+  EndPointAddress - address of endpoint\r
+  DataToggle      - stored data toggle\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+    \r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  EHCI_ASYNC_REQUEST  *AsyncRequestPtr;\r
+  EHCI_ASYNC_REQUEST  *MatchPtr;\r
+  EHCI_QH_HW          *QhHwPtr;\r
+  UINT8               EndPointNum;\r
+\r
+  if (NULL == HcDev->AsyncRequestList) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto exit;\r
+  }\r
+\r
+  MatchPtr        = NULL;\r
+  QhHwPtr         = NULL;\r
+  EndPointNum     = EndPointAddress & 0x0f;\r
+  AsyncRequestPtr = HcDev->AsyncRequestList;\r
+\r
+  //\r
+  // Find QH of AsyncRequest by DeviceAddress and EndPointNum\r
+  //\r
+  do {\r
+\r
+    QhHwPtr = &(AsyncRequestPtr->QhPtr->Qh);\r
+    if (QhHwPtr->DeviceAddr == DeviceAddress && QhHwPtr->EndpointNum == EndPointNum) {\r
+      MatchPtr = AsyncRequestPtr;\r
+      break;\r
+    }\r
+\r
+    AsyncRequestPtr = AsyncRequestPtr->Next;\r
+\r
+  } while (NULL != AsyncRequestPtr);\r
+\r
+  if (NULL == MatchPtr) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto exit;\r
+  }\r
+\r
+  Status = DisablePeriodicSchedule (HcDev);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto exit;\r
+  }\r
+\r
+  Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleDisable TimeOut\n"));\r
+    Status = EFI_TIMEOUT;\r
+    goto exit;\r
+  }\r
+\r
+  *DataToggle = (UINT8) MatchPtr->QhPtr->Qh.DataToggle;\r
+  UnlinkQhFromPeriodicList (HcDev, MatchPtr->QhPtr, MatchPtr->QhPtr->Interval);\r
+  UnlinkFromAsyncReqeust (HcDev, MatchPtr);\r
+\r
+  if (NULL == HcDev->AsyncRequestList) {\r
+\r
+    Status = StopPollingTimer (HcDev);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto exit;\r
+    }\r
+\r
+  } else {\r
+\r
+    Status = EnablePeriodicSchedule (HcDev);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto exit;\r
+    }\r
+\r
+    Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleEnable TimeOut\n"));\r
+      Status = EFI_TIMEOUT;\r
+      goto exit;\r
+    }\r
+\r
+    if (IsEhcHalted (HcDev)) {\r
+      Status = StartScheduleExecution (HcDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto exit;\r
+      }\r
+    }\r
+\r
+  }\r
+\r
+  DestoryQtds (HcDev, MatchPtr->QhPtr->FirstQtdPtr);\r
+  DestoryQh (HcDev, MatchPtr->QhPtr);\r
+  EhciFreePool (HcDev, (UINT8 *) MatchPtr, sizeof (EHCI_ASYNC_REQUEST));\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r
+VOID\r
+CleanUpAllAsyncRequestTransfer (\r
+  IN USB2_HC_DEV  *HcDev\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clean up all asynchronous request transfer\r
+  \r
+Arguments:\r
+\r
+  HcDev - USB2_HC_DEV \r
+  \r
+Returns:\r
+\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  EHCI_ASYNC_REQUEST  *AsyncRequestPtr;\r
+  EHCI_ASYNC_REQUEST  *FreePtr;\r
+\r
+  AsyncRequestPtr = NULL;\r
+  FreePtr         = NULL;\r
+\r
+  StopPollingTimer (HcDev);\r
+\r
+  AsyncRequestPtr = HcDev->AsyncRequestList;\r
+  while (NULL != AsyncRequestPtr) {\r
+\r
+    FreePtr         = AsyncRequestPtr;\r
+    AsyncRequestPtr = AsyncRequestPtr->Next;\r
+    UnlinkFromAsyncReqeust (HcDev, FreePtr);\r
+    UnlinkQhFromPeriodicList (HcDev, FreePtr->QhPtr, FreePtr->QhPtr->Interval);\r
+    DestoryQtds (HcDev, FreePtr->QhPtr->FirstQtdPtr);\r
+    DestoryQh (HcDev, FreePtr->QhPtr);\r
+    EhciFreePool (HcDev, (UINT8 *) FreePtr, sizeof (EHCI_ASYNC_REQUEST));\r
+\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+VOID\r
+ZeroOutQhOverlay (\r
+  IN EHCI_QH_ENTITY  *QhPtr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Zero out the fields in Qh structure\r
+  \r
+Arguments:\r
+\r
+  QhPtr - A pointer to Qh structure\r
+  \r
+Returns:\r
+\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  QhPtr->Qh.CurrentQtdPointer   = 0;\r
+  QhPtr->Qh.AltNextQtdPointer   = 0;\r
+  QhPtr->Qh.NakCount            = 0;\r
+  QhPtr->Qh.AltNextQtdTerminate = 0;\r
+  QhPtr->Qh.TotalBytes          = 0;\r
+  QhPtr->Qh.InterruptOnComplete = 0;\r
+  QhPtr->Qh.CurrentPage         = 0;\r
+  QhPtr->Qh.ErrorCount          = 0;\r
+  QhPtr->Qh.PidCode             = 0;\r
+  QhPtr->Qh.Status              = 0;\r
+  QhPtr->Qh.BufferPointer0      = 0;\r
+  QhPtr->Qh.CurrentOffset       = 0;\r
+  QhPtr->Qh.BufferPointer1      = 0;\r
+  QhPtr->Qh.CompleteSplitMask   = 0;\r
+  QhPtr->Qh.BufferPointer2      = 0;\r
+  QhPtr->Qh.SplitBytes          = 0;\r
+  QhPtr->Qh.FrameTag            = 0;\r
+  QhPtr->Qh.BufferPointer3      = 0;\r
+  QhPtr->Qh.BufferPointer4      = 0;\r
+  QhPtr->Qh.ExtBufferPointer0   = 0;\r
+  QhPtr->Qh.ExtBufferPointer1   = 0;\r
+  QhPtr->Qh.ExtBufferPointer2   = 0;\r
+  QhPtr->Qh.ExtBufferPointer3   = 0;\r
+  QhPtr->Qh.ExtBufferPointer4   = 0;\r
+}\r
+\r
+VOID\r
+UpdateAsyncRequestTransfer (\r
+  IN EHCI_ASYNC_REQUEST *AsyncRequestPtr,\r
+  IN UINT32             TransferResult,\r
+  IN UINTN              ErrQtdPos\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Update asynchronous request transfer\r
+  \r
+Arguments:\r
+\r
+  AsyncRequestPtr  - A pointer to async request  \r
+  TransferResult   - transfer result \r
+  ErrQtdPos        - postion of error Qtd\r
+  \r
+Returns:\r
+\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  EHCI_QTD_ENTITY *QtdPtr;\r
+\r
+  QtdPtr      = NULL;\r
+\r
+  if (EFI_USB_NOERROR == TransferResult) {\r
+  \r
+    //\r
+    // Update Qh for next trigger\r
+    //\r
+\r
+    QtdPtr = AsyncRequestPtr->QhPtr->FirstQtdPtr;\r
+\r
+    //\r
+    // Update fields in Qh\r
+    //\r
+\r
+    //\r
+    // Get DataToggle from Overlay in Qh\r
+    //\r
+    // ZeroOut Overlay in Qh except DataToggle, HostController will update this field\r
+    //\r
+    ZeroOutQhOverlay (AsyncRequestPtr->QhPtr);\r
+    AsyncRequestPtr->QhPtr->Qh.NextQtdPointer   = (UINT32) (GET_0B_TO_31B (&(QtdPtr->Qtd)) >> 5);\r
+    AsyncRequestPtr->QhPtr->Qh.NextQtdTerminate = FALSE;\r
+\r
+    //\r
+    // Update fields in Qtd\r
+    //\r
+    while (NULL != QtdPtr) {\r
+      QtdPtr->Qtd.TotalBytes    = QtdPtr->StaticTotalBytes;\r
+      QtdPtr->Qtd.CurrentOffset = QtdPtr->StaticCurrentOffset;\r
+      QtdPtr->Qtd.CurrentPage   = 0;\r
+      QtdPtr->Qtd.ErrorCount    = QTD_ERROR_COUNTER;\r
+      QtdPtr->Qtd.Status        = QTD_STATUS_ACTIVE;\r
+\r
+      QtdPtr->TotalBytes        = QtdPtr->StaticTotalBytes;\r
+      QtdPtr                    = QtdPtr->Next;\r
+    }\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+BOOLEAN\r
+CheckQtdsTransferResult (\r
+  IN  BOOLEAN            IsControl,\r
+  IN  EHCI_QH_ENTITY     *QhPtr,\r
+  OUT UINT32             *Result,\r
+  OUT UINTN              *ErrQtdPos,\r
+  OUT UINTN              *ActualLen\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check transfer result of Qtds\r
+\r
+Arguments:\r
+\r
+  IsControl    - Is control transfer or not\r
+  QhPtr        - A pointer to Qh\r
+  Result       - Transfer result\r
+  ErrQtdPos    - Error TD Position\r
+  ActualLen    - Actual Transfer Size\r
+\r
+Returns:\r
+\r
+  TRUE    Qtds finished\r
+  FALSE   Not finish\r
+  \r
+--*/\r
+{\r
+  UINTN           ActualLenPerQtd;\r
+  EHCI_QTD_ENTITY *QtdPtr;\r
+  EHCI_QTD_HW     *QtdHwPtr;\r
+  BOOLEAN         Value;\r
+\r
+  ASSERT (QhPtr);\r
+  ASSERT (Result);\r
+  ASSERT (ErrQtdPos);\r
+  ASSERT (ActualLen);\r
+\r
+  Value     = TRUE;\r
+  QtdPtr    = QhPtr->FirstQtdPtr;\r
+  QtdHwPtr  = &(QtdPtr->Qtd);\r
+\r
+  while (NULL != QtdHwPtr) {\r
+\r
+    if (IsQtdStatusActive (QtdHwPtr)) {\r
+      *Result |= EFI_USB_ERR_NOTEXECUTE;\r
+    }\r
+\r
+    if (IsQtdStatusHalted (QtdHwPtr)) {\r
+      *Result |= EFI_USB_ERR_STALL;\r
+    }\r
+\r
+    if (IsQtdStatusBufferError (QtdHwPtr)) {\r
+      *Result |= EFI_USB_ERR_BUFFER;\r
+    }\r
+\r
+    if (IsQtdStatusBabbleError (QtdHwPtr)) {\r
+      *Result |= EFI_USB_ERR_BABBLE;\r
+    }\r
+\r
+    if (IsQtdStatusTransactionError (QtdHwPtr)) {\r
+      *Result |= EFI_USB_ERR_TIMEOUT;\r
+    }\r
+\r
+    ActualLenPerQtd     = QtdPtr->TotalBytes - QtdHwPtr->TotalBytes;\r
+    QtdPtr->TotalBytes  = QtdHwPtr->TotalBytes;\r
+    //\r
+    // Accumulate actual transferred data length in each DataQtd.\r\r
+    //\r
+    if (SETUP_PACKET_PID_CODE != QtdHwPtr->PidCode) {\r
+      *ActualLen += ActualLenPerQtd;\r
+    }\r
+\r
+    if (*Result) {\r
+      Value = FALSE;\r
+      break;\r
+    }\r
+\r
+    if ((!IsControl) && (QtdPtr->TotalBytes > 0)) {\r
+      //\r
+      // Did something, but isn't full workload\r
+      //\r
+      break;\r
+    }\r
+\r
+    (*ErrQtdPos)++;\r
+    QtdHwPtr = GetQtdNextPointer (QtdHwPtr);\r
+    QtdPtr = (EHCI_QTD_ENTITY *) GET_QTD_ENTITY_ADDR (QtdHwPtr);\r
+\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+EFI_STATUS\r
+ExecuteTransfer (\r
+  IN  USB2_HC_DEV         *HcDev,\r
+  IN  BOOLEAN             IsControl,\r
+  IN  EHCI_QH_ENTITY      *QhPtr,\r
+  IN  OUT UINTN           *ActualLen,\r
+  OUT UINT8               *DataToggle,\r
+  IN  UINTN               TimeOut,\r
+  OUT UINT32              *TransferResult\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Execute Bulk or SyncInterrupt Transfer\r
+\r
+Arguments:\r
+\r
+  HcDev            - USB2_HC_DEV\r
+  IsControl        - Is control transfer or not\r
+  QhPtr            - A pointer to Qh\r
+  ActualLen        - Actual transfered Len \r
+  DataToggle       - Data Toggle\r
+  TimeOut          - TimeOut threshold\r
+  TransferResult   - Transfer result\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS      Sucess\r
+  EFI_DEVICE_ERROR Fail\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       ErrQtdPos;\r
+  UINTN       Delay;\r
+  UINTN       RequireLen;\r
+  BOOLEAN     Finished;\r
+\r
+  Status          = EFI_SUCCESS;\r
+  ErrQtdPos       = 0;\r
+  *TransferResult = EFI_USB_NOERROR;\r
+  RequireLen      = *ActualLen;\r
+  *ActualLen      = 0;\r
+  Finished        = FALSE;\r
+\r
+  Delay           = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;\r
+\r
+  do {\r
+    *TransferResult = 0;\r
+    Finished = CheckQtdsTransferResult (\r
+                 IsControl,\r
+                 QhPtr,\r
+                 TransferResult,\r
+                 &ErrQtdPos,\r
+                 ActualLen\r
+                 );\r
+    if (Finished) {\r
+      break;\r
+    }\r
+    //\r
+    // Qtd is inactive, which means bulk or interrupt transfer's end.\r
+    //\r
+    if (!(*TransferResult & EFI_USB_ERR_NOTEXECUTE)) {\r
+      break;\r
+    }\r
+\r
+    gBS->Stall (EHCI_SYNC_REQUEST_POLLING_TIME);\r
+\r
+  } while (--Delay);\r
+\r
+  if (EFI_USB_NOERROR != *TransferResult) {\r
+    if (0 == Delay) {\r
+      Status = EFI_TIMEOUT;\r
+    } else {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Special for Bulk and Interrupt Transfer\r
+  //\r
+  *DataToggle = (UINT8) QhPtr->Qh.DataToggle;\r
+  \r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+AsyncRequestMoniter (\r
+  IN EFI_EVENT     Event,\r
+  IN VOID          *Context\r
+  )\r
+/*++\r
+Routine Description:\r
+  \r
+  Interrupt transfer periodic check handler\r
+    \r
+Arguments:\r
+  Event    - Interrupt event\r
+  Context  - Pointer to USB2_HC_DEV\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS        Success\r
+  EFI_DEVICE_ERROR   Fail\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  USB2_HC_DEV         *HcDev;\r
+  EHCI_ASYNC_REQUEST  *AsyncRequestPtr;\r
+  EHCI_QTD_HW         *QtdHwPtr;\r
+  UINTN               ErrQtdPos;\r
+  UINTN               ActualLen;\r
+  UINT32              TransferResult;\r
+  UINT8               *ReceiveBuffer;\r
+  UINT8               *ProcessBuffer;\r
+\r
+  Status          = EFI_SUCCESS;\r
+  QtdHwPtr        = NULL;\r
+  ReceiveBuffer   = NULL;\r
+  ProcessBuffer   = NULL;\r
+  HcDev           = (USB2_HC_DEV *) Context;\r
+  AsyncRequestPtr = HcDev->AsyncRequestList;\r
+\r
+  while (NULL != AsyncRequestPtr) {\r
+\r
+    TransferResult  = 0;\r
+    ErrQtdPos       = 0;\r
+    ActualLen       = 0;\r
+\r
+    CheckQtdsTransferResult (\r
+      FALSE, \r
+      AsyncRequestPtr->QhPtr, \r
+      &TransferResult, \r
+      &ErrQtdPos, \r
+      &ActualLen\r
+      );\r
+\r
+    if ((TransferResult & EFI_USB_ERR_NAK) || (TransferResult & EFI_USB_ERR_NOTEXECUTE)) {\r
+      AsyncRequestPtr = AsyncRequestPtr->Next;\r
+      continue;\r
+    }\r
+    //\r
+    // Allocate memory for EHC private data structure\r
+    //\r
+    ProcessBuffer = AllocateZeroPool (ActualLen);\r
+    if (NULL == ProcessBuffer) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto exit;\r
+    }\r
+\r
+    QtdHwPtr = &(AsyncRequestPtr->QhPtr->FirstQtdPtr->Qtd);\r
+    ReceiveBuffer = (UINT8 *) GET_0B_TO_31B ((QtdHwPtr->BufferPointer0 << 12) | AsyncRequestPtr->QhPtr->FirstQtdPtr->StaticCurrentOffset);\r
+    CopyMem (\r
+      ProcessBuffer,\r
+      ReceiveBuffer,\r
+      ActualLen\r
+      );\r
+\r
+    UpdateAsyncRequestTransfer (AsyncRequestPtr, TransferResult, ErrQtdPos);\r
+\r
+    if (EFI_USB_NOERROR == TransferResult) {\r
+\r
+      if (AsyncRequestPtr->CallBackFunc != NULL) {\r
+        (AsyncRequestPtr->CallBackFunc) (ProcessBuffer, ActualLen, AsyncRequestPtr->Context, TransferResult);\r
+      }\r
+\r
+    } else {\r
+\r
+      //\r
+      // leave error recovery to its related device driver. A common case of \r
+      // the error recovery is to re-submit the interrupt transfer.\r
+      // When an interrupt transfer is re-submitted, its position in the linked\r
+      // list is changed. It is inserted to the head of the linked list, while\r
+      // this function scans the whole list from head to tail. Thus, the\r
+      // re-submitted interrupt transfer's callback function will not be called\r
+      // again in this round.\r
+      //\r
+      if (AsyncRequestPtr->CallBackFunc != NULL) {\r
+        (AsyncRequestPtr->CallBackFunc) (NULL, 0, AsyncRequestPtr->Context, TransferResult);\r
+      }\r
+\r
+    }\r
+\r
+    if (NULL != ProcessBuffer) {\r
+      gBS->FreePool (ProcessBuffer);\r
+    }\r
+\r
+    AsyncRequestPtr = AsyncRequestPtr->Next;\r
+\r
+  }\r
+\r
+exit:\r
+  return Status;\r
+}\r
+\r