+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ Uhci.c\r
+\r
+Abstract:\r
+\r
+ The UHCI driver model and HC protocol routines.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#include "Uhci.h"\r
+\r
+\r
+/**\r
+ Provides software reset for the USB host controller.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ Attributes: A bit mask of the reset operation to perform.\r
+\r
+ @return EFI_SUCCESS : The reset operation succeeded.\r
+ @return EFI_INVALID_PARAMETER : Attributes is not valid.\r
+ @return EFI_DEVICE_ERROR : An error was encountered while attempting\r
+ @return to perform the reset operation.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciReset (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT16 Attributes\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ EFI_TPL OldTpl;\r
+\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+ switch (Attributes) {\r
+ case EFI_USB_HC_RESET_GLOBAL:\r
+ //\r
+ // Stop schedule and set the Global Reset bit in the command register\r
+ //\r
+ UhciStopHc (Uhc, STALL_1_SECOND);\r
+ UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);\r
+\r
+ //\r
+ // Wait 50ms for root port to let reset complete\r
+ // See UHCI spec page122 Reset signaling\r
+ //\r
+ gBS->Stall (ROOT_PORT_REST_TIME);\r
+\r
+ //\r
+ // Clear the Global Reset bit to zero.\r
+ //\r
+ UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);\r
+\r
+ //\r
+ // UHCI spec page120 reset recovery time\r
+ //\r
+ gBS->Stall (PORT_RESET_RECOVERY_TIME);\r
+ break;\r
+\r
+ case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
+ //\r
+ // Stop schedule and set Host Controller Reset bit to 1\r
+ //\r
+ UhciStopHc (Uhc, STALL_1_SECOND);\r
+ UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);\r
+\r
+ //\r
+ // this bit will be reset by Host Controller when reset is completed.\r
+ // wait 10ms to let reset complete\r
+ //\r
+ gBS->Stall (PORT_RESET_RECOVERY_TIME);\r
+ break;\r
+\r
+ default:\r
+ goto ON_INVAILD_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Delete all old transactions on the USB bus, then\r
+ // reinitialize the frame list\r
+ //\r
+ UhciFreeAllAsyncReq (Uhc);\r
+ UhciDestoryFrameList (Uhc);\r
+ UhciInitFrameList (Uhc);\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ON_INVAILD_PARAMETER:\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+\r
+/**\r
+ Retrieves current state of the USB host controller.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ State : A pointer to the EFI_USB_HC_STATE data structure that\r
+ indicates current state of the USB host controller.\r
+\r
+ @return EFI_SUCCESS : State was returned\r
+ @return EFI_INVALID_PARAMETER : State is NULL.\r
+ @return EFI_DEVICE_ERROR : An error was encountered\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciGetState (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ OUT EFI_USB_HC_STATE *State\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ UINT16 UsbSts;\r
+ UINT16 UsbCmd;\r
+\r
+ if (State == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+ UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
+ UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);\r
+\r
+ if (UsbCmd & USBCMD_EGSM) {\r
+ *State = EfiUsbHcStateSuspend;\r
+\r
+ } else if ((UsbSts & USBSTS_HCH) != 0) {\r
+ *State = EfiUsbHcStateHalt;\r
+\r
+ } else {\r
+ *State = EfiUsbHcStateOperational;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Sets the USB host controller to a specific state.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ State : Indicates the state of the host controller that will be set.\r
+\r
+ @return EFI_SUCCESS : The USB host controller was successfully set\r
+ @return EFI_INVALID_PARAMETER : State is invalid.\r
+ @return EFI_DEVICE_ERROR : Failed to set the state specified\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciSetState (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN EFI_USB_HC_STATE State\r
+ )\r
+{\r
+ EFI_USB_HC_STATE CurState;\r
+ USB_HC_DEV *Uhc;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ UINT16 UsbCmd;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+ Status = UhciGetState (This, &CurState);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (CurState == State) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+ switch (State) {\r
+ case EfiUsbHcStateHalt:\r
+ Status = UhciStopHc (Uhc, STALL_1_SECOND);\r
+ break;\r
+\r
+ case EfiUsbHcStateOperational:\r
+ UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
+\r
+ if (CurState == EfiUsbHcStateHalt) {\r
+ //\r
+ // Set Run/Stop bit to 1, also set the bandwidht reclamation\r
+ // point to 64 bytes\r
+ //\r
+ UsbCmd |= USBCMD_RS | USBCMD_MAXP;\r
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
+\r
+ } else if (CurState == EfiUsbHcStateSuspend) {\r
+ //\r
+ // If FGR(Force Global Resume) bit is 0, set it\r
+ //\r
+ if ((UsbCmd & USBCMD_FGR) == 0) {\r
+ UsbCmd |= USBCMD_FGR;\r
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
+ }\r
+\r
+ //\r
+ // wait 20ms to let resume complete (20ms is specified by UHCI spec)\r
+ //\r
+ gBS->Stall (FORCE_GLOBAL_RESUME_TIME);\r
+\r
+ //\r
+ // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0\r
+ //\r
+ UsbCmd &= ~USBCMD_FGR;\r
+ UsbCmd &= ~USBCMD_EGSM;\r
+ UsbCmd |= USBCMD_RS;\r
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
+ }\r
+\r
+ break;\r
+\r
+ case EfiUsbHcStateSuspend:\r
+ Status = UhciSetState (This, EfiUsbHcStateHalt);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Set Enter Global Suspend Mode bit to 1.\r
+ //\r
+ UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
+ UsbCmd |= USBCMD_EGSM;\r
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ PortNumber : A pointer to the number of the root hub ports.\r
+\r
+ @return EFI_SUCCESS : The port number was retrieved successfully.\r
+ @return EFI_INVALID_PARAMETER : PortNumber is NULL.\r
+ @return EFI_DEVICE_ERROR : An error was encountered\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciGetRootHubPortNumber (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ OUT UINT8 *PortNumber\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ UINT32 Offset;\r
+ UINT16 PortSC;\r
+ UINT32 Index;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+ if (PortNumber == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *PortNumber = 0;\r
+\r
+ for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {\r
+ Offset = USBPORTSC_OFFSET + Index * 2;\r
+ PortSC = UhciReadReg (Uhc->PciIo, Offset);\r
+\r
+ //\r
+ // Port status's bit 7 is reserved and always returns 1 if\r
+ // the port number is valid. Intel's UHCI (in EHCI controller)\r
+ // returns 0 in this bit if port number is invalid. Also, if\r
+ // PciIo IoRead returns error, 0xFFFF is returned to caller.\r
+ //\r
+ if (((PortSC & 0x80) != 0) && (PortSC != 0xFFFF)) {\r
+ (*PortNumber)++;\r
+ }\r
+ }\r
+\r
+ Uhc->RootPorts = *PortNumber;\r
+\r
+ UHCI_DEBUG (("UhciGetRootHubPortNumber: %d ports\n", Uhc->RootPorts));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL.\r
+ PortNumber : Specifies the root hub port. This value is zero-based.\r
+ PortStatus : A pointer to the current port status bits and port status change bits.\r
+\r
+ @return EFI_SUCCESS : The port status was returned in PortStatus.\r
+ @return EFI_INVALID_PARAMETER : PortNumber is invalid.\r
+ @return EFI_DEVICE_ERROR : Can't read register\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhciGetRootHubPortStatus (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ UINT32 Offset;\r
+ UINT16 PortSC;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+ if (PortStatus == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (PortNumber >= Uhc->RootPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Offset = USBPORTSC_OFFSET + PortNumber * 2;\r
+ PortStatus->PortStatus = 0;\r
+ PortStatus->PortChangeStatus = 0;\r
+\r
+ PortSC = UhciReadReg (Uhc->PciIo, Offset);\r
+\r
+ if (PortSC & USBPORTSC_CCS) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
+ }\r
+\r
+ if (PortSC & USBPORTSC_PED) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
+ }\r
+\r
+ if (PortSC & USBPORTSC_SUSP) {\r
+ UHCI_DEBUG (("UhciGetRootHubPortStatus: port %d is suspended\n", PortNumber));\r
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+ }\r
+\r
+ if (PortSC & USBPORTSC_PR) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
+ }\r
+\r
+ if (PortSC & USBPORTSC_LSDA) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+ }\r
+\r
+ //\r
+ // CHC will always return one in port owner bit\r
+ //\r
+ PortStatus->PortStatus |= USB_PORT_STAT_OWNER;\r
+\r
+ if (PortSC & USBPORTSC_CSC) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
+ }\r
+\r
+ if (PortSC & USBPORTSC_PEDC) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL.\r
+ PortNumber : Specifies the root hub port whose feature\r
+ is requested to be set.\r
+ PortFeature : Indicates the feature selector associated\r
+ with the feature set request.\r
+\r
+ @return EFI_SUCCESS : The feature was set for the port.\r
+ @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+ @return EFI_DEVICE_ERROR : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciSetRootHubPortFeature (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ EFI_TPL OldTpl;\r
+ UINT32 Offset;\r
+ UINT16 PortSC;\r
+ UINT16 Command;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+ if (PortNumber >= Uhc->RootPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Offset = USBPORTSC_OFFSET + PortNumber * 2;\r
+\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+ PortSC = UhciReadReg (Uhc->PciIo, Offset);\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortSuspend:\r
+ Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);\r
+ if (!(Command & USBCMD_EGSM)) {\r
+ //\r
+ // if global suspend is not active, can set port suspend\r
+ //\r
+ PortSC &= 0xfff5;\r
+ PortSC |= USBPORTSC_SUSP;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ PortSC &= 0xfff5;\r
+ PortSC |= USBPORTSC_PR;\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ //\r
+ // No action\r
+ //\r
+ break;\r
+\r
+ case EfiUsbPortEnable:\r
+ PortSC &= 0xfff5;\r
+ PortSC |= USBPORTSC_PED;\r
+ break;\r
+\r
+ default:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ UhciWriteReg (Uhc->PciIo, Offset, PortSC);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ PortNumber : Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ PortFeature : Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @return EFI_SUCCESS : The feature was cleared for the port.\r
+ @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+ @return EFI_DEVICE_ERROR : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciClearRootHubPortFeature (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ EFI_TPL OldTpl;\r
+ UINT32 Offset;\r
+ UINT16 PortSC;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+\r
+ if (PortNumber >= Uhc->RootPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Offset = USBPORTSC_OFFSET + PortNumber * 2;\r
+\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+ PortSC = UhciReadReg (Uhc->PciIo, Offset);\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ PortSC &= 0xfff5;\r
+ PortSC &= ~USBPORTSC_PED;\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ //\r
+ // Cause a resume on the specified port if in suspend mode.\r
+ //\r
+ PortSC &= 0xfff5;\r
+ PortSC &= ~USBPORTSC_SUSP;\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ //\r
+ // No action\r
+ //\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ PortSC &= 0xfff5;\r
+ PortSC &= ~USBPORTSC_PR;\r
+ break;\r
+\r
+ case EfiUsbPortConnectChange:\r
+ PortSC &= 0xfff5;\r
+ PortSC |= USBPORTSC_CSC;\r
+ break;\r
+\r
+ case EfiUsbPortEnableChange:\r
+ PortSC &= 0xfff5;\r
+ PortSC |= USBPORTSC_PEDC;\r
+ break;\r
+\r
+ case EfiUsbPortSuspendChange:\r
+ //\r
+ // Root hub does not support this\r
+ //\r
+ break;\r
+\r
+ case EfiUsbPortOverCurrentChange:\r
+ //\r
+ // Root hub does not support this\r
+ //\r
+ break;\r
+\r
+ case EfiUsbPortResetChange:\r
+ //\r
+ // Root hub does not support this\r
+ //\r
+ break;\r
+\r
+ default:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ UhciWriteReg (Uhc->PciIo, Offset, PortSC);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ DeviceAddress : Usb device address\r
+ IsSlowDevice : Whether the device is of slow speed or full speed\r
+ MaximumPacketLength : maximum packet size of the default control endpoint\r
+ Request : USB device request to send\r
+ TransferDirection : Specifies the data direction for the transfer.\r
+ Data : Data buffer to transmit from or receive into\r
+ DataLength : Number of bytes of the data\r
+ TimeOut : Maximum time, in microseconds\r
+ TransferResult : Return result in this\r
+\r
+ @return EFI_SUCCESS : Transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : Failed due to a lack of resources.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : Failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciControlTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaximumPacketLength,\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_HC_DEV *Uhc;\r
+ UHCI_TD_SW *TDs;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ UHCI_QH_RESULT QhResult;\r
+ UINT8 PktId;\r
+ UINT8 *RequestPhy;\r
+ VOID *RequestMap;\r
+ UINT8 *DataPhy;\r
+ VOID *DataMap;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+ TDs = NULL;\r
+ DataPhy = NULL;\r
+ DataMap = NULL;\r
+ RequestPhy = NULL;\r
+ RequestMap = NULL;\r
+\r
+ //\r
+ // Parameters Checking\r
+ //\r
+ if (Request == NULL || TransferResult == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IsSlowDevice && (MaximumPacketLength != 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection != EfiUsbNoData) && (DataLength == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+ //\r
+ // If errors exist that cause host controller halt,\r
+ // clear status then return EFI_DEVICE_ERROR.\r
+ //\r
+ UhciAckAllInterrupt (Uhc);\r
+\r
+ if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+ //\r
+ // Map the Request and data for bus master access,\r
+ // then create a list of TD for this transfer\r
+ //\r
+ Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ TDs = UhciCreateCtrlTds (\r
+ Uhc,\r
+ DeviceAddress,\r
+ PktId,\r
+ RequestPhy,\r
+ DataPhy,\r
+ *DataLength,\r
+ MaximumPacketLength,\r
+ IsSlowDevice\r
+ );\r
+\r
+ if (TDs == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto UNMAP_DATA;\r
+ }\r
+\r
+ //\r
+ // According to the speed of the end point, link\r
+ // the TD to corrosponding queue head, then check\r
+ // the execution result\r
+ //\r
+ UhciLinkTdToQh (Uhc->CtrlQh, TDs);\r
+ Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);\r
+ UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);\r
+\r
+ Uhc->PciIo->Flush (Uhc->PciIo);\r
+\r
+ *TransferResult = QhResult.Result;\r
+\r
+ if (DataLength != NULL) {\r
+ *DataLength = QhResult.Complete;\r
+ }\r
+\r
+ UhciDestoryTds (Uhc, TDs);\r
+\r
+UNMAP_DATA:\r
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+ Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+ This :A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ DeviceAddress : Usb device address\r
+ EndPointAddress : Endpoint number and endpoint direction\r
+ MaximumPacketLength : Maximum packet size of the target endpoint\r
+ Data : Data buffer to transmit from or receive into\r
+ DataLength : Length of the data buffer\r
+ DataToggle : On input, data toggle to use, on output, the next toggle\r
+ TimeOut : Indicates the maximum time\r
+ TransferResult : Variable to receive the transfer result\r
+\r
+ @return EFI_SUCCESS : The bulk transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : Failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciBulkTransfer (\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 OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ EFI_USB_DATA_DIRECTION Direction;\r
+ EFI_TPL OldTpl;\r
+ USB_HC_DEV *Uhc;\r
+ UHCI_TD_SW *TDs;\r
+ UHCI_QH_SW *BulkQh;\r
+ UHCI_QH_RESULT QhResult;\r
+ EFI_STATUS Status;\r
+ UINT8 PktId;\r
+ UINT8 *DataPhy;\r
+ VOID *DataMap;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+ DataPhy = NULL;\r
+ DataMap = NULL;\r
+\r
+ if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (*DataLength == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+\r
+ //\r
+ // If has errors that cause host controller halt,\r
+ // then return EFI_DEVICE_ERROR directly.\r
+ //\r
+ UhciAckAllInterrupt (Uhc);\r
+\r
+ if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+ //\r
+ // Map the source data buffer for bus master access,\r
+ // then create a list of TDs\r
+ //\r
+ if (EndPointAddress & 0x80) {\r
+ Direction = EfiUsbDataIn;\r
+ } else {\r
+ Direction = EfiUsbDataOut;\r
+ }\r
+\r
+ Status = UhciMapUserData (Uhc, Direction, Data, DataLength, &PktId, &DataPhy, &DataMap);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ TDs = UhciCreateBulkOrIntTds (\r
+ Uhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ PktId,\r
+ DataPhy,\r
+ *DataLength,\r
+ DataToggle,\r
+ MaximumPacketLength,\r
+ FALSE\r
+ );\r
+\r
+ if (TDs == NULL) {\r
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+\r
+ //\r
+ // Link the TDs to bulk queue head. According to the platfore\r
+ // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured\r
+ // to do full speed bandwidth reclamation or not.\r
+ //\r
+ BulkQh = Uhc->BulkQh;\r
+\r
+ UhciLinkTdToQh (BulkQh, TDs);\r
+ Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);\r
+ UhciUnlinkTdFromQh (BulkQh, TDs);\r
+\r
+ Uhc->PciIo->Flush (Uhc->PciIo);\r
+\r
+ *TransferResult = QhResult.Result;\r
+ *DataToggle = QhResult.NextToggle;\r
+ *DataLength = QhResult.Complete;\r
+\r
+ UhciDestoryTds (Uhc, TDs);\r
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ EndPointAddress : Endpoint number with direction\r
+ IsSlowDevice : Whether the target device is slow device or full-speed device.\r
+ MaximumPacketLength : Maximum packet size of the target endpoint\r
+ IsNewTransfer : If TRUE, submit a new async interrupt transfer, otherwise\r
+ cancel an existed one\r
+ DataToggle : On input, the data toggle to use; On output, next data toggle\r
+ PollingInterval : Interrupt poll rate in milliseconds\r
+ DataLength : Length of data to receive\r
+ CallBackFunction : Function to call periodically\r
+ Context : User context\r
+\r
+ @return EFI_SUCCESS : Request is submitted or cancelled\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_OUT_OF_RESOURCES : Failed due to a lack of resources.\r
+ @return EFI_DEVICE_ERROR : Failed to due to device error\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciAsyncInterruptTransfer (\r
+ IN EFI_USB_HC_PROTOCOL * This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN BOOLEAN IsNewTransfer,\r
+ IN OUT UINT8 *DataToggle,\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
+ USB_HC_DEV *Uhc;\r
+ UHCI_QH_SW *Qh;\r
+ UHCI_TD_SW *IntTds;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ UINT8 *DataPtr;\r
+ UINT8 *DataPhy;\r
+ VOID *DataMap;\r
+ UINT8 PktId;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+ Qh = NULL;\r
+ IntTds = NULL;\r
+ DataPtr = NULL;\r
+ DataPhy = NULL;\r
+ DataMap = NULL;\r
+\r
+ if ((EndPointAddress & 0x80) == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Delete Async interrupt transfer request\r
+ //\r
+ if (!IsNewTransfer) {\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+ Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+ }\r
+\r
+ if (PollingInterval < 1 || PollingInterval > 255) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DataLength == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If has errors that cause host controller halt,\r
+ // then return EFI_DEVICE_ERROR directly.\r
+ //\r
+ UhciAckAllInterrupt (Uhc);\r
+\r
+ if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Allocate and map source data buffer for bus master access.\r
+ //\r
+ DataPtr = AllocatePool (DataLength);\r
+\r
+ if (DataPtr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+ //\r
+ // Map the user data then create a queue head and\r
+ // list of TD for it.\r
+ //\r
+ Status = UhciMapUserData (\r
+ Uhc,\r
+ EfiUsbDataIn,\r
+ DataPtr,\r
+ &DataLength,\r
+ &PktId,\r
+ &DataPhy,\r
+ &DataMap\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_DATA;\r
+ }\r
+\r
+ Qh = UhciCreateQh (Uhc, PollingInterval);\r
+\r
+ if (Qh == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto UNMAP_DATA;\r
+ }\r
+\r
+ IntTds = UhciCreateBulkOrIntTds (\r
+ Uhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ PktId,\r
+ DataPhy,\r
+ DataLength,\r
+ DataToggle,\r
+ MaximumPacketLength,\r
+ IsSlowDevice\r
+ );\r
+\r
+ if (IntTds == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto DESTORY_QH;\r
+ }\r
+\r
+ UhciLinkTdToQh (Qh, IntTds);\r
+\r
+ //\r
+ // Save QH-TD structures to async Interrupt transfer list,\r
+ // for monitor interrupt transfer execution routine use.\r
+ //\r
+ Status = UhciCreateAsyncReq (\r
+ Uhc,\r
+ Qh,\r
+ IntTds,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DataLength,\r
+ PollingInterval,\r
+ DataMap,\r
+ DataPtr,\r
+ CallBackFunction,\r
+ Context,\r
+ IsSlowDevice\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto DESTORY_QH;\r
+ }\r
+\r
+ UhciLinkQhToFrameList (Uhc->FrameBase, Qh);\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ return EFI_SUCCESS;\r
+\r
+DESTORY_QH:\r
+ UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));\r
+\r
+UNMAP_DATA:\r
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+\r
+FREE_DATA:\r
+ gBS->FreePool (DataPtr);\r
+ Uhc->PciIo->Flush (Uhc->PciIo);\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits synchronous interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ DeviceAddress : Device address of the target USB device\r
+ EndPointAddress : Endpoint number and direction\r
+ IsSlowDevice : Whether the target device is of slow speed or full speed\r
+ MaximumPacketLength : Maximum packet size of target endpoint\r
+ Data : Data to transmit or receive\r
+ DataLength : On input, data length to transmit or buffer size.\r
+ On output, the number of bytes transferred.\r
+ DataToggle : On input, data toggle to use; On output, next data toggle\r
+ TimeOut : Maximum time, in microseconds, transfer is allowed to complete.\r
+ TransferResult : Variable to receive transfer result\r
+\r
+ @return EFI_SUCCESS : Transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : Failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : Failed due to host controller or device error\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciSyncInterruptTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaximumPacketLength,\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
+ EFI_STATUS Status;\r
+ USB_HC_DEV *Uhc;\r
+ UHCI_TD_SW *TDs;\r
+ UHCI_QH_RESULT QhResult;\r
+ EFI_TPL OldTpl;\r
+ UINT8 *DataPhy;\r
+ VOID *DataMap;\r
+ UINT8 PktId;\r
+\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+ DataPhy = NULL;\r
+ DataMap = NULL;\r
+ TDs = NULL;\r
+\r
+ if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((EndPointAddress & 0x80) == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataLength == 0) || (MaximumPacketLength > 64)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IsSlowDevice && (MaximumPacketLength > 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+\r
+ UhciAckAllInterrupt (Uhc);\r
+\r
+ if (!UhciIsHcWorking (Uhc->PciIo)) {\r
+ return Status;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (UHCI_TPL);\r
+\r
+ //\r
+ // Map the source data buffer for bus master access.\r
+ // Create Tds list, then link it to the UHC's interrupt list\r
+ //\r
+ Status = UhciMapUserData (\r
+ Uhc,\r
+ EfiUsbDataIn,\r
+ Data,\r
+ DataLength,\r
+ &PktId,\r
+ &DataPhy,\r
+ &DataMap\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ TDs = UhciCreateBulkOrIntTds (\r
+ Uhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ PktId,\r
+ DataPhy,\r
+ *DataLength,\r
+ DataToggle,\r
+ MaximumPacketLength,\r
+ IsSlowDevice\r
+ );\r
+\r
+ if (TDs == NULL) {\r
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+\r
+ UhciLinkTdToQh (Uhc->SyncIntQh, TDs);\r
+\r
+ Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);\r
+\r
+ UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);\r
+ Uhc->PciIo->Flush (Uhc->PciIo);\r
+\r
+ *TransferResult = QhResult.Result;\r
+ *DataToggle = QhResult.NextToggle;\r
+ *DataLength = QhResult.Complete;\r
+\r
+ UhciDestoryTds (Uhc, TDs);\r
+ Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits isochronous transfer to a target USB device.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ EndPointAddress : End point address withdirection\r
+ MaximumPacketLength : Maximum packet size of the endpoint\r
+ Data : Data to transmit or receive\r
+ DataLength : Bytes of the data\r
+ TransferResult : Variable to receive the result\r
+\r
+ @return EFI_UNSUPPORTED\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciIsochronousTransfer (\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 UINTN DataLength,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Submits Async isochronous transfer to a target USB device.\r
+\r
+ This : A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ EndPointAddress : End point address withdirection\r
+ MaximumPacketLength : Maximum packet size of the endpoint\r
+ Data : Data to transmit or receive\r
+ IsochronousCallBack : Function to call when the transfer completes\r
+ Context : User context\r
+\r
+ @return EFI_UNSUPPORTED\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UhciAsyncIsochronousTransfer (\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 UINTN DataLength,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
+ IN VOID *Context OPTIONAL\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Provides software reset for the USB host controller according to UEFI 2.0 spec.\r
+\r
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+ @param Attributes A bit mask of the reset operation to perform. See\r
+ below for a list of the supported bit mask values.\r
+\r
+ @return EFI_SUCCESS : The reset operation succeeded.\r
+ @return EFI_INVALID_PARAMETER : Attributes is not valid.\r
+ @return EFI_UNSUPPORTED : This type of reset is not currently supported\r
+ @return EFI_DEVICE_ERROR : Other errors\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2Reset (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT16 Attributes\r
+ )\r
+{\r
+ USB_HC_DEV *UhciDev;\r
+\r
+ UhciDev = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+ if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||\r
+ (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return UhciReset (&UhciDev->UsbHc, Attributes);\r
+}\r
+\r
+\r
+/**\r
+ Retrieves current state of the USB host controller according to UEFI 2.0 spec.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param State Variable to receive current device state\r
+\r
+ @return EFI_SUCCESS : The state is returned\r
+ @return EFI_INVALID_PARAMETER : State is not valid.\r
+ @return EFI_DEVICE_ERROR : Other errors2006\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2GetState (\r
+ IN CONST EFI_USB2_HC_PROTOCOL *This,\r
+ OUT EFI_USB_HC_STATE *State\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+ return UhciGetState (&Uhc->UsbHc, State);\r
+}\r
+\r
+\r
+/**\r
+ Sets the USB host controller to a specific state according to UEFI 2.0 spec.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param State Indicates the state of the host controller that will\r
+ be set.\r
+\r
+ @return EFI_SUCCESS : Host controller was successfully placed in the state\r
+ @return EFI_INVALID_PARAMETER : State is invalid.\r
+ @return EFI_DEVICE_ERROR : Failed to set the state\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2SetState (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN EFI_USB_HC_STATE State\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+ return UhciSetState (&Uhc->UsbHc, State);\r
+}\r
+\r
+\r
+/**\r
+ Retrieves capabilities of USB host controller according to UEFI 2.0 spec.\r
+\r
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance\r
+ @param MaxSpeed A pointer to the max speed USB host controller\r
+ supports.\r
+ @param PortNumber A pointer to the number of root hub ports.\r
+ @param Is64BitCapable A pointer to an integer to show whether USB host\r
+ controller supports 64-bit memory addressing.\r
+\r
+ @return EFI_SUCCESS : capabilities were retrieved successfully.\r
+ @return EFI_INVALID_PARAMETER : MaxSpeed or PortNumber or Is64BitCapable is NULL.\r
+ @return EFI_DEVICE_ERROR : An error was encountered\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2GetCapability (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ OUT UINT8 *MaxSpeed,\r
+ OUT UINT8 *PortNumber,\r
+ OUT UINT8 *Is64BitCapable\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+ if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *MaxSpeed = EFI_USB_SPEED_FULL;\r
+ *Is64BitCapable = (UINT8) FALSE;\r
+\r
+ return UhciGetRootHubPortNumber (&Uhc->UsbHc, PortNumber);\r
+}\r
+\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.\r
+\r
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL.\r
+ @param PortNumber The port to get status\r
+ @param PortStatus A pointer to the current port status bits and port\r
+ status change bits.\r
+\r
+ @return EFI_SUCCESS : status of the USB root hub port was returned in PortStatus.\r
+ @return EFI_INVALID_PARAMETER : PortNumber is invalid.\r
+ @return EFI_DEVICE_ERROR : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2GetRootHubPortStatus (\r
+ IN CONST EFI_USB2_HC_PROTOCOL *This,\r
+ IN CONST UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+ return UhciGetRootHubPortStatus (&Uhc->UsbHc, PortNumber, PortStatus);\r
+}\r
+\r
+\r
+/**\r
+ Sets a feature for the specified root hub port according to UEFI 2.0 spec.\r
+\r
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL.\r
+ @param PortNumber Specifies the root hub port whose feature is\r
+ requested to be set.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature set request.\r
+\r
+ @return EFI_SUCCESS : PortFeature was set for the root port\r
+ @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+ @return EFI_DEVICE_ERROR : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2SetRootHubPortFeature (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+ return UhciSetRootHubPortFeature (&Uhc->UsbHc, PortNumber, PortFeature);\r
+}\r
+\r
+\r
+/**\r
+ Clears a feature for the specified root hub port according to Uefi 2.0 spec.\r
+\r
+ @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+ @param PortNumber Specifies the root hub port whose feature is\r
+ requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @return EFI_SUCCESS : PortFeature was cleared for the USB root hub port\r
+ @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.\r
+ @return EFI_DEVICE_ERROR : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2ClearRootHubPortFeature (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+ return UhciClearRootHubPortFeature (&Uhc->UsbHc, PortNumber, PortFeature);\r
+}\r
+\r
+\r
+/**\r
+ Submits control transfer to a target USB device accroding to UEFI 2.0 spec..\r
+\r
+ This : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ DeviceSpeed : Device speed\r
+ MaximumPacketLength : Maximum packet size of the target endpoint\r
+ Request : USB device request to send\r
+ TransferDirection : Data direction of the Data stage in control transfer\r
+ Data : Data to transmit/receive in data stage\r
+ DataLength : Length of the data\r
+ TimeOut : Maximum time, in microseconds, for transfer to complete.\r
+ TransferResult : Variable to receive the transfer result\r
+\r
+ @return EFI_SUCCESS : The control transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : Failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2ControlTransfer (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ BOOLEAN IsSlow;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+ IsSlow = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;\r
+\r
+ return UhciControlTransfer (\r
+ &Uhc->UsbHc,\r
+ DeviceAddress,\r
+ IsSlow,\r
+ (UINT8) MaximumPacketLength,\r
+ Request,\r
+ TransferDirection,\r
+ Data,\r
+ DataLength,\r
+ TimeOut,\r
+ TransferResult\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device\r
+\r
+ This : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ EndPointAddress : Endpoint number and direction\r
+ DeviceSpeed : Device speed\r
+ MaximumPacketLength : Maximum packet size of the target endpoint\r
+ DataBuffersNumber : Number of data buffers prepared for the transfer.\r
+ Data : Array of pointers to the buffers of data\r
+ DataLength : On input, size of the data buffer, On output,\r
+ actually transferred data size.\r
+ DataToggle : On input, data toggle to use; On output, next data toggle\r
+ Translator : A pointr to the transaction translator data.\r
+ TimeOut : Maximum time out, in microseconds\r
+ TransferResult : Variable to receive transfer result\r
+\r
+ @return EFI_SUCCESS : The bulk transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : Failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2BulkTransfer (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN UINT8 DataBuffersNumber,\r
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+\r
+ if (Data == NULL || DeviceSpeed == EFI_USB_SPEED_LOW) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // For full-speed bulk transfers only the data pointed by Data[0] shall be used\r
+ //\r
+ return UhciBulkTransfer (\r
+ &Uhc->UsbHc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ (UINT8) MaximumPacketLength,\r
+ *Data,\r
+ DataLength,\r
+ DataToggle,\r
+ TimeOut,\r
+ TransferResult\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Submits an asynchronous interrupt transfer to an\r
+ interrupt endpoint of a USB device according to UEFI 2.0 spec.\r
+\r
+ This : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ EndPointAddress : Endpoint number and direction\r
+ DeviceSpeed : Device speed\r
+ MaximumPacketLength : Maximum packet size of the target endpoint\r
+ IsNewTransfer : If TRUE, submit a new transfer, if FALSE cancel old transfer\r
+ DataToggle : On input, data toggle to use; On output, next data toggle\r
+ PollingInterval : Interrupt poll rate in milliseconds\r
+ DataLength : On input, size of the data buffer, On output,\r
+ actually transferred data size.\r
+ Translator : A pointr to the transaction translator data.\r
+ CallBackFunction : Function to call periodically\r
+ Context : User context\r
+\r
+ @return EFI_SUCCESS : Transfer was submitted\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_OUT_OF_RESOURCES : Failed due to a lack of resources.\r
+ @return EFI_DEVICE_ERROR : Can't read register\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2AsyncInterruptTransfer (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN BOOLEAN IsNewTransfer,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN PollingInterval,\r
+ IN UINTN DataLength,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ BOOLEAN IsSlow;\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+ IsSlow = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;\r
+\r
+ return UhciAsyncInterruptTransfer (\r
+ &Uhc->UsbHc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ IsSlow,\r
+ (UINT8) MaximumPacketLength,\r
+ IsNewTransfer,\r
+ DataToggle,\r
+ PollingInterval,\r
+ DataLength,\r
+ CallBackFunction,\r
+ Context\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Submits synchronous interrupt transfer to an interrupt endpoint\r
+ of a USB device according to UEFI 2.0 spec.\r
+\r
+ This : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ EndPointAddress : Endpoint number and direction\r
+ DeviceSpeed : Device speed\r
+ MaximumPacketLength : Maximum packet size of the target endpoint\r
+ DataBuffersNumber : Number of data buffers prepared for the transfer.\r
+ Data : Array of pointers to the buffers of data\r
+ DataLength : On input, size of the data buffer, On output,\r
+ actually transferred data size.\r
+ DataToggle : On input, data toggle to use; On output, next data toggle\r
+ TimeOut : Maximum time out, in microseconds\r
+ Translator : A pointr to the transaction translator data.\r
+ TransferResult : Variable to receive transfer result\r
+\r
+ @return EFI_SUCCESS : The transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : Failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : Failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2SyncInterruptTransfer (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ BOOLEAN IsSlow;\r
+\r
+ if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Uhc = UHC_FROM_USB2_HC_PROTO (This);\r
+ IsSlow = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;\r
+\r
+ return UhciSyncInterruptTransfer (\r
+ &Uhc->UsbHc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ IsSlow,\r
+ (UINT8) MaximumPacketLength,\r
+ Data,\r
+ DataLength,\r
+ DataToggle,\r
+ TimeOut,\r
+ TransferResult\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.\r
+\r
+ This : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ EndPointAddress : Endpoint number and direction\r
+ DeviceSpeed : Device speed\r
+ MaximumPacketLength : Maximum packet size of the target endpoint\r
+ DataBuffersNumber : Number of data buffers prepared for the transfer.\r
+ Data : Array of pointers to the buffers of data\r
+ DataLength : On input, size of the data buffer, On output,\r
+ actually transferred data size.\r
+ Translator : A pointr to the transaction translator data.\r
+ TransferResult : Variable to receive transfer result\r
+\r
+ @return EFI_UNSUPPORTED\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2IsochronousTransfer (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN UINT8 DataBuffersNumber,\r
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+ IN UINTN DataLength,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.\r
+\r
+ This : A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
+ DeviceAddress : Target device address\r
+ EndPointAddress : Endpoint number and direction\r
+ DeviceSpeed : Device speed\r
+ MaximumPacketLength : Maximum packet size of the target endpoint\r
+ DataBuffersNumber : Number of data buffers prepared for the transfer.\r
+ Data : Array of pointers to the buffers of data\r
+ Translator : A pointr to the transaction translator data.\r
+ IsochronousCallBack : Function to call when the transfer complete\r
+ Context : Pass to the call back function as parameter\r
+\r
+ @return EFI_UNSUPPORTED\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+Uhci2AsyncIsochronousTransfer (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN UINT8 DataBuffersNumber,\r
+ IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+ IN UINTN DataLength,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (UhciDriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UhciDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Entry point for EFI drivers.\r
+\r
+ Arguments:\r
+\r
+ ImageHandle - EFI_HANDLE\r
+ SystemTable - EFI_SYSTEM_TABLE\r
+\r
+ Returns:\r
+\r
+ EFI_SUCCESS : Driver is successfully loaded\r
+ Others : Failed\r
+\r
+--*/\r
+{\r
+ return EfiLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gUhciDriverBinding,\r
+ ImageHandle,\r
+ &gUhciComponentName,\r
+ NULL,\r
+ NULL\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
+UhciDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS OpenStatus;\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ USB_CLASSC UsbClassCReg;\r
+\r
+ //\r
+ // Test whether there is PCI IO Protocol attached on the controller handle.\r
+ //\r
+ OpenStatus = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (OpenStatus)) {\r
+ return OpenStatus;\r
+ }\r
+\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ CLASSC_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
+ //\r
+ // Test whether the controller belongs to UHCI type\r
+ //\r
+ if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
+ (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
+ (UsbClassCReg.PI != PCI_CLASSC_PI_UHCI)\r
+ ) {\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ }\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 UHCI device\r
+\r
+ @param PciIo The PCIIO to use\r
+\r
+ @return Allocated UHCI device\r
+\r
+**/\r
+STATIC\r
+USB_HC_DEV *\r
+UhciAllocateDev (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+ EFI_STATUS Status;\r
+\r
+ Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));\r
+\r
+ if (Uhc == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.\r
+ // USB_HC_PROTOCOL is for EFI 1.1 backward compability.\r
+ //\r
+ Uhc->Signature = USB_HC_DEV_SIGNATURE;\r
+ Uhc->UsbHc.Reset = UhciReset;\r
+ Uhc->UsbHc.GetState = UhciGetState;\r
+ Uhc->UsbHc.SetState = UhciSetState;\r
+ Uhc->UsbHc.ControlTransfer = UhciControlTransfer;\r
+ Uhc->UsbHc.BulkTransfer = UhciBulkTransfer;\r
+ Uhc->UsbHc.AsyncInterruptTransfer = UhciAsyncInterruptTransfer;\r
+ Uhc->UsbHc.SyncInterruptTransfer = UhciSyncInterruptTransfer;\r
+ Uhc->UsbHc.IsochronousTransfer = UhciIsochronousTransfer;\r
+ Uhc->UsbHc.AsyncIsochronousTransfer = UhciAsyncIsochronousTransfer;\r
+ Uhc->UsbHc.GetRootHubPortNumber = UhciGetRootHubPortNumber;\r
+ Uhc->UsbHc.GetRootHubPortStatus = UhciGetRootHubPortStatus;\r
+ Uhc->UsbHc.SetRootHubPortFeature = UhciSetRootHubPortFeature;\r
+ Uhc->UsbHc.ClearRootHubPortFeature = UhciClearRootHubPortFeature;\r
+ Uhc->UsbHc.MajorRevision = 0x1;\r
+ Uhc->UsbHc.MinorRevision = 0x1;\r
+\r
+ Uhc->Usb2Hc.GetCapability = Uhci2GetCapability;\r
+ Uhc->Usb2Hc.Reset = Uhci2Reset;\r
+ Uhc->Usb2Hc.GetState = Uhci2GetState;\r
+ Uhc->Usb2Hc.SetState = Uhci2SetState;\r
+ Uhc->Usb2Hc.ControlTransfer = Uhci2ControlTransfer;\r
+ Uhc->Usb2Hc.BulkTransfer = Uhci2BulkTransfer;\r
+ Uhc->Usb2Hc.AsyncInterruptTransfer = Uhci2AsyncInterruptTransfer;\r
+ Uhc->Usb2Hc.SyncInterruptTransfer = Uhci2SyncInterruptTransfer;\r
+ Uhc->Usb2Hc.IsochronousTransfer = Uhci2IsochronousTransfer;\r
+ Uhc->Usb2Hc.AsyncIsochronousTransfer = Uhci2AsyncIsochronousTransfer;\r
+ Uhc->Usb2Hc.GetRootHubPortStatus = Uhci2GetRootHubPortStatus;\r
+ Uhc->Usb2Hc.SetRootHubPortFeature = Uhci2SetRootHubPortFeature;\r
+ Uhc->Usb2Hc.ClearRootHubPortFeature = Uhci2ClearRootHubPortFeature;\r
+ Uhc->Usb2Hc.MajorRevision = 0x1;\r
+ Uhc->Usb2Hc.MinorRevision = 0x1;\r
+\r
+ Uhc->PciIo = PciIo;\r
+ Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);\r
+\r
+ if (Uhc->MemPool == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ InitializeListHead (&Uhc->AsyncIntList);\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ UhciMonitorAsyncReqList,\r
+ Uhc,\r
+ &Uhc->AsyncIntMonitor\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ UsbHcFreeMemPool (Uhc->MemPool);\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ return Uhc;\r
+\r
+ON_ERROR:\r
+ gBS->FreePool (Uhc);\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Free the UHCI device and release its associated resources\r
+\r
+ @param Uhc The UHCI device to release\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciFreeDev (\r
+ IN USB_HC_DEV *Uhc\r
+ )\r
+{\r
+ if (Uhc->AsyncIntMonitor != NULL) {\r
+ gBS->CloseEvent (Uhc->AsyncIntMonitor);\r
+ }\r
+\r
+ if (Uhc->MemPool != NULL) {\r
+ UsbHcFreeMemPool (Uhc->MemPool);\r
+ }\r
+\r
+ if (Uhc->CtrlNameTable) {\r
+ FreeUnicodeStringTable (Uhc->CtrlNameTable);\r
+ }\r
+\r
+ gBS->FreePool (Uhc);\r
+}\r
+\r
+\r
+/**\r
+ Uninstall all Uhci Interface\r
+\r
+ @param Controller Controller handle\r
+ @param This Protocol instance pointer.\r
+\r
+ @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UhciCleanDevUp (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_USB_HC_PROTOCOL *This\r
+ )\r
+{\r
+ USB_HC_DEV *Uhc;\r
+\r
+ //\r
+ // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller\r
+ //\r
+ Uhc = UHC_FROM_USB_HC_PROTO (This);\r
+ UhciStopHc (Uhc, STALL_1_SECOND);\r
+\r
+ gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiUsbHcProtocolGuid,\r
+ &Uhc->UsbHc\r
+ );\r
+\r
+ gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ &Uhc->Usb2Hc\r
+ );\r
+\r
+ UhciFreeAllAsyncReq (Uhc);\r
+ UhciDestoryFrameList (Uhc);\r
+\r
+ Uhc->PciIo->Attributes (\r
+ Uhc->PciIo,\r
+ EfiPciIoAttributeOperationDisable,\r
+ EFI_PCI_DEVICE_ENABLE,\r
+ NULL\r
+ );\r
+\r
+ UhciFreeDev (Uhc);\r
+}\r
+\r
+\r
+/**\r
+ Starting the Usb UHCI 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\r
+ shortage\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhciDriverBindingStart (\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_HC_DEV *Uhc;\r
+\r
+ //\r
+ // Open PCIIO, then enable the EHC device and turn off emulation\r
+ //\r
+ Uhc = NULL;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ &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
+ UhciTurnOffUsbEmulation (PciIo);\r
+\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_DEVICE_ENABLE,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto CLOSE_PCIIO;\r
+ }\r
+\r
+ Uhc = UhciAllocateDev (PciIo);\r
+\r
+ if (Uhc == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto CLOSE_PCIIO;\r
+ }\r
+\r
+ //\r
+ // Allocate and Init Host Controller's Frame List Entry\r
+ //\r
+ Status = UhciInitFrameList (Uhc);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FREE_UHC;\r
+ }\r
+\r
+ Status = gBS->SetTimer (\r
+ Uhc->AsyncIntMonitor,\r
+ TimerPeriodic,\r
+ INTERRUPT_POLLING_TIME\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_UHC;\r
+ }\r
+\r
+ //\r
+ // Install both USB_HC_PROTOCOL and USB2_HC_PROTOCOL\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Controller,\r
+ &gEfiUsbHcProtocolGuid,\r
+ &Uhc->UsbHc,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ &Uhc->Usb2Hc,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_UHC;\r
+ }\r
+\r
+ //\r
+ // Install the component name protocol\r
+ //\r
+ Uhc->CtrlNameTable = NULL;\r
+\r
+ AddUnicodeString (\r
+ "eng",\r
+ gUhciComponentName.SupportedLanguages,\r
+ &Uhc->CtrlNameTable,\r
+ L"Usb Universal Host Controller"\r
+ );\r
+\r
+ //\r
+ // Start the UHCI hardware, also set its reclamation point to 64 bytes\r
+ //\r
+ UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+FREE_UHC:\r
+ UhciFreeDev (Uhc);\r
+\r
+CLOSE_PCIIO:\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\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
+UhciDriverBindingStop (\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_USB_HC_PROTOCOL *UsbHc;\r
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUsbHcProtocolGuid,\r
+ &UsbHc,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ //\r
+ // Test whether the Controller handler passed in is a valid\r
+ // Usb controller handle that should be supported, if not,\r
+ // return the error status directly\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ &Usb2Hc,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ //\r
+ // Test whether the Controller handler passed in is a valid\r
+ // Usb controller handle that should be supported, if not,\r
+ // return the error status directly\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ UhciCleanDevUp (Controller, UsbHc);\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {\r
+ UhciDriverBindingSupported,\r
+ UhciDriverBindingStart,\r
+ UhciDriverBindingStop,\r
+ 0x20,\r
+ NULL,\r
+ NULL\r
+};\r