/** @file\r
The XHCI controller driver.\r
\r
-Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
{XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
};\r
\r
+USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {\r
+ {XHC_PORTSC_CSC, EfiUsbPortConnectChange},\r
+ {XHC_PORTSC_PEC, EfiUsbPortEnableChange},\r
+ {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
+ {XHC_PORTSC_PRC, EfiUsbPortResetChange}\r
+};\r
+\r
+USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {\r
+ {XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},\r
+ {XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},\r
+ {XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},\r
+ {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}\r
+};\r
+\r
+USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {\r
+ {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
+ {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
+ {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
+ {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
+};\r
+\r
+USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {\r
+ {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},\r
+ {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},\r
+ {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
+ {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},\r
+ {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}\r
+};\r
+\r
EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = {\r
XhcDriverBindingSupported,\r
XhcDriverBindingStart,\r
Xhc = XHC_FROM_THIS (This);\r
*MaxSpeed = EFI_USB_SPEED_SUPER;\r
*PortNumber = (UINT8) (Xhc->HcSParams1.Data.MaxPorts);\r
- *Is64BitCapable = (UINT8) (Xhc->HcCParams.Data.Ac64);\r
+ *Is64BitCapable = (UINT8) Xhc->Support64BitDma;\r
DEBUG ((EFI_D_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
\r
gBS->RestoreTPL (OldTpl);\r
EFI_STATUS Status;\r
EFI_TPL OldTpl;\r
\r
- OldTpl = gBS->RaiseTPL (XHC_TPL);\r
+ Xhc = XHC_FROM_THIS (This);\r
\r
- Xhc = XHC_FROM_THIS (This);\r
+ if (Xhc->DevicePath != NULL) {\r
+ //\r
+ // Report Status Code to indicate reset happens\r
+ //\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),\r
+ Xhc->DevicePath\r
+ );\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (XHC_TPL);\r
\r
switch (Attributes) {\r
case EFI_USB_HC_RESET_GLOBAL:\r
// Flow through, same behavior as Host Controller Reset\r
//\r
case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
+ if ((Xhc->DebugCapSupOffset != 0xFFFFFFFF) && ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) == XHC_CAP_USB_DEBUG) &&\r
+ ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) != 0)) {\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
+ }\r
//\r
// Host Controller must be Halt when Reset it\r
//\r
State = XhcReadOpReg (Xhc, Offset);\r
\r
//\r
- // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.\r
+ // According to XHCI 1.1 spec November 2017,\r
+ // bit 10~13 of the root port status register identifies the speed of the attached device.\r
//\r
switch ((State & XHC_PORTSC_PS) >> 10) {\r
case 2:\r
break;\r
\r
case 4:\r
+ case 5:\r
PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
break;\r
\r
}\r
}\r
\r
+ MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {\r
+ XhcClearRootHubPortFeature (This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);\r
+ }\r
+ }\r
+\r
//\r
// Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.\r
// For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.\r
UINT32 Offset;\r
UINT32 State;\r
UINT32 TotalPort;\r
- UINT8 SlotId;\r
- USB_DEV_ROUTE RouteChart;\r
EFI_STATUS Status;\r
EFI_TPL OldTpl;\r
\r
}\r
}\r
\r
- RouteChart.Route.RouteString = 0;\r
- RouteChart.Route.RootPortNum = PortNumber + 1;\r
- RouteChart.Route.TierNum = 1;\r
//\r
- // If the port reset operation happens after the usb super speed device is enabled,\r
- // The subsequent configuration, such as getting device descriptor, will fail.\r
- // So here a workaround is introduced to skip the reset operation if the device is enabled.\r
+ // 4.3.1 Resetting a Root Hub Port\r
+ // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
//\r
- SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
- if (SlotId == 0) {\r
- //\r
- // 4.3.1 Resetting a Root Hub Port\r
- // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
- //\r
- State |= XHC_PORTSC_RESET;\r
- XhcWriteOpReg (Xhc, Offset, State);\r
- XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
- }\r
+ State |= XHC_PORTSC_RESET;\r
+ XhcWriteOpReg (Xhc, Offset, State);\r
+ XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
break;\r
\r
case EfiUsbPortPower:\r
return Status;\r
}\r
\r
+/**\r
+ Submits a new transaction to a target USB device.\r
+\r
+ @param Xhc The XHCI Instance.\r
+ @param DeviceAddress The target device address.\r
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7\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 Type The transaction type.\r
+ @param Request USB device request to send.\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 TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+**/\r
+EFI_STATUS\r
+XhcTransfer (\r
+ IN USB_XHCI_INSTANCE *Xhc,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN UINTN Type,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN Timeout,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS RecoveryStatus;\r
+ URB *Urb;\r
+\r
+ ASSERT ((Type == XHC_CTRL_TRANSFER) || (Type == XHC_BULK_TRANSFER) || (Type == XHC_INT_TRANSFER_SYNC));\r
+ Urb = XhcCreateUrb (\r
+ Xhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ Type,\r
+ Request,\r
+ Data,\r
+ *DataLength,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: failed to create URB!\n", Type));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
+\r
+ if (Status == EFI_TIMEOUT) {\r
+ //\r
+ // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+ //\r
+ RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
+ if (RecoveryStatus == EFI_ALREADY_STARTED) {\r
+ //\r
+ // The URB is finished just before stopping endpoint.\r
+ // Change returning status from EFI_TIMEOUT to EFI_SUCCESS.\r
+ //\r
+ ASSERT (Urb->Result == EFI_USB_NOERROR);\r
+ Status = EFI_SUCCESS;\r
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: pending URB is finished, Length = %d.\n", Type, Urb->Completed));\r
+ } else if (EFI_ERROR(RecoveryStatus)) {\r
+ DEBUG((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcDequeueTrbFromEndpoint failed!\n", Type));\r
+ }\r
+ }\r
+\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+\r
+ if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {\r
+ ASSERT (Status == EFI_DEVICE_ERROR);\r
+ RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+ if (EFI_ERROR (RecoveryStatus)) {\r
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcRecoverHaltedEndpoint failed!\n", Type));\r
+ }\r
+ }\r
+\r
+ Xhc->PciIo->Flush (Xhc->PciIo);\r
+ XhcFreeUrb (Xhc, Urb);\r
+ return Status;\r
+}\r
\r
/**\r
Submits control transfer to a target USB device.\r
)\r
{\r
USB_XHCI_INSTANCE *Xhc;\r
- URB *Urb;\r
UINT8 Endpoint;\r
UINT8 Index;\r
- UINT8 XhciDevAddr;\r
UINT8 DescriptorType;\r
UINT8 SlotId;\r
UINT8 TTT;\r
EFI_USB_HUB_DESCRIPTOR *HubDesc;\r
EFI_TPL OldTpl;\r
EFI_STATUS Status;\r
- EFI_STATUS RecoveryStatus;\r
UINTN MapSize;\r
EFI_USB_PORT_STATUS PortStatus;\r
UINT32 State;\r
+ EFI_USB_DEVICE_REQUEST ClearPortRequest;\r
+ UINTN Len;\r
\r
//\r
// Validate parameters\r
\r
Status = EFI_DEVICE_ERROR;\r
*TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Len = 0;\r
\r
if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
DEBUG ((EFI_D_ERROR, "XhcControlTransfer: HC halted at entrance\n"));\r
goto ON_EXIT;\r
}\r
\r
- //\r
- // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
- //\r
- XhciDevAddr = Xhc->UsbDevContext[SlotId].XhciDevAddr;\r
-\r
//\r
// Hook the Set_Address request from UsbBus.\r
// According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.\r
//\r
for (Index = 0; Index < 255; Index++) {\r
if (!Xhc->UsbDevContext[Index + 1].Enabled &&\r
- (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
+ (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&\r
(Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value)) {\r
Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;\r
}\r
}\r
+\r
+ if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto ON_EXIT;\r
+ }\r
//\r
// The actual device address has been assigned by XHCI during initializing the device slot.\r
// So we just need establish the mapping relationship between the device address requested from UsbBus\r
Status = EFI_SUCCESS;\r
goto ON_EXIT;\r
}\r
- \r
- //\r
- // If the port reset operation happens after the usb super speed device is enabled,\r
- // The subsequent configuration, such as getting device descriptor, will fail.\r
- // So here a workaround is introduced to skip the reset operation if the device is enabled.\r
- //\r
- if ((Request->Request == USB_REQ_SET_FEATURE) &&\r
- (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER)) &&\r
- (Request->Value == EfiUsbPortReset)) {\r
- if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
- Status = EFI_SUCCESS;\r
- goto ON_EXIT;\r
- }\r
- }\r
\r
//\r
// Create a new URB, insert it into the asynchronous\r
// combination of Ep addr and its direction.\r
//\r
Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
- Urb = XhcCreateUrb (\r
- Xhc,\r
- XhciDevAddr,\r
- Endpoint,\r
- DeviceSpeed,\r
- MaximumPacketLength,\r
- XHC_CTRL_TRANSFER,\r
- Request,\r
- Data,\r
- *DataLength,\r
- NULL,\r
- NULL\r
- );\r
+ Status = XhcTransfer (\r
+ Xhc,\r
+ DeviceAddress,\r
+ Endpoint,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ XHC_CTRL_TRANSFER,\r
+ Request,\r
+ Data,\r
+ DataLength,\r
+ Timeout,\r
+ TransferResult\r
+ );\r
\r
- if (Urb == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcControlTransfer: failed to create URB"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
+ if (EFI_ERROR (Status)) {\r
goto ON_EXIT;\r
}\r
- ASSERT (Urb->EvtRing == &Xhc->CtrlTrEventRing);\r
- Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
-\r
- //\r
- // Get the status from URB. The result is updated in XhcCheckUrbResult\r
- // which is called by XhcExecTransfer\r
- //\r
- *TransferResult = Urb->Result;\r
- *DataLength = Urb->Completed;\r
-\r
- if (*TransferResult == EFI_USB_NOERROR) {\r
- Status = EFI_SUCCESS;\r
- } else if ((*TransferResult == EFI_USB_ERR_STALL) ||\r
- (*TransferResult == EFI_USB_ERR_TIMEOUT)) {\r
- RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
- ASSERT_EFI_ERROR (RecoveryStatus);\r
- goto FREE_URB;\r
- }\r
\r
//\r
// Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
// Hook Set_Config request from UsbBus as we need configure device endpoint.\r
//\r
if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&\r
- (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||\r
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {\r
DescriptorType = (UINT8)(Request->Value >> 8);\r
- if ((DescriptorType == USB_DESC_TYPE_DEVICE) && (*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR))) {\r
+ if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {\r
ASSERT (Data != NULL);\r
//\r
// Store a copy of device scriptor as hub device need this info to configure endpoint.\r
//\r
CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);\r
- if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) {\r
+ if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {\r
//\r
// If it's a usb3.0 device, then its max packet size is a 2^n.\r
//\r
MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
}\r
Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
- Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);\r
- ASSERT_EFI_ERROR (Status);\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);\r
+ } else {\r
+ Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);\r
+ }\r
} else if (DescriptorType == USB_DESC_TYPE_CONFIG) {\r
ASSERT (Data != NULL);\r
if (*DataLength == ((UINT16 *)Data)[1]) {\r
ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);\r
Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool(*DataLength);\r
CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
+ //\r
+ // Default to use AlternateSetting 0 for all interfaces.\r
+ //\r
+ Xhc->UsbDevContext[SlotId].ActiveAlternateSetting = AllocateZeroPool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->NumInterfaces * sizeof (UINT8));\r
}\r
- } else if ((DescriptorType == USB_DESC_TYPE_HUB) ||\r
- (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) {\r
+ } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||\r
+ (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {\r
ASSERT (Data != NULL);\r
HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;\r
+ ASSERT (HubDesc->NumPorts <= 15);\r
//\r
// The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.\r
//\r
//\r
// Don't support multi-TT feature for super speed hub now.\r
//\r
- MTT = 1;\r
- ASSERT (FALSE);\r
+ MTT = 0;\r
+ DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));\r
} else {\r
MTT = 0;\r
}\r
\r
- Status = XhcConfigHubContext (\r
- Xhc,\r
- SlotId,\r
- HubDesc->NumPorts,\r
- TTT,\r
- MTT\r
- );\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
+ } else {\r
+ Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
+ }\r
}\r
} else if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
(Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
//\r
for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {\r
- XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+ } else {\r
+ Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
+ }\r
break;\r
}\r
}\r
+ } else if ((Request->Request == USB_REQ_SET_INTERFACE) &&\r
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE))) {\r
+ //\r
+ // Hook Set_Interface request from UsbBus as we need configure interface setting.\r
+ // Request->Value indicates AlterlateSetting to set\r
+ // Request->Index indicates Interface to set\r
+ //\r
+ if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] != (UINT8) Request->Value) {\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ Status = XhcSetInterface (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);\r
+ } else {\r
+ Status = XhcSetInterface64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);\r
+ }\r
+ }\r
} else if ((Request->Request == USB_REQ_GET_STATUS) &&\r
(Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {\r
ASSERT (Data != NULL);\r
//\r
// For super speed hub, its bit10~12 presents the attached device speed.\r
//\r
- if ((*(UINT32 *)Data & XHC_PORTSC_PS) >> 10 == 0) {\r
+ if ((State & XHC_PORTSC_PS) >> 10 == 0) {\r
PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
}\r
- } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+ } else {\r
//\r
- // For high speed hub, its bit9~10 presents the attached device speed.\r
+ // For high or full/low speed hub, its bit9~10 presents the attached device speed.\r
//\r
- if (XHC_BIT_IS_SET (*(UINT32 *)Data, BIT9)) {\r
+ if (XHC_BIT_IS_SET (State, BIT9)) {\r
PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
- } else if (XHC_BIT_IS_SET (*(UINT32 *)Data, BIT10)) {\r
+ } else if (XHC_BIT_IS_SET (State, BIT10)) {\r
PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
}\r
- } else {\r
- ASSERT (0);\r
}\r
\r
//\r
// Convert the XHCI port/port change state to UEFI status\r
//\r
- MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+ MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
for (Index = 0; Index < MapSize; Index++) {\r
- if (XHC_BIT_IS_SET (*(UINT32 *)Data, mUsbPortStateMap[Index].HwState)) {\r
- PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbPortStateMap[Index].UefiState);\r
+ if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {\r
+ PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);\r
}\r
}\r
- MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
\r
+ MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
for (Index = 0; Index < MapSize; Index++) {\r
- if (XHC_BIT_IS_SET (*(UINT32 *)Data, mUsbPortChangeMap[Index].HwState)) {\r
- PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
+ if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {\r
+ PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);\r
+ }\r
+ }\r
+\r
+ MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {\r
+ ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+ ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);\r
+ ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;\r
+ ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;\r
+ ClearPortRequest.Index = Request->Index;\r
+ ClearPortRequest.Length = 0;\r
+\r
+ XhcControlTransfer (\r
+ This,\r
+ DeviceAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ &ClearPortRequest,\r
+ EfiUsbNoData,\r
+ NULL,\r
+ &Len,\r
+ Timeout,\r
+ Translator,\r
+ TransferResult\r
+ );\r
}\r
}\r
\r
XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);\r
- }\r
\r
-FREE_URB:\r
- FreePool (Urb);\r
+ *(UINT32 *)Data = *(UINT32*)&PortStatus;\r
+ }\r
\r
ON_EXIT:\r
-\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
}\r
)\r
{\r
USB_XHCI_INSTANCE *Xhc;\r
- URB *Urb;\r
- UINT8 XhciDevAddr;\r
UINT8 SlotId;\r
EFI_STATUS Status;\r
- EFI_STATUS RecoveryStatus;\r
EFI_TPL OldTpl;\r
\r
//\r
goto ON_EXIT;\r
}\r
\r
- //\r
- // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
- //\r
- XhciDevAddr = Xhc->UsbDevContext[SlotId].XhciDevAddr;\r
-\r
//\r
// Create a new URB, insert it into the asynchronous\r
// schedule list, then poll the execution status.\r
//\r
- Urb = XhcCreateUrb (\r
- Xhc,\r
- XhciDevAddr,\r
- EndPointAddress,\r
- DeviceSpeed,\r
- MaximumPacketLength,\r
- XHC_BULK_TRANSFER,\r
- NULL,\r
- Data[0],\r
- *DataLength,\r
- NULL,\r
- NULL\r
- );\r
-\r
- if (Urb == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: failed to create URB\n"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- ASSERT (Urb->EvtRing == &Xhc->BulkTrEventRing);\r
-\r
- Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
-\r
- *TransferResult = Urb->Result;\r
- *DataLength = Urb->Completed;\r
-\r
- if (*TransferResult == EFI_USB_NOERROR) {\r
- Status = EFI_SUCCESS;\r
- } else if ((*TransferResult == EFI_USB_ERR_STALL) ||\r
- (*TransferResult == EFI_USB_ERR_TIMEOUT)) {\r
- RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
- ASSERT_EFI_ERROR (RecoveryStatus);\r
- }\r
-\r
- FreePool (Urb);\r
+ Status = XhcTransfer (\r
+ Xhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ XHC_BULK_TRANSFER,\r
+ NULL,\r
+ Data[0],\r
+ DataLength,\r
+ Timeout,\r
+ TransferResult\r
+ );\r
\r
ON_EXIT:\r
-\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
}\r
USB_XHCI_INSTANCE *Xhc;\r
URB *Urb;\r
EFI_STATUS Status;\r
- UINT8 XhciDevAddr;\r
UINT8 SlotId;\r
UINT8 Index;\r
- UINT8 *Data;\r
EFI_TPL OldTpl;\r
\r
//\r
// The delete request may happen after device is detached.\r
//\r
for (Index = 0; Index < 255; Index++) {\r
- if ((Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
- (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress)) {\r
+ if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) {\r
break;\r
}\r
}\r
goto ON_EXIT;\r
}\r
\r
- //\r
- // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
- //\r
- XhciDevAddr = Xhc->UsbDevContext[Index + 1].XhciDevAddr;\r
-\r
- Status = XhciDelAsyncIntTransfer (Xhc, XhciDevAddr, EndPointAddress);\r
- DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer, Status = %r\n", Status));\r
+ Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);\r
+ DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));\r
goto ON_EXIT;\r
}\r
\r
goto ON_EXIT;\r
}\r
\r
- //\r
- // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
- //\r
- XhciDevAddr = Xhc->UsbDevContext[SlotId].XhciDevAddr;\r
-\r
- Data = AllocateZeroPool (DataLength);\r
-\r
- if (Data == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- Urb = XhcCreateUrb (\r
+ Urb = XhciInsertAsyncIntTransfer (\r
Xhc,\r
- XhciDevAddr,\r
+ DeviceAddress,\r
EndPointAddress,\r
DeviceSpeed,\r
MaximumPacketLength,\r
- XHC_INT_TRANSFER_ASYNC,\r
- NULL,\r
- Data,\r
DataLength,\r
CallBackFunction,\r
Context\r
);\r
-\r
if (Urb == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to create URB\n"));\r
- FreePool (Data);\r
Status = EFI_OUT_OF_RESOURCES;\r
goto ON_EXIT;\r
}\r
\r
- ASSERT (Urb->EvtRing == &Xhc->AsynIntTrEventRing);\r
-\r
- InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);\r
//\r
// Ring the doorbell\r
//\r
Status = RingIntTransferDoorBell (Xhc, Urb);\r
\r
ON_EXIT:\r
+ Xhc->PciIo->Flush (Xhc->PciIo);\r
gBS->RestoreTPL (OldTpl);\r
\r
return Status;\r
)\r
{\r
USB_XHCI_INSTANCE *Xhc;\r
- URB *Urb;\r
- UINT8 XhciDevAddr;\r
UINT8 SlotId;\r
EFI_STATUS Status;\r
- EFI_STATUS RecoveryStatus;\r
EFI_TPL OldTpl;\r
\r
//\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (!XHCI_IS_DATAIN (EndPointAddress)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
goto ON_EXIT;\r
}\r
\r
- //\r
- // Acquire the actual device address assigned by XHCI's Address_Device cmd.\r
- //\r
- XhciDevAddr = Xhc->UsbDevContext[SlotId].XhciDevAddr;\r
-\r
- Urb = XhcCreateUrb (\r
- Xhc,\r
- XhciDevAddr,\r
- EndPointAddress,\r
- DeviceSpeed,\r
- MaximumPacketLength,\r
- XHC_INT_TRANSFER_SYNC,\r
- NULL,\r
- Data,\r
- *DataLength,\r
- NULL,\r
- NULL\r
- );\r
-\r
- if (Urb == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: failed to create URB\n"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
-\r
- *TransferResult = Urb->Result;\r
- *DataLength = Urb->Completed;\r
-\r
- if (*TransferResult == EFI_USB_NOERROR) {\r
- Status = EFI_SUCCESS;\r
- } else if ((*TransferResult == EFI_USB_ERR_STALL) ||\r
- (*TransferResult == EFI_USB_ERR_TIMEOUT)) {\r
- RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
- ASSERT_EFI_ERROR (RecoveryStatus);\r
- }\r
-\r
- FreePool (Urb);\r
+ Status = XhcTransfer (\r
+ Xhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ XHC_INT_TRANSFER_SYNC,\r
+ NULL,\r
+ Data,\r
+ DataLength,\r
+ Timeout,\r
+ TransferResult\r
+ );\r
\r
ON_EXIT:\r
if (EFI_ERROR (Status)) {\r
Create and initialize a USB_XHCI_INSTANCE structure.\r
\r
@param PciIo The PciIo on this device.\r
+ @param DevicePath The device path of host controller.\r
@param OriginalPciAttributes Original PCI attributes.\r
\r
@return The allocated and initialized USB_XHCI_INSTANCE structure if created,\r
**/\r
USB_XHCI_INSTANCE*\r
XhcCreateUsbHc (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT64 OriginalPciAttributes\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN UINT64 OriginalPciAttributes\r
)\r
{\r
USB_XHCI_INSTANCE *Xhc;\r
EFI_STATUS Status;\r
UINT32 PageSize;\r
UINT16 ExtCapReg;\r
+ UINT8 ReleaseNumber;\r
\r
Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));\r
\r
//\r
Xhc->Signature = XHCI_INSTANCE_SIG;\r
Xhc->PciIo = PciIo;\r
+ Xhc->DevicePath = DevicePath;\r
Xhc->OriginalPciAttributes = OriginalPciAttributes;\r
CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));\r
\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ XHC_PCI_SBRN_OFFSET,\r
+ 1,\r
+ &ReleaseNumber\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Xhc->Usb2Hc.MajorRevision = (ReleaseNumber & 0xF0) >> 4;\r
+ Xhc->Usb2Hc.MinorRevision = (ReleaseNumber & 0x0F);\r
+ }\r
+\r
InitializeListHead (&Xhc->AsyncIntTransfers);\r
\r
//\r
\r
ExtCapReg = (UINT16) (Xhc->HcCParams.Data.ExtCapReg);\r
Xhc->ExtCapRegBase = ExtCapReg << 2;\r
- Xhc->UsbLegSupOffset = XhcGetLegSupCapAddr (Xhc);\r
+ Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);\r
+ Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);\r
\r
DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));\r
DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));\r
DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));\r
DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));\r
DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));\r
+ DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));\r
\r
//\r
// Create AsyncRequest Polling Timer\r
//\r
Status = gBS->CreateEvent (\r
EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
XhcMonitorAsyncRequests,\r
Xhc,\r
&Xhc->PollTimer\r
One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
\r
@param Event Pointer to this event\r
- @param Context Event hanlder private data\r
+ @param Context Event handler private data\r
\r
**/\r
VOID\r
gBS->CloseEvent (Xhc->PollTimer);\r
}\r
\r
+ XhcClearBiosOwnership (Xhc);\r
+\r
//\r
// Restore original PCI attributes\r
//\r
Xhc->OriginalPciAttributes,\r
NULL\r
);\r
-\r
- XhcClearBiosOwnership (Xhc);\r
}\r
\r
/**\r
UINT64 OriginalPciAttributes;\r
BOOLEAN PciAttributesSaved;\r
USB_XHCI_INSTANCE *Xhc;\r
+ EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;\r
\r
//\r
// Open the PciIo Protocol, then enable the USB host controller\r
return Status;\r
}\r
\r
+ //\r
+ // Open Device Path Protocol for on USB host controller\r
+ //\r
+ HcDevicePath = NULL;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &HcDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
PciAttributesSaved = FALSE;\r
//\r
// Save original PCI attributes\r
&Supports\r
);\r
if (!EFI_ERROR (Status)) {\r
- Supports &= EFI_PCI_DEVICE_ENABLE;\r
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
Status = PciIo->Attributes (\r
PciIo,\r
EfiPciIoAttributeOperationEnable,\r
//\r
// Create then install USB2_HC_PROTOCOL\r
//\r
- Xhc = XhcCreateUsbHc (PciIo, OriginalPciAttributes);\r
+ Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);\r
\r
if (Xhc == NULL) {\r
DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
+ //\r
+ // Enable 64-bit DMA support in the PCI layer if this controller\r
+ // supports it.\r
+ //\r
+ if (Xhc->HcCParams.Data.Ac64 != 0) {\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Xhc->Support64BitDma = TRUE;\r
+ } else {\r
+ DEBUG ((EFI_D_WARN,\r
+ "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",\r
+ __FUNCTION__, Controller, Status));\r
+ }\r
+ }\r
+\r
XhcSetBiosOwnership (Xhc);\r
\r
XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
\r
\r
/**\r
- Stop this driver on ControllerHandle. Support stoping any child handles\r
+ Stop this driver on ControllerHandle. Support stopping any child handles\r
created by this driver.\r
\r
@param This Protocol instance pointer.\r
return Status;\r
}\r
\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiUsb2HcProtocolGuid,\r
+ Usb2Hc\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
Xhc = XHC_FROM_THIS (Usb2Hc);\r
PciIo = Xhc->PciIo;\r
\r
(Xhc->UsbDevContext[Index + 1].SlotId == 0)) {\r
continue;\r
}\r
-\r
- XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
- }\r
-\r
- XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
- XhcClearBiosOwnership (Xhc);\r
-\r
- Status = gBS->UninstallProtocolInterface (\r
- Controller,\r
- &gEfiUsb2HcProtocolGuid,\r
- Usb2Hc\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+ if (Xhc->HcCParams.Data.Csz == 0) {\r
+ XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
+ } else {\r
+ XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
+ }\r
}\r
\r
if (Xhc->PollTimer != NULL) {\r
gBS->CloseEvent (Xhc->ExitBootServiceEvent);\r
}\r
\r
+ XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+ XhcClearBiosOwnership (Xhc);\r
XhciDelAllAsyncIntTransfers (Xhc);\r
XhcFreeSched (Xhc);\r
\r
// Restore original PCI attributes\r
//\r
PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSet,\r
- Xhc->OriginalPciAttributes,\r
- NULL\r
- );\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ Xhc->OriginalPciAttributes,\r
+ NULL\r
+ );\r
\r
gBS->CloseProtocol (\r
Controller,\r