/** @file\r
The XHCI controller driver.\r
\r
-Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2017, 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
{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
+ 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
- Xhc = XHC_FROM_THIS (This);\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
}\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) {\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
// 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
\r
Urb = XhcCreateUrb (\r
Xhc,\r
- XhciDevAddr,\r
+ DeviceAddress,\r
EndPointAddress,\r
DeviceSpeed,\r
MaximumPacketLength,\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
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
//\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
\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