--- /dev/null
+/** @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