]> git.proxmox.com Git - mirror_edk2.git/blobdiff - QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
QuarkSocPkg: Add new package for Quark SoC X1000
[mirror_edk2.git] / QuarkSocPkg / QuarkSouthCluster / Usb / Ohci / Dxe / Ohci.c
diff --git a/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c b/QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/Ohci.c
new file mode 100644 (file)
index 0000000..f73a09b
--- /dev/null
@@ -0,0 +1,2488 @@
+/** @file\r
+This file contains the implementation of Usb Hc Protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+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
+**/\r
+\r
+\r
+#include "Ohci.h"\r
+\r
+/**\r
+  Provides software reset for the USB host controller.\r
+\r
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.\r
+  @param  Attributes            A bit mask of the reset operation to perform.\r
+\r
+  @retval EFI_SUCCESS           The reset operation succeeded.\r
+  @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
+  @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is\r
+                                not currently supported by the host controller.\r
+  @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciReset (\r
+  IN EFI_USB_HC_PROTOCOL  *This,\r
+  IN UINT16               Attributes\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+  UINT8                   Index;\r
+  UINT8                   NumOfPorts;\r
+  UINT32                  PowerOnGoodTime;\r
+  UINT32                  Data32;\r
+  BOOLEAN                 Flag = FALSE;\r
+\r
+  if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+  if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {\r
+    gBS->Stall (50 * 1000);\r
+    Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    gBS->Stall (50 * 1000);\r
+    //\r
+    // Wait for host controller reset.\r
+    //\r
+    PowerOnGoodTime = 50;\r
+    do {\r
+      gBS->Stall (1 * 1000);\r
+      Data32 = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS );\r
+      if (EFI_ERROR (Status)) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      if ((Data32 & HC_RESET) == 0) {\r
+        Flag = TRUE;\r
+        break;\r
+      }\r
+    }while(PowerOnGoodTime--);\r
+    if (!Flag){\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+  OhciFreeIntTransferMemory (Ohc);\r
+  Status = OhciInitializeInterruptList (Ohc);\r
+  OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
+  if ((Attributes &  EFI_USB_HC_RESET_GLOBAL) != 0) {\r
+    Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    gBS->Stall (50 * 1000);\r
+  }\r
+  //\r
+  // Initialize host controller operational registers\r
+  //\r
+  OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);\r
+  OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
+  OhciSetPeriodicStart (Ohc, 0x2a2f);\r
+  OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3);\r
+  OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);\r
+  OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);\r
+  OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);\r
+  //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);\r
+  //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);\r
+\r
+  OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);\r
+  OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);\r
+  OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);\r
+  OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);\r
+  OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
+  for (Index = 0; Index < NumOfPorts; Index++) {\r
+    if (!EFI_ERROR (OhciSetRootHubPortFeature (This, Index, EfiUsbPortReset))) {\r
+      gBS->Stall (200 * 1000);\r
+      OhciClearRootHubPortFeature (This, Index, EfiUsbPortReset);\r
+      gBS->Stall (1000);\r
+      OhciSetRootHubPortFeature (This, Index, EfiUsbPortEnable);\r
+      gBS->Stall (1000);\r
+    }\r
+  }\r
+  OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock);\r
+  OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
+  OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
+  OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); /*ISOCHRONOUS_ENABLE*/\r
+  OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);\r
+  gBS->Stall (50*1000);\r
+  //\r
+  // Wait till first SOF occurs, and then clear it\r
+  //\r
+  while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);\r
+  OhciClearInterruptStatus (Ohc, START_OF_FRAME);\r
+  gBS->Stall (1000);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieve the current state of the USB host controller.\r
+\r
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.\r
+  @param  State                 Variable to return the current host controller\r
+                                state.\r
+\r
+  @retval EFI_SUCCESS           Host controller state was returned in State.\r
+  @retval EFI_INVALID_PARAMETER State is NULL.\r
+  @retval EFI_DEVICE_ERROR      An error was encountered while attempting to\r
+                                retrieve the host controller's current state.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetState (\r
+  IN  EFI_USB_HC_PROTOCOL  *This,\r
+  OUT EFI_USB_HC_STATE     *State\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+  UINT32                  FuncState;\r
+\r
+  if (State == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+  FuncState = OhciGetHcControl (Ohc, HC_FUNCTIONAL_STATE);\r
+\r
+  switch (FuncState) {\r
+    case HC_STATE_RESET:\r
+    case HC_STATE_RESUME:\r
+      *State = EfiUsbHcStateHalt;\r
+      break;\r
+\r
+    case HC_STATE_OPERATIONAL:\r
+      *State = EfiUsbHcStateOperational;\r
+      break;\r
+\r
+    case HC_STATE_SUSPEND:\r
+      *State = EfiUsbHcStateSuspend;\r
+      break;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Sets the USB host controller to a specific state.\r
+\r
+  @param  This                  This EFI_USB_HC_PROTOCOL instance.\r
+  @param  State                 The state of the host controller that will be set.\r
+\r
+  @retval EFI_SUCCESS           The USB host controller was successfully placed\r
+                                in the state specified by State.\r
+  @retval EFI_INVALID_PARAMETER State is invalid.\r
+  @retval EFI_DEVICE_ERROR      Failed to set the state due to device error.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSetState(\r
+  IN EFI_USB_HC_PROTOCOL  *This,\r
+  IN EFI_USB_HC_STATE     State\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);\r
+\r
+  switch (State) {\r
+    case EfiUsbHcStateHalt:\r
+      Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);\r
+      break;\r
+\r
+    case EfiUsbHcStateOperational:\r
+      Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);\r
+      break;\r
+\r
+    case EfiUsbHcStateSuspend:\r
+      Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_SUSPEND);\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  gBS->Stall (1000);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Submits control transfer to a target USB device.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  DeviceAddress         Represents the address of the target device on the USB,\r
+                                which is assigned during USB enumeration.\r
+  @param  IsSlowDevice          Indicates whether the target device is slow device\r
+                                or full-speed device.\r
+  @param  MaxPaketLength        Indicates the maximum packet size that the\r
+                                default control transfer endpoint is capable of\r
+                                sending or receiving.\r
+  @param  Request               A pointer to the USB device request that will be sent\r
+                                to the USB device.\r
+  @param  TransferDirection     Specifies the data direction for the transfer.\r
+                                There are three values available, DataIn, DataOut\r
+                                and NoData.\r
+  @param  Data                  A pointer to the buffer of data that will be transmitted\r
+                                to USB device or received from USB device.\r
+  @param  DataLength            Indicates the size, in bytes, of the data buffer\r
+                                specified by Data.\r
+  @param  TimeOut               Indicates the maximum time, in microseconds,\r
+                                which the transfer is allowed to complete.\r
+  @param  TransferResult        A pointer to the detailed result information generated\r
+                                by this control transfer.\r
+\r
+  @retval EFI_SUCCESS           The control transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The control transfer could not be completed due to a lack of resources.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_TIMEOUT           The control transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The control transfer failed due to host controller or device error.\r
+                                Caller should check TranferResult for detailed error information.\r
+\r
+--*/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciControlTransfer (\r
+  IN     EFI_USB_HC_PROTOCOL     *This,\r
+  IN     UINT8                   DeviceAddress,\r
+  IN     BOOLEAN                 IsSlowDevice,\r
+  IN     UINT8                   MaxPacketLength,\r
+  IN     EFI_USB_DEVICE_REQUEST  *Request,\r
+  IN     EFI_USB_DATA_DIRECTION  TransferDirection,\r
+  IN OUT VOID                    *Data                 OPTIONAL,\r
+  IN OUT UINTN                   *DataLength           OPTIONAL,\r
+  IN     UINTN                   TimeOut,\r
+  OUT    UINT32                  *TransferResult\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV                *Ohc;\r
+  ED_DESCRIPTOR                  *HeadEd;\r
+  ED_DESCRIPTOR                  *Ed;\r
+  TD_DESCRIPTOR                  *HeadTd;\r
+  TD_DESCRIPTOR                  *SetupTd;\r
+  TD_DESCRIPTOR                  *DataTd;\r
+  TD_DESCRIPTOR                  *StatusTd;\r
+  TD_DESCRIPTOR                  *EmptyTd;\r
+  EFI_STATUS                     Status;\r
+  UINT32                         DataPidDir;\r
+  UINT32                         StatusPidDir;\r
+  UINTN                          TimeCount;\r
+  OHCI_ED_RESULT                 EdResult;\r
+\r
+  EFI_PCI_IO_PROTOCOL_OPERATION  MapOp;\r
+\r
+  UINTN                          ActualSendLength;\r
+  UINTN                          LeftLength;\r
+  UINT8                          DataToggle;\r
+\r
+  VOID                           *ReqMapping = NULL;\r
+  UINTN                          ReqMapLength = 0;\r
+  EFI_PHYSICAL_ADDRESS           ReqMapPhyAddr = 0;\r
+\r
+  VOID                           *DataMapping = NULL;\r
+  UINTN                          DataMapLength = 0;\r
+  EFI_PHYSICAL_ADDRESS           DataMapPhyAddr = 0;\r
+\r
+  HeadTd = NULL;\r
+  DataTd = NULL;\r
+\r
+  if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&\r
+       TransferDirection != EfiUsbNoData) ||\r
+      Request == NULL || DataLength == NULL || TransferResult == NULL ||\r
+      (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||\r
+      (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||\r
+      (IsSlowDevice && MaxPacketLength != 8) ||\r
+      (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
+       MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*DataLength > MAX_BYTES_PER_TD) {\r
+    DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\r\n"));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);\r
+\r
+  if (TransferDirection == EfiUsbDataIn) {\r
+    DataPidDir = TD_IN_PID;\r
+    StatusPidDir = TD_OUT_PID;\r
+  } else {\r
+    DataPidDir = TD_OUT_PID;\r
+    StatusPidDir = TD_IN_PID;\r
+  }\r
+\r
+  Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n"));\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 0);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n"));\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  gBS->Stall(20 * 1000);\r
+\r
+  OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
+  Ed = OhciCreateED (Ohc);\r
+  if (Ed == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\r\n"));\r
+    goto CTRL_EXIT;\r
+  }\r
+  OhciSetEDField (Ed, ED_SKIP, 1);\r
+  OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
+  OhciSetEDField (Ed, ED_ENDPT_NUM, 0);\r
+  OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
+  OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);\r
+  OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
+  OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
+  OhciSetEDField (Ed, ED_PDATA, 0);\r
+  OhciSetEDField (Ed, ED_ZERO, 0);\r
+  OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
+  OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
+  OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
+  HeadEd = OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);\r
+  //\r
+  // Setup Stage\r
+  //\r
+  if(Request != NULL) {\r
+    ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST);\r
+    MapOp = EfiPciIoOperationBusMasterRead;\r
+    Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Request, &ReqMapLength, &ReqMapPhyAddr, &ReqMapping);\r
+    if (EFI_ERROR(Status)) {\r
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to Map Request Buffer\r\n"));\r
+      goto FREE_ED_BUFF;\r
+    }\r
+  }\r
+  SetupTd = OhciCreateTD (Ohc);\r
+  if (SetupTd == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n"));\r
+    goto UNMAP_SETUP_BUFF;\r
+  }\r
+  HeadTd = SetupTd;\r
+  OhciSetTDField (SetupTd, TD_PDATA, 0);\r
+  OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);\r
+  OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);\r
+  OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);\r
+  OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);\r
+  OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);\r
+  OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+  OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINT32)ReqMapPhyAddr);\r
+  OhciSetTDField (SetupTd, TD_NEXT_PTR, 0);\r
+  OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINT32)(ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1));\r
+  SetupTd->ActualSendLength = sizeof (EFI_USB_DEVICE_REQUEST);\r
+  SetupTd->DataBuffer = (UINT32)ReqMapPhyAddr;\r
+  SetupTd->NextTDPointer = 0;\r
+\r
+  if (TransferDirection == EfiUsbDataIn) {\r
+    MapOp = EfiPciIoOperationBusMasterWrite;\r
+  } else {\r
+    MapOp = EfiPciIoOperationBusMasterRead;\r
+  }\r
+  DataMapLength = *DataLength;\r
+  if ((Data != NULL) && (DataMapLength != 0)) {\r
+    Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, Data, &DataMapLength, &DataMapPhyAddr, &DataMapping);\r
+    if (EFI_ERROR(Status)) {\r
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail To Map Data Buffer\r\n"));\r
+      goto FREE_TD_BUFF;\r
+    }\r
+  }\r
+  //\r
+  //Data Stage\r
+  //\r
+  LeftLength = DataMapLength;\r
+  ActualSendLength = DataMapLength;\r
+  DataToggle = 1;\r
+  while (LeftLength > 0) {\r
+    ActualSendLength = LeftLength;\r
+    if (LeftLength > MaxPacketLength) {\r
+      ActualSendLength = MaxPacketLength;\r
+    }\r
+    DataTd = OhciCreateTD (Ohc);\r
+    if (DataTd == NULL) {\r
+      DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto UNMAP_DATA_BUFF;\r
+    }\r
+    OhciSetTDField (DataTd, TD_PDATA, 0);\r
+    OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
+    OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
+    OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
+    OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);\r
+    OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+    OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+    OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);\r
+    OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(DataMapPhyAddr + ActualSendLength - 1));\r
+    OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
+    DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
+    DataTd->DataBuffer = (UINT32)DataMapPhyAddr;\r
+    DataTd->NextTDPointer = 0;\r
+    OhciLinkTD (HeadTd, DataTd);\r
+    DataToggle ^= 1;\r
+    DataMapPhyAddr += ActualSendLength;\r
+    LeftLength -= ActualSendLength;\r
+  }\r
+  //\r
+  // Status Stage\r
+  //\r
+  StatusTd = OhciCreateTD (Ohc);\r
+  if (StatusTd == NULL) {\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto UNMAP_DATA_BUFF;\r
+  }\r
+  OhciSetTDField (StatusTd, TD_PDATA, 0);\r
+  OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);\r
+  OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);\r
+  OhciSetTDField (StatusTd, TD_DELAY_INT, 7);\r
+  OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);\r
+  OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);\r
+  OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+  OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, 0);\r
+  OhciSetTDField (StatusTd, TD_NEXT_PTR, 0);\r
+  OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, 0);\r
+  StatusTd->ActualSendLength = 0;\r
+  StatusTd->DataBuffer = 0;\r
+  StatusTd->NextTDPointer = 0;\r
+  OhciLinkTD (HeadTd, StatusTd);\r
+  //\r
+  // Empty Stage\r
+  //\r
+  EmptyTd = OhciCreateTD (Ohc);\r
+  if (EmptyTd == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto UNMAP_DATA_BUFF;\r
+  }\r
+  OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
+  OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
+  OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
+  OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
+  //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
+  EmptyTd->Word0.DataToggle = 0;\r
+  OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
+  OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
+  OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
+  OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
+  OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
+  EmptyTd->ActualSendLength = 0;\r
+  EmptyTd->DataBuffer = 0;\r
+  EmptyTd->NextTDPointer = 0;\r
+  OhciLinkTD (HeadTd, EmptyTd);\r
+  Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;\r
+  OhciAttachTDListToED (Ed, HeadTd);\r
+  //\r
+  // For debugging,  dump ED & TD buffer befor transferring\r
+  //\r
+  //\r
+  //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE);\r
+  //\r
+  OhciSetEDField (Ed, ED_SKIP, 0);\r
+  Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n"));\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto UNMAP_DATA_BUFF;\r
+  }\r
+  Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n"));\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto UNMAP_DATA_BUFF;\r
+  }\r
+  gBS->Stall(20 * 1000);\r
+\r
+\r
+  TimeCount = 0;\r
+  Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);\r
+\r
+  while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
+    gBS->Stall (1000);\r
+    TimeCount++;\r
+    Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);\r
+  }\r
+  //\r
+  // For debugging, dump ED & TD buffer after transferring\r
+  //\r
+  //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE);\r
+  //\r
+  *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
+\r
+  if (EdResult.ErrorCode != TD_NO_ERROR) {\r
+    if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {\r
+      DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));\r
+    } else {\r
+      DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));\r
+    }\r
+    *DataLength = 0;\r
+  } else {\r
+    DEBUG ((EFI_D_INFO, "Control transfer successed\r\n"));\r
+  }\r
+\r
+UNMAP_DATA_BUFF:\r
+  OhciSetEDField (Ed, ED_SKIP, 1);\r
+  if (HeadEd == Ed) {\r
+    OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
+  } else {\r
+    HeadEd->NextED = Ed->NextED;\r
+  }\r
+  if(DataMapping != NULL) {\r
+    Ohc->PciIo->Unmap(Ohc->PciIo, DataMapping);\r
+  }\r
+\r
+FREE_TD_BUFF:\r
+  while (HeadTd) {\r
+    DataTd = HeadTd;\r
+    HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
+    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
+  }\r
+\r
+UNMAP_SETUP_BUFF:\r
+  if(ReqMapping != NULL) {\r
+    Ohc->PciIo->Unmap(Ohc->PciIo, ReqMapping);\r
+  }\r
+\r
+FREE_ED_BUFF:\r
+  UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+\r
+CTRL_EXIT:\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  DeviceAddress         Represents the address of the target device on the USB,\r
+                                which is assigned during USB enumeration.\r
+  @param  EndPointAddress       The combination of an endpoint number and an\r
+                                endpoint direction of the target USB device.\r
+                                Each endpoint address supports data transfer in\r
+                                one direction except the control endpoint\r
+                                (whose default endpoint address is 0).\r
+                                It is the caller's responsibility to make sure that\r
+                                the EndPointAddress represents a bulk endpoint.\r
+  @param  MaximumPacketLength   Indicates the maximum packet size the target endpoint\r
+                                is capable of sending or receiving.\r
+  @param  Data                  A pointer to the buffer of data that will be transmitted\r
+                                to USB device or received from USB device.\r
+  @param  DataLength            When input, indicates the size, in bytes, of the data buffer\r
+                                specified by Data. When output, indicates the actually\r
+                                transferred data size.\r
+  @param  DataToggle            A pointer to the data toggle value. On input, it indicates\r
+                                the initial data toggle value the bulk transfer should adopt;\r
+                                on output, it is updated to indicate the data toggle value\r
+                                of the subsequent bulk transfer.\r
+  @param  TimeOut               Indicates the maximum time, in microseconds, which the\r
+                                transfer is allowed to complete.\r
+  TransferResult                A pointer to the detailed result information of the\r
+                                bulk transfer.\r
+\r
+  @retval EFI_SUCCESS           The bulk transfer was completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The bulk transfer could not be submitted due to lack of resource.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_TIMEOUT           The bulk transfer failed due to timeout.\r
+  @retval EFI_DEVICE_ERROR      The bulk transfer failed due to host controller or device error.\r
+                                Caller should check TranferResult for detailed error information.\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciBulkTransfer(\r
+  IN     EFI_USB_HC_PROTOCOL  *This,\r
+  IN     UINT8                DeviceAddress,\r
+  IN     UINT8                EndPointAddress,\r
+  IN     UINT8                MaxPacketLength,\r
+  IN OUT VOID                 *Data,\r
+  IN OUT UINTN                *DataLength,\r
+  IN OUT UINT8                *DataToggle,\r
+  IN     UINTN                TimeOut,\r
+  OUT    UINT32               *TransferResult\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV                *Ohc;\r
+  ED_DESCRIPTOR                  *HeadEd;\r
+  ED_DESCRIPTOR                  *Ed;\r
+  UINT8                          EdDir;\r
+  UINT32                         DataPidDir;\r
+  TD_DESCRIPTOR                  *HeadTd;\r
+  TD_DESCRIPTOR                  *DataTd;\r
+  TD_DESCRIPTOR                  *EmptyTd;\r
+  EFI_STATUS                     Status;\r
+  EFI_USB_DATA_DIRECTION         TransferDirection;\r
+  UINT8                          EndPointNum;\r
+  UINTN                          TimeCount;\r
+  OHCI_ED_RESULT                 EdResult;\r
+\r
+  EFI_PCI_IO_PROTOCOL_OPERATION  MapOp;\r
+  VOID                           *Mapping;\r
+  UINTN                          MapLength;\r
+  EFI_PHYSICAL_ADDRESS           MapPyhAddr;\r
+  UINTN                          LeftLength;\r
+  UINTN                          ActualSendLength;\r
+  BOOLEAN                        FirstTD;\r
+\r
+  Mapping = NULL;\r
+  MapLength = 0;\r
+  MapPyhAddr = 0;\r
+  LeftLength = 0;\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||\r
+      *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||\r
+      (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
+       MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+  if ((EndPointAddress & 0x80) != 0) {\r
+    TransferDirection = EfiUsbDataIn;\r
+    EdDir = ED_IN_DIR;\r
+    DataPidDir = TD_IN_PID;\r
+    MapOp = EfiPciIoOperationBusMasterWrite;\r
+  } else {\r
+    TransferDirection = EfiUsbDataOut;\r
+    EdDir = ED_OUT_DIR;\r
+    DataPidDir = TD_OUT_PID;\r
+    MapOp = EfiPciIoOperationBusMasterRead;\r
+  }\r
+\r
+  EndPointNum = (EndPointAddress & 0xF);\r
+  EdResult.NextToggle = *DataToggle;\r
+\r
+  Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n"));\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n"));\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  gBS->Stall(20 * 1000);\r
+\r
+  OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
+\r
+  Ed = OhciCreateED (Ohc);\r
+  if (Ed == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  OhciSetEDField (Ed, ED_SKIP, 1);\r
+  OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
+  OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
+  OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
+  OhciSetEDField (Ed, ED_SPEED, HI_SPEED);\r
+  OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
+  OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
+  OhciSetEDField (Ed, ED_PDATA, 0);\r
+  OhciSetEDField (Ed, ED_ZERO, 0);\r
+  OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
+  OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
+  OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
+  HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);\r
+\r
+  if(Data != NULL) {\r
+    MapLength = *DataLength;\r
+    Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping);\r
+    if (EFI_ERROR(Status)) {\r
+      DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n"));\r
+      goto FREE_ED_BUFF;\r
+    }\r
+  }\r
+  //\r
+  //Data Stage\r
+  //\r
+  LeftLength = MapLength;\r
+  ActualSendLength = MapLength;\r
+  HeadTd = NULL;\r
+  FirstTD = TRUE;\r
+  while (LeftLength > 0) {\r
+    ActualSendLength = LeftLength;\r
+    if (LeftLength > MaxPacketLength) {\r
+      ActualSendLength = MaxPacketLength;\r
+    }\r
+    DataTd = OhciCreateTD (Ohc);\r
+    if (DataTd == NULL) {\r
+      DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto FREE_OHCI_TDBUFF;\r
+    }\r
+    OhciSetTDField (DataTd, TD_PDATA, 0);\r
+    OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
+    OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
+    OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
+    OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);\r
+    OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+    OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+    OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
+    OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));\r
+    OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
+    DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
+    DataTd->DataBuffer = (UINT32)MapPyhAddr;\r
+    DataTd->NextTDPointer = 0;\r
+    if (FirstTD) {\r
+      HeadTd = DataTd;\r
+      FirstTD = FALSE;\r
+    } else {\r
+      OhciLinkTD (HeadTd, DataTd);\r
+    }\r
+    *DataToggle ^= 1;\r
+    MapPyhAddr += ActualSendLength;\r
+    LeftLength -= ActualSendLength;\r
+  }\r
+  //\r
+  // Empty Stage\r
+  //\r
+  EmptyTd = OhciCreateTD (Ohc);\r
+  if (EmptyTd == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n"));\r
+    goto FREE_OHCI_TDBUFF;\r
+  }\r
+  OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
+  OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
+  OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
+  OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
+  //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
+  EmptyTd->Word0.DataToggle = 0;\r
+  OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
+  OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
+  OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
+  OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
+  OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
+  EmptyTd->ActualSendLength = 0;\r
+  EmptyTd->DataBuffer = 0;\r
+  EmptyTd->NextTDPointer = 0;\r
+  OhciLinkTD (HeadTd, EmptyTd);\r
+  Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;\r
+  OhciAttachTDListToED (Ed, HeadTd);\r
+\r
+  OhciSetEDField (Ed, ED_SKIP, 0);\r
+  Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);\r
+  if (EFI_ERROR(Status)) {\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    Status = EFI_DEVICE_ERROR;\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n"));\r
+    goto FREE_OHCI_TDBUFF;\r
+  }\r
+  Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1);\r
+  if (EFI_ERROR(Status)) {\r
+    *TransferResult = EFI_USB_ERR_SYSTEM;\r
+    Status = EFI_DEVICE_ERROR;\r
+    DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n"));\r
+    goto FREE_OHCI_TDBUFF;\r
+  }\r
+  gBS->Stall(20 * 1000);\r
+\r
+  TimeCount = 0;\r
+  Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);\r
+  while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
+    gBS->Stall (1000);\r
+    TimeCount++;\r
+    Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);\r
+  }\r
+\r
+  *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
+\r
+  if (EdResult.ErrorCode != TD_NO_ERROR) {\r
+    if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {\r
+      DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));\r
+    } else {\r
+      DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));\r
+      *DataToggle = EdResult.NextToggle;\r
+    }\r
+    *DataLength = 0;\r
+  } else {\r
+    DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n"));\r
+  }\r
+  //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);\r
+\r
+FREE_OHCI_TDBUFF:\r
+  OhciSetEDField (Ed, ED_SKIP, 1);\r
+  if (HeadEd == Ed) {\r
+    OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
+  }else {\r
+    HeadEd->NextED = Ed->NextED;\r
+  }\r
+  while (HeadTd) {\r
+    DataTd = HeadTd;\r
+    HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
+    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
+  }\r
+\r
+  if(Mapping != NULL) {\r
+    Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);\r
+  }\r
+\r
+FREE_ED_BUFF:\r
+  UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+\r
+  return Status;\r
+}\r
+/**\r
+\r
+  Submits an interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+  @param  Ohc                   Device private data\r
+  @param  DeviceAddress         Represents the address of the target device on the USB,\r
+                                which is assigned during USB enumeration.\r
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint\r
+                                direction of the target USB device. Each endpoint address\r
+                                supports data transfer in one direction except the\r
+                                control endpoint (whose default endpoint address is 0).\r
+                                It is the caller's responsibility to make sure that\r
+                                the EndPointAddress represents an interrupt endpoint.\r
+  @param  IsSlowDevice          Indicates whether the target device is slow device\r
+                                or full-speed device.\r
+  @param  MaxPacketLength       Indicates the maximum packet size the target endpoint\r
+                                is capable of sending or receiving.\r
+  @param  IsNewTransfer         If TRUE, an asynchronous interrupt pipe is built between\r
+                                the host and the target interrupt endpoint.\r
+                                If FALSE, the specified asynchronous interrupt pipe\r
+                                is canceled.\r
+  @param  DataToggle            A pointer to the data toggle value.  On input, it is valid\r
+                                when IsNewTransfer is TRUE, and it indicates the initial\r
+                                data toggle value the asynchronous interrupt transfer\r
+                                should adopt.\r
+                                On output, it is valid when IsNewTransfer is FALSE,\r
+                                and it is updated to indicate the data toggle value of\r
+                                the subsequent asynchronous interrupt transfer.\r
+  @param  PollingInterval       Indicates the interval, in milliseconds, that the\r
+                                asynchronous interrupt transfer is polled.\r
+                                This parameter is required when IsNewTransfer is TRUE.\r
+  @param  UCBuffer              Uncacheable buffer\r
+  @param  DataLength            Indicates the length of data to be received at the\r
+                                rate specified by PollingInterval from the target\r
+                                asynchronous interrupt endpoint.  This parameter\r
+                                is only required when IsNewTransfer is TRUE.\r
+  @param  CallBackFunction      The Callback function.This function is called at the\r
+                                rate specified by PollingInterval.This parameter is\r
+                                only required when IsNewTransfer is TRUE.\r
+  @param  Context               The context that is passed to the CallBackFunction.\r
+                                This is an optional parameter and may be NULL.\r
+  @param  IsPeriodic            Periodic interrupt or not\r
+  @param  OutputED              The correspoding ED carried out\r
+  @param  OutputTD              The correspoding TD carried out\r
+\r
+\r
+  @retval EFI_SUCCESS           The asynchronous interrupt transfer request has been successfully\r
+                                submitted or canceled.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciInterruptTransfer (\r
+  IN     USB_OHCI_HC_DEV                  *Ohc,\r
+  IN     UINT8                            DeviceAddress,\r
+  IN     UINT8                            EndPointAddress,\r
+  IN     BOOLEAN                          IsSlowDevice,\r
+  IN     UINT8                            MaxPacketLength,\r
+  IN     BOOLEAN                          IsNewTransfer,\r
+  IN OUT UINT8                            *DataToggle        OPTIONAL,\r
+  IN     UINTN                            PollingInterval    OPTIONAL,\r
+  IN     VOID                             *UCBuffer          OPTIONAL,\r
+  IN     UINTN                            DataLength         OPTIONAL,\r
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK  CallBackFunction   OPTIONAL,\r
+  IN     VOID                             *Context           OPTIONAL,\r
+  IN     BOOLEAN                          IsPeriodic         OPTIONAL,\r
+  OUT    ED_DESCRIPTOR                    **OutputED         OPTIONAL,\r
+  OUT    TD_DESCRIPTOR                    **OutputTD         OPTIONAL\r
+  )\r
+{\r
+  ED_DESCRIPTOR            *Ed;\r
+  UINT8                    EdDir;\r
+  ED_DESCRIPTOR            *HeadEd;\r
+  TD_DESCRIPTOR            *HeadTd;\r
+  TD_DESCRIPTOR            *DataTd;\r
+  TD_DESCRIPTOR            *EmptTd;\r
+  UINTN                    Depth;\r
+  UINTN                    Index;\r
+  EFI_STATUS               Status;\r
+  UINT8                    EndPointNum;\r
+  UINT32                   DataPidDir;\r
+  EFI_USB_DATA_DIRECTION   TransferDirection;\r
+  INTERRUPT_CONTEXT_ENTRY  *Entry;\r
+  EFI_TPL                  OldTpl;\r
+  BOOLEAN                  FirstTD;\r
+\r
+ VOID                      *Mapping;\r
+ UINTN                     MapLength;\r
+ EFI_PHYSICAL_ADDRESS      MapPyhAddr;\r
+ UINTN                     LeftLength;\r
+ UINTN                     ActualSendLength;\r
+\r
+\r
+  if (DataLength > MAX_BYTES_PER_TD) {\r
+    DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n"));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((EndPointAddress & 0x80) != 0) {\r
+    TransferDirection = EfiUsbDataIn;\r
+    EdDir = ED_IN_DIR;\r
+    DataPidDir = TD_IN_PID;\r
+  } else {\r
+    TransferDirection = EfiUsbDataOut;\r
+    EdDir = ED_OUT_DIR;\r
+    DataPidDir = TD_OUT_PID;\r
+  }\r
+\r
+  EndPointNum = (EndPointAddress & 0xF);\r
+\r
+  if (!IsNewTransfer) {\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0);\r
+    OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle);\r
+    Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum);\r
+    OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);\r
+    gBS->RestoreTPL (OldTpl);\r
+    return Status;\r
+  }\r
+  MapLength = DataLength;\r
+  Status = Ohc->PciIo->Map(\r
+                         Ohc->PciIo,\r
+                         EfiPciIoOperationBusMasterWrite,\r
+                         UCBuffer,\r
+                         &MapLength,\r
+                         &MapPyhAddr,\r
+                         &Mapping\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n"));\r
+    goto EXIT;\r
+  }\r
+  Depth = 5;\r
+  Index = 1;\r
+  while (PollingInterval >= Index * 2 && Depth > 0) {\r
+    Index *= 2;\r
+    Depth--;\r
+  }\r
+  //\r
+  //ED Stage\r
+  //\r
+  HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth);\r
+  if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) {\r
+    OhciSetEDField (Ed, ED_SKIP, 1);\r
+  } else {\r
+    Ed = OhciCreateED (Ohc);\r
+    if (Ed == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n"));\r
+      goto UNMAP_OHCI_XBUFF;\r
+    }\r
+    OhciSetEDField (Ed, ED_SKIP, 1);\r
+    OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
+    OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
+    OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
+    OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);\r
+    OhciSetEDField (Ed, ED_FORMAT, 0);\r
+    OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
+    OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0);\r
+    OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
+    OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
+    OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
+    OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd);\r
+  }\r
+  //\r
+  //Data Stage\r
+  //\r
+  LeftLength = MapLength;\r
+  ActualSendLength = MapLength;\r
+  HeadTd = NULL;\r
+  FirstTD = TRUE;\r
+  while (LeftLength > 0) {\r
+    ActualSendLength = LeftLength;\r
+    if (LeftLength > MaxPacketLength) {\r
+      ActualSendLength = MaxPacketLength;\r
+    }\r
+    DataTd = OhciCreateTD (Ohc);\r
+    if (DataTd == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
+      goto FREE_OHCI_TDBUFF;\r
+    }\r
+    OhciSetTDField (DataTd, TD_PDATA, 0);\r
+    OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
+    OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
+    OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
+    OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);\r
+    OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+    OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+    OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
+    OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));\r
+    OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
+    DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
+    DataTd->DataBuffer = (UINT32)MapPyhAddr;\r
+    DataTd->NextTDPointer = 0;\r
+    if (FirstTD) {\r
+      HeadTd = DataTd;\r
+      FirstTD = FALSE;\r
+    } else {\r
+      OhciLinkTD (HeadTd, DataTd);\r
+    }\r
+    *DataToggle ^= 1;\r
+    MapPyhAddr += ActualSendLength;\r
+    LeftLength -= ActualSendLength;\r
+  }\r
+\r
+  EmptTd = OhciCreateTD (Ohc);\r
+  if (EmptTd == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n"));\r
+    goto FREE_OHCI_TDBUFF;\r
+  }\r
+  OhciSetTDField (EmptTd, TD_PDATA, 0);\r
+  OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0);\r
+  OhciSetTDField (EmptTd, TD_DIR_PID, 0);\r
+  OhciSetTDField (EmptTd, TD_DELAY_INT, 0);\r
+  //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle);\r
+  EmptTd->Word0.DataToggle = 0;\r
+  OhciSetTDField (EmptTd, TD_ERROR_CNT, 0);\r
+  OhciSetTDField (EmptTd, TD_COND_CODE, 0);\r
+  OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0);\r
+  OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0);\r
+  OhciSetTDField (EmptTd, TD_NEXT_PTR, 0);\r
+  EmptTd->ActualSendLength = 0;\r
+  EmptTd->DataBuffer = 0;\r
+  EmptTd->NextTDPointer = 0;\r
+  OhciLinkTD (HeadTd, EmptTd);\r
+  Ed->TdTailPointer = (UINT32)(UINTN)EmptTd;\r
+  OhciAttachTDListToED (Ed, HeadTd);\r
+\r
+  if (OutputED != NULL) {\r
+    *OutputED = Ed;\r
+  }\r
+  if (OutputTD != NULL) {\r
+    *OutputTD = HeadTd;\r
+  }\r
+\r
+  if (CallBackFunction != NULL) {\r
+    Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY));\r
+    if (Entry == NULL) {\r
+      goto FREE_OHCI_TDBUFF;\r
+    }\r
+\r
+    Entry->DeviceAddress = DeviceAddress;\r
+    Entry->EndPointAddress = EndPointAddress;\r
+    Entry->Ed = Ed;\r
+    Entry->DataTd = HeadTd;\r
+    Entry->IsSlowDevice = IsSlowDevice;\r
+    Entry->MaxPacketLength = MaxPacketLength;\r
+    Entry->PollingInterval = PollingInterval;\r
+    Entry->CallBackFunction = CallBackFunction;\r
+    Entry->Context = Context;\r
+    Entry->IsPeriodic = IsPeriodic;\r
+    Entry->UCBuffer = UCBuffer;\r
+    Entry->UCBufferMapping = Mapping;\r
+    Entry->DataLength = DataLength;\r
+    Entry->Toggle = DataToggle;\r
+    Entry->NextEntry = NULL;\r
+    OhciAddInterruptContextEntry (Ohc, Entry);\r
+  }\r
+  OhciSetEDField (Ed, ED_SKIP, 0);\r
+\r
+  if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) {\r
+    Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);\r
+    gBS->Stall (1000);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+FREE_OHCI_TDBUFF:\r
+  while (HeadTd) {\r
+    DataTd = HeadTd;\r
+    HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
+    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
+  }\r
+\r
+//FREE_OHCI_EDBUFF:\r
+  if ((HeadEd != Ed) && HeadEd && Ed) {\r
+    while(HeadEd->NextED != (UINT32)(UINTN)Ed) {\r
+      HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED);\r
+    }\r
+  HeadEd->NextED = Ed->NextED;\r
+    UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+  }\r
+\r
+UNMAP_OHCI_XBUFF:\r
+  Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);\r
+\r
+EXIT:\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  DeviceAddress         Represents the address of the target device on the USB,\r
+                                which is assigned during USB enumeration.\r
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint\r
+                                direction of the target USB device. Each endpoint address\r
+                                supports data transfer in one direction except the\r
+                                control endpoint (whose default endpoint address is 0).\r
+                                It is the caller's responsibility to make sure that\r
+                                the EndPointAddress represents an interrupt endpoint.\r
+  @param  IsSlowDevice          Indicates whether the target device is slow device\r
+                                or full-speed device.\r
+  @param  MaxiumPacketLength    Indicates the maximum packet size the target endpoint\r
+                                is capable of sending or receiving.\r
+  @param  IsNewTransfer         If TRUE, an asynchronous interrupt pipe is built between\r
+                                the host and the target interrupt endpoint.\r
+                                If FALSE, the specified asynchronous interrupt pipe\r
+                                is canceled.\r
+  @param  DataToggle            A pointer to the data toggle value.  On input, it is valid\r
+                                when IsNewTransfer is TRUE, and it indicates the initial\r
+                                data toggle value the asynchronous interrupt transfer\r
+                                should adopt.\r
+                                On output, it is valid when IsNewTransfer is FALSE,\r
+                                and it is updated to indicate the data toggle value of\r
+                                the subsequent asynchronous interrupt transfer.\r
+  @param  PollingInterval       Indicates the interval, in milliseconds, that the\r
+                                asynchronous interrupt transfer is polled.\r
+                                This parameter is required when IsNewTransfer is TRUE.\r
+  @param  DataLength            Indicates the length of data to be received at the\r
+                                rate specified by PollingInterval from the target\r
+                                asynchronous interrupt endpoint.  This parameter\r
+                                is only required when IsNewTransfer is TRUE.\r
+  @param  CallBackFunction      The Callback function.This function is called at the\r
+                                rate specified by PollingInterval.This parameter is\r
+                                only required when IsNewTransfer is TRUE.\r
+  @param  Context               The context that is passed to the CallBackFunction.\r
+                                This is an optional parameter and may be NULL.\r
+\r
+  @retval EFI_SUCCESS           The asynchronous interrupt transfer request has been successfully\r
+                                submitted or canceled.\r
+  @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciAsyncInterruptTransfer (\r
+  IN     EFI_USB_HC_PROTOCOL              *This,\r
+  IN     UINT8                            DeviceAddress,\r
+  IN     UINT8                            EndPointAddress,\r
+  IN     BOOLEAN                          IsSlowDevice,\r
+  IN     UINT8                            MaxPacketLength,\r
+  IN     BOOLEAN                          IsNewTransfer,\r
+  IN OUT UINT8                            *DataToggle        OPTIONAL,\r
+  IN     UINTN                            PollingInterval    OPTIONAL,\r
+  IN     UINTN                            DataLength         OPTIONAL,\r
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK  CallBackFunction   OPTIONAL,\r
+  IN     VOID                             *Context           OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+  VOID                    *UCBuffer;\r
+\r
+  if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 ||\r
+    (IsNewTransfer && (DataLength == 0 ||\r
+    (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+  if ( IsNewTransfer ) {\r
+    UCBuffer = AllocatePool(DataLength);\r
+    if (UCBuffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  } else {\r
+    UCBuffer = NULL;\r
+  }\r
+  Status = OhciInterruptTransfer (\r
+             Ohc,\r
+             DeviceAddress,\r
+             EndPointAddress,\r
+             IsSlowDevice,\r
+             MaxPacketLength,\r
+             IsNewTransfer,\r
+             DataToggle,\r
+             PollingInterval,\r
+             UCBuffer,\r
+             DataLength,\r
+             CallBackFunction,\r
+             Context,\r
+             TRUE,\r
+             NULL,\r
+             NULL\r
+             );\r
+  if ( IsNewTransfer ) {\r
+    if (EFI_ERROR(Status)) {\r
+      gBS->FreePool (UCBuffer);\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+  Submits synchronous interrupt transfer to an interrupt endpoint\r
+  of a USB device.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  DeviceAddress         Represents the address of the target device on the USB,\r
+                                which is assigned during USB enumeration.\r
+  @param  EndPointAddress       The combination of an endpoint number and an endpoint\r
+                                direction of the target USB device. Each endpoint\r
+                                address supports data transfer in one direction\r
+                                except the control endpoint (whose default\r
+                                endpoint address is 0). It is the caller's responsibility\r
+                                to make sure that the EndPointAddress represents\r
+                                an interrupt endpoint.\r
+  @param  IsSlowDevice          Indicates whether the target device is slow device\r
+                                or full-speed device.\r
+  @param  MaxPacketLength       Indicates the maximum packet size the target endpoint\r
+                                is capable of sending or receiving.\r
+  @param  Data                  A pointer to the buffer of data that will be transmitted\r
+                                to USB device or received from USB device.\r
+  @param  DataLength            On input, the size, in bytes, of the data buffer specified\r
+                                by Data. On output, the number of bytes transferred.\r
+  @param  DataToggle            A pointer to the data toggle value. On input, it indicates\r
+                                the initial data toggle value the synchronous interrupt\r
+                                transfer should adopt;\r
+                                on output, it is updated to indicate the data toggle value\r
+                                of the subsequent synchronous interrupt transfer.\r
+  @param  TimeOut               Indicates the maximum time, in microseconds, which the\r
+                                transfer is allowed to complete.\r
+  @param  TransferResult        A pointer to the detailed result information from\r
+                                the synchronous interrupt transfer.\r
+\r
+  @retval EFI_UNSUPPORTED       This interface not available.\r
+  @retval EFI_INVALID_PARAMETER Parameters not follow spec\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSyncInterruptTransfer (\r
+  IN     EFI_USB_HC_PROTOCOL  *This,\r
+  IN     UINT8                DeviceAddress,\r
+  IN     UINT8                EndPointAddress,\r
+  IN     BOOLEAN              IsSlowDevice,\r
+  IN     UINT8                MaxPacketLength,\r
+  IN OUT VOID                 *Data,\r
+  IN OUT UINTN                *DataLength,\r
+  IN OUT UINT8                *DataToggle,\r
+  IN     UINTN                TimeOut,\r
+  OUT    UINT32               *TransferResult\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+  EFI_STATUS              Status;\r
+  ED_DESCRIPTOR           *Ed;\r
+  TD_DESCRIPTOR           *HeadTd;\r
+  OHCI_ED_RESULT          EdResult;\r
+  VOID                    *UCBuffer;\r
+\r
+  if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 ||\r
+      (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) ||\r
+      DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+  UCBuffer = AllocatePool (*DataLength);\r
+  if (UCBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  Status = OhciInterruptTransfer (\r
+             Ohc,\r
+             DeviceAddress,\r
+             EndPointAddress,\r
+             IsSlowDevice,\r
+             MaxPacketLength,\r
+             TRUE,\r
+             DataToggle,\r
+             1,\r
+             UCBuffer,\r
+             *DataLength,\r
+             NULL,\r
+             NULL,\r
+             FALSE,\r
+             &Ed,\r
+             &HeadTd\r
+             );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);\r
+    while (Status == EFI_NOT_READY && TimeOut > 0) {\r
+      gBS->Stall (1000);\r
+      TimeOut--;\r
+      Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);\r
+    }\r
+\r
+    *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
+  }\r
+  CopyMem(Data, UCBuffer, *DataLength);\r
+  Status = OhciInterruptTransfer (\r
+             Ohc,\r
+             DeviceAddress,\r
+             EndPointAddress,\r
+             IsSlowDevice,\r
+             MaxPacketLength,\r
+             FALSE,\r
+             DataToggle,\r
+             0,\r
+             NULL,\r
+             0,\r
+             NULL,\r
+             NULL,\r
+             FALSE,\r
+             NULL,\r
+             NULL\r
+             );\r
+\r
+  return Status;\r
+}\r
+/**\r
+\r
+  Submits isochronous transfer to a target USB device.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  DeviceAddress         Represents the address of the target device on the USB,\r
+                                which is assigned during USB enumeration.\r
+  @param  EndPointAddress       End point address\r
+  @param  MaximumPacketLength   Indicates the maximum packet size that the\r
+                                default control transfer endpoint is capable of\r
+                                sending or receiving.\r
+  @param  Data                  A pointer to the buffer of data that will be transmitted\r
+                                to USB device or received from USB device.\r
+  @param  DataLength            Indicates the size, in bytes, of the data buffer\r
+                                specified by Data.\r
+  @param  TransferResult        A pointer to the detailed result information generated\r
+                                by this control transfer.\r
+\r
+  @retval EFI_UNSUPPORTED       This interface not available\r
+  @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciIsochronousTransfer (\r
+  IN     EFI_USB_HC_PROTOCOL  *This,\r
+  IN     UINT8                DeviceAddress,\r
+  IN     UINT8                EndPointAddress,\r
+  IN     UINT8                MaximumPacketLength,\r
+  IN OUT VOID                 *Data,\r
+  IN OUT UINTN                DataLength,\r
+  OUT    UINT32               *TransferResult\r
+  )\r
+{\r
+  if (Data == NULL || DataLength == 0 || TransferResult == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+\r
+  Submits Async isochronous transfer to a target USB device.\r
+\r
+  @param  his                   A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  DeviceAddress         Represents the address of the target device on the USB,\r
+                                which is assigned during USB enumeration.\r
+  @param  EndPointAddress       End point address\r
+  @param  MaximumPacketLength   Indicates the maximum packet size that the\r
+                                default control transfer endpoint is capable of\r
+                                sending or receiving.\r
+  @param  Data                  A pointer to the buffer of data that will be transmitted\r
+                                to USB device or received from USB device.\r
+  @param  IsochronousCallBack   When the transfer complete, the call back function will be called\r
+  @param  Context               Pass to the call back function as parameter\r
+\r
+  @retval EFI_UNSUPPORTED       This interface not available\r
+  @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciAsyncIsochronousTransfer (\r
+  IN     EFI_USB_HC_PROTOCOL                *This,\r
+  IN     UINT8                              DeviceAddress,\r
+  IN     UINT8                              EndPointAddress,\r
+  IN     UINT8                              MaximumPacketLength,\r
+  IN OUT VOID                               *Data,\r
+  IN OUT UINTN                              DataLength,\r
+  IN     EFI_ASYNC_USB_TRANSFER_CALLBACK    IsochronousCallBack,\r
+  IN     VOID                               *Context OPTIONAL\r
+  )\r
+{\r
+\r
+  if (Data == NULL || DataLength == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+\r
+  Retrieves the number of root hub ports.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  NumOfPorts            A pointer to the number of the root hub ports.\r
+\r
+  @retval EFI_SUCCESS           The port number was retrieved successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubNumOfPorts (\r
+  IN  EFI_USB_HC_PROTOCOL  *This,\r
+  OUT UINT8                *NumOfPorts\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV  *Ohc;\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+  if (NumOfPorts == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+\r
+  Retrieves the current status of a USB root hub port.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL.\r
+  @param  PortNumber            Specifies the root hub port from which the status\r
+                                is to be retrieved.  This value is zero-based. For example,\r
+                                if a root hub has two ports, then the first port is numbered 0,\r
+                                and the second port is numbered 1.\r
+  @param  PortStatus            A pointer to the current port status bits and\r
+                                port status change bits.\r
+\r
+  @retval EFI_SUCCESS           The status of the USB root hub port specified by PortNumber\r
+                                was returned in PortStatus.\r
+  @retval EFI_INVALID_PARAMETER Port number not valid\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubPortStatus (\r
+  IN  EFI_USB_HC_PROTOCOL  *This,\r
+  IN  UINT8                PortNumber,\r
+  OUT EFI_USB_PORT_STATUS  *PortStatus\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV  *Ohc;\r
+  UINT8            NumOfPorts;\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+  OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
+  if (PortNumber >= NumOfPorts) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  PortStatus->PortStatus = 0;\r
+  PortStatus->PortChangeStatus = 0;\r
+\r
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_POWER;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {\r
+    PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;\r
+  }\r
+  if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {\r
+    PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+\r
+  Sets a feature for the specified root hub port.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL.\r
+  @param  PortNumber            Specifies the root hub port whose feature\r
+                                is requested to be set.\r
+  @param  PortFeature           Indicates the feature selector associated\r
+                                with the feature set request.\r
+\r
+  @retval EFI_SUCCESS           The feature specified by PortFeature was set for the\r
+                                USB root hub port specified by PortNumber.\r
+  @retval EFI_DEVICE_ERROR      Set feature failed because of hardware issue\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSetRootHubPortFeature (\r
+  IN EFI_USB_HC_PROTOCOL   *This,\r
+  IN UINT8                 PortNumber,\r
+  IN EFI_USB_PORT_FEATURE  PortFeature\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+  EFI_STATUS              Status;\r
+  UINT8                   NumOfPorts;\r
+  UINTN                   RetryTimes;\r
+\r
+  OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
+  if (PortNumber >= NumOfPorts) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+\r
+  switch (PortFeature) {\r
+    case EfiUsbPortPower:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortReset:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||\r
+                OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+\r
+      OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
+      break;\r
+\r
+    case EfiUsbPortEnable:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+\r
+    case EfiUsbPortSuspend:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Clears a feature for the specified root hub port.\r
+\r
+  @param  This                  A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+  @param  PortNumber            Specifies the root hub port whose feature\r
+                                is requested to be cleared.\r
+  @param  PortFeature           Indicates the feature selector associated with the\r
+                                feature clear request.\r
+\r
+  @retval EFI_SUCCESS           The feature specified by PortFeature was cleared for the\r
+                                USB root hub port specified by PortNumber.\r
+  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+  @retval EFI_DEVICE_ERROR      Some error happened when clearing feature\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciClearRootHubPortFeature (\r
+  IN EFI_USB_HC_PROTOCOL   *This,\r
+  IN UINT8                 PortNumber,\r
+  IN EFI_USB_PORT_FEATURE  PortFeature\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+  EFI_STATUS              Status;\r
+  UINT8                   NumOfPorts;\r
+  UINTN                   RetryTimes;\r
+\r
+\r
+  OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
+  if (PortNumber >= NumOfPorts) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (PortFeature) {\r
+    case EfiUsbPortEnable:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortSuspend:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortReset:\r
+      break;\r
+\r
+    case EfiUsbPortPower:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortConnectChange:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortResetChange:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+\r
+    case EfiUsbPortEnableChange:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortSuspendChange:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    case EfiUsbPortOverCurrentChange:\r
+      Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);\r
+\r
+      //\r
+      // Verify the state\r
+      //\r
+      RetryTimes = 0;\r
+      do {\r
+        gBS->Stall (1000);\r
+        RetryTimes++;\r
+      } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&\r
+               RetryTimes < MAX_RETRY_TIMES);\r
+\r
+      if (RetryTimes >= MAX_RETRY_TIMES) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = {\r
+  OHCIDriverBindingSupported,\r
+  OHCIDriverBindingStart,\r
+  OHCIDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+\r
+/**\r
+  Entry point for EFI drivers.\r
+\r
+  @param  ImageHandle           EFI_HANDLE.\r
+  @param  SystemTable           EFI_SYSTEM_TABLE.\r
+\r
+  @retval EFI_SUCCESS           Driver is successfully loaded.\r
+  @return Others                Failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverEntryPoint (\r
+  IN EFI_HANDLE          ImageHandle,\r
+  IN EFI_SYSTEM_TABLE    *SystemTable\r
+  )\r
+{\r
+  return EfiLibInstallDriverBindingComponentName2 (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gOhciDriverBinding,\r
+           ImageHandle,\r
+           &gOhciComponentName,\r
+           &gOhciComponentName2\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle. Any\r
+  ControllerHandle that has UsbHcProtocol installed will be supported.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to test.\r
+  @param  RemainingDevicePath  Not used.\r
+\r
+  @return EFI_SUCCESS          This driver supports this device.\r
+  @return EFI_UNSUPPORTED      This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+  USB_CLASSC              UsbClassCReg;\r
+  //\r
+  // Test whether there is PCI IO Protocol attached on the controller handle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        PCI_CLASSCODE_OFFSET,\r
+                        sizeof (USB_CLASSC) / sizeof (UINT8),\r
+                        &UsbClassCReg\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Test whether the controller belongs to OHCI type\r
+  //\r
+  if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
+      (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
+      (UsbClassCReg.ProgInterface != PCI_IF_OHCI)\r
+      ) {\r
+\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+ON_EXIT:\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+\r
+}\r
+\r
+/**\r
+\r
+  Allocate and initialize the empty OHCI device.\r
+\r
+  @param  PciIo                  The PCIIO to use.\r
+  @param  OriginalPciAttributes  The original PCI attributes.\r
+\r
+  @return Allocated OHCI device  If err, return NULL.\r
+\r
+**/\r
+\r
+USB_OHCI_HC_DEV *\r
+OhciAllocateDev (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN UINT64               OriginalPciAttributes\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+  EFI_STATUS              Status;\r
+  VOID                    *Buf;\r
+  EFI_PHYSICAL_ADDRESS    PhyAddr;\r
+  VOID                    *Map;\r
+  UINTN                   Pages;\r
+  UINTN                   Bytes;\r
+\r
+  Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV));\r
+  if (Ohc == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Ohc->Signature                      = USB_OHCI_HC_DEV_SIGNATURE;\r
+  Ohc->PciIo                          = PciIo;\r
+\r
+  Ohc->UsbHc.Reset                    = OhciReset;\r
+  Ohc->UsbHc.GetState                 = OhciGetState;\r
+  Ohc->UsbHc.SetState                 = OhciSetState;\r
+  Ohc->UsbHc.ControlTransfer          = OhciControlTransfer;\r
+  Ohc->UsbHc.BulkTransfer             = OhciBulkTransfer;\r
+  Ohc->UsbHc.AsyncInterruptTransfer   = OhciAsyncInterruptTransfer;\r
+  Ohc->UsbHc.SyncInterruptTransfer    = OhciSyncInterruptTransfer;\r
+  Ohc->UsbHc.IsochronousTransfer      = OhciIsochronousTransfer;\r
+  Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer;\r
+  Ohc->UsbHc.GetRootHubPortNumber     = OhciGetRootHubNumOfPorts;\r
+  Ohc->UsbHc.GetRootHubPortStatus     = OhciGetRootHubPortStatus;\r
+  Ohc->UsbHc.SetRootHubPortFeature    = OhciSetRootHubPortFeature;\r
+  Ohc->UsbHc.ClearRootHubPortFeature  = OhciClearRootHubPortFeature;\r
+  Ohc->UsbHc.MajorRevision            = 0x1;\r
+  Ohc->UsbHc.MinorRevision            = 0x1;\r
+\r
+  Ohc->OriginalPciAttributes = OriginalPciAttributes;\r
+\r
+  Ohc->HccaMemoryBlock = NULL;\r
+  Ohc->HccaMemoryMapping   = NULL;\r
+  Ohc->HccaMemoryBuf = NULL;\r
+  Ohc->HccaMemoryPages = 0;\r
+  Ohc->InterruptContextList = NULL;\r
+  Ohc->ControllerNameTable = NULL;\r
+  Ohc->HouseKeeperTimer = NULL;\r
+\r
+  Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0);\r
+  if(Ohc->MemPool == NULL) {\r
+    goto FREE_DEV_BUFFER;\r
+  }\r
+\r
+  Bytes = 4096;\r
+  Pages = EFI_SIZE_TO_PAGES (Bytes);\r
+\r
+  Status = PciIo->AllocateBuffer (\r
+                    PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    Pages,\r
+                    &Buf,\r
+                    0\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_MEM_POOL;\r
+  }\r
+\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    EfiPciIoOperationBusMasterCommonBuffer,\r
+                    Buf,\r
+                    &Bytes,\r
+                    &PhyAddr,\r
+                    &Map\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != 4096)) {\r
+    goto FREE_MEM_PAGE;\r
+  }\r
+\r
+  Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr;\r
+  Ohc->HccaMemoryMapping = Map;\r
+  Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf;\r
+  Ohc->HccaMemoryPages = Pages;\r
+\r
+  return Ohc;\r
+\r
+FREE_MEM_PAGE:\r
+  PciIo->FreeBuffer (PciIo, Pages, Buf);\r
+FREE_MEM_POOL:\r
+  UsbHcFreeMemPool (Ohc->MemPool);\r
+FREE_DEV_BUFFER:\r
+  FreePool(Ohc);\r
+\r
+  return NULL;\r
+}\r
+/**\r
+\r
+  Free the OHCI device and release its associated resources.\r
+\r
+  @param  Ohc                   The OHCI device to release.\r
+\r
+**/\r
+VOID\r
+OhciFreeDev (\r
+  IN USB_OHCI_HC_DEV      *Ohc\r
+  )\r
+{\r
+  OhciFreeFixedIntMemory (Ohc);\r
+\r
+  if (Ohc->HouseKeeperTimer != NULL) {\r
+    gBS->CloseEvent (Ohc->HouseKeeperTimer);\r
+  }\r
+\r
+  if (Ohc->ExitBootServiceEvent != NULL) {\r
+    gBS->CloseEvent (Ohc->ExitBootServiceEvent);\r
+  }\r
+\r
+  if (Ohc->MemPool != NULL) {\r
+    UsbHcFreeMemPool (Ohc->MemPool);\r
+  }\r
+\r
+  if (Ohc->HccaMemoryMapping != NULL ) {\r
+    Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf);\r
+  }\r
+\r
+  if (Ohc->ControllerNameTable != NULL) {\r
+    FreeUnicodeStringTable (Ohc->ControllerNameTable);\r
+  }\r
+\r
+  FreePool (Ohc);\r
+}\r
+/**\r
+\r
+  Uninstall all Ohci Interface.\r
+\r
+  @param  Controller            Controller handle.\r
+  @param  This                  Protocol instance pointer.\r
+\r
+**/\r
+VOID\r
+OhciCleanDevUp (\r
+  IN  EFI_HANDLE           Controller,\r
+  IN  EFI_USB_HC_PROTOCOL  *This\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV  *Ohc;\r
+\r
+  //\r
+  // Retrieve private context structure\r
+  //\r
+  Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Uninstall the USB_HC and USB_HC2 protocol\r
+  //\r
+  gBS->UninstallProtocolInterface (\r
+         Controller,\r
+         &gEfiUsbHcProtocolGuid,\r
+         &Ohc->UsbHc\r
+         );\r
+\r
+  //\r
+  // Cancel the timer event\r
+  //\r
+  gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0);\r
+\r
+  //\r
+  // Stop the host controller\r
+  //\r
+  OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);\r
+  This->Reset (This, EFI_USB_HC_RESET_GLOBAL);\r
+  This->SetState (This, EfiUsbHcStateHalt);\r
+\r
+  //\r
+  // Free resources\r
+  //\r
+  OhciFreeDynamicIntMemory (Ohc);\r
+\r
+  //\r
+  // Restore original PCI attributes\r
+  //\r
+  Ohc->PciIo->Attributes (\r
+                Ohc->PciIo,\r
+                EfiPciIoAttributeOperationSet,\r
+                Ohc->OriginalPciAttributes,\r
+                NULL\r
+                );\r
+\r
+  //\r
+  // Free the private context structure\r
+  //\r
+  OhciFreeDev (Ohc);\r
+}\r
+\r
+/**\r
+\r
+  One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
+\r
+  @param  Event                 Pointer to this event\r
+  @param  Context               Event hanlder private data\r
+**/\r
+VOID\r
+EFIAPI\r
+OhcExitBootService (\r
+  EFI_EVENT                      Event,\r
+  VOID                           *Context\r
+  )\r
+{\r
+  USB_OHCI_HC_DEV           *Ohc;\r
+  EFI_USB_HC_PROTOCOL       *UsbHc;\r
+  Ohc = (USB_OHCI_HC_DEV *) Context;\r
+\r
+  UsbHc = &Ohc->UsbHc;\r
+  //\r
+  // Stop the Host Controller\r
+  //\r
+  //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT);\r
+  OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);\r
+  UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL);\r
+  UsbHc->SetState (UsbHc, EfiUsbHcStateHalt);\r
+\r
+  return;\r
+}\r
+\r
+\r
+/**\r
+  Starting the Usb OHCI Driver.\r
+\r
+  @param  This                  Protocol instance pointer.\r
+  @param  Controller            Handle of device to test.\r
+  @param  RemainingDevicePath   Not used.\r
+\r
+  @retval EFI_SUCCESS           This driver supports this device.\r
+  @retval EFI_UNSUPPORTED       This driver does not support this device.\r
+  @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.\r
+                                EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_PCI_IO_PROTOCOL     *PciIo;\r
+  USB_OHCI_HC_DEV         *Ohc;\r
+  UINT64                  Supports;\r
+  UINT64                  OriginalPciAttributes;\r
+  BOOLEAN                 PciAttributesSaved;\r
+\r
+  //\r
+  // Open PCIIO, then enable the HC device and turn off emulation\r
+  //\r
+  Ohc = NULL;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  PciAttributesSaved = FALSE;\r
+  //\r
+  // Save original PCI attributes\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationGet,\r
+                    0,\r
+                    &OriginalPciAttributes\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto CLOSE_PCIIO;\r
+  }\r
+  PciAttributesSaved = TRUE;\r
+\r
+  //\r
+  // Robustnesss improvement such as for UoL\r
+  // Default is not required.\r
+  //\r
+  //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
+  //  OhciTurnOffUsbEmulation (PciIo);\r
+  //}\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= EFI_PCI_DEVICE_ENABLE;\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      Supports,\r
+                      NULL\r
+                      );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto CLOSE_PCIIO;\r
+  }\r
+  //\r
+  //Allocate memory for OHC private data structure\r
+  //\r
+  Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes);\r
+  if (Ohc == NULL){\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto CLOSE_PCIIO;\r
+  }\r
+\r
+  //Status = OhciInitializeInterruptList ( Uhc );\r
+  //if (EFI_ERROR (Status)) {\r
+  //  goto FREE_OHC;\r
+  //}\r
+\r
+  //\r
+  // Set 0.01 s timer\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  OhciHouseKeeper,\r
+                  Ohc,\r
+                  &Ohc->HouseKeeperTimer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_OHC;\r
+  }\r
+\r
+  Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FREE_OHC;\r
+  }\r
+\r
+  //\r
+  //Install Host Controller Protocol\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &gEfiUsbHcProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &Ohc->UsbHc\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "Install protocol error"));\r
+    goto FREE_OHC;\r
+  }\r
+  //\r
+  // Create event to stop the HC when exit boot service.\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  OhcExitBootService,\r
+                  Ohc,\r
+                  &gEfiEventExitBootServicesGuid,\r
+                  &Ohc->ExitBootServiceEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "Create exit boot event error"));\r
+    goto UNINSTALL_USBHC;\r
+  }\r
+  AddUnicodeString2 (\r
+    "eng",\r
+    gOhciComponentName.SupportedLanguages,\r
+    &Ohc->ControllerNameTable,\r
+    L"Usb Universal Host Controller",\r
+    TRUE\r
+    );\r
+  AddUnicodeString2 (\r
+    "en",\r
+    gOhciComponentName2.SupportedLanguages,\r
+    &Ohc->ControllerNameTable,\r
+    L"Usb Universal Host Controller",\r
+    FALSE\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+\r
+UNINSTALL_USBHC:\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         Controller,\r
+         &gEfiUsbHcProtocolGuid,\r
+         &Ohc->UsbHc,\r
+         NULL\r
+         );\r
+\r
+FREE_OHC:\r
+  OhciFreeDev (Ohc);\r
+\r
+CLOSE_PCIIO:\r
+  if (PciAttributesSaved) {\r
+  //\r
+  // Restore original PCI attributes\r
+  //\r
+    PciIo->Attributes (\r
+             PciIo,\r
+             EfiPciIoAttributeOperationSet,\r
+             OriginalPciAttributes,\r
+             NULL\r
+             );\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stop this driver on ControllerHandle. Support stoping any child handles\r
+  created by this driver.\r
+\r
+  @param  This                  Protocol instance pointer.\r
+  @param  Controller            Handle of device to stop driver on.\r
+  @param  NumberOfChildren      Number of Children in the ChildHandleBuffer.\r
+  @param  ChildHandleBuffer     List of handles for the children we need to stop.\r
+\r
+  @return EFI_SUCCESS\r
+  @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  EFI_USB_HC_PROTOCOL  *UsbHc;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsbHcProtocolGuid,\r
+                  (VOID **)&UsbHc,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  OhciCleanDevUp(Controller, UsbHc);\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r