--- /dev/null
+/** @file\r
+\r
+Copyright 2006 - 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
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Ehci.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+EhciComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EhciComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle, OPTIONAL\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gEhciComponentName = {\r
+ EhciComponentNameGetDriverName,\r
+ EhciComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mEhciDriverNameTable[] = {\r
+ { "eng", L"Usb Ehci Driver" },\r
+ { NULL , NULL }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EhciComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ Language - A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages specified\r
+ in SupportedLanguages. The number of languages supported by a\r
+ driver is up to the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode string\r
+ is the name of the driver specified by This in the language\r
+ specified by Language.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the Driver specified by This\r
+ and the language specified by Language was returned\r
+ in DriverName.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - DriverName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gEhciComponentName.SupportedLanguages,\r
+ mEhciDriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EhciComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle, OPTIONAL\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ ControllerHandle - The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ ChildHandle - The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL. It\r
+ will be NULL for device drivers. It will also be NULL\r
+ for a bus drivers that wish to retrieve the name of the\r
+ bus controller. It will not be NULL for a bus driver\r
+ that wishes to retrieve the name of a child controller.\r
+ Language - A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller name\r
+ that that the caller is requesting, and it must match one\r
+ of the languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up to the\r
+ driver writer.\r
+ ControllerName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language\r
+ specified by Language from the point of view of the\r
+ driver specified by This.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the user readable name in the\r
+ language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ USB2_HC_DEV *EhciDev;\r
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
+\r
+ //\r
+ // This is a device driver, so ChildHandle must be NULL.\r
+ //\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Make sure this driver is currently managing ControllerHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gEhciDriverBinding.DriverBindingHandle,\r
+ &gEfiPciIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the device context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ (VOID **) &Usb2Hc,\r
+ gEhciDriverBinding.DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ EhciDev = EHC_FROM_THIS (Usb2Hc);\r
+\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gEhciComponentName.SupportedLanguages,\r
+ EhciDev->ControllerNameTable,\r
+ ControllerName\r
+ );\r
+\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 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
+ Ehci.c\r
+\r
+Abstract:\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+\r
+#include "Ehci.h"\r
+\r
+//\r
+// Two arrays used to translate the EHCI port state (change)\r
+// to the UEFI protocol's port state (change).\r
+//\r
+USB_PORT_STATE_MAP mUsbPortStateMap[] = {\r
+ {PORTSC_CONN, USB_PORT_STAT_CONNECTION},\r
+ {PORTSC_ENABLED, USB_PORT_STAT_ENABLE},\r
+ {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND},\r
+ {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT},\r
+ {PORTSC_RESET, USB_PORT_STAT_RESET},\r
+ {PORTSC_POWER, USB_PORT_STAT_POWER},\r
+ {PORTSC_OWNER, USB_PORT_STAT_OWNER}\r
+};\r
+\r
+USB_PORT_STATE_MAP mUsbPortChangeMap[] = {\r
+ {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION},\r
+ {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE},\r
+ {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}\r
+};\r
+\r
+\r
+/**\r
+ Retrieves the capablility of root hub ports.\r
+\r
+ @param This This EFI_USB_HC_PROTOCOL instance.\r
+ @param MaxSpeed Max speed supported by the controller\r
+ @param PortNumber Number of the root hub ports.\r
+ @param Is64BitCapable Whether the controller supports 64-bit memory\r
+ addressing.\r
+\r
+ @return EFI_SUCCESS : host controller capability were retrieved successfully.\r
+ @return EFI_INVALID_PARAMETER : Either of the three capability pointer is NULL\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetCapability (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ OUT UINT8 *MaxSpeed,\r
+ OUT UINT8 *PortNumber,\r
+ OUT UINT8 *Is64BitCapable\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+\r
+ *MaxSpeed = EFI_USB_SPEED_HIGH;\r
+ *PortNumber = (UINT8) (Ehc->HcStructParams & HCSP_NPORTS);\r
+ *Is64BitCapable = (UINT8) (Ehc->HcCapParams & HCCP_64BIT);\r
+\r
+ EHC_DEBUG (("EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Provides software reset for the USB host controller.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param 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_UNSUPPOURTED : The type of reset specified by Attributes is\r
+ @return not currently supported by the host controller.\r
+ @return EFI_DEVICE_ERROR : Host controller isn't halted to reset.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcReset (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT16 Attributes\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+\r
+ switch (Attributes) {\r
+ case EFI_USB_HC_RESET_GLOBAL:\r
+ //\r
+ // Flow through, same behavior as Host Controller Reset\r
+ //\r
+ case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
+ //\r
+ // Host Controller must be Halt when Reset it\r
+ //\r
+ if (!EhcIsHalt (Ehc)) {\r
+ Status = EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Clean up the asynchronous transfers, currently only\r
+ // interrupt supports asynchronous operation.\r
+ //\r
+ EhciDelAllAsyncIntTransfers (Ehc);\r
+ EhcAckAllInterrupt (Ehc);\r
+ EhcFreeSched (Ehc);\r
+\r
+ Status = EhcResetHC (Ehc, EHC_STALL_1_SECOND);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = EhcInitHC (Ehc);\r
+ break;\r
+\r
+ case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:\r
+ case EFI_USB_HC_RESET_HOST_WITH_DEBUG:\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ON_EXIT:\r
+ EHC_DEBUG (("EhcReset: exit status %r\n", Status));\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Retrieve the current state of the USB host controller.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param State Variable to return the current host controller\r
+ state.\r
+\r
+ @return EFI_SUCCESS : Host controller state was returned in State.\r
+ @return EFI_INVALID_PARAMETER : State is NULL.\r
+ @return EFI_DEVICE_ERROR : An error was encountered while attempting to\r
+ @return retrieve the host controller's current state.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetState (\r
+ IN CONST EFI_USB2_HC_PROTOCOL *This,\r
+ OUT EFI_USB_HC_STATE *State\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ USB2_HC_DEV *Ehc;\r
+\r
+ if (State == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+\r
+ if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
+ *State = EfiUsbHcStateHalt;\r
+ } else {\r
+ *State = EfiUsbHcStateOperational;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ EHC_DEBUG (("EhcGetState: current state %d\n", *State));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Sets the USB host controller to a specific state.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param State The state of the host controller that will be set.\r
+\r
+ @return EFI_SUCCESS : The USB host controller was successfully placed\r
+ @return in the state specified by State.\r
+ @return EFI_INVALID_PARAMETER : State is invalid.\r
+ @return EFI_DEVICE_ERROR : Failed to set the state due to device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcSetState (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN EFI_USB_HC_STATE State\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ EFI_USB_HC_STATE CurState;\r
+\r
+ Status = EhcGetState (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
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+\r
+ switch (State) {\r
+ case EfiUsbHcStateHalt:\r
+ Status = EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+ break;\r
+\r
+ case EfiUsbHcStateOperational:\r
+ if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+\r
+ Status = EhcRunHC (Ehc, EHC_GENERIC_TIME);\r
+ break;\r
+\r
+ case EfiUsbHcStateSuspend:\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ EHC_DEBUG (("EhcSetState: exit status %r\n", Status));\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param PortNumber The root hub port to retrieve the state from. This\r
+ value is zero-based.\r
+ @param PortStatus Variable to receive the port state\r
+\r
+ @return EFI_SUCCESS : The status of the USB root hub port specified\r
+ @return by PortNumber 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
+EhcGetRootHubPortStatus (\r
+ IN CONST EFI_USB2_HC_PROTOCOL *This,\r
+ IN CONST UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ EFI_TPL OldTpl;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ UINT32 TotalPort;\r
+ UINTN Index;\r
+ UINTN MapSize;\r
+ EFI_STATUS Status;\r
+\r
+ if (PortStatus == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+\r
+ Ehc = EHC_FROM_THIS (This);\r
+ Status = EFI_SUCCESS;\r
+\r
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+ if (PortNumber >= TotalPort) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
+ PortStatus->PortStatus = 0;\r
+ PortStatus->PortChangeStatus = 0;\r
+\r
+ State = EhcReadOpReg (Ehc, Offset);\r
+\r
+ //\r
+ // Identify device speed. If in K state, it is low speed.\r
+ // If the port is enabled after reset, the device is of\r
+ // high speed. The USB bus driver should retrieve the actual\r
+ // port speed after reset.\r
+ //\r
+ if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+\r
+ } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+ }\r
+\r
+ //\r
+ // Convert the EHCI port/port change state to UEFI status\r
+ //\r
+ MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
+ PortStatus->PortStatus |= mUsbPortStateMap[Index].UefiState;\r
+ }\r
+ }\r
+\r
+ MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
+ PortStatus->PortChangeStatus |= mUsbPortChangeMap[Index].UefiState;\r
+ }\r
+ }\r
+\r
+ON_EXIT:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param PortNumber Root hub port to set.\r
+ @param PortFeature Feature to set\r
+\r
+ @return EFI_SUCCESS : The feature specified by PortFeature was set\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
+EhcSetRootHubPortFeature (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ EFI_TPL OldTpl;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ UINT32 TotalPort;\r
+ EFI_STATUS Status;\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+ Status = EFI_SUCCESS;\r
+\r
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+ if (PortNumber >= TotalPort) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
+ State = EhcReadOpReg (Ehc, Offset);\r
+\r
+ //\r
+ // Mask off the port status change bits, these bits are\r
+ // write clean bit\r
+ //\r
+ State &= ~PORTSC_CHANGE_MASK;\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ //\r
+ // Sofeware can't set this bit, Port can only be enable by\r
+ // EHCI as a part of the reset and enable\r
+ //\r
+ State |= PORTSC_ENABLED;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ State |= PORTSC_SUSPEND;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ //\r
+ // Make sure Host Controller not halt before reset it\r
+ //\r
+ if (EhcIsHalt (Ehc)) {\r
+ Status = EhcRunHC (Ehc, EHC_GENERIC_TIME);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_DEBUG (("EhcSetRootHubPortFeature :failed to start HC - %r\n", Status));\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Set one to PortReset bit must also set zero to PortEnable bit\r
+ //\r
+ State |= PORTSC_RESET;\r
+ State &= ~PORTSC_ENABLED;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ //\r
+ // Not supported, ignore the operation\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+\r
+ case EfiUsbPortOwner:\r
+ State |= PORTSC_OWNER;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ON_EXIT:\r
+ EHC_DEBUG (("EhcSetRootHubPortFeature: exit status %r\n", Status));\r
+\r
+ gBS->RestoreTPL (OldTpl);\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_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 : The feature specified by PortFeature was cleared\r
+ @return for the USB root hub port specified by PortNumber.\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
+EhcClearRootHubPortFeature (\r
+ IN EFI_USB2_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ EFI_TPL OldTpl;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ UINT32 TotalPort;\r
+ EFI_STATUS Status;\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+ Status = EFI_SUCCESS;\r
+\r
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+ if (PortNumber >= TotalPort) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);\r
+ State = EhcReadOpReg (Ehc, Offset);\r
+ State &= ~PORTSC_CHANGE_MASK;\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ //\r
+ // Clear PORT_ENABLE feature means disable port.\r
+ //\r
+ State &= ~PORTSC_ENABLED;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ //\r
+ // A write of zero to this bit is ignored by the host\r
+ // controller. The host controller will unconditionally\r
+ // set this bit to a zero when:\r
+ // 1. software sets the Forct Port Resume bit to a zero from a one.\r
+ // 2. software sets the Port Reset bit to a one frome a zero.\r
+ //\r
+ State &= ~PORSTSC_RESUME;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ //\r
+ // Clear PORT_RESET means clear the reset signal.\r
+ //\r
+ State &= ~PORTSC_RESET;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortOwner:\r
+ //\r
+ // Clear port owner means this port owned by EHC\r
+ //\r
+ State &= ~PORTSC_OWNER;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortConnectChange:\r
+ //\r
+ // Clear connect status change\r
+ //\r
+ State |= PORTSC_CONN_CHANGE;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortEnableChange:\r
+ //\r
+ // Clear enable status change\r
+ //\r
+ State |= PORTSC_ENABLE_CHANGE;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortOverCurrentChange:\r
+ //\r
+ // Clear PortOverCurrent change\r
+ //\r
+ State |= PORTSC_OVERCUR_CHANGE;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ case EfiUsbPortSuspendChange:\r
+ case EfiUsbPortResetChange:\r
+ //\r
+ // Not supported or not related operation\r
+ //\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ON_EXIT:\r
+ EHC_DEBUG (("EhcClearRootHubPortFeature: exit status %r\n", Status));\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param DeviceAddress The target device address\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer\r
+ endpoint is capable of sending or receiving.\r
+ @param Request USB device request to send\r
+ @param TransferDirection Specifies the data direction for the data stage\r
+ @param Data Data buffer to be transmitted or received from USB\r
+ device.\r
+ @param DataLength The size (in bytes) of the data buffer\r
+ @param TimeOut Indicates the maximum timeout, in millisecond,\r
+ @param Translator Transaction translator to be used by this device.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @return EFI_SUCCESS : Transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : The transfer failed due to lack of resources.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : Transfer failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : Transfer failed due to host controller or device error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcControlTransfer (\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
+ USB2_HC_DEV *Ehc;\r
+ URB *Urb;\r
+ EFI_TPL OldTpl;\r
+ UINT8 Endpoint;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Validate parameters\r
+ //\r
+ if ((Request == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection != EfiUsbDataIn) &&\r
+ (TransferDirection != EfiUsbDataOut) &&\r
+ (TransferDirection != EfiUsbNoData)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection == EfiUsbNoData) &&\r
+ ((Data != NULL) || (*DataLength != 0))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection != EfiUsbNoData) &&\r
+ ((Data == NULL) || (*DataLength == 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
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+\r
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+ EHC_ERROR (("EhcControlTransfer: HC halted at entrance\n"));\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+\r
+ //\r
+ // Create a new URB, insert it into the asynchronous\r
+ // schedule list, then poll the execution status.\r
+ //\r
+ //\r
+ // Encode the direction in address, although default control\r
+ // endpoint is bidirectional. EhcCreateUrb expects this\r
+ // combination of Ep addr and its direction.\r
+ //\r
+ Endpoint = 0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0);\r
+ Urb = EhcCreateUrb (\r
+ Ehc,\r
+ DeviceAddress,\r
+ Endpoint,\r
+ DeviceSpeed,\r
+ 0,\r
+ MaximumPacketLength,\r
+ Translator,\r
+ EHC_CTRL_TRANSFER,\r
+ Request,\r
+ Data,\r
+ *DataLength,\r
+ NULL,\r
+ NULL,\r
+ 1\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ EHC_ERROR (("EhcControlTransfer: failed to create URB"));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcLinkQhToAsync (Ehc, Urb->Qh);\r
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
+ EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
+\r
+ //\r
+ // Get the status from URB. The result is updated in EhcCheckUrbResult\r
+ // which is called by EhcExecTransfer\r
+ //\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+\r
+ if (*TransferResult == EFI_USB_NOERROR) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+ EhcFreeUrb (Ehc, Urb);\r
+\r
+ON_EXIT:\r
+ Ehc->PciIo->Flush (Ehc->PciIo);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param DeviceAddress Target device address\r
+ @param EndPointAddress Endpoint number and its direction in bit 7. .\r
+ @param DeviceSpeed Device speed, Low speed device doesn't support bulk\r
+ transfer.\r
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of\r
+ sending or receiving.\r
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
+ @param Data Array of pointers to the buffers of data to transmit\r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer\r
+ @param DataToggle On input, the initial data toggle for the transfer;\r
+ On output, it is updated to to next data toggle to\r
+ use of the subsequent bulk\r
+ transfer.\r
+ @param Translator A pointr to the transaction translator data.\r
+ @param TimeOut Indicates the maximum time, in millisecond, which\r
+ the transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @return EFI_SUCCESS : The transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : The transfer failed due to lack of resource.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : The transfer failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : The transfer failed due to host controller error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcBulkTransfer (\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
+ USB2_HC_DEV *Ehc;\r
+ URB *Urb;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Validate the parameters\r
+ //\r
+ if ((DataLength == NULL) || (*DataLength == 0) ||\r
+ (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+ ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+ EHC_ERROR (("EhcBulkTransfer: HC is halted\n"));\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+\r
+ //\r
+ // Create a new URB, insert it into the asynchronous\r
+ // schedule list, then poll the execution status.\r
+ //\r
+ Urb = EhcCreateUrb (\r
+ Ehc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ *DataToggle,\r
+ MaximumPacketLength,\r
+ Translator,\r
+ EHC_BULK_TRANSFER,\r
+ NULL,\r
+ Data[0],\r
+ *DataLength,\r
+ NULL,\r
+ NULL,\r
+ 1\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ EHC_ERROR (("EhcBulkTransfer: failed to create URB\n"));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcLinkQhToAsync (Ehc, Urb->Qh);\r
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
+ EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
+\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+ *DataToggle = Urb->DataToggle;\r
+\r
+ if (*TransferResult == EFI_USB_NOERROR) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+ EhcFreeUrb (Ehc, Urb);\r
+\r
+ON_EXIT:\r
+ Ehc->PciIo->Flush (Ehc->PciIo);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits an asynchronous interrupt transfer to an\r
+ interrupt endpoint of a USB device.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param DeviceAddress Target device address\r
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
+ @param DeviceSpeed Indicates device speed.\r
+ @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
+ @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt\r
+ transfer If FALSE, to remove the specified\r
+ asynchronous interrupt\r
+ @param DataToggle On input, the initial data toggle to use; on output,\r
+ it is updated to indicate the next data toggle\r
+ @param PollingInterval The he interval, in milliseconds, that the transfer\r
+ is polled.\r
+ @param DataLength The length of data to receive at the rate specified\r
+ by PollingInterval.\r
+ @param Translator Transaction translator to use.\r
+ @param CallBackFunction Function to call at the rate specified by\r
+ PollingInterval\r
+ @param Context Context to CallBackFunction.\r
+\r
+ @return EFI_SUCCESS : The request has been successfully submitted or canceled.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_OUT_OF_RESOURCES : The request failed due to a lack of resources.\r
+ @return EFI_DEVICE_ERROR : The transfer failed due to host controller error.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcAsyncInterruptTransfer (\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 OPTIONAL\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ URB *Urb;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ UINT8 *Data;\r
+\r
+ //\r
+ // Validate parameters\r
+ //\r
+ if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IsNewTransfer) {\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 ((PollingInterval > 255) || (PollingInterval < 1)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+\r
+ //\r
+ // Delete Async interrupt transfer request. DataToggle will return\r
+ // the next data toggle to use.\r
+ //\r
+ if (!IsNewTransfer) {\r
+ Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);\r
+\r
+ EHC_DEBUG (("EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+ EHC_ERROR (("EhcAsyncInterruptTransfer: HC is halt\n"));\r
+ EhcAckAllInterrupt (Ehc);\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+\r
+ Data = AllocatePool (DataLength);\r
+\r
+ if (Data == NULL) {\r
+ EHC_ERROR (("EhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Urb = EhcCreateUrb (\r
+ Ehc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ *DataToggle,\r
+ MaximumPacketLength,\r
+ Translator,\r
+ EHC_INT_TRANSFER_ASYNC,\r
+ NULL,\r
+ Data,\r
+ DataLength,\r
+ CallBackFunction,\r
+ Context,\r
+ PollingInterval\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ EHC_ERROR (("EhcAsyncInterruptTransfer: failed to create URB\n"));\r
+\r
+ gBS->FreePool (Data);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // New asynchronous transfer must inserted to the head.\r
+ // Check the comments in EhcMoniteAsyncRequests\r
+ //\r
+ EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
+ InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);\r
+\r
+ON_EXIT:\r
+ Ehc->PciIo->Flush (Ehc->PciIo);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits synchronous interrupt transfer to an interrupt endpoint\r
+ of a USB device.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param DeviceAddress Target device address\r
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
+ @param DeviceSpeed Indicates device speed.\r
+ @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
+ of sending or receiving.\r
+ @param Data Buffer of data that will be transmitted to USB\r
+ device or received from USB device.\r
+ @param DataLength On input, the size, in bytes, of the data buffer; On\r
+ output, the number of bytes transferred.\r
+ @param DataToggle On input, the initial data toggle to use; on output,\r
+ it is updated to indicate the next data toggle\r
+ @param TimeOut Maximum time, in second, to complete\r
+ @param Translator Transaction translator to use.\r
+ @param TransferResult Variable to receive the transfer result\r
+\r
+ @return EFI_SUCCESS : The transfer was completed successfully.\r
+ @return EFI_OUT_OF_RESOURCES : The transfer failed due to lack of resource.\r
+ @return EFI_INVALID_PARAMETER : Some parameters are invalid.\r
+ @return EFI_TIMEOUT : The transfer failed due to timeout.\r
+ @return EFI_DEVICE_ERROR : The failed due to host controller or device error\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcSyncInterruptTransfer (\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
+ USB2_HC_DEV *Ehc;\r
+ EFI_TPL OldTpl;\r
+ URB *Urb;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Validates parameters\r
+ //\r
+ if ((DataLength == NULL) || (*DataLength == 0) ||\r
+ (Data == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!EHCI_IS_DATAIN (EndPointAddress)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||\r
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+ ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = EHC_FROM_THIS (This);\r
+\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+ EHC_ERROR (("EhcSyncInterruptTransfer: HC is halt\n"));\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+\r
+ Urb = EhcCreateUrb (\r
+ Ehc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ *DataToggle,\r
+ MaximumPacketLength,\r
+ Translator,\r
+ EHC_INT_TRANSFER_SYNC,\r
+ NULL,\r
+ Data,\r
+ *DataLength,\r
+ NULL,\r
+ NULL,\r
+ 1\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ EHC_ERROR (("EhcSyncInterruptTransfer: failed to create URB\n"));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcLinkQhToPeriod (Ehc, Urb->Qh);\r
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
+ EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
+\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+ *DataToggle = Urb->DataToggle;\r
+\r
+ if (*TransferResult == EFI_USB_NOERROR) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ON_EXIT:\r
+ Ehc->PciIo->Flush (Ehc->PciIo);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submits isochronous transfer to a target USB device.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param DeviceAddress Target device address\r
+ @param EndPointAddress End point address with its direction\r
+ @param DeviceSpeed Device speed, Low speed device doesn't support this\r
+ type.\r
+ @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
+ sending or receiving.\r
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
+ @param Data Array of pointers to the buffers of data that will\r
+ be transmitted to USB device or received from USB\r
+ device.\r
+ @param DataLength The size, in bytes, of the data buffer\r
+ @param Translator Transaction translator to use.\r
+ @param TransferResult Variable to receive the transfer result\r
+\r
+ @return EFI_UNSUPPORTED : Isochronous transfer is unsupported.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcIsochronousTransfer (\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.\r
+\r
+ @param This This EFI_USB2_HC_PROTOCOL instance.\r
+ @param DeviceAddress Target device address\r
+ @param EndPointAddress End point address with its direction\r
+ @param DeviceSpeed Device speed, Low speed device doesn't support this\r
+ type.\r
+ @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
+ sending or receiving.\r
+ @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
+ @param Data Array of pointers to the buffers of data that will\r
+ be transmitted to USB device or received from USB\r
+ device.\r
+ @param DataLength The size, in bytes, of the data buffer\r
+ @param Translator Transaction translator to use.\r
+ @param IsochronousCallBack Function to be called when the transfer complete\r
+ @param Context Context passed to the call back function as\r
+ parameter\r
+\r
+ @return EFI_UNSUPPORTED : Isochronous transfer isn't supported\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EhcAsyncIsochronousTransfer (\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 (EhcDriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EhcDriverEntryPoint (\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 Success\r
+ EFI_DEVICE_ERROR Fail\r
+\r
+--*/\r
+{\r
+ return EfiLibInstallAllDriverProtocols (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gEhciDriverBinding,\r
+ ImageHandle,\r
+ &gEhciComponentName,\r
+ NULL,\r
+ NULL\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that has Usb2HcProtocol installed will\r
+ be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controlle 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
+EhcDriverBindingSupported (\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
+ //\r
+ // Test whether there is PCI IO Protocol attached on the controller handle.\r
+ //\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 EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EHC_PCI_CLASSC,\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 Ehci type\r
+ //\r
+ if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
+ (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
+ (UsbClassCReg.PI != EHC_PCI_CLASSC_PI)) {\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
+ Create and initialize a USB2_HC_DEV\r
+\r
+ @param PciIo The PciIo on this device\r
+\r
+ @return The allocated and initialized USB2_HC_DEV structure\r
+ @return if created, otherwise NULL.\r
+\r
+**/\r
+STATIC\r
+USB2_HC_DEV *\r
+EhcCreateUsb2Hc (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ EFI_STATUS Status;\r
+\r
+ Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));\r
+\r
+ if (Ehc == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Init EFI_USB2_HC_PROTOCOL interface and private data structure\r
+ //\r
+ Ehc->Signature = USB2_HC_DEV_SIGNATURE;\r
+\r
+ Ehc->Usb2Hc.GetCapability = EhcGetCapability;\r
+ Ehc->Usb2Hc.Reset = EhcReset;\r
+ Ehc->Usb2Hc.GetState = EhcGetState;\r
+ Ehc->Usb2Hc.SetState = EhcSetState;\r
+ Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer;\r
+ Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer;\r
+ Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer;\r
+ Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer;\r
+ Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer;\r
+ Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer;\r
+ Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus;\r
+ Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature;\r
+ Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature;\r
+ Ehc->Usb2Hc.MajorRevision = 0x1;\r
+ Ehc->Usb2Hc.MinorRevision = 0x1;\r
+\r
+ Ehc->PciIo = PciIo;\r
+\r
+ InitializeListHead (&Ehc->AsyncIntTransfers);\r
+\r
+ Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);\r
+ Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);\r
+ Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;\r
+\r
+ EHC_DEBUG (("EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));\r
+\r
+ //\r
+ // Create AsyncRequest Polling Timer\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ EhcMoniteAsyncRequests,\r
+ Ehc,\r
+ &Ehc->PollTimer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (Ehc);\r
+ return NULL;\r
+ }\r
+\r
+ return Ehc;\r
+}\r
+\r
+\r
+/**\r
+ Starting the Usb EHCI Driver\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 : supports this device.\r
+ @return EFI_UNSUPPORTED : do not support this device.\r
+ @return EFI_DEVICE_ERROR : cannot be started due to device Error\r
+ @return EFI_OUT_OF_RESOURCES : cannot allocate resources\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcDriverBindingStart (\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
+ USB2_HC_DEV *Ehc;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ //\r
+ // Open the PciIo Protocol, then enable the USB host controller\r
+ //\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
+ EHC_ERROR (("EhcDriverBindingStart: failed to open PCI_IO\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_DEVICE_ENABLE,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcDriverBindingStart: failed to enable controller\n"));\r
+ goto CLOSE_PCIIO;\r
+ }\r
+\r
+ //\r
+ // Create then install USB2_HC_PROTOCOL\r
+ //\r
+ Ehc = EhcCreateUsb2Hc (PciIo);\r
+\r
+ if (Ehc == NULL) {\r
+ EHC_ERROR (("EhcDriverBindingStart: failed to create USB2_HC\n"));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto CLOSE_PCIIO;\r
+ }\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &Ehc->Usb2Hc\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
+ goto FREE_POOL;\r
+ }\r
+\r
+ //\r
+ // Robustnesss improvement such as for UoL\r
+ //\r
+ EhcClearLegacySupport (Ehc);\r
+ EhcResetHC (Ehc, EHC_STALL_1_SECOND);\r
+\r
+ Status = EhcInitHC (Ehc);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcDriverBindingStart: failed to init host controller\n"));\r
+ goto UNINSTALL_USBHC;\r
+ }\r
+\r
+ //\r
+ // Start the asynchronous interrupt monitor\r
+ //\r
+ Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_TIME);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
+\r
+ EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+ goto UNINSTALL_USBHC;\r
+ }\r
+\r
+ //\r
+ // Install the component name protocol, don't fail the start\r
+ // because of something for display.\r
+ //\r
+ AddUnicodeString (\r
+ "eng",\r
+ gEhciComponentName.SupportedLanguages,\r
+ &Ehc->ControllerNameTable,\r
+ L"Enhanced Host Controller (USB 2.0)"\r
+ );\r
+\r
+ EHC_DEBUG (("EhcDriverBindingStart: EHCI started for controller @ %x\n", Controller));\r
+ return EFI_SUCCESS;\r
+\r
+UNINSTALL_USBHC:\r
+ gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ &Ehc->Usb2Hc\r
+ );\r
+\r
+FREE_POOL:\r
+ EhcFreeSched (Ehc);\r
+ gBS->CloseEvent (Ehc->PollTimer);\r
+ gBS->FreePool (Ehc);\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 Success\r
+ @return EFI_DEVICE_ERROR Fail\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcDriverBindingStop (\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_USB2_HC_PROTOCOL *Usb2Hc;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ USB2_HC_DEV *Ehc;\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
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ &Usb2Hc,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Ehc = EHC_FROM_THIS (Usb2Hc);\r
+ PciIo = Ehc->PciIo;\r
+\r
+ //\r
+ // Stop AsyncRequest Polling timer then stop the EHCI driver\r
+ // and uninstall the EHCI protocl.\r
+ //\r
+ gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_TIME);\r
+ EhcHaltHC (Ehc, EHC_GENERIC_TIME);\r
+\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ Usb2Hc\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Ehc->PollTimer != NULL) {\r
+ gBS->CloseEvent (Ehc->PollTimer);\r
+ }\r
+\r
+ EhcFreeSched (Ehc);\r
+\r
+ if (Ehc->ControllerNameTable) {\r
+ FreeUnicodeStringTable (Ehc->ControllerNameTable);\r
+ }\r
+\r
+ //\r
+ // Disable the USB Host Controller\r
+ //\r
+ PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationDisable,\r
+ EFI_PCI_DEVICE_ENABLE,\r
+ NULL\r
+ );\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ gBS->FreePool (Ehc);\r
+ return Status;\r
+}\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL\r
+gEhciDriverBinding = {\r
+ EhcDriverBindingSupported,\r
+ EhcDriverBindingStart,\r
+ EhcDriverBindingStop,\r
+ 0x10,\r
+ NULL,\r
+ NULL\r
+};\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 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
+ Ehci.h\r
+\r
+Abstract:\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_H_\r
+#define _EFI_EHCI_H_\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Protocol/Usb2HostController.h>\r
+#include <Protocol/PciIo.h>\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+typedef struct _USB2_HC_DEV USB2_HC_DEV;\r
+\r
+#include "UsbHcMem.h"\r
+#include "EhciReg.h"\r
+#include "EhciUrb.h"\r
+#include "EhciSched.h"\r
+#include "EhciDebug.h"\r
+\r
+enum {\r
+ USB2_HC_DEV_SIGNATURE = EFI_SIGNATURE_32 ('e', 'h', 'c', 'i'),\r
+ EHC_STALL_1_MICROSECOND = 1,\r
+ EHC_STALL_1_MILLISECOND = 1000 * EHC_STALL_1_MICROSECOND,\r
+ EHC_STALL_1_SECOND = 1000 * EHC_STALL_1_MILLISECOND,\r
+\r
+ EHC_SET_PORT_RESET_TIME = 50 * EHC_STALL_1_MILLISECOND,\r
+ EHC_CLEAR_PORT_RESET_TIME = EHC_STALL_1_MILLISECOND,\r
+ EHC_GENERIC_TIME = 10 * EHC_STALL_1_MILLISECOND,\r
+ EHC_SYNC_POLL_TIME = 20 * EHC_STALL_1_MICROSECOND,\r
+ EHC_ASYNC_POLL_TIME = 50 * 10000UL, // The unit of time is 100us\r
+\r
+ EHC_TPL = TPL_NOTIFY,\r
+};\r
+\r
+//\r
+//Iterate through the doule linked list. NOT delete safe\r
+//\r
+#define EFI_LIST_FOR_EACH(Entry, ListHead) \\r
+ for(Entry = (ListHead)->ForwardLink; Entry != (ListHead); Entry = Entry->ForwardLink)\r
+\r
+//\r
+//Iterate through the doule linked list. This is delete-safe.\r
+//Don't touch NextEntry\r
+//\r
+#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \\r
+ for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\\r
+ Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink)\r
+\r
+#define EFI_LIST_CONTAINER(Entry, Type, Field) _CR(Entry, Type, Field)\r
+\r
+\r
+#define EHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))\r
+#define EHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+#define EHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+#define EHC_REG_BIT_IS_SET(Ehc, Offset, Bit) \\r
+ (EHC_BIT_IS_SET(EhcReadOpReg ((Ehc), (Offset)), (Bit)))\r
+\r
+#define EHC_FROM_THIS(a) CR(a, USB2_HC_DEV, Usb2Hc, USB2_HC_DEV_SIGNATURE)\r
+\r
+typedef struct _USB2_HC_DEV {\r
+ UINTN Signature;\r
+ EFI_USB2_HC_PROTOCOL Usb2Hc;\r
+\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ USBHC_MEM_POOL *MemPool;\r
+\r
+ //\r
+ // Schedule data shared between asynchronous and periodic\r
+ // transfers:\r
+ // ShortReadStop, as its name indicates, is used to terminate\r
+ // the short read except the control transfer. EHCI follows\r
+ // the alternative next QTD point when a short read happens.\r
+ // For control transfer, even the short read happens, try the\r
+ // status stage.\r
+ //\r
+ EHC_QTD *ShortReadStop;\r
+ EFI_EVENT PollTimer;\r
+\r
+ //\r
+ // Asynchronous(bulk and control) transfer schedule data:\r
+ // ReclaimHead is used as the head of the asynchronous transfer\r
+ // list. It acts as the reclamation header.\r
+ //\r
+ EHC_QH *ReclaimHead;\r
+\r
+ //\r
+ // Peroidic (interrupt) transfer schedule data:\r
+ //\r
+ VOID *PeriodFrame; // Mapped as common buffer\r
+ VOID *PeriodFrameHost;\r
+ VOID *PeriodFrameMap;\r
+\r
+ EHC_QH *PeriodOne;\r
+ LIST_ENTRY AsyncIntTransfers;\r
+\r
+ //\r
+ // EHCI configuration data\r
+ //\r
+ UINT32 HcStructParams; // Cache of HC structure parameter, EHC_HCSPARAMS_OFFSET\r
+ UINT32 HcCapParams; // Cache of HC capability parameter, HCCPARAMS\r
+ UINT32 CapLen; // Capability length\r
+ UINT32 High32bitAddr;\r
+\r
+ //\r
+ // Misc\r
+ //\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+} USB2_HC_DEV;\r
+\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL gEhciDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gEhciComponentName;\r
+\r
+#endif\r
--- /dev/null
+#/** @file\r
+# Component name for module Ehci\r
+#\r
+# FIX ME!\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\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
+#\r
+#**/\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = Ehci\r
+ FILE_GUID = BDFE430E-8F2A-4db0-9991-6F856594777E\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ EDK_RELEASE_VERSION = 0x00020000\r
+ EFI_SPECIFICATION_VERSION = 0x00020000\r
+\r
+ ENTRY_POINT = EhcDriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+################################################################################\r
+#\r
+# Sources Section - list of files that are required for the build to succeed.\r
+#\r
+################################################################################\r
+\r
+[Sources.common]\r
+ UsbHcMem.h\r
+ EhciUrb.c\r
+ EhciReg.h\r
+ UsbHcMem.c\r
+ EhciSched.c\r
+ EhciDebug.c\r
+ EhciReg.c\r
+ EhciDebug.h\r
+ ComponentName.c\r
+ EhciUrb.h\r
+ Ehci.h\r
+ EhciSched.h\r
+ Ehci.c\r
+\r
+################################################################################\r
+#\r
+# Package Dependency Section - list of Package files that are required for\r
+# this module.\r
+#\r
+################################################################################\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+################################################################################\r
+#\r
+# Library Class Section - list of Library Classes that are required for\r
+# this module.\r
+#\r
+################################################################################\r
+\r
+[LibraryClasses]\r
+ MemoryAllocationLib\r
+ BaseLib\r
+ UefiLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ BaseMemoryLib\r
+ DebugLib\r
+\r
+\r
+################################################################################\r
+#\r
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names\r
+# that this module uses or produces.\r
+#\r
+################################################################################\r
+\r
+[Protocols]\r
+ gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiUsb2HcProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
--- /dev/null
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+ <MsaHeader>\r
+ <ModuleName>Ehci</ModuleName>\r
+ <ModuleType>DXE_DRIVER</ModuleType>\r
+ <GuidValue>BDFE430E-8F2A-4db0-9991-6F856594777E</GuidValue>\r
+ <Version>1.0</Version>\r
+ <Abstract>Component name for module Ehci</Abstract>\r
+ <Description>FIX ME!</Description>\r
+ <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+ <License>All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>\r
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>\r
+ </MsaHeader>\r
+ <ModuleDefinitions>\r
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+ <BinaryModule>false</BinaryModule>\r
+ <OutputFileBasename>Ehci</OutputFileBasename>\r
+ </ModuleDefinitions>\r
+ <LibraryClassDefinitions>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>DebugLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseMemoryLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiDriverEntryPoint</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiBootServicesTableLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>UefiLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>BaseLib</Keyword>\r
+ </LibraryClass>\r
+ <LibraryClass Usage="ALWAYS_CONSUMED">\r
+ <Keyword>MemoryAllocationLib</Keyword>\r
+ </LibraryClass>\r
+ </LibraryClassDefinitions>\r
+ <SourceFiles>\r
+ <Filename>Ehci.c</Filename>\r
+ <Filename>EhciSched.h</Filename>\r
+ <Filename>Ehci.h</Filename>\r
+ <Filename>EhciUrb.h</Filename>\r
+ <Filename>ComponentName.c</Filename>\r
+ <Filename>EhciDebug.h</Filename>\r
+ <Filename>EhciReg.c</Filename>\r
+ <Filename>EhciDebug.c</Filename>\r
+ <Filename>EhciSched.c</Filename>\r
+ <Filename>UsbHcMem.c</Filename>\r
+ <Filename>EhciReg.h</Filename>\r
+ <Filename>EhciUrb.c</Filename>\r
+ <Filename>UsbHcMem.h</Filename>\r
+ </SourceFiles>\r
+ <PackageDependencies>\r
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+ </PackageDependencies>\r
+ <Protocols>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiUsb2HcProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ <Protocol Usage="ALWAYS_CONSUMED">\r
+ <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>\r
+ </Protocol>\r
+ </Protocols>\r
+ <Externs>\r
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+ <Extern>\r
+ <ModuleEntryPoint>EhcDriverEntryPoint</ModuleEntryPoint>\r
+ </Extern>\r
+ </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciDebug.c\r
+\r
+Abstract:\r
+ This file provides the information dump support for EHCI when in debug mode.\r
+You can dynamically adjust the debug level by changing variable mEhcDebugLevel\r
+and mEhcErrorLevel.\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+\r
+#include "Ehci.h"\r
+\r
+#ifdef EFI_DEBUG\r
+UINTN mEhcDebugMask = USB_DEBUG_FORCE_OUTPUT;\r
+\r
+\r
+/**\r
+ EHCI's debug output function. It determines whether\r
+ to output by the mask and level\r
+\r
+ @param Level The output level\r
+ @param Format The format parameters to the print\r
+ @param ... The variable length parameters after format\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhciDebugPrint (\r
+ IN UINTN Level,\r
+ IN CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+\r
+ VA_LIST Marker;\r
+\r
+ VA_START (Marker, Format);\r
+\r
+ if (Level & mEhcDebugMask) {\r
+ if (mEhcDebugMask & USB_DEBUG_FORCE_OUTPUT) {\r
+ DebugVPrint (DEBUG_ERROR, Format, Marker);\r
+ } else {\r
+ DebugVPrint (DEBUG_INFO, Format, Marker);\r
+ }\r
+ }\r
+\r
+ VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+ EHCI's debug output function. It determines whether\r
+ to output by the mask and level\r
+\r
+ @param Format The format parameters to the print\r
+ @param ... The variable length parameters after format\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcDebug (\r
+ IN CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+\r
+ VA_START (Marker, Format);\r
+ DebugVPrint (DEBUG_INFO, Format, Marker);\r
+ VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+ EHCI's error output function. It determines whether\r
+ to output by the mask and level\r
+\r
+ @param Format The format parameters to the print\r
+ @param ... The variable length parameters after format\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcError (\r
+ IN CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+\r
+ VA_LIST Marker;\r
+\r
+ VA_START (Marker, Format);\r
+ DebugVPrint (DEBUG_ERROR, Format, Marker);\r
+ VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+ Dump the status byte in QTD/QH to a more friendly\r
+ format\r
+\r
+ @param State The state in the QTD/QH\r
+ @param Level The output level\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcDumpStatus (\r
+ IN UINT32 State,\r
+ IN UINTN Level\r
+ )\r
+{\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_DO_PING)) {\r
+ EhciDebugPrint (Level, " Do_Ping");\r
+ } else {\r
+ EhciDebugPrint (Level, " Do_Out");\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_DO_CS)) {\r
+ EhciDebugPrint (Level, " Do_CS");\r
+ } else {\r
+ EhciDebugPrint (Level, " Do_SS");\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR)) {\r
+ EhciDebugPrint (Level, " Transfer_Error");\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {\r
+ EhciDebugPrint (Level, " Babble_Error");\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {\r
+ EhciDebugPrint (Level, " Buffer_Error");\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {\r
+ EhciDebugPrint (Level, " Halted");\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {\r
+ EhciDebugPrint (Level, " Active");\r
+ }\r
+\r
+ EhciDebugPrint (Level, "\n");\r
+}\r
+\r
+\r
+/**\r
+ Dump the fields of a QTD\r
+\r
+ @param Qtd The QTD to dump\r
+ @param Msg The message to print before the dump\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpQtd (\r
+ IN EHC_QTD *Qtd,\r
+ IN UINT8 *Msg\r
+ )\r
+{\r
+ QTD_HW *QtdHw;\r
+ UINTN Index;\r
+ UINTN Level;\r
+\r
+ Level = EHC_DEBUG_QTD;\r
+\r
+ if (Msg != NULL) {\r
+ EhciDebugPrint (Level, Msg);\r
+ }\r
+\r
+ EhciDebugPrint (Level, "Queue TD @ 0x%x, data length %d\n", Qtd, Qtd->DataLen);\r
+\r
+ QtdHw = &Qtd->QtdHw;\r
+\r
+ EhciDebugPrint (Level, "Next QTD : %x\n", QtdHw->NextQtd);\r
+ EhciDebugPrint (Level, "AltNext QTD : %x\n", QtdHw->AltNext);\r
+ EhciDebugPrint (Level, "Status : %x\n", QtdHw->Status);\r
+ EhcDumpStatus (QtdHw->Status, Level);\r
+\r
+ if (QtdHw->Pid == QTD_PID_SETUP) {\r
+ EhciDebugPrint (Level, "PID : Setup\n");\r
+\r
+ } else if (QtdHw->Pid == QTD_PID_INPUT) {\r
+ EhciDebugPrint (Level, "PID : IN\n");\r
+\r
+ } else if (QtdHw->Pid == QTD_PID_OUTPUT) {\r
+ EhciDebugPrint (Level, "PID : OUT\n");\r
+\r
+ }\r
+\r
+ EhciDebugPrint (Level, "Error Count : %d\n", QtdHw->ErrCnt);\r
+ EhciDebugPrint (Level, "Current Page : %d\n", QtdHw->CurPage);\r
+ EhciDebugPrint (Level, "IOC : %d\n", QtdHw->IOC);\r
+ EhciDebugPrint (Level, "Total Bytes : %d\n", QtdHw->TotalBytes);\r
+ EhciDebugPrint (Level, "Data Toggle : %d\n", QtdHw->DataToggle);\r
+\r
+ for (Index = 0; Index < 5; Index++) {\r
+ EhciDebugPrint (Level, "Page[%d] : 0x%x\n", Index, QtdHw->Page[Index]);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Dump the queue head\r
+\r
+ @param Qh The queue head to dump\r
+ @param Msg The message to print before the dump\r
+ @param DumpBuf Whether to dump the memory buffer of the associated QTD\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpQh (\r
+ IN EHC_QH *Qh,\r
+ IN UINT8 *Msg,\r
+ IN BOOLEAN DumpBuf\r
+ )\r
+{\r
+ EHC_QTD *Qtd;\r
+ QH_HW *QhHw;\r
+ LIST_ENTRY *Entry;\r
+ UINTN Index;\r
+ UINTN Level;\r
+\r
+ Level = EHC_DEBUG_QH;\r
+\r
+ if (Msg != NULL) {\r
+ EhciDebugPrint (Level, Msg);\r
+ }\r
+\r
+ EhciDebugPrint (Level, "Queue head @ 0x%x, interval %d, next qh %x\n",\r
+ Qh, Qh->Interval, Qh->NextQh);\r
+\r
+ QhHw = &Qh->QhHw;\r
+\r
+ EhciDebugPrint (Level, "Hoziontal link: %x\n", QhHw->HorizonLink);\r
+ EhciDebugPrint (Level, "Device address: %d\n", QhHw->DeviceAddr);\r
+ EhciDebugPrint (Level, "Inactive : %d\n", QhHw->Inactive);\r
+ EhciDebugPrint (Level, "EP number : %d\n", QhHw->EpNum);\r
+ EhciDebugPrint (Level, "EP speed : %d\n", QhHw->EpSpeed);\r
+ EhciDebugPrint (Level, "DT control : %d\n", QhHw->DtCtrl);\r
+ EhciDebugPrint (Level, "Reclaim head : %d\n", QhHw->ReclaimHead);\r
+ EhciDebugPrint (Level, "Max packet len: %d\n", QhHw->MaxPacketLen);\r
+ EhciDebugPrint (Level, "Ctrl EP : %d\n", QhHw->CtrlEp);\r
+ EhciDebugPrint (Level, "Nak reload : %d\n", QhHw->NakReload);\r
+\r
+ EhciDebugPrint (Level, "SMask : %x\n", QhHw->SMask);\r
+ EhciDebugPrint (Level, "CMask : %x\n", QhHw->CMask);\r
+ EhciDebugPrint (Level, "Hub address : %d\n", QhHw->HubAddr);\r
+ EhciDebugPrint (Level, "Hub port : %d\n", QhHw->PortNum);\r
+ EhciDebugPrint (Level, "Multiplier : %d\n", QhHw->Multiplier);\r
+\r
+ EhciDebugPrint (Level, "Cur QTD : %x\n", QhHw->CurQtd);\r
+\r
+ EhciDebugPrint (Level, "Next QTD : %x\n", QhHw->NextQtd);\r
+ EhciDebugPrint (Level, "AltNext QTD : %x\n", QhHw->AltQtd);\r
+ EhciDebugPrint (Level, "Status : %x\n", QhHw->Status);\r
+ EhcDumpStatus (QhHw->Status, Level);\r
+\r
+ if (QhHw->Pid == QTD_PID_SETUP) {\r
+ EhciDebugPrint (Level, "PID : Setup\n");\r
+\r
+ } else if (QhHw->Pid == QTD_PID_INPUT) {\r
+ EhciDebugPrint (Level, "PID : IN\n");\r
+\r
+ } else if (QhHw->Pid == QTD_PID_OUTPUT) {\r
+ EhciDebugPrint (Level, "PID : OUT\n");\r
+ }\r
+\r
+ EhciDebugPrint (Level, "Error Count : %d\n", QhHw->ErrCnt);\r
+ EhciDebugPrint (Level, "Current Page : %d\n", QhHw->CurPage);\r
+ EhciDebugPrint (Level, "IOC : %d\n", QhHw->IOC);\r
+ EhciDebugPrint (Level, "Total Bytes : %d\n", QhHw->TotalBytes);\r
+ EhciDebugPrint (Level, "Data Toggle : %d\n", QhHw->DataToggle);\r
+\r
+ for (Index = 0; Index < 5; Index++) {\r
+ EhciDebugPrint (Level, "Page[%d] : 0x%x\n", Index, QhHw->Page[Index]);\r
+ }\r
+\r
+ EhciDebugPrint (Level, "\n");\r
+\r
+ EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
+ EhcDumpQtd (Qtd, NULL);\r
+\r
+ if (DumpBuf && (Qtd->DataLen != 0)) {\r
+ EhcDumpBuf (Qtd->Data, Qtd->DataLen);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Dump the buffer in the form of hex\r
+\r
+ @param Buf The buffer to dump\r
+ @param Len The length of buffer\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpBuf (\r
+ IN UINT8 *Buf,\r
+ IN UINTN Len\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < Len; Index++) {\r
+ if (Index % 16 == 0) {\r
+ EhciDebugPrint (EHC_DEBUG_BUF, "\n");\r
+ }\r
+\r
+ EhciDebugPrint (EHC_DEBUG_BUF, "%02x ", Buf[Index]);\r
+ }\r
+\r
+ EhciDebugPrint (EHC_DEBUG_BUF, "\n");\r
+}\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciDebug.h\r
+\r
+Abstract:\r
+\r
+ This file contains the definination for host controller debug support routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_DEBUG_H_\r
+#define _EFI_EHCI_DEBUG_H_\r
+\r
+\r
+enum {\r
+ USB_DEBUG_FORCE_OUTPUT = (UINTN)(1 << 0),\r
+\r
+ EHC_DEBUG_QH = (UINTN)(1 << 8),\r
+ EHC_DEBUG_QTD = (UINTN)(1 << 9),\r
+ EHC_DEBUG_BUF = (UINTN)(1 << 10),\r
+};\r
+\r
+\r
+/**\r
+ EHCI's debug output function. It determines whether\r
+ to output by the mask and level\r
+\r
+ @param Level The output level\r
+ @param Format The format parameters to the print\r
+ @param ... The variable length parameters after format\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhciDebugPrint (\r
+ IN UINTN Level,\r
+ IN CHAR8 *Format,\r
+ ...\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ EHCI's debug output function. It determines whether\r
+ to output by the mask and level\r
+\r
+ @param Format The format parameters to the print\r
+ @param ... The variable length parameters after format\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcDebug (\r
+ IN CHAR8 *Format,\r
+ ...\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ EHCI's error output function. It determines whether\r
+ to output by the mask and level\r
+\r
+ @param Format The format parameters to the print\r
+ @param ... The variable length parameters after format\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcError (\r
+ IN CHAR8 *Format,\r
+ ...\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Dump the fields of a QTD\r
+\r
+ @param Qtd The QTD to dump\r
+ @param Msg The message to print before the dump\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpQtd (\r
+ IN EHC_QTD *Qtd,\r
+ IN UINT8 *Msg\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Dump the queue head\r
+\r
+ @param Qh The queue head to dump\r
+ @param Msg The message to print before the dump\r
+ @param DumpBuf Whether to dump the memory buffer of the associated QTD\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpQh (\r
+ IN EHC_QH *Qh,\r
+ IN UINT8 *Msg,\r
+ IN BOOLEAN DumpBuf\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Dump the buffer in the form of hex\r
+\r
+ @param Buf The buffer to dump\r
+ @param Len The length of buffer\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcDumpBuf (\r
+ IN UINT8 *Buf,\r
+ IN UINTN Len\r
+ )\r
+;\r
+\r
+#ifdef EFI_DEBUG\r
+ #define EHC_DEBUG(arg) EhcDebug arg\r
+ #define EHC_ERROR(arg) EhcError arg\r
+ #define EHC_DUMP_QH(arg) EhcDumpQh arg\r
+#else\r
+ #define EHC_DEBUG(arg)\r
+ #define EHC_ERROR(arg)\r
+ #define EHC_DUMP_QH(arg)\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciReg.c\r
+\r
+Abstract:\r
+\r
+ The EHCI register operation routines.\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+\r
+#include "Ehci.h"\r
+\r
+\r
+/**\r
+ Read EHCI capability register\r
+\r
+ @param Ehc The Ehc device\r
+ @param Offset Capability register address\r
+\r
+ @return The register content read\r
+\r
+**/\r
+UINT32\r
+EhcReadCapRegister (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+ EFI_STATUS Status;\r
+\r
+ Status = Ehc->PciIo->Mem.Read (\r
+ Ehc->PciIo,\r
+ EfiPciIoWidthUint32,\r
+ EHC_BAR_INDEX,\r
+ (UINT64) Offset,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcReadCapRegister: Pci Io read error - %r at %d\n", Status, Offset));\r
+ Data = 0xFFFF;\r
+ }\r
+\r
+ return Data;\r
+}\r
+\r
+\r
+/**\r
+ Read Ehc Operation register\r
+\r
+ @param Ehc The EHCI device\r
+ @param Offset The operation register offset\r
+\r
+ @return The register content read\r
+\r
+**/\r
+UINT32\r
+EhcReadOpReg (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Ehc->CapLen != 0);\r
+\r
+ Status = Ehc->PciIo->Mem.Read (\r
+ Ehc->PciIo,\r
+ EfiPciIoWidthUint32,\r
+ EHC_BAR_INDEX,\r
+ (UINT64) (Ehc->CapLen + Offset),\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcReadOpReg: Pci Io Read error - %r at %d\n", Status, Offset));\r
+ Data = 0xFFFF;\r
+ }\r
+\r
+ return Data;\r
+}\r
+\r
+\r
+/**\r
+ Write the data to the EHCI operation register\r
+\r
+ @param Ehc The EHCI device\r
+ @param Offset EHCI operation register offset\r
+ @param Data The data to write\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcWriteOpReg (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Ehc->CapLen != 0);\r
+\r
+ Status = Ehc->PciIo->Mem.Write (\r
+ Ehc->PciIo,\r
+ EfiPciIoWidthUint32,\r
+ EHC_BAR_INDEX,\r
+ (UINT64) (Ehc->CapLen + Offset),\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcWriteOpReg: Pci Io Write error: %r at %d\n", Status, Offset));\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Set one bit of the operational register while keeping other bits\r
+\r
+ @param Ehc The EHCI device\r
+ @param Offset The offset of the operational register\r
+ @param Bit The bit mask of the register to set\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcSetOpRegBit (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = EhcReadOpReg (Ehc, Offset);\r
+ Data |= Bit;\r
+ EhcWriteOpReg (Ehc, Offset, Data);\r
+}\r
+\r
+\r
+/**\r
+ Clear one bit of the operational register while keeping other bits\r
+\r
+ @param Ehc The EHCI device\r
+ @param Offset The offset of the operational register\r
+ @param Bit The bit mask of the register to clear\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcClearOpRegBit (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = EhcReadOpReg (Ehc, Offset);\r
+ Data &= ~Bit;\r
+ EhcWriteOpReg (Ehc, Offset, Data);\r
+}\r
+\r
+\r
+/**\r
+ Wait the operation register's bit as specified by Bit\r
+ to become set (or clear)\r
+\r
+ @param Ehc The EHCI device\r
+ @param Offset The offset of the operation register\r
+ @param Bit The bit of the register to wait for\r
+ @param WaitToSet Wait the bit to set or clear\r
+ @param Timeout The time to wait before abort (in millisecond)\r
+\r
+ @retval EFI_SUCCESS The bit successfully changed by host controller\r
+ @retval EFI_TIMEOUT The time out occurred\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcWaitOpRegBit (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit,\r
+ IN BOOLEAN WaitToSet,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < Timeout / EHC_SYNC_POLL_TIME + 1; Index++) {\r
+ if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ gBS->Stall (EHC_SYNC_POLL_TIME);\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+\r
+/**\r
+ Add support for UEFI Over Legacy (UoL) feature, stop\r
+ the legacy USB SMI support\r
+\r
+ @param Ehc The EHCI device.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcClearLegacySupport (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ UINT32 ExtendCap;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 Value;\r
+ UINT32 TimeOut;\r
+\r
+ EHC_DEBUG (("EhcClearLegacySupport: called to clear legacy support\n"));\r
+\r
+ PciIo = Ehc->PciIo;\r
+ ExtendCap = (Ehc->HcCapParams >> 8) & 0xFF;\r
+\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);\r
+\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+ Value |= (0x1 << 24);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+\r
+ TimeOut = 40;\r
+ while (TimeOut--) {\r
+ gBS->Stall (500);\r
+\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+\r
+ if ((Value & 0x01010000) == 0x01000000) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value);\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Set door bell and wait it to be ACKed by host controller.\r
+ This function is used to synchronize with the hardware.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout The time to wait before abort (in millisecond, ms)\r
+\r
+ @return EFI_SUCCESS : Synchronized with the hardware\r
+ @return EFI_TIMEOUT : Time out happened while waiting door bell to set\r
+\r
+**/\r
+EFI_STATUS\r
+EhcSetAndWaitDoorBell (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Data;\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);\r
+\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);\r
+\r
+ //\r
+ // ACK the IAA bit in USBSTS register. Make sure other\r
+ // interrupt bits are not ACKed. These bits are WC (Write Clean).\r
+ //\r
+ Data = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);\r
+ Data &= ~USBSTS_INTACK_MASK;\r
+ Data |= USBSTS_IAA;\r
+\r
+ EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Clear all the interrutp status bits, these bits\r
+ are Write-Clean\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcAckAllInterrupt (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);\r
+}\r
+\r
+\r
+/**\r
+ Enable the periodic schedule then wait EHC to\r
+ actually enable it.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout The time to wait before abort (in millisecond, ms)\r
+\r
+ @return EFI_SUCCESS : The periodical schedule is enabled\r
+ @return EFI_TIMEOUT : Time out happened while enabling periodic schedule\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcEnablePeriodSchd (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);\r
+\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Disable periodic schedule\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort (in millisecond, ms)\r
+\r
+ @return EFI_SUCCESS : Periodic schedule is disabled.\r
+ @return EFI_DEVICE_ERROR : Fail to disable periodic schedule\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcDisablePeriodSchd (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);\r
+\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, FALSE, Timeout);\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Enable asynchrounous schedule\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort\r
+\r
+ @return EFI_SUCCESS : The EHCI asynchronous schedule is enabled\r
+ @return Others : Failed to enable the asynchronous scheudle\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcEnableAsyncSchd (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);\r
+\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Disable asynchrounous schedule\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort (in millisecond, ms)\r
+\r
+ @return EFI_SUCCESS : The asynchronous schedule is disabled\r
+ @return Others : Failed to disable the asynchronous schedule\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcDisableAsyncSchd (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);\r
+\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, FALSE, Timeout);\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Whether Ehc is halted\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return TRUE : The controller is halted\r
+ @return FALSE : It isn't halted\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsHalt (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);\r
+}\r
+\r
+\r
+/**\r
+ Whether system error occurred\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return TRUE : System error happened\r
+ @return FALSE : No system error\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsSysError (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);\r
+}\r
+\r
+\r
+/**\r
+ Reset the host controller\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort (in millisecond, ms)\r
+\r
+ @return EFI_SUCCESS : The host controller is reset\r
+ @return Others : Failed to reset the host\r
+\r
+**/\r
+EFI_STATUS\r
+EhcResetHC (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Host can only be reset when it is halt. If not so, halt it\r
+ //\r
+ if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
+ Status = EhcHaltHC (Ehc, Timeout);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Halt the host controller\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort\r
+\r
+ @return EFI_SUCCESS : The EHCI is halt\r
+ @return EFI_TIMEOUT : Failed to halt the controller before Timeout\r
+\r
+**/\r
+EFI_STATUS\r
+EhcHaltHC (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Set the EHCI to run\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort\r
+\r
+ @return EFI_SUCCESS : The EHCI is running\r
+ @return Others : Failed to set the EHCI to run\r
+\r
+**/\r
+EFI_STATUS\r
+EhcRunHC (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Initialize the HC hardware.\r
+ EHCI spec lists the five things to do to initialize the hardware\r
+ 1. Program CTRLDSSEGMENT\r
+ 2. Set USBINTR to enable interrupts\r
+ 3. Set periodic list base\r
+ 4. Set USBCMD, interrupt threshold, frame list size etc\r
+ 5. Write 1 to CONFIGFLAG to route all ports to EHCI\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return EFI_SUCCESS : The EHCI has come out of halt state\r
+ @return EFI_TIMEOUT : Time out happened\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitHC (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (EhcIsHalt (Ehc));\r
+\r
+ //\r
+ // Allocate the periodic frame and associated memeory\r
+ // management facilities if not already done.\r
+ //\r
+ if (Ehc->PeriodFrame != NULL) {\r
+ EhcFreeSched (Ehc);\r
+ }\r
+\r
+ Status = EhcInitSched (Ehc);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr\r
+ //\r
+ EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);\r
+\r
+ //\r
+ // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling\r
+ //\r
+ EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);\r
+\r
+ //\r
+ // 3. Program periodic frame list, already done in EhcInitSched\r
+ // 4. Start the Host Controller\r
+ //\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+\r
+ //\r
+ // 5. Set all ports routing to EHC\r
+ //\r
+ EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);\r
+\r
+ Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIME);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcInitHC: failed to enable period schedule\n"));\r
+ return Status;\r
+ }\r
+\r
+ Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIME);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcInitHC: failed to enable async schedule\n"));\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciReg.h\r
+\r
+Abstract:\r
+\r
+ This file contains the definination for host controller register operation routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_REG_H_\r
+#define _EFI_EHCI_REG_H_\r
+\r
+\r
+enum {\r
+ //\r
+ // Capability register offset\r
+ //\r
+ EHC_CAPLENGTH_OFFSET = 0, // Capability register length offset\r
+ EHC_HCSPARAMS_OFFSET = 0x04, // Structural Parameters 04-07h\r
+ EHC_HCCPARAMS_OFFSET = 0x08, // Capability parameters offset\r
+\r
+ //\r
+ // Capability register bit definition\r
+ //\r
+ HCSP_NPORTS = 0x0F, // Number of root hub port\r
+ HCCP_64BIT = 0x01, // 64-bit addressing capability\r
+\r
+ //\r
+ // Operational register offset\r
+ //\r
+ EHC_USBCMD_OFFSET = 0x0, // USB command register offset\r
+ EHC_USBSTS_OFFSET = 0x04, // Statue register offset\r
+ EHC_USBINTR_OFFSET = 0x08, // USB interrutp offset\r
+ EHC_FRINDEX_OFFSET = 0x0C, // Frame index offset\r
+ EHC_CTRLDSSEG_OFFSET = 0x10, // Control data structure segment offset\r
+ EHC_FRAME_BASE_OFFSET = 0x14, // Frame list base address offset\r
+ EHC_ASYNC_HEAD_OFFSET = 0x18, // Next asynchronous list address offset\r
+ EHC_CONFIG_FLAG_OFFSET = 0x40, // Configure flag register offset\r
+ EHC_PORT_STAT_OFFSET = 0x44, // Port status/control offset\r
+\r
+ EHC_FRAME_LEN = 1024,\r
+\r
+ //\r
+ // Register bit definition\r
+ //\r
+ CONFIGFLAG_ROUTE_EHC = 0x01, // Route port to EHC\r
+\r
+ USBCMD_RUN = 0x01, // Run/stop\r
+ USBCMD_RESET = 0x02, // Start the host controller reset\r
+ USBCMD_ENABLE_PERIOD = 0x10, // Enable periodic schedule\r
+ USBCMD_ENABLE_ASYNC = 0x20, // Enable asynchronous schedule\r
+ USBCMD_IAAD = 0x40, // Interrupt on async advance doorbell\r
+\r
+ USBSTS_IAA = 0x20, // Interrupt on async advance\r
+ USBSTS_PERIOD_ENABLED = 0x4000, // Periodic schedule status\r
+ USBSTS_ASYNC_ENABLED = 0x8000, // Asynchronous schedule status\r
+ USBSTS_HALT = 0x1000, // Host controller halted\r
+ USBSTS_SYS_ERROR = 0x10, // Host system error\r
+ USBSTS_INTACK_MASK = 0x003F, // Mask for the interrupt ACK, the WC\r
+ // (write clean) bits in USBSTS register\r
+\r
+ PORTSC_CONN = 0x01, // Current Connect Status\r
+ PORTSC_CONN_CHANGE = 0x02, // Connect Status Change\r
+ PORTSC_ENABLED = 0x04, // Port Enable / Disable\r
+ PORTSC_ENABLE_CHANGE = 0x08, // Port Enable / Disable Change\r
+ PORTSC_OVERCUR = 0x10, // Over current Active\r
+ PORTSC_OVERCUR_CHANGE = 0x20, // Over current Change\r
+ PORSTSC_RESUME = 0x40, // Force Port Resume\r
+ PORTSC_SUSPEND = 0x80, // Port Suspend State\r
+ PORTSC_RESET = 0x100, // Port Reset\r
+ PORTSC_LINESTATE_K = 0x400, // Line Status K-state\r
+ PORTSC_LINESTATE_J = 0x800, // Line Status J-state\r
+ PORTSC_POWER = 0x1000, // Port Power\r
+ PORTSC_OWNER = 0x2000, // Port Owner\r
+ PORTSC_CHANGE_MASK = 0x2A, // Mask of the port change bits,\r
+ // they are WC (write clean)\r
+ //\r
+ // PCI Configuration Registers\r
+ //\r
+ EHC_PCI_CLASSC = 0x09,\r
+ EHC_PCI_CLASSC_PI = 0x20,\r
+ EHC_BAR_INDEX = 0, /* how many bytes away from USB_BASE to 0x10 */\r
+};\r
+\r
+#define EHC_LINK_TERMINATED(Link) (((Link) & 0x01) != 0)\r
+\r
+#define EHC_ADDR(High, QhHw32) \\r
+ ((VOID *) (UINTN) (LShiftU64 ((High), 32) | ((QhHw32) & 0xFFFFFFF0)))\r
+\r
+#define EHCI_IS_DATAIN(EndpointAddr) EHC_BIT_IS_SET((EndpointAddr), 0x80)\r
+\r
+//\r
+// Structure to map the hardware port states to the\r
+// UEFI's port states.\r
+//\r
+typedef struct {\r
+ UINT16 HwState;\r
+ UINT16 UefiState;\r
+} USB_PORT_STATE_MAP;\r
+\r
+//\r
+// Ehci Data and Ctrl Structures\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+ UINT8 PI;\r
+ UINT8 SubClassCode;\r
+ UINT8 BaseCode;\r
+} USB_CLASSC;\r
+#pragma pack()\r
+\r
+\r
+UINT32\r
+EhcReadCapRegister (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Read EHCI capability register\r
+\r
+Arguments:\r
+\r
+ Ehc - The Ehc device\r
+ Offset - Capability register address\r
+\r
+Returns:\r
+\r
+ The register content read\r
+\r
+--*/\r
+;\r
+\r
+\r
+/**\r
+ Read Ehc Operation register\r
+\r
+ @param Ehc The EHCI device\r
+ @param Offset The operation register offset\r
+\r
+ @return The register content read\r
+\r
+**/\r
+UINT32\r
+EhcReadOpReg (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Write the data to the EHCI operation register\r
+\r
+ @param Ehc The EHCI device\r
+ @param Offset EHCI operation register offset\r
+ @param Data The data to write\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcWriteOpReg (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Add support for UEFI Over Legacy (UoL) feature, stop\r
+ the legacy USB SMI support\r
+\r
+ @param Ehc The EHCI device.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcClearLegacySupport (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Set door bell and wait it to be ACKed by host controller.\r
+ This function is used to synchronize with the hardware.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout The time to wait before abort (in millisecond, ms)\r
+\r
+ @return EFI_SUCCESS : Synchronized with the hardware\r
+ @return EFI_TIMEOUT : Time out happened while waiting door bell to set\r
+\r
+**/\r
+EFI_STATUS\r
+EhcSetAndWaitDoorBell (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Clear all the interrutp status bits, these bits\r
+ are Write-Clean\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcAckAllInterrupt (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Whether Ehc is halted\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return TRUE : The controller is halted\r
+ @return FALSE : It isn't halted\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsHalt (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Whether system error occurred\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return TRUE : System error happened\r
+ @return FALSE : No system error\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsSysError (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Reset the host controller\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort (in millisecond, ms)\r
+\r
+ @return EFI_SUCCESS : The host controller is reset\r
+ @return Others : Failed to reset the host\r
+\r
+**/\r
+EFI_STATUS\r
+EhcResetHC (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Halt the host controller\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort\r
+\r
+ @return EFI_SUCCESS : The EHCI is halt\r
+ @return EFI_TIMEOUT : Failed to halt the controller before Timeout\r
+\r
+**/\r
+EFI_STATUS\r
+EhcHaltHC (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Set the EHCI to run\r
+\r
+ @param Ehc The EHCI device\r
+ @param Timeout Time to wait before abort\r
+\r
+ @return EFI_SUCCESS : The EHCI is running\r
+ @return Others : Failed to set the EHCI to run\r
+\r
+**/\r
+EFI_STATUS\r
+EhcRunHC (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Initialize the HC hardware.\r
+ EHCI spec lists the five things to do to initialize the hardware\r
+ 1. Program CTRLDSSEGMENT\r
+ 2. Set USBINTR to enable interrupts\r
+ 3. Set periodic list base\r
+ 4. Set USBCMD, interrupt threshold, frame list size etc\r
+ 5. Write 1 to CONFIGFLAG to route all ports to EHCI\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return EFI_SUCCESS : The EHCI has come out of halt state\r
+ @return EFI_TIMEOUT : Time out happened\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitHC (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciSched.c\r
+\r
+Abstract:\r
+\r
+ EHCI transfer scheduling routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#include "Ehci.h"\r
+\r
+\r
+/**\r
+ Create helper QTD/QH for the EHCI device\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for helper QTD/QH\r
+ @retval EFI_SUCCESS Helper QH/QTD are created\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcCreateHelpQ (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ USB_ENDPOINT Ep;\r
+ EHC_QH *Qh;\r
+ QH_HW *QhHw;\r
+ EHC_QTD *Qtd;\r
+\r
+ //\r
+ // Create an inactive Qtd to terminate the short packet read.\r
+ //\r
+ Qtd = EhcCreateQtd (Ehc, NULL, 0, QTD_PID_INPUT, 0, 64);\r
+\r
+ if (Qtd == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Qtd->QtdHw.Status = QTD_STAT_HALTED;\r
+ Ehc->ShortReadStop = Qtd;\r
+\r
+ //\r
+ // Create a QH to act as the EHC reclamation header.\r
+ // Set the header to loopback to itself.\r
+ //\r
+ Ep.DevAddr = 0;\r
+ Ep.EpAddr = 1;\r
+ Ep.Direction = EfiUsbDataIn;\r
+ Ep.DevSpeed = EFI_USB_SPEED_HIGH;\r
+ Ep.MaxPacket = 64;\r
+ Ep.HubAddr = 0;\r
+ Ep.HubPort = 0;\r
+ Ep.Toggle = 0;\r
+ Ep.Type = EHC_BULK_TRANSFER;\r
+ Ep.PollRate = 1;\r
+\r
+ Qh = EhcCreateQh (Ehc, &Ep);\r
+\r
+ if (Qh == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ QhHw = &Qh->QhHw;\r
+ QhHw->HorizonLink = QH_LINK (QhHw, EHC_TYPE_QH, FALSE);\r
+ QhHw->Status = QTD_STAT_HALTED;\r
+ QhHw->ReclaimHead = 1;\r
+ Ehc->ReclaimHead = Qh;\r
+\r
+ //\r
+ // Create a dummy QH to act as the terminator for periodical schedule\r
+ //\r
+ Ep.EpAddr = 2;\r
+ Ep.Type = EHC_INT_TRANSFER_SYNC;\r
+\r
+ Qh = EhcCreateQh (Ehc, &Ep);\r
+\r
+ if (Qh == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Qh->QhHw.Status = QTD_STAT_HALTED;\r
+ Ehc->PeriodOne = Qh;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Initialize the schedule data structure such as frame list\r
+\r
+ @param Ehc The EHCI device to init schedule data for\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data\r
+ @retval EFI_SUCCESS The schedule data is initialized\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitSched (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ VOID *Buf;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ VOID *Map;\r
+ UINTN Pages;\r
+ UINTN Bytes;\r
+ UINTN Index;\r
+ UINT32 *Desc;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // First initialize the periodical schedule data:\r
+ // 1. Allocate and map the memory for the frame list\r
+ // 2. Create the help QTD/QH\r
+ // 3. Initialize the frame entries\r
+ // 4. Set the frame list register\r
+ //\r
+ PciIo = Ehc->PciIo;\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
+ return EFI_OUT_OF_RESOURCES;\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
+ PciIo->FreeBuffer (PciIo, Pages, Buf);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Ehc->PeriodFrameHost = Buf;\r
+ Ehc->PeriodFrame = (VOID *) ((UINTN) PhyAddr);\r
+ Ehc->PeriodFrameMap = Map;\r
+ Ehc->High32bitAddr = EHC_HIGH_32BIT (PhyAddr);\r
+\r
+ //\r
+ // Init memory pool management then create the helper\r
+ // QTD/QH. If failed, previously allocated resources\r
+ // will be freed by EhcFreeSched\r
+ //\r
+ Ehc->MemPool = UsbHcInitMemPool (\r
+ PciIo,\r
+ EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT),\r
+ Ehc->High32bitAddr\r
+ );\r
+\r
+ if (Ehc->MemPool == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = EhcCreateHelpQ (Ehc);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Initialize the frame list entries then set the registers\r
+ //\r
+ Desc = (UINT32 *) Ehc->PeriodFrame;\r
+\r
+ for (Index = 0; Index < EHC_FRAME_LEN; Index++) {\r
+ Desc[Index] = QH_LINK (Ehc->PeriodOne, EHC_TYPE_QH, FALSE);\r
+ }\r
+\r
+ EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (Ehc->PeriodFrame));\r
+\r
+ //\r
+ // Second initialize the asynchronous schedule:\r
+ // Only need to set the AsynListAddr register to\r
+ // the reclamation header\r
+ //\r
+ EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (Ehc->ReclaimHead));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Free the schedule data. It may be partially initialized.\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcFreeSched (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0);\r
+ EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0);\r
+\r
+ if (Ehc->PeriodOne != NULL) {\r
+ UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));\r
+ Ehc->PeriodOne = NULL;\r
+ }\r
+\r
+ if (Ehc->ReclaimHead != NULL) {\r
+ UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));\r
+ Ehc->ReclaimHead = NULL;\r
+ }\r
+\r
+ if (Ehc->ShortReadStop != NULL) {\r
+ UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));\r
+ Ehc->ShortReadStop = NULL;\r
+ }\r
+\r
+ if (Ehc->MemPool != NULL) {\r
+ UsbHcFreeMemPool (Ehc->MemPool);\r
+ Ehc->MemPool = NULL;\r
+ }\r
+\r
+ if (Ehc->PeriodFrame != NULL) {\r
+ PciIo = Ehc->PciIo;\r
+ ASSERT (PciIo != NULL);\r
+\r
+ PciIo->Unmap (PciIo, Ehc->PeriodFrameMap);\r
+\r
+ PciIo->FreeBuffer (\r
+ PciIo,\r
+ EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE),\r
+ Ehc->PeriodFrameHost\r
+ );\r
+\r
+ Ehc->PeriodFrame = NULL;\r
+ }\r
+}\r
+\r
+\r
+\r
+/**\r
+ Link the queue head to the asynchronous schedule list.\r
+ UEFI only supports one CTRL/BULK transfer at a time\r
+ due to its interfaces. This simplifies the AsynList\r
+ management: A reclamation header is always linked to\r
+ the AsyncListAddr, the only active QH is appended to it.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qh The queue head to link\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToAsync (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN EHC_QH *Qh\r
+ )\r
+{\r
+ EHC_QH *Head;\r
+\r
+ //\r
+ // Append the queue head after the reclaim header, then\r
+ // fix the hardware visiable parts (EHCI R1.0 page 72).\r
+ // ReclaimHead is always linked to the EHCI's AsynListAddr.\r
+ //\r
+ Head = Ehc->ReclaimHead;\r
+\r
+ Qh->NextQh = Head->NextQh;\r
+ Head->NextQh = Qh;\r
+\r
+ Qh->QhHw.HorizonLink = QH_LINK (Head, EHC_TYPE_QH, FALSE);;\r
+ Head->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+}\r
+\r
+\r
+/**\r
+ Unlink a queue head from the asynchronous schedule list.\r
+ Need to synchronize with hardware\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qh The queue head to unlink\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromAsync (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN EHC_QH *Qh\r
+ )\r
+{\r
+ EHC_QH *Head;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Ehc->ReclaimHead->NextQh == Qh);\r
+\r
+ //\r
+ // Remove the QH from reclamation head, then update the hardware\r
+ // visiable part: Only need to loopback the ReclaimHead. The Qh\r
+ // is pointing to ReclaimHead (which is staill in the list).\r
+ //\r
+ Head = Ehc->ReclaimHead;\r
+\r
+ Head->NextQh = Qh->NextQh;\r
+ Qh->NextQh = NULL;\r
+\r
+ Head->QhHw.HorizonLink = QH_LINK (Head, EHC_TYPE_QH, FALSE);\r
+\r
+ //\r
+ // Set and wait the door bell to synchronize with the hardware\r
+ //\r
+ Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIME);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EHC_ERROR (("EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n"));\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Link a queue head for interrupt transfer to the periodic\r
+ schedule frame list. This code is very much the same as\r
+ that in UHCI.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qh The queue head to link\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToPeriod (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN EHC_QH *Qh\r
+ )\r
+{\r
+ UINT32 *Frames;\r
+ UINTN Index;\r
+ EHC_QH *Prev;\r
+ EHC_QH *Next;\r
+\r
+ Frames = Ehc->PeriodFrame;\r
+\r
+ for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {\r
+ //\r
+ // First QH can't be NULL because we always keep PeriodOne\r
+ // heads on the frame list\r
+ //\r
+ ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));\r
+ Next = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);\r
+ Prev = NULL;\r
+\r
+ //\r
+ // Now, insert the queue head (Qh) into this frame:\r
+ // 1. Find a queue head with the same poll interval, just insert\r
+ // Qh after this queue head, then we are done.\r
+ //\r
+ // 2. Find the position to insert the queue head into:\r
+ // Previous head's interval is bigger than Qh's\r
+ // Next head's interval is less than Qh's\r
+ // Then, insert the Qh between then\r
+ //\r
+ while (Next->Interval > Qh->Interval) {\r
+ Prev = Next;\r
+ Next = Next->NextQh;\r
+ }\r
+\r
+ ASSERT (Next != NULL);\r
+\r
+ //\r
+ // The entry may have been linked into the frame by early insertation.\r
+ // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh\r
+ // with Qh.Interval == 8 on the frame. If so, we are done with this frame.\r
+ // It isn't necessary to compare all the QH with the same interval to\r
+ // Qh. This is because if there is other QH with the same interval, Qh\r
+ // should has been inserted after that at Frames[0] and at Frames[0] it is\r
+ // impossible for (Next == Qh)\r
+ //\r
+ if (Next == Qh) {\r
+ continue;\r
+ }\r
+\r
+ if (Next->Interval == Qh->Interval) {\r
+ //\r
+ // If there is a QH with the same interval, it locates at\r
+ // Frames[0], and we can simply insert it after this QH. We\r
+ // are all done.\r
+ //\r
+ ASSERT ((Index == 0) && (Qh->NextQh == NULL));\r
+\r
+ Prev = Next;\r
+ Next = Next->NextQh;\r
+\r
+ Qh->NextQh = Next;\r
+ Prev->NextQh = Qh;\r
+\r
+ Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink;\r
+ Prev->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+ break;\r
+ }\r
+\r
+ //\r
+ // OK, find the right position, insert it in. If Qh's next\r
+ // link has already been set, it is in position. This is\r
+ // guarranted by 2^n polling interval.\r
+ //\r
+ if (Qh->NextQh == NULL) {\r
+ Qh->NextQh = Next;\r
+ Qh->QhHw.HorizonLink = QH_LINK (Next, EHC_TYPE_QH, FALSE);\r
+ }\r
+\r
+ if (Prev == NULL) {\r
+ Frames[Index] = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+ } else {\r
+ Prev->NextQh = Qh;\r
+ Prev->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Unlink an interrupt queue head from the periodic\r
+ schedule frame list\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qh The queue head to unlink\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromPeriod (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN EHC_QH *Qh\r
+ )\r
+{\r
+ UINT32 *Frames;\r
+ UINTN Index;\r
+ EHC_QH *Prev;\r
+ EHC_QH *This;\r
+\r
+ Frames = Ehc->PeriodFrame;\r
+\r
+ for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {\r
+ //\r
+ // Frame link can't be NULL because we always keep PeroidOne\r
+ // on the frame list\r
+ //\r
+ ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));\r
+ This = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);\r
+ Prev = NULL;\r
+\r
+ //\r
+ // Walk through the frame's QH list to find the\r
+ // queue head to remove\r
+ //\r
+ while ((This != NULL) && (This != Qh)) {\r
+ Prev = This;\r
+ This = This->NextQh;\r
+ }\r
+\r
+ //\r
+ // Qh may have already been unlinked from this frame\r
+ // by early action. See the comments in EhcLinkQhToPeriod.\r
+ //\r
+ if (This == NULL) {\r
+ continue;\r
+ }\r
+\r
+ if (Prev == NULL) {\r
+ //\r
+ // Qh is the first entry in the frame\r
+ //\r
+ Frames[Index] = Qh->QhHw.HorizonLink;\r
+ } else {\r
+ Prev->NextQh = Qh->NextQh;\r
+ Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+/**\r
+ Check the URB's execution result and update the URB's\r
+ result accordingly.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Urb The URB to check result\r
+\r
+ @return Whether the result of URB transfer is finialized.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EhcCheckUrbResult (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ EHC_QTD *Qtd;\r
+ QTD_HW *QtdHw;\r
+ UINT8 State;\r
+ BOOLEAN Finished;\r
+\r
+ ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));\r
+\r
+ Finished = TRUE;\r
+ Urb->Completed = 0;\r
+\r
+ Urb->Result = EFI_USB_NOERROR;\r
+\r
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+ Urb->Result |= EFI_USB_ERR_SYSTEM;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
+ QtdHw = &Qtd->QtdHw;\r
+ State = (UINT8) QtdHw->Status;\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {\r
+ //\r
+ // EHCI will halt the queue head when met some error.\r
+ // If it is halted, the result of URB is finialized.\r
+ //\r
+ if ((State & QTD_STAT_ERR_MASK) == 0) {\r
+ Urb->Result |= EFI_USB_ERR_STALL;\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {\r
+ Urb->Result |= EFI_USB_ERR_BABBLE;\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {\r
+ Urb->Result |= EFI_USB_ERR_BUFFER;\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) {\r
+ Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
+ }\r
+\r
+ Finished = TRUE;\r
+ goto ON_EXIT;\r
+\r
+ } else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {\r
+ //\r
+ // The QTD is still active, no need to check furthur.\r
+ //\r
+ Urb->Result |= EFI_USB_ERR_NOTEXECUTE;\r
+\r
+ Finished = FALSE;\r
+ goto ON_EXIT;\r
+\r
+ } else {\r
+ //\r
+ // This QTD is finished OK or met short packet read. Update the\r
+ // transfer length if it isn't a setup.\r
+ //\r
+ if (QtdHw->Pid != QTD_PID_SETUP) {\r
+ Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes;\r
+ }\r
+\r
+ if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {\r
+ EHC_DUMP_QH ((Urb->Qh, "Short packet read", FALSE));\r
+\r
+ //\r
+ // Short packet read condition. If it isn't a setup transfer,\r
+ // no need to check furthur: the queue head will halt at the\r
+ // ShortReadStop. If it is a setup transfer, need to check the\r
+ // Status Stage of the setup transfer to get the finial result\r
+ //\r
+ if (QtdHw->AltNext == QTD_LINK (Ehc->ShortReadStop, FALSE)) {\r
+ EHC_DEBUG (("EhcCheckUrbResult: Short packet read, break\n"));\r
+\r
+ Finished = TRUE;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EHC_DEBUG (("EhcCheckUrbResult: Short packet read, continue\n"));\r
+ }\r
+ }\r
+ }\r
+\r
+ON_EXIT:\r
+ //\r
+ // Return the data toggle set by EHCI hardware, bulk and interrupt\r
+ // transfer will use this to initialize the next transaction. For\r
+ // Control transfer, it always start a new data toggle sequence for\r
+ // new transfer.\r
+ //\r
+ // NOTICE: don't move DT update before the loop, otherwise there is\r
+ // a race condition that DT is wrong.\r
+ //\r
+ Urb->DataToggle = (UINT8) Urb->Qh->QhHw.DataToggle;\r
+\r
+ return Finished;\r
+}\r
+\r
+\r
+/**\r
+ Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Urb The URB to execute\r
+ @param TimeOut The time to wait before abort, in millisecond.\r
+\r
+ @return EFI_DEVICE_ERROR : The transfer failed due to transfer error\r
+ @return EFI_TIMEOUT : The transfer failed due to time out\r
+ @return EFI_SUCCESS : The transfer finished OK\r
+\r
+**/\r
+EFI_STATUS\r
+EhcExecTransfer (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN URB *Urb,\r
+ IN UINTN TimeOut\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN Loop;\r
+ BOOLEAN Finished;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Loop = (TimeOut * EHC_STALL_1_MILLISECOND / EHC_SYNC_POLL_TIME) + 1;\r
+ Finished = FALSE;\r
+\r
+ for (Index = 0; Index < Loop; Index++) {\r
+ Finished = EhcCheckUrbResult (Ehc, Urb);\r
+\r
+ if (Finished) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (EHC_SYNC_POLL_TIME);\r
+ }\r
+\r
+ if (!Finished) {\r
+ EHC_ERROR (("EhcExecTransfer: transfer not finished in %dms\n", TimeOut));\r
+ EHC_DUMP_QH ((Urb->Qh, NULL, FALSE));\r
+\r
+ Status = EFI_TIMEOUT;\r
+\r
+ } else if (Urb->Result != EFI_USB_NOERROR) {\r
+ EHC_ERROR (("EhcExecTransfer: transfer failed with %x\n", Urb->Result));\r
+ EHC_DUMP_QH ((Urb->Qh, NULL, FALSE));\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Delete a single asynchronous interrupt transfer for\r
+ the device and endpoint\r
+\r
+ @param Ehc The EHCI device\r
+ @param DevAddr The address of the target device\r
+ @param EpNum The endpoint of the target\r
+ @param DataToggle Return the next data toggle to use\r
+\r
+ @retval EFI_SUCCESS An asynchronous transfer is removed\r
+ @retval EFI_NOT_FOUND No transfer for the device is found\r
+\r
+**/\r
+EFI_STATUS\r
+EhciDelAsyncIntTransfer (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpNum,\r
+ OUT UINT8 *DataToggle\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *Next;\r
+ URB *Urb;\r
+ EFI_USB_DATA_DIRECTION Direction;\r
+\r
+ Direction = ((EpNum & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+ EpNum &= 0x0F;\r
+\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+\r
+ if ((Urb->Ep.DevAddr == DevAddr) && (Urb->Ep.EpAddr == EpNum) &&\r
+ (Urb->Ep.Direction == Direction)) {\r
+ //\r
+ // Check the URB status to retrieve the next data toggle\r
+ // from the associated queue head.\r
+ //\r
+ EhcCheckUrbResult (Ehc, Urb);\r
+ *DataToggle = Urb->DataToggle;\r
+\r
+ EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
+ RemoveEntryList (&Urb->UrbList);\r
+\r
+ gBS->FreePool (Urb->Data);\r
+ EhcFreeUrb (Ehc, Urb);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Remove all the asynchronous interrutp transfers\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhciDelAllAsyncIntTransfers (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *Next;\r
+ URB *Urb;\r
+\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+\r
+ EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
+ RemoveEntryList (&Urb->UrbList);\r
+\r
+ gBS->FreePool (Urb->Data);\r
+ EhcFreeUrb (Ehc, Urb);\r
+ }\r
+}\r
+\r
+\r
+\r
+/**\r
+ Update the queue head for next round of asynchronous transfer\r
+\r
+ @param Urb The URB to update\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcUpdateAsyncRequest (\r
+ IN URB *Urb\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ EHC_QTD *FirstQtd;\r
+ QH_HW *QhHw;\r
+ EHC_QTD *Qtd;\r
+ QTD_HW *QtdHw;\r
+ UINTN Index;\r
+\r
+ Qtd = NULL;\r
+\r
+ if (Urb->Result == EFI_USB_NOERROR) {\r
+ FirstQtd = NULL;\r
+\r
+ EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
+\r
+ if (FirstQtd == NULL) {\r
+ FirstQtd = Qtd;\r
+ }\r
+\r
+ //\r
+ // Update the QTD for next round of transfer. Host control\r
+ // may change dt/Total Bytes to Transfer/C_Page/Cerr/Status/\r
+ // Current Offset. These fields need to be updated. DT isn't\r
+ // used by interrupt transfer. It uses DT in queue head.\r
+ // Current Offset is in Page[0], only need to reset Page[0]\r
+ // to initial data buffer.\r
+ //\r
+ QtdHw = &Qtd->QtdHw;\r
+ QtdHw->Status = QTD_STAT_ACTIVE;\r
+ QtdHw->ErrCnt = QTD_MAX_ERR;\r
+ QtdHw->CurPage = 0;\r
+ QtdHw->TotalBytes = (UINT32) Qtd->DataLen;\r
+ QtdHw->Page[0] = EHC_LOW_32BIT (Qtd->Data);\r
+ }\r
+\r
+ //\r
+ // Update QH for next round of transfer. Host control only\r
+ // touch the fields in transfer overlay area. Only need to\r
+ // zero out the overlay area and set NextQtd to the first\r
+ // QTD. DateToggle bit is left untouched.\r
+ //\r
+ QhHw = &Urb->Qh->QhHw;\r
+ QhHw->CurQtd = QTD_LINK (0, TRUE);\r
+ QhHw->AltQtd = 0;\r
+\r
+ QhHw->Status = 0;\r
+ QhHw->Pid = 0;\r
+ QhHw->ErrCnt = 0;\r
+ QhHw->CurPage = 0;\r
+ QhHw->IOC = 0;\r
+ QhHw->TotalBytes = 0;\r
+\r
+ for (Index = 0; Index < 5; Index++) {\r
+ QhHw->Page[Index] = 0;\r
+ QhHw->PageHigh[Index] = 0;\r
+ }\r
+\r
+ QhHw->NextQtd = QTD_LINK (FirstQtd, FALSE);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Interrupt transfer periodic check handler\r
+\r
+ @param Event Interrupt event\r
+ @param Context Pointer to USB2_HC_DEV\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcMoniteAsyncRequests (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ USB2_HC_DEV *Ehc;\r
+ EFI_TPL OldTpl;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *Next;\r
+ BOOLEAN Finished;\r
+ UINT8 *ProcBuf;\r
+ URB *Urb;\r
+\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ Ehc = (USB2_HC_DEV *) Context;\r
+\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+ Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+\r
+ //\r
+ // Check the result of URB execution. If it is still\r
+ // active, check the next one.\r
+ //\r
+ Finished = EhcCheckUrbResult (Ehc, Urb);\r
+\r
+ if (!Finished) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Allocate a buffer then copy the transferred data for user.\r
+ // If failed to allocate the buffer, update the URB for next\r
+ // round of transfer. Ignore the data of this round.\r
+ //\r
+ ProcBuf = NULL;\r
+\r
+ if (Urb->Result == EFI_USB_NOERROR) {\r
+ ASSERT (Urb->Completed <= Urb->DataLen);\r
+\r
+ ProcBuf = AllocatePool (Urb->Completed);\r
+\r
+ if (ProcBuf == NULL) {\r
+ EhcUpdateAsyncRequest (Urb);\r
+ continue;\r
+ }\r
+\r
+ CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
+ }\r
+\r
+ EhcUpdateAsyncRequest (Urb);\r
+\r
+ //\r
+ // Leave error recovery to its related device driver. A\r
+ // common case of the error recovery is to re-submit the\r
+ // interrupt transfer which is linked to the head of the\r
+ // list. This function scans from head to tail. So the\r
+ // re-submitted interrupt transfer's callback function\r
+ // will not be called again in this round. Don't touch this\r
+ // URB after the callback, it may have been removed by the\r
+ // callback.\r
+ //\r
+ if (Urb->Callback != NULL) {\r
+ //\r
+ // Restore the old TPL, USB bus maybe connect device in\r
+ // his callback. Some drivers may has a lower TPL restriction.\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+ (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
+ OldTpl = gBS->RaiseTPL (EHC_TPL);\r
+ }\r
+\r
+ if (ProcBuf != NULL) {\r
+ gBS->FreePool (ProcBuf);\r
+ }\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciSched.h\r
+\r
+Abstract:\r
+\r
+ This file contains the definination for host controller schedule routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_SCHED_H_\r
+#define _EFI_EHCI_SCHED_H_\r
+\r
+EFI_STATUS\r
+EhcInitSched (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize the schedule data structure such as frame list\r
+\r
+Arguments:\r
+\r
+ Ehc - The EHCI device to init schedule data for\r
+\r
+Returns:\r
+\r
+ EFI_OUT_OF_RESOURCES - Failed to allocate resource to init schedule data\r
+ EFI_SUCCESS - The schedule data is initialized\r
+\r
+--*/\r
+;\r
+\r
+\r
+\r
+/**\r
+ Free the schedule data. It may be partially initialized.\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcFreeSched (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Link the queue head to the asynchronous schedule list.\r
+ UEFI only supports one CTRL/BULK transfer at a time\r
+ due to its interfaces. This simplifies the AsynList\r
+ management: A reclamation header is always linked to\r
+ the AsyncListAddr, the only active QH is appended to it.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qh The queue head to link\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToAsync (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN EHC_QH *Qh\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Unlink a queue head from the asynchronous schedule list.\r
+ Need to synchronize with hardware\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qh The queue head to unlink\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromAsync (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN EHC_QH *Qh\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Link a queue head for interrupt transfer to the periodic\r
+ schedule frame list. This code is very much the same as\r
+ that in UHCI.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qh The queue head to link\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToPeriod (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN EHC_QH *Qh\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Unlink an interrupt queue head from the periodic\r
+ schedule frame list\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qh The queue head to unlink\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromPeriod (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN EHC_QH *Qh\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Execute the transfer by polling the URB. This is a synchronous operation.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Urb The URB to execute\r
+ @param TimeOut The time to wait before abort, in millisecond.\r
+\r
+ @return EFI_DEVICE_ERROR : The transfer failed due to transfer error\r
+ @return EFI_TIMEOUT : The transfer failed due to time out\r
+ @return EFI_SUCCESS : The transfer finished OK\r
+\r
+**/\r
+EFI_STATUS\r
+EhcExecTransfer (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN URB *Urb,\r
+ IN UINTN TimeOut\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Delete a single asynchronous interrupt transfer for\r
+ the device and endpoint\r
+\r
+ @param Ehc The EHCI device\r
+ @param DevAddr The address of the target device\r
+ @param EpNum The endpoint of the target\r
+ @param DataToggle Return the next data toggle to use\r
+\r
+ @retval EFI_SUCCESS An asynchronous transfer is removed\r
+ @retval EFI_NOT_FOUND No transfer for the device is found\r
+\r
+**/\r
+EFI_STATUS\r
+EhciDelAsyncIntTransfer (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpNum,\r
+ OUT UINT8 *DataToggle\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Remove all the asynchronous interrutp transfers\r
+\r
+ @param Ehc The EHCI device\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhciDelAllAsyncIntTransfers (\r
+ IN USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Interrupt transfer periodic check handler\r
+\r
+ @param Event Interrupt event\r
+ @param Context Pointer to USB2_HC_DEV\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcMoniteAsyncRequests (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciUrb.c\r
+\r
+Abstract:\r
+\r
+ This file contains URB request, each request is warpped in a\r
+ URB (Usb Request Block)\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#include "Ehci.h"\r
+\r
+\r
+/**\r
+ Create a single QTD to hold the data\r
+\r
+ @param Ehc The EHCI device\r
+ @param Data Current data not associated with a QTD\r
+ @param DataLen The length of the data\r
+ @param PktId Packet ID to use in the QTD\r
+ @param Toggle Data toggle to use in the QTD\r
+ @param MaxPacket Maximu packet length of the endpoint\r
+\r
+ @return Created QTD or NULL if failed to create one\r
+\r
+**/\r
+EHC_QTD *\r
+EhcCreateQtd (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT8 *Data,\r
+ IN UINTN DataLen,\r
+ IN UINT8 PktId,\r
+ IN UINT8 Toggle,\r
+ IN UINTN MaxPacket\r
+ )\r
+{\r
+ EHC_QTD *Qtd;\r
+ QTD_HW *QtdHw;\r
+ UINTN Index;\r
+ UINTN Len;\r
+ UINTN ThisBufLen;\r
+\r
+ ASSERT (Ehc != NULL);\r
+\r
+ Qtd = UsbHcAllocateMem (Ehc->MemPool, sizeof (EHC_QTD));\r
+\r
+ if (Qtd == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Qtd->Signature = EHC_QTD_SIG;\r
+ Qtd->Data = Data;\r
+ Qtd->DataLen = 0;\r
+\r
+ InitializeListHead (&Qtd->QtdList);\r
+\r
+ QtdHw = &Qtd->QtdHw;\r
+ QtdHw->NextQtd = QTD_LINK (NULL, TRUE);\r
+ QtdHw->AltNext = QTD_LINK (NULL, TRUE);\r
+ QtdHw->Status = QTD_STAT_ACTIVE;\r
+ QtdHw->Pid = PktId;\r
+ QtdHw->ErrCnt = QTD_MAX_ERR;\r
+ QtdHw->IOC = 0;\r
+ QtdHw->TotalBytes = 0;\r
+ QtdHw->DataToggle = Toggle;\r
+\r
+ //\r
+ // Fill in the buffer points\r
+ //\r
+ if (Data != NULL) {\r
+ Len = 0;\r
+\r
+ for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {\r
+ //\r
+ // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to\r
+ // compute the offset and clear Reserved fields. This is already\r
+ // done in the data point.\r
+ //\r
+ QtdHw->Page[Index] = EHC_LOW_32BIT (Data);\r
+ QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (Data);\r
+\r
+ ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (Data) & QTD_BUF_MASK);\r
+\r
+ if (Len + ThisBufLen >= DataLen) {\r
+ Len = DataLen;\r
+ break;\r
+ }\r
+\r
+ Len += ThisBufLen;\r
+ Data += ThisBufLen;\r
+ }\r
+\r
+ //\r
+ // Need to fix the last pointer if the Qtd can't hold all the\r
+ // user's data to make sure that the length is in the unit of\r
+ // max packets. If it can hold all the data, there is no such\r
+ // need.\r
+ //\r
+ if (Len < DataLen) {\r
+ Len = Len - Len % MaxPacket;\r
+ }\r
+\r
+ QtdHw->TotalBytes = (UINT32) Len;\r
+ Qtd->DataLen = Len;\r
+ }\r
+\r
+ return Qtd;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Initialize the queue head for interrupt transfer,\r
+ that is, initialize the following three fields:\r
+ 1. SplitXState in the Status field\r
+ 2. Microframe S-mask\r
+ 3. Microframe C-mask\r
+\r
+ @param Ep The queue head's related endpoint\r
+ @param QhHw The queue head to initialize\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcInitIntQh (\r
+ IN USB_ENDPOINT *Ep,\r
+ IN QH_HW *QhHw\r
+ )\r
+{\r
+ //\r
+ // Because UEFI interface can't utilitize an endpoint with\r
+ // poll rate faster than 1ms, only need to set one bit in\r
+ // the queue head. simple. But it may be changed later. If\r
+ // sub-1ms interrupt is supported, need to update the S-Mask\r
+ // here\r
+ //\r
+ if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {\r
+ QhHw->SMask = QH_MICROFRAME_0;\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // For low/full speed device, the transfer must go through\r
+ // the split transaction. Need to update three fields\r
+ // 1. SplitXState in the status\r
+ // 2. Microframe S-Mask\r
+ // 3. Microframe C-Mask\r
+ // UEFI USB doesn't exercise admission control. It simplely\r
+ // schedule the high speed transactions in microframe 0, and\r
+ // full/low speed transactions at microframe 1. This also\r
+ // avoid the use of FSTN.\r
+ //\r
+ QhHw->SMask = QH_MICROFRAME_1;\r
+ QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Allocate and initialize a EHCI queue head\r
+\r
+ @param Ehci The EHCI device\r
+ @param Ep The endpoint to create queue head for\r
+\r
+ @return Created queue head or NULL if failed to create one\r
+\r
+**/\r
+EHC_QH *\r
+EhcCreateQh (\r
+ IN USB2_HC_DEV *Ehci,\r
+ IN USB_ENDPOINT *Ep\r
+ )\r
+{\r
+ EHC_QH *Qh;\r
+ QH_HW *QhHw;\r
+\r
+ Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));\r
+\r
+ if (Qh == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Qh->Signature = EHC_QH_SIG;\r
+ Qh->NextQh = NULL;\r
+ Qh->Interval = Ep->PollRate;\r
+\r
+ InitializeListHead (&Qh->Qtds);\r
+\r
+ QhHw = &Qh->QhHw;\r
+ QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);\r
+ QhHw->DeviceAddr = Ep->DevAddr;\r
+ QhHw->Inactive = 0;\r
+ QhHw->EpNum = Ep->EpAddr;\r
+ QhHw->EpSpeed = Ep->DevSpeed;\r
+ QhHw->DtCtrl = 0;\r
+ QhHw->ReclaimHead = 0;\r
+ QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;\r
+ QhHw->CtrlEp = 0;\r
+ QhHw->NakReload = QH_NAK_RELOAD;\r
+ QhHw->HubAddr = Ep->HubAddr;\r
+ QhHw->PortNum = Ep->HubPort;\r
+ QhHw->Multiplier = 1;\r
+ QhHw->DataToggle = Ep->Toggle;\r
+\r
+ if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r
+ QhHw->Status |= QTD_STAT_DO_SS;\r
+ }\r
+\r
+ switch (Ep->Type) {\r
+ case EHC_CTRL_TRANSFER:\r
+ //\r
+ // Special initialization for the control transfer:\r
+ // 1. Control transfer initialize data toggle from each QTD\r
+ // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.\r
+ //\r
+ QhHw->DtCtrl = 1;\r
+\r
+ if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r
+ QhHw->CtrlEp = 1;\r
+ }\r
+ break;\r
+\r
+ case EHC_INT_TRANSFER_ASYNC:\r
+ case EHC_INT_TRANSFER_SYNC:\r
+ //\r
+ // Special initialization for the interrupt transfer\r
+ // to set the S-Mask and C-Mask\r
+ //\r
+ QhHw->NakReload = 0;\r
+ EhcInitIntQh (Ep, QhHw);\r
+ break;\r
+\r
+ case EHC_BULK_TRANSFER:\r
+ if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {\r
+ QhHw->Status |= QTD_STAT_DO_PING;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ return Qh;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Convert the poll interval from application to that\r
+ be used by EHCI interface data structure. Only need\r
+ to get the max 2^n that is less than interval. UEFI\r
+ can't support high speed endpoint with a interval less\r
+ than 8 microframe because interval is specified in\r
+ the unit of ms (millisecond)\r
+\r
+ @param Interval The interval to convert\r
+\r
+ @return The converted interval\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+EhcConvertPollRate (\r
+ IN UINTN Interval\r
+ )\r
+{\r
+ UINTN BitCount;\r
+\r
+ if (Interval == 0) {\r
+ return 1;\r
+ }\r
+\r
+ //\r
+ // Find the index (1 based) of the highest non-zero bit\r
+ //\r
+ BitCount = 0;\r
+\r
+ while (Interval != 0) {\r
+ Interval >>= 1;\r
+ BitCount++;\r
+ }\r
+\r
+ return 1 << (BitCount - 1);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Free a list of QTDs\r
+\r
+ @param Ehc The EHCI device\r
+ @param Qtds The list head of the QTD\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EhcFreeQtds (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN LIST_ENTRY *Qtds\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *Next;\r
+ EHC_QTD *Qtd;\r
+\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
+\r
+ RemoveEntryList (&Qtd->QtdList);\r
+ UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Free an allocated URB. It is possible for it to be partially inited.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Urb The URB to free\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcFreeUrb (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ PciIo = Ehc->PciIo;\r
+\r
+ if (Urb->RequestPhy != NULL) {\r
+ PciIo->Unmap (PciIo, Urb->RequestMap);\r
+ }\r
+\r
+ if (Urb->DataMap != NULL) {\r
+ PciIo->Unmap (PciIo, Urb->DataMap);\r
+ }\r
+\r
+ if (Urb->Qh != NULL) {\r
+ //\r
+ // Ensure that this queue head has been unlinked from the\r
+ // schedule data structures. Free all the associated QTDs\r
+ //\r
+ EhcFreeQtds (Ehc, &Urb->Qh->Qtds);\r
+ UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));\r
+ }\r
+\r
+ gBS->FreePool (Urb);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Create a list of QTDs for the URB\r
+\r
+ @param Ehc The EHCI device\r
+ @param Urb The URB to create QTDs for\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD\r
+ @retval EFI_SUCCESS The QTDs are allocated for the URB\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EhcCreateQtds (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ USB_ENDPOINT *Ep;\r
+ EHC_QH *Qh;\r
+ EHC_QTD *Qtd;\r
+ EHC_QTD *StatusQtd;\r
+ EHC_QTD *NextQtd;\r
+ LIST_ENTRY *Entry;\r
+ UINT32 AlterNext;\r
+ UINT8 Toggle;\r
+ UINTN Len;\r
+ UINT8 Pid;\r
+\r
+ ASSERT ((Urb != NULL) && (Urb->Qh != NULL));\r
+\r
+ //\r
+ // EHCI follows the alternet next QTD pointer if it meets\r
+ // a short read and the AlterNext pointer is valid. UEFI\r
+ // EHCI driver should terminate the transfer except the\r
+ // control transfer.\r
+ //\r
+ Toggle = 0;\r
+ Qh = Urb->Qh;\r
+ Ep = &Urb->Ep;\r
+ StatusQtd = NULL;\r
+ AlterNext = QTD_LINK (NULL, TRUE);\r
+\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE);\r
+ }\r
+\r
+ //\r
+ // Build the Setup and status packets for control transfer\r
+ //\r
+ if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {\r
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
+ Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);\r
+\r
+ if (Qtd == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
+\r
+ //\r
+ // Create the status packet now. Set the AlterNext to it. So, when\r
+ // EHCI meets a short control read, it can resume at the status stage.\r
+ // Use the opposite direction of the data stage, or IN if there is\r
+ // no data stage.\r
+ //\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ Pid = QTD_PID_OUTPUT;\r
+ } else {\r
+ Pid = QTD_PID_INPUT;\r
+ }\r
+\r
+ StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket);\r
+\r
+ if (StatusQtd == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ AlterNext = QTD_LINK (StatusQtd, FALSE);\r
+ }\r
+\r
+ Toggle = 1;\r
+ }\r
+\r
+ //\r
+ // Build the data packets for all the transfers\r
+ //\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ Pid = QTD_PID_INPUT;\r
+ } else {\r
+ Pid = QTD_PID_OUTPUT;\r
+ }\r
+\r
+ Qtd = NULL;\r
+ Len = 0;\r
+\r
+ while (Len < Urb->DataLen) {\r
+ Qtd = EhcCreateQtd (\r
+ Ehc,\r
+ (UINT8 *) Urb->DataPhy + Len,\r
+ Urb->DataLen - Len,\r
+ Pid,\r
+ Toggle,\r
+ Ep->MaxPacket\r
+ );\r
+\r
+ if (Qtd == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Qtd->QtdHw.AltNext = AlterNext;\r
+ InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
+\r
+ //\r
+ // Switch the Toggle bit if odd number of packets are included in the QTD.\r
+ //\r
+ if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {\r
+ Toggle = 1 - Toggle;\r
+ }\r
+\r
+ Len += Qtd->DataLen;\r
+ }\r
+\r
+ //\r
+ // Insert the status packet for control transfer\r
+ //\r
+ if (Ep->Type == EHC_CTRL_TRANSFER) {\r
+ InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);\r
+ }\r
+\r
+ //\r
+ // OK, all the QTDs needed are created. Now, fix the NextQtd point\r
+ //\r
+ EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
+\r
+ //\r
+ // break if it is the last entry on the list\r
+ //\r
+ if (Entry->ForwardLink == &Qh->Qtds) {\r
+ break;\r
+ }\r
+\r
+ NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);\r
+ Qtd->QtdHw.NextQtd = QTD_LINK (NextQtd, FALSE);\r
+ }\r
+\r
+ //\r
+ // Link the QTDs to the queue head\r
+ //\r
+ NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);\r
+ Qh->QhHw.NextQtd = QTD_LINK (NextQtd, FALSE);\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ EhcFreeQtds (Ehc, &Qh->Qtds);\r
+ return EFI_OUT_OF_RESOURCES;\r
+}\r
+\r
+\r
+/**\r
+ Create a new URB and its associated QTD\r
+\r
+ @param Ehc The EHCI device\r
+ @param DevAddr The device address\r
+ @param EpAddr Endpoint addrress & its direction\r
+ @param DevSpeed The device speed\r
+ @param Toggle Initial data toggle to use\r
+ @param MaxPacket The max packet length of the endpoint\r
+ @param Hub The transaction translator to use\r
+ @param Type The transaction type\r
+ @param Request The standard USB request for control transfer\r
+ @param Data The user data to transfer\r
+ @param DataLen The length of data buffer\r
+ @param Callback The function to call when data is transferred\r
+ @param Context The context to the callback\r
+ @param Interval The interval for interrupt transfer\r
+\r
+ @return Created URB or NULL\r
+\r
+**/\r
+URB *\r
+EhcCreateUrb (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpAddr,\r
+ IN UINT8 DevSpeed,\r
+ IN UINT8 Toggle,\r
+ IN UINTN MaxPacket,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
+ IN UINTN Type,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN VOID *Data,\r
+ IN UINTN DataLen,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
+ IN VOID *Context,\r
+ IN UINTN Interval\r
+ )\r
+{\r
+ USB_ENDPOINT *Ep;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+ UINTN Len;\r
+ URB *Urb;\r
+ VOID *Map;\r
+\r
+ Urb = AllocateZeroPool (sizeof (URB));\r
+\r
+ if (Urb == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Urb->Signature = EHC_URB_SIG;\r
+ InitializeListHead (&Urb->UrbList);\r
+\r
+ Ep = &Urb->Ep;\r
+ Ep->DevAddr = DevAddr;\r
+ Ep->EpAddr = EpAddr & 0x0F;\r
+ Ep->Direction = ((EpAddr & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+ Ep->DevSpeed = DevSpeed;\r
+ Ep->MaxPacket = MaxPacket;\r
+\r
+ Ep->HubAddr = 0;\r
+ Ep->HubPort = 0;\r
+\r
+ if (DevSpeed != EFI_USB_SPEED_HIGH) {\r
+ ASSERT (Hub != NULL);\r
+\r
+ Ep->HubAddr = Hub->TranslatorHubAddress;\r
+ Ep->HubPort = Hub->TranslatorPortNumber;\r
+ }\r
+\r
+ Ep->Toggle = Toggle;\r
+ Ep->Type = Type;\r
+ Ep->PollRate = EhcConvertPollRate (Interval);\r
+\r
+ Urb->Request = Request;\r
+ Urb->Data = Data;\r
+ Urb->DataLen = DataLen;\r
+ Urb->Callback = Callback;\r
+ Urb->Context = Context;\r
+\r
+ PciIo = Ehc->PciIo;\r
+ Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);\r
+\r
+ if (Urb->Qh == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Map the request and user data\r
+ //\r
+ if (Request != NULL) {\r
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
+ MapOp = EfiPciIoOperationBusMasterRead;\r
+ Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);\r
+\r
+ if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);\r
+ Urb->RequestMap = Map;\r
+ }\r
+\r
+ if (Data != NULL) {\r
+ Len = DataLen;\r
+\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ MapOp = EfiPciIoOperationBusMasterWrite;\r
+ } else {\r
+ MapOp = EfiPciIoOperationBusMasterRead;\r
+ }\r
+\r
+ Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);\r
+\r
+ if (EFI_ERROR (Status) || (Len != DataLen)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
+ Urb->DataMap = Map;\r
+ }\r
+\r
+ Status = EhcCreateQtds (Ehc, Urb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ return Urb;\r
+\r
+ON_ERROR:\r
+ EhcFreeUrb (Ehc, Urb);\r
+ return NULL;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciUrb.h\r
+\r
+Abstract:\r
+\r
+ This file contains URB request, each request is warpped in a\r
+ URB (Usb Request Block)\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_URB_H_\r
+#define _EFI_EHCI_URB_H_\r
+\r
+\r
+typedef struct _EHC_QTD EHC_QTD;\r
+typedef struct _EHC_QH EHC_QH;\r
+typedef struct _URB URB;\r
+\r
+enum {\r
+ //\r
+ // Transfer types, used in URB to identify the transfer type\r
+ //\r
+ EHC_CTRL_TRANSFER = 0x01,\r
+ EHC_BULK_TRANSFER = 0x02,\r
+ EHC_INT_TRANSFER_SYNC = 0x04,\r
+ EHC_INT_TRANSFER_ASYNC = 0x08,\r
+\r
+ EHC_QTD_SIG = EFI_SIGNATURE_32 ('U', 'S', 'B', 'T'),\r
+ EHC_QH_SIG = EFI_SIGNATURE_32 ('U', 'S', 'B', 'H'),\r
+ EHC_URB_SIG = EFI_SIGNATURE_32 ('U', 'S', 'B', 'R'),\r
+\r
+ //\r
+ // Hardware related bit definitions\r
+ //\r
+ EHC_TYPE_ITD = 0x00,\r
+ EHC_TYPE_QH = 0x02,\r
+ EHC_TYPE_SITD = 0x04,\r
+ EHC_TYPE_FSTN = 0x06,\r
+\r
+ QH_NAK_RELOAD = 3,\r
+ QH_HSHBW_MULTI = 1,\r
+\r
+ QTD_MAX_ERR = 3,\r
+ QTD_PID_OUTPUT = 0x00,\r
+ QTD_PID_INPUT = 0x01,\r
+ QTD_PID_SETUP = 0x02,\r
+\r
+ QTD_STAT_DO_OUT = 0,\r
+ QTD_STAT_DO_SS = 0,\r
+ QTD_STAT_DO_PING = 0x01,\r
+ QTD_STAT_DO_CS = 0x02,\r
+ QTD_STAT_TRANS_ERR = 0x08,\r
+ QTD_STAT_BABBLE_ERR = 0x10,\r
+ QTD_STAT_BUFF_ERR = 0x20,\r
+ QTD_STAT_HALTED = 0x40,\r
+ QTD_STAT_ACTIVE = 0x80,\r
+ QTD_STAT_ERR_MASK = QTD_STAT_TRANS_ERR | QTD_STAT_BABBLE_ERR | QTD_STAT_BUFF_ERR,\r
+\r
+ QTD_MAX_BUFFER = 4,\r
+ QTD_BUF_LEN = 4096,\r
+ QTD_BUF_MASK = 0x0FFF,\r
+\r
+ QH_MICROFRAME_0 = 0x01,\r
+ QH_MICROFRAME_1 = 0x02,\r
+ QH_MICROFRAME_2 = 0x04,\r
+ QH_MICROFRAME_3 = 0x08,\r
+ QH_MICROFRAME_4 = 0x10,\r
+ QH_MICROFRAME_5 = 0x20,\r
+ QH_MICROFRAME_6 = 0x40,\r
+ QH_MICROFRAME_7 = 0x80,\r
+\r
+ USB_ERR_SHORT_PACKET = 0x200,\r
+};\r
+\r
+//\r
+// Fill in the hardware link point: pass in a EHC_QH/QH_HW\r
+// pointer to QH_LINK; A EHC_QTD/QTD_HW pointer to QTD_LINK\r
+//\r
+#define QH_LINK(Addr, Type, Term) \\r
+ ((UINT32) ((EHC_LOW_32BIT (Addr) & 0xFFFFFFE0) | (Type) | ((Term) ? 1 : 0)))\r
+\r
+#define QTD_LINK(Addr, Term) QH_LINK((Addr), 0, (Term))\r
+\r
+//\r
+// The defination of EHCI hardware used data structure for\r
+// little endian architecture. The QTD and QH structures\r
+// are required to be 32 bytes aligned. Don't add members\r
+// to the head of the associated software strucuture.\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+ UINT32 NextQtd;\r
+ UINT32 AltNext;\r
+\r
+ UINT32 Status : 8;\r
+ UINT32 Pid : 2;\r
+ UINT32 ErrCnt : 2;\r
+ UINT32 CurPage : 3;\r
+ UINT32 IOC : 1;\r
+ UINT32 TotalBytes : 15;\r
+ UINT32 DataToggle : 1;\r
+\r
+ UINT32 Page[5];\r
+ UINT32 PageHigh[5];\r
+} QTD_HW;\r
+\r
+typedef struct {\r
+ UINT32 HorizonLink;\r
+ //\r
+ // Endpoint capabilities/Characteristics DWord 1 and DWord 2\r
+ //\r
+ UINT32 DeviceAddr : 7;\r
+ UINT32 Inactive : 1;\r
+ UINT32 EpNum : 4;\r
+ UINT32 EpSpeed : 2;\r
+ UINT32 DtCtrl : 1;\r
+ UINT32 ReclaimHead : 1;\r
+ UINT32 MaxPacketLen : 11;\r
+ UINT32 CtrlEp : 1;\r
+ UINT32 NakReload : 4;\r
+\r
+ UINT32 SMask : 8;\r
+ UINT32 CMask : 8;\r
+ UINT32 HubAddr : 7;\r
+ UINT32 PortNum : 7;\r
+ UINT32 Multiplier : 2;\r
+\r
+ //\r
+ // Transaction execution overlay area\r
+ //\r
+ UINT32 CurQtd;\r
+ UINT32 NextQtd;\r
+ UINT32 AltQtd;\r
+\r
+ UINT32 Status : 8;\r
+ UINT32 Pid : 2;\r
+ UINT32 ErrCnt : 2;\r
+ UINT32 CurPage : 3;\r
+ UINT32 IOC : 1;\r
+ UINT32 TotalBytes : 15;\r
+ UINT32 DataToggle : 1;\r
+\r
+ UINT32 Page[5];\r
+ UINT32 PageHigh[5];\r
+} QH_HW;\r
+#pragma pack()\r
+\r
+\r
+//\r
+// Endpoint address and its capabilities\r
+//\r
+typedef struct _USB_ENDPOINT {\r
+ UINT8 DevAddr;\r
+ UINT8 EpAddr; // Endpoint address, no direction encoded in\r
+ EFI_USB_DATA_DIRECTION Direction;\r
+ UINT8 DevSpeed;\r
+ UINTN MaxPacket;\r
+ UINT8 HubAddr;\r
+ UINT8 HubPort;\r
+ UINT8 Toggle; // Data toggle, not used for control transfer\r
+ UINTN Type;\r
+ UINTN PollRate; // Polling interval used by EHCI\r
+} USB_ENDPOINT;\r
+\r
+//\r
+// Software QTD strcture, this is used to manage all the\r
+// QTD generated from a URB. Don't add fields before QtdHw.\r
+//\r
+typedef struct _EHC_QTD {\r
+ QTD_HW QtdHw;\r
+ UINT32 Signature;\r
+ LIST_ENTRY QtdList; // The list of QTDs to one end point\r
+ UINT8 *Data; // Buffer of the original data\r
+ UINTN DataLen; // Original amount of data in this QTD\r
+} EHC_QTD;\r
+\r
+//\r
+// Software QH structure. All three different transaction types\r
+// supported by UEFI USB, that is the control/bulk/interrupt\r
+// transfers use the queue head and queue token strcuture.\r
+//\r
+// Interrupt QHs are linked to periodic frame list in the reversed\r
+// 2^N tree. Each interrupt QH is linked to the list starting at\r
+// frame 0. There is a dummy interrupt QH linked to each frame as\r
+// a sentinental whose polling interval is 1. Synchronous interrupt\r
+// transfer is linked after this dummy QH.\r
+//\r
+// For control/bulk transfer, only synchronous (in the sense of UEFI)\r
+// transfer is supported. A dummy QH is linked to EHCI AsyncListAddr\r
+// as the reclamation header. New transfer is inserted after this QH.\r
+//\r
+typedef struct _EHC_QH {\r
+ QH_HW QhHw;\r
+ UINT32 Signature;\r
+ EHC_QH *NextQh; // The queue head pointed to by horizontal link\r
+ LIST_ENTRY Qtds; // The list of QTDs to this queue head\r
+ UINTN Interval;\r
+} EHC_QH;\r
+\r
+//\r
+// URB (Usb Request Block) contains information for all kinds of\r
+// usb requests.\r
+//\r
+typedef struct _URB {\r
+ UINT32 Signature;\r
+ LIST_ENTRY UrbList;\r
+\r
+ //\r
+ // Transaction information\r
+ //\r
+ USB_ENDPOINT Ep;\r
+ EFI_USB_DEVICE_REQUEST *Request; // Control transfer only\r
+ VOID *RequestPhy; // Address of the mapped request\r
+ VOID *RequestMap;\r
+ VOID *Data;\r
+ UINTN DataLen;\r
+ VOID *DataPhy; // Address of the mapped user data\r
+ VOID *DataMap;\r
+ EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;\r
+ VOID *Context;\r
+\r
+ //\r
+ // Schedule data\r
+ //\r
+ EHC_QH *Qh;\r
+\r
+ //\r
+ // Transaction result\r
+ //\r
+ UINT32 Result;\r
+ UINTN Completed; // completed data length\r
+ UINT8 DataToggle;\r
+} URB;\r
+\r
+\r
+\r
+/**\r
+ Create a single QTD to hold the data\r
+\r
+ @param Ehc The EHCI device\r
+ @param Data Current data not associated with a QTD\r
+ @param DataLen The length of the data\r
+ @param PktId Packet ID to use in the QTD\r
+ @param Toggle Data toggle to use in the QTD\r
+ @param MaxPacket Maximu packet length of the endpoint\r
+\r
+ @return Created QTD or NULL if failed to create one\r
+\r
+**/\r
+EHC_QTD *\r
+EhcCreateQtd (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT8 *Data,\r
+ IN UINTN DataLen,\r
+ IN UINT8 PktId,\r
+ IN UINT8 Toggle,\r
+ IN UINTN MaxPacket\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Allocate and initialize a EHCI queue head\r
+\r
+ @param Ehci The EHCI device\r
+ @param Ep The endpoint to create queue head for\r
+\r
+ @return Created queue head or NULL if failed to create one\r
+\r
+**/\r
+EHC_QH *\r
+EhcCreateQh (\r
+ IN USB2_HC_DEV *Ehci,\r
+ IN USB_ENDPOINT *Ep\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Free an allocated URB. It is possible for it to be partially inited.\r
+\r
+ @param Ehc The EHCI device\r
+ @param Urb The URB to free\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EhcFreeUrb (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN URB *Urb\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Create a new URB and its associated QTD\r
+\r
+ @param Ehc The EHCI device\r
+ @param DevAddr The device address\r
+ @param EpAddr Endpoint addrress & its direction\r
+ @param DevSpeed The device speed\r
+ @param Toggle Initial data toggle to use\r
+ @param MaxPacket The max packet length of the endpoint\r
+ @param Hub The transaction translator to use\r
+ @param Type The transaction type\r
+ @param Request The standard USB request for control transfer\r
+ @param Data The user data to transfer\r
+ @param DataLen The length of data buffer\r
+ @param Callback The function to call when data is transferred\r
+ @param Context The context to the callback\r
+ @param Interval The interval for interrupt transfer\r
+\r
+ @return Created URB or NULL\r
+\r
+**/\r
+URB *\r
+EhcCreateUrb (\r
+ IN USB2_HC_DEV *Ehc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpAddr,\r
+ IN UINT8 DevSpeed,\r
+ IN UINT8 Toggle,\r
+ IN UINTN MaxPacket,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
+ IN UINTN Type,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN VOID *Data,\r
+ IN UINTN DataLen,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
+ IN VOID *Context,\r
+ IN UINTN Interval\r
+ )\r
+;\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciMem.c\r
+\r
+Abstract:\r
+\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+\r
+#include "Ehci.h"\r
+\r
+\r
+UINTN mUsbHcDebugLevel = DEBUG_INFO;\r
+\r
+\r
+/**\r
+ Allocate a block of memory to be used by the buffer pool\r
+\r
+ @param Pool The buffer pool to allocate memory for\r
+ @param Pages How many pages to allocate\r
+\r
+ @return The allocated memory block or NULL if failed\r
+\r
+**/\r
+STATIC\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ VOID *BufHost;\r
+ VOID *Mapping;\r
+ EFI_PHYSICAL_ADDRESS MappedAddr;\r
+ UINTN Bytes;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Pool->PciIo;\r
+\r
+ Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
+ if (Block == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // each bit in the bit array represents USBHC_MEM_UNIT\r
+ // bytes of memory in the memory block.\r
+ //\r
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+\r
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+ Block->Bits = AllocateZeroPool (Block->BitsLen);\r
+\r
+ if (Block->Bits == NULL) {\r
+ gBS->FreePool (Block);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Allocate the number of Pages of memory, then map it for\r
+ // bus master read and write.\r
+ //\r
+ Status = PciIo->AllocateBuffer (\r
+ PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ Pages,\r
+ &BufHost,\r
+ 0\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_BITARRAY;\r
+ }\r
+\r
+ Bytes = EFI_PAGES_TO_SIZE (Pages);\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ BufHost,\r
+ &Bytes,\r
+ &MappedAddr,\r
+ &Mapping\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
+ goto FREE_BUFFER;\r
+ }\r
+\r
+ //\r
+ // Check whether the data structure used by the host controller\r
+ // should be restricted into the same 4G\r
+ //\r
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
+ PciIo->Unmap (PciIo, Mapping);\r
+ goto FREE_BUFFER;\r
+ }\r
+\r
+ Block->BufHost = BufHost;\r
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);\r
+ Block->Mapping = Mapping;\r
+\r
+ DEBUG ((mUsbHcDebugLevel, "UsbHcAllocMemBlock: block %x created with buffer %x\n",\r
+ Block, Block->Buf));\r
+\r
+ return Block;\r
+\r
+FREE_BUFFER:\r
+ PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
+\r
+FREE_BITARRAY:\r
+ gBS->FreePool (Block->Bits);\r
+ gBS->FreePool (Block);\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Free the memory block from the memory pool\r
+\r
+ @param Pool The memory pool to free the block from\r
+ @param Block The memory block to free\r
+\r
+ @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbHcFreeMemBlock (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ ASSERT ((Pool != NULL) && (Block != NULL));\r
+\r
+ PciIo = Pool->PciIo;\r
+\r
+ //\r
+ // Unmap the common buffer then free the structures\r
+ //\r
+ PciIo->Unmap (PciIo, Block->Mapping);\r
+ PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
+\r
+ gBS->FreePool (Block->Bits);\r
+ gBS->FreePool (Block);\r
+}\r
+\r
+\r
+/**\r
+ Alloc some memory from the block\r
+\r
+ @param Block The memory block to allocate memory from\r
+ @param Mem The variable to store the memory allocated\r
+ @param Units Number of memory units to allocate\r
+\r
+ @return EFI_SUCCESS : The needed memory is allocated\r
+ @return EFI_NOT_FOUND : Can't find the free memory\r
+\r
+**/\r
+STATIC\r
+VOID *\r
+UsbHcAllocMemFromBlock (\r
+ IN USBHC_MEM_BLOCK *Block,\r
+ IN UINTN Units\r
+ )\r
+{\r
+ UINTN Byte;\r
+ UINT8 Bit;\r
+ UINTN StartByte;\r
+ UINT8 StartBit;\r
+ UINTN Available;\r
+ UINTN Count;\r
+\r
+ ASSERT ((Block != 0) && (Units != 0));\r
+\r
+ StartByte = 0;\r
+ StartBit = 0;\r
+ Available = 0;\r
+\r
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+ //\r
+ // If current bit is zero, the corresponding memory unit is\r
+ // available, otherwise we need to restart our searching.\r
+ // Available counts the consective number of zero bit.\r
+ //\r
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+ Available++;\r
+\r
+ if (Available >= Units) {\r
+ break;\r
+ }\r
+\r
+ NEXT_BIT (Byte, Bit);\r
+\r
+ } else {\r
+ NEXT_BIT (Byte, Bit);\r
+\r
+ Available = 0;\r
+ StartByte = Byte;\r
+ StartBit = Bit;\r
+ }\r
+ }\r
+\r
+ if (Available < Units) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Mark the memory as allocated\r
+ //\r
+ Byte = StartByte;\r
+ Bit = StartBit;\r
+\r
+ for (Count = 0; Count < Units; Count++) {\r
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] |= USB_HC_BIT (Bit);\r
+ NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
+}\r
+\r
+\r
+/**\r
+ Insert the memory block to the pool's list of the blocks\r
+\r
+ @param Head The head of the memory pool's block list\r
+ @param Block The memory block to insert\r
+\r
+ @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbHcInsertMemBlockToPool (\r
+ IN USBHC_MEM_BLOCK *Head,\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Head != NULL) && (Block != NULL));\r
+ Block->Next = Head->Next;\r
+ Head->Next = Block;\r
+}\r
+\r
+\r
+/**\r
+ Is the memory block empty?\r
+\r
+ @param Block The memory block to check\r
+\r
+ @return TRUE : The memory block is empty\r
+ @return FALSE : The memory block isn't empty\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+UsbHcIsMemBlockEmpty (\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < Block->BitsLen; Index++) {\r
+ if (Block->Bits[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Unlink the memory block from the pool's list\r
+\r
+ @param Head The block list head of the memory's pool\r
+ @param BlockToUnlink The memory block to unlink.\r
+\r
+ @return VOID\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbHcUnlinkMemBlock (\r
+ IN USBHC_MEM_BLOCK *Head,\r
+ IN USBHC_MEM_BLOCK *BlockToUnlink\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+\r
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ if (Block->Next == BlockToUnlink) {\r
+ Block->Next = BlockToUnlink->Next;\r
+ BlockToUnlink->Next = NULL;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller\r
+\r
+ @param Pool The USB memory pool to initialize\r
+ @param PciIo The PciIo that can be used to access the host controller\r
+ @param Check4G Whether the host controller requires allocated memory\r
+ from one 4G address space.\r
+ @param Which4G The 4G memory area each memory allocated should be from\r
+\r
+ @return EFI_SUCCESS : The memory pool is initialized\r
+ @return EFI_OUT_OF_RESOURCE : Fail to init the memory pool\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN BOOLEAN Check4G,\r
+ IN UINT32 Which4G\r
+ )\r
+{\r
+ USBHC_MEM_POOL *Pool;\r
+\r
+ Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
+\r
+ if (Pool == NULL) {\r
+ return Pool;\r
+ }\r
+\r
+ Pool->PciIo = PciIo;\r
+ Pool->Check4G = Check4G;\r
+ Pool->Which4G = Which4G;\r
+ Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
+\r
+ if (Pool->Head == NULL) {\r
+ gBS->FreePool (Pool);\r
+ Pool = NULL;\r
+ }\r
+\r
+ return Pool;\r
+}\r
+\r
+\r
+/**\r
+ Release the memory management pool\r
+\r
+ @param Pool The USB memory pool to free\r
+\r
+ @return EFI_SUCCESS : The memory pool is freed\r
+ @return EFI_DEVICE_ERROR : Failed to free the memory pool\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+\r
+ ASSERT (Pool->Head != NULL);\r
+\r
+ //\r
+ // Unlink all the memory blocks from the pool, then free them.\r
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
+ // first block.\r
+ //\r
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+ UsbHcUnlinkMemBlock (Pool->Head, Block);\r
+ UsbHcFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ UsbHcFreeMemBlock (Pool, Pool->Head);\r
+ gBS->FreePool (Pool);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool\r
+ @param Size Size of the memory to allocate\r
+\r
+ @return The allocated memory or NULL\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ USBHC_MEM_BLOCK *NewBlock;\r
+ VOID *Mem;\r
+ UINTN AllocSize;\r
+ UINTN Pages;\r
+\r
+ Mem = NULL;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+ Head = Pool->Head;\r
+ ASSERT (Head != NULL);\r
+\r
+ //\r
+ // First check whether current memory blocks can satisfy the allocation.\r
+ //\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Mem != NULL) {\r
+ return Mem;\r
+ }\r
+\r
+ //\r
+ // Create a new memory block if there is not enough memory\r
+ // in the pool. If the allocation size is larger than the\r
+ // default page number, just allocate a large enough memory\r
+ // block. Otherwise allocate default pages.\r
+ //\r
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+ } else {\r
+ Pages = USBHC_MEM_DEFAULT_PAGES;\r
+ }\r
+\r
+ NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
+\r
+ if (NewBlock == NULL) {\r
+ DEBUG ((mUsbHcDebugLevel, "UsbHcAllocateMem: failed to allocate block\n"));\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Add the new memory block to the pool, then allocate memory from it\r
+ //\r
+ UsbHcInsertMemBlockToPool (Head, NewBlock);\r
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ }\r
+\r
+ return Mem;\r
+}\r
+\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool\r
+\r
+ @param Pool The memory pool of the host controller\r
+ @param Mem The memory to free\r
+ @param Size The size of the memory to free\r
+\r
+ @return VOID\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ UINT8 *ToFree;\r
+ UINTN AllocSize;\r
+ UINTN Byte;\r
+ UINTN Bit;\r
+ UINTN Count;\r
+\r
+ Head = Pool->Head;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+ ToFree = (UINT8 *) Mem;\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ //\r
+ // scan the memory block list for the memory block that\r
+ // completely contains the memory to free.\r
+ //\r
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+ //\r
+ // compute the start byte and bit in the bit array\r
+ //\r
+ Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
+ Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
+\r
+ //\r
+ // reset associated bits in bit arry\r
+ //\r
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] ^= (UINT8) USB_HC_BIT (Bit);\r
+ NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If Block == NULL, it means that the current memory isn't\r
+ // in the host controller's pool. This is critical because\r
+ // the caller has passed in a wrong memory point\r
+ //\r
+ ASSERT (Block != NULL);\r
+\r
+ //\r
+ // Release the current memory block if it is empty and not the head\r
+ //\r
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
+ DEBUG ((mUsbHcDebugLevel, "UsbHcFreeMem: block %x is empty, recycle\n", Block));\r
+\r
+ UsbHcUnlinkMemBlock (Head, Block);\r
+ UsbHcFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 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
+ EhciMem.h\r
+\r
+Abstract:\r
+\r
+ This file contains the definination for host controller memory management routines\r
+\r
+Revision History\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_MEM_H_\r
+#define _EFI_EHCI_MEM_H_\r
+\r
+\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))\r
+\r
+#define USB_HC_BIT_IS_SET(Data, Bit) \\r
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))\r
+\r
+#define USB_HC_HIGH_32BIT(Addr64) \\r
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+\r
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;\r
+\r
+typedef struct _USBHC_MEM_BLOCK {\r
+ UINT8 *Bits; // Bit array to record which unit is allocated\r
+ UINTN BitsLen;\r
+ UINT8 *Buf;\r
+ UINT8 *BufHost;\r
+ UINTN BufLen; // Memory size in bytes\r
+ VOID *Mapping;\r
+ USBHC_MEM_BLOCK *Next;\r
+} USBHC_MEM_BLOCK;\r
+\r
+//\r
+// USBHC_MEM_POOL is used to manage the memory used by USB\r
+// host controller. EHCI requires the control memory and transfer\r
+// data to be on the same 4G memory.\r
+//\r
+typedef struct _USBHC_MEM_POOL {\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ BOOLEAN Check4G;\r
+ UINT32 Which4G;\r
+ USBHC_MEM_BLOCK *Head;\r
+} USBHC_MEM_POOL;\r
+\r
+enum {\r
+ USBHC_MEM_UNIT = 64, // Memory allocation unit, must be 2^n, n>4\r
+\r
+ USBHC_MEM_UNIT_MASK = USBHC_MEM_UNIT - 1,\r
+ USBHC_MEM_DEFAULT_PAGES = 16,\r
+};\r
+\r
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define NEXT_BIT(Byte, Bit) \\r
+ do { \\r
+ (Bit)++; \\r
+ if ((Bit) > 7) { \\r
+ (Byte)++; \\r
+ (Bit) = 0; \\r
+ } \\r
+ } while (0)\r
+\r
+\r
+\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN BOOLEAN Check4G,\r
+ IN UINT32 Which4G\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize the memory management pool for the host controller\r
+\r
+Arguments:\r
+\r
+ Pool - The USB memory pool to initialize\r
+ PciIo - The PciIo that can be used to access the host controller\r
+ Check4G - Whether the host controller requires allocated memory\r
+ from one 4G address space.\r
+ Which4G - The 4G memory area each memory allocated should be from\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS : The memory pool is initialized\r
+ EFI_OUT_OF_RESOURCE : Fail to init the memory pool\r
+\r
+--*/\r
+;\r
+\r
+\r
+\r
+/**\r
+ Release the memory management pool\r
+\r
+ @param Pool The USB memory pool to free\r
+\r
+ @return EFI_SUCCESS : The memory pool is freed\r
+ @return EFI_DEVICE_ERROR : Failed to free the memory pool\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool\r
+ @param Size Size of the memory to allocate\r
+\r
+ @return The allocated memory or NULL\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ )\r
+;\r
+\r
+\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool\r
+\r
+ @param Pool The memory pool of the host controller\r
+ @param Mem The memory to free\r
+ @param Size The size of the memory to free\r
+\r
+ @return VOID\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+;\r
+#endif\r
--- /dev/null
+/** @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
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "uhci.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+UhciComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UhciComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle, OPTIONAL\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gUhciComponentName = {\r
+ UhciComponentNameGetDriverName,\r
+ UhciComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mUhciDriverNameTable[] = {\r
+ { "eng", L"Usb Uhci Driver" },\r
+ { NULL, NULL }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UhciComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ Language - A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages specified\r
+ in SupportedLanguages. The number of languages supported by a\r
+ driver is up to the driver writer.\r
+ DriverName - A pointer to the Unicode string to return. This Unicode string\r
+ is the name of the driver specified by This in the language\r
+ specified by Language.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the Driver specified by This\r
+ and the language specified by Language was returned\r
+ in DriverName.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - DriverName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gUhciComponentName.SupportedLanguages,\r
+ mUhciDriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UhciComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle, OPTIONAL\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+ Arguments:\r
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ ControllerHandle - The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ ChildHandle - The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL. It\r
+ will be NULL for device drivers. It will also be NULL\r
+ for a bus drivers that wish to retrieve the name of the\r
+ bus controller. It will not be NULL for a bus driver\r
+ that wishes to retrieve the name of a child controller.\r
+ Language - A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller name\r
+ that that the caller is requesting, and it must match one\r
+ of the languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up to the\r
+ driver writer.\r
+ ControllerName - A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language\r
+ specified by Language from the point of view of the\r
+ driver specified by This.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The Unicode string for the user readable name in the\r
+ language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+ EFI_INVALID_PARAMETER - Language is NULL.\r
+ EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+ EFI_UNSUPPORTED - The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+ EFI_UNSUPPORTED - The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ USB_HC_DEV *UhciDev;\r
+ EFI_USB_HC_PROTOCOL *UsbHc;\r
+\r
+ //\r
+ // This is a device driver, so ChildHandle must be NULL.\r
+ //\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllerHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gUhciDriverBinding.DriverBindingHandle,\r
+ &gEfiPciIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the device context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiUsbHcProtocolGuid,\r
+ (VOID **) &UsbHc,\r
+ gUhciDriverBinding.DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ UhciDev = UHC_FROM_USB_HC_PROTO (UsbHc);\r
+\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gUhciComponentName.SupportedLanguages,\r
+ UhciDev->CtrlNameTable,\r
+ ControllerName\r
+ );\r
+\r
+}\r
--- /dev/null
+/** @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