ReactOS 0.4.17-dev-1281-g065abb3
XhciRootHub Class Reference

#include <rootports.h>

Collaboration diagram for XhciRootHub:

Classes

struct  Port
 

Public Member Functions

NTSTATUS Create (_In_ XhciController *Controller)
 
NTSTATUS Prepare ()
 
VOID Release ()
 
VOID D0Entry ()
 
VOID PostInterruptsEntry ()
 
VOID D0Exit ()
 
VOID PostReset ()
 
VOID OnHostLost ()
 
ULONG PortCount () const
 
USHORT HighestUsbVersion () const
 
VOID OnPortStatusChangeEvent (_In_ const XHCI_TRB *Event)
 
VOID SetWakeEnables (_In_ BOOLEAN Arm)
 
VOID SignalPortChange ()
 
VOID Update20HardwareLpm (_In_ ULONG PortNumber, _In_ ULONG SlotId, _In_ const USBDEVICE_UPDATE_20_HARDWARE_LPM_PARAMETERS *Parameters)
 
VOID DisableLpmForSlot (_In_ ULONG PortNumber, _In_ ULONG SlotId)
 
VOID ArmPortResumeTimer (_In_ ULONG PortNumber, _In_ ULONG Milliseconds)
 
VOID DisarmPortResumeTimer (_In_ ULONG PortNumber)
 
BOOLEAN IsUsb20Port (_In_ ULONG PortNumber) const
 
UCHAR QueryTunnelState (_In_ ULONG PortNumber) const
 

Private Types

enum class  Outcome : ULONG {
  Ok , Stall , Gone , Halted ,
  OperationPending
}
 

Private Member Functions

NTSTATUS ParseProtocol (_In_ ULONG Capability, _Out_ PBOOLEAN Usable)
 
Port * PortAt (_In_ ULONG PortNumber) const
 
ULONG ReadPortSc (_In_ const Port *P) const
 
ULONG UpdatePortSc (_In_ Port *P, _In_ ULONG Keep, _In_ ULONG Set)
 
ULONG UpdatePortScLocked (_In_ Port *P, _In_ ULONG Keep, _In_ ULONG Set)
 
VOID UpdatePortReg (_In_ Port *P, _In_ ULONG Offset, _In_ ULONG Clear, _In_ ULONG Set)
 
VOID ClearUsb20LpmLocked (_In_ Port *P)
 
BOOLEAN IsHiddenDebugPort (_In_ const Port *P) const
 
VOID StartResumeTimer (_In_ Port *P)
 
BOOLEAN AcknowledgeResume (_In_ Port *P, _In_ BOOLEAN PowerUp)
 
NTSTATUS WaitForU3 (_In_ Port *P, _In_ BOOLEAN RepeatRequest)
 
NTSTATUS WaitU0 (_In_ Port *P)
 
VOID SuspendPort (_In_ Port *P)
 
VOID ResuspendResumedPorts ()
 
BOOLEAN IsPortConnected (_In_ const Port *P) const
 
Outcome CheckRunning ()
 
Outcome ClearHubFeature (_In_ PURB Urb)
 
Outcome GetHubStatus (_In_ PURB Urb)
 
Outcome GetPortStatus (_In_ PURB Urb)
 
Outcome ClearPortFeature (_In_ PURB Urb)
 
Outcome ClearUsb20PortFeature (_In_ Port *P, _In_ USHORT Feature, _In_ UCHAR Value)
 
Outcome ClearUsb30PortFeature (_In_ Port *P, _In_ USHORT Feature, _In_ UCHAR Value)
 
Outcome SetPortFeature (_In_ PURB Urb)
 
Outcome SetUsb20PortFeature (_In_ Port *P, _In_ USHORT Feature, _In_ UCHAR Value)
 
Outcome SetUsb30PortFeature (_In_ Port *P, _In_ USHORT Feature, _In_ UCHAR Value)
 
Outcome SetUsb30LinkState (_In_ Port *P, _In_ UCHAR LinkState)
 
Outcome GetPortErrorCount (_In_ PURB Urb)
 
Outcome InterruptTransfer (_In_ PURB Urb)
 
NTSTATUS FillSpeeds (_In_ const Port *P, _Inout_ PROOTHUB_30PORT_INFO_EX Entry) const
 

Static Private Member Functions

static XhciRootHub * FromUcx (_In_ UCXROOTHUB UcxRootHub)
 
static VOID CompleteHubRequest (_In_ WDFREQUEST Request, _In_ PURB Urb, _In_ Outcome Result)
 

Private Attributes

XhciController * m_Controller
 
UCXROOTHUB m_Ucx
 
Port * m_Ports
 
ULONG m_PortCount
 
ULONG m_DebugCapability
 
USHORT m_Usb20PortCount
 
USHORT m_Usb30PortCount
 
USHORT m_U1ExitLatency
 
USHORT m_U2ExitLatency
 
BOOLEAN m_AwaitingStatusRead
 
BOOLEAN m_PortScTunnelValid
 
ULONG m_FirstUsb30Port
 

Static Private Attributes

static EVT_UCX_ROOTHUB_CONTROL_URB EvtClearHubFeature
 
static EVT_UCX_ROOTHUB_CONTROL_URB EvtClearPortFeature
 
static EVT_UCX_ROOTHUB_CONTROL_URB EvtGetHubStatus
 
static EVT_UCX_ROOTHUB_CONTROL_URB EvtGetPortStatus
 
static EVT_UCX_ROOTHUB_CONTROL_URB EvtSetHubFeature
 
static EVT_UCX_ROOTHUB_CONTROL_URB EvtSetPortFeature
 
static EVT_UCX_ROOTHUB_CONTROL_URB EvtGetPortErrorCount
 
static EVT_UCX_ROOTHUB_INTERRUPT_TX EvtInterruptTransfer
 
static EVT_UCX_ROOTHUB_GET_INFO EvtGetInfo
 
static EVT_UCX_ROOTHUB_GET_20PORT_INFO EvtGet20PortInfo
 
static EVT_UCX_ROOTHUB_GET_30PORT_INFO EvtGet30PortInfo
 
static KDEFERRED_ROUTINE ResumeTimerDpc
 

Detailed Description

Root hub.

Definition at line 13 of file rootports.h.

Member Enumeration Documentation

◆ Outcome

How a hub class request completes.

Enumerator
Ok 
Stall 
Gone 
Halted 
OperationPending 

Definition at line 104 of file rootports.h.

Member Function Documentation

◆ AcknowledgeResume()

BOOLEAN XhciRootHub::AcknowledgeResume ( _In_ Port *  P,
_In_ BOOLEAN  PowerUp 
)
private

Acknowledges a device or power up resume (xHCI 4.15.2.1). TRUE means the change stays hidden from the hub until the link is back in U0.

Definition at line 582 of file rootports.cpp.

585{
587 ULONG PortSc;
588
589 if (P->Major == 0)
590 return FALSE;
591
592 KeAcquireSpinLock(&P->Lock, &OldIrql);
593
594 PortSc = ReadPortSc(P);
595 if (PortSc == XhciPortGone)
596 {
597 KeReleaseSpinLock(&P->Lock, OldIrql);
598 return FALSE;
599 }
600
601 if (P->Major == 3 &&
602 (PortSc & XHCI_PORTSC_PLC) &&
604 m_Controller->HasErrata(XhciErrata::PortWakeToU0BeforeSuspend))
605 {
606 /* Put back the U1/U2 timeouts WaitU0 zeroed */
610 P->U1Timeout | ((ULONG)P->U2Timeout << XHCI_PORTPMSC_U2_TIMEOUT_SHIFT));
611 }
612
613 if (XhciLinkState(PortSc) != XHCI_PLS_RESUME ||
614 (!PowerUp && !(PortSc & XHCI_PORTSC_PLC)))
615 {
616 KeReleaseSpinLock(&P->Lock, OldIrql);
617 return FALSE;
618 }
619
620 if (P->ResumeHandled)
621 {
622 KeReleaseSpinLock(&P->Lock, OldIrql);
623 return TRUE;
624 }
625
626 P->ResumeHandled = TRUE;
627
628 if (P->Major == 2)
629 {
630 KeReleaseSpinLock(&P->Lock, OldIrql);
631 DPRINT1("Port %lu: USB 2.x device initiated resume\n", P->Number);
632
633 /* PLC stays set until the timer, so a power down in between still wakes */
635 return TRUE;
636 }
637
638 /* PLC rides along so it is cleared only if it was set */
640 KeReleaseSpinLock(&P->Lock, OldIrql);
641
642 DPRINT1("Port %lu: USB 3.x device initiated resume\n", P->Number);
643 return TRUE;
644}
#define DPRINT1
Definition: precomp.h:8
BOOLEAN HasErrata(_In_ XhciErrata Bit) const
Definition: hc.h:58
ULONG ReadPortSc(_In_ const Port *P) const
Definition: rootports.cpp:440
VOID StartResumeTimer(_In_ Port *P)
Definition: rootports.cpp:536
XhciController * m_Controller
Definition: rootports.h:243
VOID UpdatePortReg(_In_ Port *P, _In_ ULONG Offset, _In_ ULONG Clear, _In_ ULONG Set)
Definition: rootports.cpp:472
ULONG UpdatePortScLocked(_In_ Port *P, _In_ ULONG Keep, _In_ ULONG Set)
Definition: rootports.cpp:448
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define P(row, col)
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
static const ULONG XhciPortGone
Definition: rootports.cpp:54
FORCEINLINE ULONG NTAPI XhciLinkState(_In_ ULONG PortSc)
Definition: rootports.cpp:66
FORCEINLINE ULONG NTAPI XhciLinkWrite(_In_ ULONG State)
Definition: rootports.cpp:85
uint32_t ULONG
Definition: typedefs.h:59
#define PORT_LINK_STATE_U0
Definition: usb200.h:192
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
#define XHCI_PORTSC_PLC
Definition: xhcihw.h:226
#define XHCI_PORTPMSC_U2_TIMEOUT_MASK
Definition: xhcihw.h:249
#define XHCI_PORTPMSC_U2_TIMEOUT_SHIFT
Definition: xhcihw.h:248
#define XHCI_PORTPMSC_U1_TIMEOUT_MASK
Definition: xhcihw.h:247
#define XHCI_PORTSC_PRESERVE
Definition: xhcihw.h:235
#define XHCI_PLS_RESUME
Definition: xhcihw.h:238
#define XHCI_PORT_PMSC
Definition: xhcihw.h:204

Referenced by OnPortStatusChangeEvent(), and PostInterruptsEntry().

◆ ArmPortResumeTimer()

VOID XhciRootHub::ArmPortResumeTimer ( _In_ ULONG  PortNumber,
_In_ ULONG  Milliseconds 
)

Definition at line 1140 of file rootports.cpp.

1143{
1144 Port* P = PortAt(PortNumber);
1145
1146 if (P == NULL)
1147 return;
1148
1149 XhciSpinLockGuard Guard(&P->Lock);
1150
1151 P->ResumeOverrideMs = Milliseconds;
1152 P->ResumeOverrideCount++;
1153}
Port * PortAt(_In_ ULONG PortNumber) const
Definition: rootports.cpp:430
#define NULL
Definition: types.h:112
CPPORT Port[4]
Definition: headless.c:38
_In_ ULONG PortNumber
Definition: hubucx.h:272

Referenced by XhciUsbDevice::ApplyUpdate().

◆ CheckRunning()

XhciRootHub::Outcome XhciRootHub::CheckRunning ( )
private

PORTSC writes need a running controller (xHCI 5.4.8).

Definition at line 1215 of file rootports.cpp.

1216{
1218
1219 if (Status == XhciPortGone)
1220 {
1221 DPRINT1("Root hub port feature: USBSTS reads all ones, controller gone\n");
1223 return Outcome::Gone;
1224 }
1225
1226 if (Status & XHCI_USBSTS_HCH)
1227 {
1228 DPRINT1("Root hub port feature: controller halted, USBSTS 0x%08lx\n", Status);
1229 return Outcome::Halted;
1230 }
1231
1232 return Outcome::Ok;
1233}
XhciRegisters m_Registers
Definition: hc.h:91
VOID MarkGone()
Definition: hc.cpp:1924
ULONG ReadOperational32(_In_ ULONG Offset) const
Definition: mmio.cpp:431
Status
Definition: gdiplustypes.h:24
#define XHCI_OP_USBSTS
Definition: xhcihw.h:382
#define XHCI_USBSTS_HCH
Definition: xhcihw.h:401

Referenced by ClearPortFeature(), and SetPortFeature().

◆ ClearHubFeature()

XhciRootHub::Outcome XhciRootHub::ClearHubFeature ( _In_ PURB  Urb)
private

Definition at line 1236 of file rootports.cpp.

1238{
1240
1241 if (Setup->bmRequestType.B == HubRequestToHub &&
1242 Setup->bRequest == USB_REQUEST_CLEAR_FEATURE &&
1243 Setup->wIndex.W == 0 &&
1244 Setup->wLength == 0 &&
1246 {
1247 return Outcome::Ok;
1248 }
1249
1250 XhciTraceBadRequest("ClearHubFeature", Urb);
1251 return Outcome::Stall;
1252}
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn UINT32 *TableIdx UINT32 ACPI_TABLE_HEADER *OutTableHeader ACPI_TABLE_HEADER **OutTable ACPI_HANDLE UINT32 ACPI_WALK_CALLBACK ACPI_WALK_CALLBACK void void **ReturnValue UINT32 ACPI_BUFFER *RetPathPtr ACPI_OBJECT_HANDLER void *Data ACPI_OBJECT_HANDLER void **Data ACPI_STRING ACPI_OBJECT_LIST ACPI_BUFFER *ReturnObjectBuffer ACPI_DEVICE_INFO **ReturnBuffer ACPI_HANDLE ACPI_HANDLE ACPI_HANDLE *OutHandle ACPI_HANDLE *OutHandle void *Context void *Context ACPI_EVENT_HANDLER Handler UINT32 UINT32 ACPI_GPE_HANDLER void *Context UINT32 ACPI_NOTIFY_HANDLER void *Context ACPI_ADR_SPACE_TYPE ACPI_ADR_SPACE_HANDLER ACPI_ADR_SPACE_SETUP Setup
Definition: acpixf.h:834
FORCEINLINE PUSB_DEFAULT_PIPE_SETUP_PACKET NTAPI XhciSetupOf(_In_ PURB Urb)
Definition: rootports.cpp:122
static VOID NTAPI XhciTraceBadRequest(_In_ PCSTR Callback, _In_ PURB Urb)
Definition: rootports.cpp:166
@ FeatureHubOverCurrentChange
Definition: rootports.cpp:23
@ FeatureHubLocalPowerChange
Definition: rootports.cpp:22
static const UCHAR HubRequestToHub
Definition: rootports.cpp:15
#define USB_REQUEST_CLEAR_FEATURE
Definition: usb100.h:79
_In_opt_ PUSB_CONFIGURATION_DESCRIPTOR _Inout_ PUSBD_INTERFACE_LIST_ENTRY _Outptr_ PURB * Urb
Definition: usbdlib.h:333

◆ ClearPortFeature()

XhciRootHub::Outcome XhciRootHub::ClearPortFeature ( _In_ PURB  Urb)
private

Definition at line 1421 of file rootports.cpp.

1423{
1426 Port* P;
1427
1428 if (!m_Controller->IsAccessible())
1429 {
1430 DPRINT1("ClearPortFeature: controller not accessible\n");
1431 return Outcome::Gone;
1432 }
1433
1434 Result = CheckRunning();
1435 if (Result != Outcome::Ok)
1436 return Result;
1437
1438 P = PortAt(Setup->wIndex.LowByte);
1439 if (Setup->bmRequestType.B != HubRequestToPort ||
1440 Setup->bRequest != USB_REQUEST_CLEAR_FEATURE ||
1441 P == NULL ||
1442 Setup->wLength != 0)
1443 {
1444 XhciTraceBadRequest("ClearPortFeature", Urb);
1445 return Outcome::Stall;
1446 }
1447
1448 if (P->Major == 2)
1449 Result = ClearUsb20PortFeature(P, Setup->wValue.W, Setup->wIndex.HiByte);
1450 else if (P->Major == 3)
1451 Result = ClearUsb30PortFeature(P, Setup->wValue.W, Setup->wIndex.HiByte);
1452 else
1454
1455 if (Result == Outcome::Stall)
1456 XhciTraceBadRequest("ClearPortFeature", Urb);
1457
1458 return Result;
1459}
BOOLEAN IsAccessible() const
Definition: hc.cpp:193
Outcome ClearUsb20PortFeature(_In_ Port *P, _In_ USHORT Feature, _In_ UCHAR Value)
Definition: rootports.cpp:1462
Outcome ClearUsb30PortFeature(_In_ Port *P, _In_ USHORT Feature, _In_ UCHAR Value)
Definition: rootports.cpp:1546
Outcome CheckRunning()
Definition: rootports.cpp:1215
static const UCHAR HubRequestToPort
Definition: rootports.cpp:17
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409

◆ ClearUsb20LpmLocked()

VOID XhciRootHub::ClearUsb20LpmLocked ( _In_ Port *  P)
private

Definition at line 486 of file rootports.cpp.

488{
493 0);
497 0);
498 P->LpmDirty = FALSE;
499}
#define XHCI_PORTPMSC_HLE
Definition: xhcihw.h:258
#define XHCI_PORTHLPMC_L1_TIMEOUT_MASK
Definition: xhcihw.h:272
#define XHCI_PORTPMSC_L1_SLOT_MASK
Definition: xhcihw.h:257
#define XHCI_PORTPMSC_BESL_MASK
Definition: xhcihw.h:255
#define XHCI_PORTHLPMC_BESLD_MASK
Definition: xhcihw.h:274
#define XHCI_PORTHLPMC_HIRDM_MASK
Definition: xhcihw.h:270
#define XHCI_PORTPMSC_RWE
Definition: xhcihw.h:253
#define XHCI_PORT_HLPMC
Definition: xhcihw.h:206

Referenced by DisableLpmForSlot(), and SetUsb20PortFeature().

◆ ClearUsb20PortFeature()

XhciRootHub::Outcome XhciRootHub::ClearUsb20PortFeature ( _In_ Port *  P,
_In_ USHORT  Feature,
_In_ UCHAR  Value 
)
private

Definition at line 1462 of file rootports.cpp.

1466{
1467 ULONG PortSc;
1468
1469 if (Value != 0 && Feature != FeaturePortIndicator)
1470 return Outcome::Stall;
1471
1472 switch (Feature)
1473 {
1474 case FeaturePortEnable:
1475 if (m_Controller->HasErrata(XhciErrata::PortHighSpeedDisableSuspends))
1476 {
1477 XhciSpinLockGuard Guard(&P->Lock);
1478
1480 if (!(PortSc & XHCI_PORTSC_PED) || XhciLinkState(PortSc) >= PORT_LINK_STATE_U3)
1481 DPRINT1("Port %lu: disable mapped to suspend with PORTSC 0x%08lx\n", P->Number, PortSc);
1482 }
1483 else
1484 {
1486 }
1487 return Outcome::Ok;
1488
1489 case FeaturePortSuspend:
1490 {
1491 /* Host initiated resume (xHCI 4.15.2.2) */
1492 if (!NT_SUCCESS(WaitForU3(P, FALSE)))
1493 return Outcome::Stall;
1494
1495 {
1496 XhciSpinLockGuard Guard(&P->Lock);
1497 ULONG Link;
1498
1500 Link = XhciLinkState(PortSc);
1501 if (!(PortSc & XHCI_PORTSC_PED) || (Link != PORT_LINK_STATE_U3 && Link != XHCI_PLS_RESUME))
1502 DPRINT1("Port %lu: resume requested with PORTSC 0x%08lx\n", P->Number, PortSc);
1503 }
1504
1506 return Outcome::Ok;
1507 }
1508
1509 case FeaturePortPower:
1511 return Outcome::Ok;
1512
1514 if (Value > 3)
1515 return Outcome::Stall;
1516
1518 return Outcome::Ok;
1519
1522 return Outcome::Ok;
1523
1526 return Outcome::Ok;
1527
1530 return Outcome::Ok;
1531
1534 return Outcome::Ok;
1535
1536 case FeatureResetChange:
1538 return Outcome::Ok;
1539
1540 default:
1541 return Outcome::Stall;
1542 }
1543}
_In_ ULONG const _In_ FEATURE_NUMBER const Feature
Definition: cdrom.h:1077
NTSTATUS WaitForU3(_In_ Port *P, _In_ BOOLEAN RepeatRequest)
Definition: rootports.cpp:650
ULONG UpdatePortSc(_In_ Port *P, _In_ ULONG Keep, _In_ ULONG Set)
Definition: rootports.cpp:460
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
@ FeatureEnableChange
Definition: rootports.cpp:30
@ FeatureOverCurrentChange
Definition: rootports.cpp:32
@ FeaturePortEnable
Definition: rootports.cpp:24
@ FeaturePortPower
Definition: rootports.cpp:28
@ FeaturePortIndicator
Definition: rootports.cpp:35
@ FeatureConnectChange
Definition: rootports.cpp:29
@ FeaturePortSuspend
Definition: rootports.cpp:25
@ FeatureResetChange
Definition: rootports.cpp:33
@ FeatureSuspendChange
Definition: rootports.cpp:31
#define PORT_LINK_STATE_U3
Definition: usb200.h:195
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
#define XHCI_PORTSC_PP
Definition: xhcihw.h:215
#define XHCI_PORTSC_CSC
Definition: xhcihw.h:221
#define XHCI_PORTSC_WAKE_MASK
Definition: xhcihw.h:230
#define XHCI_PORTSC_OCC
Definition: xhcihw.h:224
#define XHCI_PORTSC_PED
Definition: xhcihw.h:210
#define XHCI_PORTSC_PRC
Definition: xhcihw.h:225
#define XHCI_PORTSC_PIC_MASK
Definition: xhcihw.h:219
#define XHCI_PORTSC_PEC
Definition: xhcihw.h:222

Referenced by ClearPortFeature().

◆ ClearUsb30PortFeature()

XhciRootHub::Outcome XhciRootHub::ClearUsb30PortFeature ( _In_ Port *  P,
_In_ USHORT  Feature,
_In_ UCHAR  Value 
)
private

Definition at line 1546 of file rootports.cpp.

1550{
1551 ULONG ChangeBit;
1552
1553 if (Value != 0)
1554 return Outcome::Stall;
1555
1556 switch (Feature)
1557 {
1558 case FeaturePortPower:
1560 return Outcome::Ok;
1561
1563 {
1564 XhciSpinLockGuard Guard(&P->Lock);
1565
1567 return Outcome::Ok;
1568 }
1569
1571 ChangeBit = XHCI_PORTSC_CSC;
1572 break;
1573
1575 ChangeBit = XHCI_PORTSC_OCC;
1576 break;
1577
1578 case FeatureResetChange:
1579 ChangeBit = XHCI_PORTSC_PRC;
1580 break;
1581
1583 ChangeBit = XHCI_PORTSC_PLC;
1584 break;
1585
1587 ChangeBit = XHCI_PORTSC_CEC;
1588 break;
1589
1591 ChangeBit = XHCI_PORTSC_WRC;
1592 break;
1593
1594 default:
1595 return Outcome::Stall;
1596 }
1597
1598 UpdatePortSc(P, XHCI_PORTSC_PRESERVE, ChangeBit);
1599 return Outcome::Ok;
1600}
@ FeatureWarmResetChange
Definition: rootports.cpp:42
@ FeatureConfigErrorChange
Definition: rootports.cpp:39
@ FeatureForceLinkPmAccept
Definition: rootports.cpp:43
@ FeatureLinkStateChange
Definition: rootports.cpp:38
#define XHCI_PORTSC_WRC
Definition: xhcihw.h:223
#define XHCI_PORTPMSC_FLA
Definition: xhcihw.h:250
#define XHCI_PORTSC_CEC
Definition: xhcihw.h:227

Referenced by ClearPortFeature().

◆ CompleteHubRequest()

VOID XhciRootHub::CompleteHubRequest ( _In_ WDFREQUEST  Request,
_In_ PURB  Urb,
_In_ Outcome  Result 
)
staticprivate

Definition at line 1172 of file rootports.cpp.

1176{
1179
1180 switch (Result)
1181 {
1182 case Outcome::Ok:
1185 break;
1186
1190 break;
1191
1192 case Outcome::Gone:
1195 break;
1196
1197 case Outcome::Halted:
1200 break;
1201
1202 case Outcome::Stall:
1203 default:
1206 break;
1207 }
1208
1209 Urb->UrbHeader.Status = UsbdStatus;
1210 WdfRequestComplete(Request, Status);
1211}
LONG NTSTATUS
Definition: precomp.h:26
#define STATUS_ADAPTER_HARDWARE_ERROR
Definition: ntstatus.h:524
#define STATUS_SUCCESS
Definition: shellext.h:65
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST Request
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define USBD_STATUS_DEVICE_GONE
Definition: usb.h:222
#define USBD_STATUS_STALL_PID
Definition: usb.h:183
#define USBD_STATUS_SUCCESS
Definition: usb.h:177
#define USBD_STATUS_PORT_OPERATION_PENDING
Definition: usb.h:178
#define USBD_STATUS_XACT_ERROR
Definition: usb.h:195
LONG USBD_STATUS
Definition: usb.h:172
_In_ NTSTATUS _In_ USBD_STATUS UsbdStatus
Definition: wdfusb.h:403

◆ Create()

NTSTATUS XhciRootHub::Create ( _In_ XhciController *  Controller)

Creates the UCXROOTHUB with every callback.

Definition at line 186 of file rootports.cpp.

188{
191 UCXROOTHUB Handle;
193
195 m_Ucx = NULL;
196 m_Ports = NULL;
197 m_PortCount = 0;
202
215
216 /* UCX gives this context to every request it sends down for the root hub and its devices */
218
220
221 Status = UcxRootHubCreate(Controller->m_Ucx, &Config, &Attributes, &Handle);
222 if (!NT_SUCCESS(Status))
223 {
224 DPRINT1("UcxRootHubCreate failed 0x%lx\n", Status);
225 return Status;
226 }
227
228 XhciGetRootHubContext(Handle)->RootHub = this;
229 m_Ucx = Handle;
230 return STATUS_SUCCESS;
231}
static EVT_UCX_ROOTHUB_INTERRUPT_TX EvtInterruptTransfer
Definition: rootports.h:120
USHORT m_Usb30PortCount
Definition: rootports.h:249
ULONG m_DebugCapability
Definition: rootports.h:247
ULONG m_PortCount
Definition: rootports.h:246
USHORT m_Usb20PortCount
Definition: rootports.h:248
BOOLEAN m_AwaitingStatusRead
Definition: rootports.h:252
UCXROOTHUB m_Ucx
Definition: rootports.h:244
Port * m_Ports
Definition: rootports.h:245
static EVT_UCX_ROOTHUB_CONTROL_URB EvtClearPortFeature
Definition: rootports.h:114
static EVT_UCX_ROOTHUB_CONTROL_URB EvtGetPortErrorCount
Definition: rootports.h:119
static EVT_UCX_ROOTHUB_GET_20PORT_INFO EvtGet20PortInfo
Definition: rootports.h:122
static EVT_UCX_ROOTHUB_CONTROL_URB EvtSetHubFeature
Definition: rootports.h:117
static EVT_UCX_ROOTHUB_GET_30PORT_INFO EvtGet30PortInfo
Definition: rootports.h:123
static EVT_UCX_ROOTHUB_CONTROL_URB EvtGetHubStatus
Definition: rootports.h:115
static EVT_UCX_ROOTHUB_CONTROL_URB EvtSetPortFeature
Definition: rootports.h:118
static EVT_UCX_ROOTHUB_CONTROL_URB EvtClearHubFeature
Definition: rootports.h:113
static EVT_UCX_ROOTHUB_CONTROL_URB EvtGetPortStatus
Definition: rootports.h:116
static EVT_UCX_ROOTHUB_GET_INFO EvtGetInfo
Definition: rootports.h:121
_In_ ULONG Attributes
Definition: dispmprt.h:1077
ULONG Handle
Definition: gdb_input.c:15
_Must_inspect_result_ _In_ WDFDEVICE _In_ PUCX_CONTROLLER_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ UCXCONTROLLER * Controller
_Must_inspect_result_ _In_ WDFDEVICE _In_ PUCX_CONTROLLER_CONFIG Config
FORCEINLINE VOID NTAPI UCX_ROOTHUB_CONFIG_INIT(_Out_ PUCX_ROOTHUB_CONFIG Config, _In_ PFN_UCX_ROOTHUB_CONTROL_URB EvtRootHubClearHubFeature, _In_ PFN_UCX_ROOTHUB_CONTROL_URB EvtRootHubClearPortFeature, _In_ PFN_UCX_ROOTHUB_CONTROL_URB EvtRootHubGetHubStatus, _In_ PFN_UCX_ROOTHUB_CONTROL_URB EvtRootHubGetPortStatus, _In_ PFN_UCX_ROOTHUB_CONTROL_URB EvtRootHubSetHubFeature, _In_ PFN_UCX_ROOTHUB_CONTROL_URB EvtRootHubSetPortFeature, _In_ PFN_UCX_ROOTHUB_CONTROL_URB EvtRootHubGetPortErrorCount, _In_ PFN_UCX_ROOTHUB_INTERRUPT_TX EvtRootHubInterruptTx, _In_ PFN_UCX_ROOTHUB_GET_INFO EvtRootHubGetInfo, _In_ PFN_UCX_ROOTHUB_GET_20PORT_INFO EvtRootHubGet20PortInfo, _In_ PFN_UCX_ROOTHUB_GET_30PORT_INFO EvtRootHubGet30PortInfo)
Definition: ucxroothub.h:252
#define WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(_attributes, _contexttype)
Definition: wdfobject.h:170

Referenced by XhciController::Initialize().

◆ D0Entry()

VOID XhciRootHub::D0Entry ( )

Definition at line 844 of file rootports.cpp.

845{
847
849
850 for (Number = 1; Number <= m_PortCount; Number++)
851 {
852 Port* P = &m_Ports[Number - 1];
853
854 if (P->Major == 0)
855 {
856 DPRINT1("Port %lu has no USB protocol, skipped at D0 entry\n", Number);
857 continue;
858 }
859
860 /* Some controllers miss connect and disconnect in D0 without the wake enables */
861 if (m_Controller->HasErrata(XhciErrata::PortHoldWakeMaskAwake))
863 }
864}
_In_ ULONG Number
Definition: haltypes.h:1940

Referenced by XhciController::D0Entry(), and PostReset().

◆ D0Exit()

VOID XhciRootHub::D0Exit ( )

Definition at line 877 of file rootports.cpp.

878{
881 BOOLEAN SystemPoweringDown = (Action >= XhciController::SystemAction::Sleep &&
884 BOOLEAN AnyConnected = FALSE;
886
888
889 for (Number = 1; Number <= m_PortCount; Number++)
890 {
891 Port* P = &m_Ports[Number - 1];
892
893 if (!FinalPowerOff)
894 {
895 /* Let the hub recover the port instead of leaving a dead device behind */
896 if (!NT_SUCCESS(WaitForU3(P, FALSE)) && S0Idle)
897 UcxRootHubPortChanged(m_Ucx);
898
899 if (IsPortConnected(P))
900 AnyConnected = TRUE;
901 }
902
903 if (m_Controller->HasErrata(XhciErrata::PortAckCscOnPowerDown))
905
906 if (SystemPoweringDown && m_Controller->HasErrata(XhciErrata::PortHoldWakeMaskAwake))
908 }
909
910 m_Controller->NotifyPortConnectState(AnyConnected);
911}
unsigned char BOOLEAN
Definition: actypes.h:127
WDF_POWER_DEVICE_STATE m_PowerState
Definition: hc.h:117
SystemAction
Definition: hc.h:121
SystemAction m_SystemAction
Definition: hc.h:131
VOID ResuspendResumedPorts()
Definition: rootports.cpp:775
BOOLEAN IsPortConnected(_In_ const Port *P) const
Definition: rootports.cpp:519
@ WdfPowerDeviceD3Final
Definition: wdfdevice.h:427
_In_ WDFIOTARGET _In_ _Strict_type_match_ WDF_IO_TARGET_SENT_IO_ACTION Action
Definition: wdfiotarget.h:510

Referenced by XhciController::D0Exit().

◆ DisableLpmForSlot()

VOID XhciRootHub::DisableLpmForSlot ( _In_ ULONG  PortNumber,
_In_ ULONG  SlotId 
)

Definition at line 1118 of file rootports.cpp.

1121{
1122 Port* P = PortAt(PortNumber);
1123 ULONG Owner;
1124
1125 if (P == NULL)
1126 return;
1127
1128 XhciSpinLockGuard Guard(&P->Lock);
1129
1130 if (!P->LpmDirty)
1131 return;
1132
1133 /* The port may already belong to a newer device */
1137}
ULONG ReadPort32(_In_ ULONG Port, _In_ ULONG Offset) const
Definition: mmio.cpp:516
VOID ClearUsb20LpmLocked(_In_ Port *P)
Definition: rootports.cpp:486
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1629
#define XHCI_PORTPMSC_L1_SLOT_SHIFT
Definition: xhcihw.h:256

Referenced by XhciUsbDevice::Disable().

◆ DisarmPortResumeTimer()

VOID XhciRootHub::DisarmPortResumeTimer ( _In_ ULONG  PortNumber)

Definition at line 1156 of file rootports.cpp.

1158{
1159 Port* P = PortAt(PortNumber);
1160
1161 if (P == NULL)
1162 return;
1163
1164 XhciSpinLockGuard Guard(&P->Lock);
1165
1166 P->ResumeOverrideCount--;
1167}

Referenced by XhciUsbDevice::Disable().

◆ FillSpeeds()

NTSTATUS XhciRootHub::FillSpeeds ( _In_ const Port *  P,
_Inout_ PROOTHUB_30PORT_INFO_EX  Entry 
) const
private

Sublink speed list of a 3.x port from its PSI table. Entries past the caller's capacity are counted but not written.

Definition at line 1991 of file rootports.cpp.

1994{
1995 XhciRegisters* Registers = &m_Controller->m_Registers;
1997 ULONG SeenIds = 0;
1998 ULONG Index;
1999
2000 List.Speeds = Entry->Speeds;
2001 List.Capacity = (Entry->Speeds != NULL) ? Entry->MaxSpeedsCount : 0;
2002 List.Count = 0;
2003 List.Minor = P->Minor;
2004
2005 for (Index = 0; Index < P->SpeedCount; Index++)
2006 {
2007 ULONG Psi = Registers->ReadExtended32(P->SpeedTable + Index * sizeof(ULONG));
2008 ULONG Id = Psi & XHCI_PSI_ID_MASK;
2010 ULONG Mantissa = Psi >> XHCI_PSI_MANTISSA_SHIFT;
2011 ULONG Next;
2012
2013 if (SeenIds & (1UL << Id))
2014 {
2015 DPRINT1("Port %lu: speed ID %lu listed twice\n", P->Number, Id);
2017 }
2018 SeenIds |= 1UL << Id;
2019
2020 switch ((Psi & XHCI_PSI_TYPE_MASK) >> XHCI_PSI_TYPE_SHIFT)
2021 {
2023 XhciAddSpeed(&List, Id, Exponent, Mantissa, 0, 0);
2024 XhciAddSpeed(&List, Id, Exponent, Mantissa, 0, 1);
2025 break;
2026
2028 XhciAddSpeed(&List, Id, Exponent, Mantissa, 1, 0);
2029
2030 if (++Index >= P->SpeedCount)
2031 {
2032 DPRINT1("Port %lu: speed ID %lu has RX but no TX entry\n", P->Number, Id);
2034 }
2035
2036 Next = Registers->ReadExtended32(P->SpeedTable + Index * sizeof(ULONG));
2037 if ((Next & XHCI_PSI_ID_MASK) != Id ||
2039 {
2040 DPRINT1("Port %lu: speed ID %lu RX entry followed by 0x%08lx\n", P->Number, Id, Next);
2042 }
2043
2047 1,
2048 1);
2049 break;
2050
2052 DPRINT1("Port %lu: speed ID %lu TX entry without RX\n", P->Number, Id);
2054
2055 default:
2056 /* Reserved type, nothing reported */
2057 break;
2058 }
2059 }
2060
2061 /*
2062 * Default 5 Gb/s and 10 Gb/s pairs. The gates test the ID bitmask against
2063 * the raw IDs instead of their bits, so both pairs are nearly always added.
2064 */
2065 if ((SeenIds & 4) == 0)
2066 {
2067 XhciAddSpeed(&List, 4, 3, 5, 0, 0);
2068 XhciAddSpeed(&List, 4, 3, 5, 0, 1);
2069 }
2070 if ((SeenIds & 5) == 0)
2071 {
2072 XhciAddSpeed(&List, 5, 3, 10, 0, 0);
2073 XhciAddSpeed(&List, 5, 3, 10, 0, 1);
2074 }
2075
2076 Entry->SpeedsCount = List.Count;
2077 return STATUS_SUCCESS;
2078}
DWORD Id
ULONG ReadExtended32(_In_ ULONG Offset) const
Definition: mmio.cpp:319
PLIST_ENTRY Entry
Definition: devhcd.cpp:1262
static VOID NTAPI XhciAddSpeed(_Inout_ PXHCI_SPEED_LIST List, _In_ ULONG Id, _In_ ULONG Exponent, _In_ ULONG Mantissa, _In_ ULONG Mode, _In_ ULONG Direction)
Definition: rootports.cpp:1962
PACPI_METHOD_ARGUMENT Next
Definition: slotdev.cpp:96
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
for(Attempt=0;Attempt< UCX_LEGACY_NAME_ATTEMPTS;Attempt++)
Definition: userreq.cpp:715
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
#define XHCI_PSI_TYPE_MASK
Definition: xhcihw.h:303
#define XHCI_PSI_TYPE_ASYMMETRIC_RX
Definition: xhcihw.h:307
#define XHCI_PSI_TYPE_ASYMMETRIC_TX
Definition: xhcihw.h:308
#define XHCI_PSI_MANTISSA_SHIFT
Definition: xhcihw.h:304
#define XHCI_PSI_TYPE_SYMMETRIC
Definition: xhcihw.h:306
#define XHCI_PSI_ID_MASK
Definition: xhcihw.h:299
#define XHCI_PSI_TYPE_SHIFT
Definition: xhcihw.h:302
#define XHCI_PSI_EXPONENT_MASK
Definition: xhcihw.h:301
#define XHCI_PSI_EXPONENT_SHIFT
Definition: xhcihw.h:300

◆ FromUcx()

XhciRootHub * XhciRootHub::FromUcx ( _In_ UCXROOTHUB  UcxRootHub)
staticprivate

Definition at line 179 of file rootports.cpp.

181{
182 return XhciGetRootHubContext(UcxRootHub)->RootHub;
183}

◆ GetHubStatus()

XhciRootHub::Outcome XhciRootHub::GetHubStatus ( _In_ PURB  Urb)
private

Definition at line 1255 of file rootports.cpp.

1257{
1259 PULONG Buffer;
1260
1261 if (Setup->bmRequestType.B != HubRequestFromHub ||
1262 Setup->bRequest != USB_REQUEST_GET_STATUS ||
1263 Setup->wValue.W != 0 ||
1264 Setup->wIndex.W != 0 ||
1265 Setup->wLength != sizeof(*Buffer))
1266 {
1267 XhciTraceBadRequest("GetHubStatus", Urb);
1268 return Outcome::Stall;
1269 }
1270
1272 if (Buffer == NULL)
1273 {
1274 XhciTraceBadRequest("GetHubStatus buffer", Urb);
1275 return Outcome::Stall;
1276 }
1277
1278 /* No local power or over current status, no changes */
1279 *Buffer = 0;
1280 return Outcome::Ok;
1281}
Definition: bufpool.h:45
static const UCHAR HubRequestFromHub
Definition: rootports.cpp:16
static PVOID NTAPI XhciHubRequestBuffer(_In_ PURB Urb, _In_ ULONG Needed)
Definition: rootports.cpp:151
uint32_t * PULONG
Definition: typedefs.h:59
#define USB_REQUEST_GET_STATUS
Definition: usb100.h:78

◆ GetPortErrorCount()

XhciRootHub::Outcome XhciRootHub::GetPortErrorCount ( _In_ PURB  Urb)
private

Definition at line 1826 of file rootports.cpp.

1828{
1831 ULONG Errors;
1832 Port* P;
1833
1834 if (!m_Controller->IsAccessible())
1835 {
1836 DPRINT("GetPortErrorCount: controller not accessible\n");
1837 return Outcome::Gone;
1838 }
1839
1840 /* UCX only routes 0x80 here, so this check fails every request it sends */
1841 P = PortAt(Setup->wIndex.W);
1842 if (Setup->bmRequestType.B != HubRequestFromPort ||
1844 Setup->wValue.W != 0 ||
1845 P == NULL ||
1846 Setup->wLength != sizeof(*Buffer) ||
1847 P->Major != 3)
1848 {
1849 XhciTraceBadRequest("GetPortErrorCount", Urb);
1850 return Outcome::Stall;
1851 }
1852
1854 if (Buffer == NULL)
1855 {
1856 XhciTraceBadRequest("GetPortErrorCount buffer", Urb);
1857 return Outcome::Stall;
1858 }
1859
1861 if (Errors > 10)
1862 DPRINT1("Port %lu: %lu link errors\n", P->Number, Errors);
1863
1864 *Buffer = (USHORT)Errors;
1865 return Outcome::Ok;
1866}
static const struct token_string Errors[]
Definition: error.c:43
unsigned short USHORT
Definition: pedump.c:61
static const UCHAR HubRequestFromPort
Definition: rootports.cpp:18
#define DPRINT
Definition: sndvol32.h:73
uint16_t * PUSHORT
Definition: typedefs.h:56
#define USB_REQUEST_GET_PORT_ERR_COUNT
Definition: usb200.h:289
#define XHCI_PORTLI_ERROR_COUNT_MASK
Definition: xhcihw.h:263
#define XHCI_PORT_LI
Definition: xhcihw.h:205

◆ GetPortStatus()

XhciRootHub::Outcome XhciRootHub::GetPortStatus ( _In_ PURB  Urb)
private

Definition at line 1284 of file rootports.cpp.

1286{
1289 BOOLEAN Extended;
1290 ULONG Length;
1291 ULONG PortSc;
1292 ULONG Link;
1293 Port* P;
1294
1295 if (!m_Controller->IsAccessible())
1296 {
1297 DPRINT1("GetPortStatus: controller not accessible\n");
1298 return Outcome::Gone;
1299 }
1300
1301 Extended = (Setup->wValue.W == USB_STATUS_EXT_PORT_STATUS);
1302 Length = Extended ? sizeof(Out->AsUlong64) : sizeof(Out->PortStatusChange);
1303 P = PortAt(Setup->wIndex.W);
1304
1305 if (Setup->bmRequestType.B != HubRequestFromPort ||
1306 Setup->bRequest != USB_REQUEST_GET_STATUS ||
1307 (Setup->wValue.W != USB_STATUS_PORT_STATUS && !Extended) ||
1308 P == NULL ||
1309 Setup->wLength != Length ||
1310 !((P->Major == 2 && !Extended) || P->Major == 3))
1311 {
1312 XhciTraceBadRequest("GetPortStatus", Urb);
1313 return Outcome::Stall;
1314 }
1315
1317 if (Out == NULL)
1318 {
1319 XhciTraceBadRequest("GetPortStatus buffer", Urb);
1320 return Outcome::Stall;
1321 }
1322
1323 PortSc = ReadPortSc(P);
1324 if (PortSc == XhciPortGone)
1325 {
1326 DPRINT1("GetPortStatus: port %lu PORTSC reads all ones\n", P->Number);
1328 return Outcome::Gone;
1329 }
1330
1331 Out->PortStatusChange.AsUlong32 = 0;
1332 Link = XhciLinkState(PortSc);
1333
1334 if (P->Major == 2)
1335 {
1336 PUSB_20_PORT_STATUS Status = &Out->PortStatusChange.PortStatus.Usb20PortStatus;
1337 PUSB_20_PORT_CHANGE Change = &Out->PortStatusChange.PortChange.Usb20PortChange;
1338 ULONG Speed = XhciPortSpeed(PortSc);
1339
1340 Status->CurrentConnectStatus = (PortSc & XHCI_PORTSC_CCS) != 0;
1341 Status->PortEnabledDisabled = (PortSc & XHCI_PORTSC_PED) != 0;
1342 Status->Suspend = (Link == PORT_LINK_STATE_U3 || Link == XHCI_PLS_RESUME);
1343 Status->OverCurrent = (PortSc & XHCI_PORTSC_OCA) != 0;
1344 Status->Reset = (PortSc & XHCI_PORTSC_PR) != 0;
1345 Status->L1 = (Link == PORT_LINK_STATE_U2);
1346 Status->PortPower = (PortSc & XHCI_PORTSC_PP) != 0;
1347 Status->LowSpeedDeviceAttached = (Speed == XHCI_SPEED_LOW);
1348 Status->HighSpeedDeviceAttached = (Speed == XHCI_SPEED_HIGH);
1349 Status->PortIndicatorControl = (PortSc & XHCI_PORTSC_PIC_MASK) != 0;
1351 {
1352 DPRINT1("GetPortStatus: port %lu is in test mode\n", P->Number);
1353 Status->PortTestMode = 1;
1354 }
1355
1356 Change->ConnectStatusChange = (PortSc & XHCI_PORTSC_CSC) != 0;
1357 Change->PortEnableDisableChange = (PortSc & XHCI_PORTSC_PEC) != 0;
1358 Change->OverCurrentIndicatorChange = (PortSc & XHCI_PORTSC_OCC) != 0;
1359 Change->ResetChange = (PortSc & XHCI_PORTSC_PRC) != 0;
1360
1361 /* A resume this driver is still timing shows as suspended with no change yet */
1362 if (Link == XHCI_PLS_RESUME)
1364
1365 Change->SuspendChange = (PortSc & XHCI_PORTSC_PLC) != 0;
1366 return Outcome::Ok;
1367 }
1368
1369 PUSB_30_PORT_STATUS Status = &Out->PortStatusChange.PortStatus.Usb30PortStatus;
1370 PUSB_30_PORT_CHANGE Change = &Out->PortStatusChange.PortChange.Usb30PortChange;
1371
1372 if (IsHiddenDebugPort(P))
1373 {
1374 /* An empty powered port; the extended dword is left as the caller had it */
1375 Status->PortPower = 1;
1376 Status->PortLinkState = PORT_LINK_STATE_RX_DETECT;
1377 return Outcome::Ok;
1378 }
1379
1380 /* Resume is no hub link state; CAS means the device likely sits in Compliance */
1381 if (Link == XHCI_PLS_RESUME)
1383 if (PortSc & XHCI_PORTSC_CAS)
1385
1386 Status->CurrentConnectStatus = (PortSc & XHCI_PORTSC_CCS) != 0;
1387 Status->PortEnabledDisabled = (PortSc & XHCI_PORTSC_PED) != 0;
1388 Status->OverCurrent = (PortSc & XHCI_PORTSC_OCA) != 0;
1389 Status->Reset = (PortSc & XHCI_PORTSC_PR) != 0;
1390 Status->PortLinkState = Link;
1391 Status->PortPower = (PortSc & XHCI_PORTSC_PP) != 0;
1392
1393 Change->ConnectStatusChange = (PortSc & XHCI_PORTSC_CSC) != 0;
1394 Change->OverCurrentIndicatorChange = (PortSc & XHCI_PORTSC_OCC) != 0;
1395 Change->ResetChange = (PortSc & XHCI_PORTSC_PRC) != 0;
1396 Change->BHResetChange = (PortSc & XHCI_PORTSC_WRC) != 0;
1397 Change->PortLinkStateChange = (PortSc & XHCI_PORTSC_PLC) != 0;
1398 Change->PortConfigErrorChange = (PortSc & XHCI_PORTSC_CEC) != 0;
1399
1400 if (Extended)
1401 {
1402 PUSB_PORT_EXT_STATUS ExtStatus = &Out->PortExtStatus;
1403 ULONG LinkInfo = m_Controller->m_Registers.ReadPort32(P->Number, XHCI_PORT_LI);
1404 ULONG Speed = XhciPortSpeed(PortSc);
1405
1406 /* Without a PSI table, speed 1 on a 3.x port means the controller did not report it */
1407 if (P->SpeedCount == 0 && Speed == XHCI_SPEED_FULL)
1408 Speed = XHCI_SPEED_SUPER;
1409
1410 ExtStatus->AsUlong32 = 0;
1411 ExtStatus->RxSublinkSpeedID = Speed;
1412 ExtStatus->TxSublinkSpeedID = Speed;
1415 }
1416
1417 return Outcome::Ok;
1418}
USHORT Change
Definition: bootdev.cpp:133
BOOLEAN IsHiddenDebugPort(_In_ const Port *P) const
Definition: rootports.cpp:503
@ Out
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
FORCEINLINE ULONG NTAPI XhciPortSpeed(_In_ ULONG PortSc)
Definition: rootports.cpp:75
ULONG TxSublinkSpeedID
Definition: usb300.h:300
ULONG RxSublinkSpeedID
Definition: usb300.h:299
#define PORT_LINK_STATE_COMPLIANCE_MODE
Definition: usb200.h:202
#define PORT_LINK_STATE_RECOVERY
Definition: usb200.h:200
#define PORT_LINK_STATE_TEST_MODE
Definition: usb200.h:204
#define PORT_LINK_STATE_U2
Definition: usb200.h:194
#define PORT_LINK_STATE_RX_DETECT
Definition: usb200.h:197
#define USB_STATUS_EXT_PORT_STATUS
Definition: usb300.h:351
#define USB_STATUS_PORT_STATUS
Definition: usb300.h:349
union _USB_PORT_EXT_STATUS_AND_CHANGE * PUSB_PORT_EXT_STATUS_AND_CHANGE
#define XHCI_SPEED_LOW
Definition: xhcihw.h:242
#define XHCI_PORTLI_TX_LANES_SHIFT
Definition: xhcihw.h:266
#define XHCI_PORTSC_CCS
Definition: xhcihw.h:209
#define XHCI_PORTLI_RX_LANES_SHIFT
Definition: xhcihw.h:264
#define XHCI_PORTSC_PR
Definition: xhcihw.h:212
#define XHCI_SPEED_SUPER
Definition: xhcihw.h:244
#define XHCI_SPEED_HIGH
Definition: xhcihw.h:243
#define XHCI_PORTSC_CAS
Definition: xhcihw.h:228
#define XHCI_SPEED_FULL
Definition: xhcihw.h:241
#define XHCI_PORTSC_OCA
Definition: xhcihw.h:211
#define XHCI_PORTLI_TX_LANES_MASK
Definition: xhcihw.h:267
#define XHCI_PORTLI_RX_LANES_MASK
Definition: xhcihw.h:265

◆ HighestUsbVersion()

USHORT XhciRootHub::HighestUsbVersion ( ) const

BCD major in the high byte, minor in the low byte.

Definition at line 972 of file rootports.cpp.

973{
974 UCHAR Major = 0;
975 UCHAR Minor = 0;
976 ULONG Index;
977
978 for (Index = 0; Index < m_PortCount; Index++)
979 {
980 const Port* P = &m_Ports[Index];
981
982 /* A later port with the same major and a higher minor does not count */
983 if (P->Major > Major)
984 {
985 Major = P->Major;
986 if (P->Minor > Minor)
987 Minor = P->Minor;
988 }
989 }
990
991 return (USHORT)((Major << 8) | Minor);
992}
ULONG Minor
Definition: classlib.cpp:73
unsigned char UCHAR
Definition: typedefs.h:53

◆ InterruptTransfer()

XhciRootHub::Outcome XhciRootHub::InterruptTransfer ( _In_ PURB  Urb)
private

Answers at once with the change bitmap; UCX holds the next transfer until a port changes.

Definition at line 1870 of file rootports.cpp.

1872{
1873 struct _URB_BULK_OR_INTERRUPT_TRANSFER* Transfer = &Urb->UrbBulkOrInterruptTransfer;
1874 ULONG Length = Transfer->TransferBufferLength;
1875 PUCHAR Bitmap;
1876 ULONG Last;
1877 ULONG Number;
1878
1879 if (!m_Controller->IsAccessible())
1880 {
1881 DPRINT1("Status change transfer: controller not accessible\n");
1882 return Outcome::Gone;
1883 }
1884
1885 /* UCX has no callback for the root hub PDO reaching D0; this is the first sign of it */
1887 {
1888 m_Controller->OnRootHubD0Entry();
1890 }
1891
1892 if (Length == 0)
1893 return Outcome::Ok;
1894
1896 if (Bitmap == NULL)
1897 {
1898 DPRINT1("Status change transfer without a buffer\n");
1899 return Outcome::Stall;
1900 }
1901
1903
1904 Last = (Length > 32) ? 255 : (Length * 8 - 1);
1905 if (Last > m_PortCount)
1906 Last = m_PortCount;
1907
1908 for (Number = 1; Number <= Last; Number++)
1909 {
1910 Port* P = &m_Ports[Number - 1];
1911 ULONG Changes;
1912 ULONG PortSc;
1913
1914 if (P->Major == 0)
1915 continue;
1916
1917 PortSc = ReadPortSc(P);
1918 if (PortSc == XhciPortGone)
1919 {
1920 DPRINT1("Status change transfer: port %lu PORTSC reads all ones\n", Number);
1922 return Outcome::Gone;
1923 }
1924
1925 if (P->Major == 2)
1926 {
1927 Changes = PortSc & (XHCI_PORTSC_CSC | XHCI_PORTSC_PEC | XHCI_PORTSC_PLC |
1929
1930 /* This driver finishes a resume itself; its PLC is not for the hub */
1931 if (XhciLinkState(PortSc) == XHCI_PLS_RESUME)
1932 Changes &= ~XHCI_PORTSC_PLC;
1933 }
1934 else
1935 {
1936 Changes = PortSc & (XHCI_PORTSC_CSC | XHCI_PORTSC_OCC | XHCI_PORTSC_PRC |
1938
1939 if (Changes != 0 && IsHiddenDebugPort(P))
1940 Changes = 0;
1941 }
1942
1943 if (Changes != 0)
1944 Bitmap[Number / 8] |= (UCHAR)(1 << (Number % 8));
1945 }
1946
1947 return Outcome::Ok;
1948}
static PVOID NTAPI XhciTransferBuffer(_In_opt_ PVOID Buffer, _In_opt_ PMDL Mdl, _In_ ULONG Length, _In_ ULONG Needed)
Definition: rootports.cpp:133
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
unsigned char * PUCHAR
Definition: typedefs.h:53

◆ IsHiddenDebugPort()

BOOLEAN XhciRootHub::IsHiddenDebugPort ( _In_ const Port *  P) const
private

The kernel debugger owns this 3.x port through the Debug Capability.

Definition at line 503 of file rootports.cpp.

505{
507
508 if (P->Major != 3 || !KD_DEBUGGER_ENABLED || m_DebugCapability == 0)
509 return FALSE;
510
511 if (!m_Controller->HasErrata(XhciErrata::PortMaskDebugPortNoise))
512 return FALSE;
513
515 return (Status >> XHCI_DBC_DCST_PORT_SHIFT) == P->Number;
516}
#define KD_DEBUGGER_ENABLED
Definition: kdfuncs.h:130
#define XHCI_DBC_DCST_PORT_SHIFT
Definition: xhcihw.h:313
#define XHCI_DBC_DCST
Definition: xhcihw.h:312

Referenced by GetPortStatus(), InterruptTransfer(), and OnPortStatusChangeEvent().

◆ IsPortConnected()

BOOLEAN XhciRootHub::IsPortConnected ( _In_ const Port *  P) const
private

Definition at line 519 of file rootports.cpp.

521{
522 ULONG PortSc = ReadPortSc(P);
523 ULONG Link = XhciLinkState(PortSc);
524
525 if (!(PortSc & XHCI_PORTSC_PP) || !(PortSc & XHCI_PORTSC_CCS))
526 return FALSE;
527
528 return Link != PORT_LINK_STATE_DISABLED &&
531}
#define PORT_LINK_STATE_DISABLED
Definition: usb200.h:196
#define PORT_LINK_STATE_INACTIVE
Definition: usb200.h:198

Referenced by D0Exit().

◆ IsUsb20Port()

BOOLEAN XhciRootHub::IsUsb20Port ( _In_ ULONG  PortNumber) const

TRUE for a USB 2.x port; everything else counts as 3.x for crash dump.

Definition at line 995 of file rootports.cpp.

997{
998 const Port* P = PortAt(PortNumber);
999
1000 return P != NULL && P->Major == 2;
1001}

◆ OnHostLost()

VOID XhciRootHub::OnHostLost ( )

Definition at line 921 of file rootports.cpp.

922{
923 ULONG Index;
924
925 if (m_Ports == NULL)
926 return;
927
928 for (Index = 0; Index < m_PortCount; Index++)
929 {
930 if (m_Ports[Index].TimerReady)
932 }
933}
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
_In_ PLARGE_INTEGER _In_opt_ PTIMER_APC_ROUTINE _In_opt_ PVOID _In_ BOOLEAN ResumeTimer
Definition: zwfuncs.h:431

Referenced by XhciController::RunRecovery().

◆ OnPortStatusChangeEvent()

VOID XhciRootHub::OnPortStatusChangeEvent ( _In_ const XHCI_TRB *  Event)

Definition at line 1044 of file rootports.cpp.

1046{
1048 Port* P = PortAt(PortNumber);
1049
1050 /* PortAt rejects a Port ID outside the port array */
1051 if (P == NULL)
1052 {
1053 DPRINT1("Port status change event for port %lu, controller has %lu\n", PortNumber, m_PortCount);
1054 return;
1055 }
1056
1057 if (IsHiddenDebugPort(P))
1058 {
1063 return;
1064 }
1065
1067 return;
1068
1069 UcxRootHubPortChanged(m_Ucx);
1070}
BOOLEAN AcknowledgeResume(_In_ Port *P, _In_ BOOLEAN PowerUp)
Definition: rootports.cpp:582
_Check_return_ _In_ DXGK_EVENT_TYPE _In_ ULONG Event
Definition: dispmprt.h:1287
#define XHCI_EVENT_PORT_ID_SHIFT
Definition: xhcihw.h:316

◆ ParseProtocol()

NTSTATUS XhciRootHub::ParseProtocol ( _In_ ULONG  Capability,
_Out_ PBOOLEAN  Usable 
)
private

Applies one Supported Protocol Capability; Usable is set for a USB 2.x or 3.x one.

Definition at line 235 of file rootports.cpp.

238{
241 ULONG Name;
242 ULONG Ports;
243 ULONG First;
244 ULONG Count;
246 UCHAR Major;
247
248 *Usable = FALSE;
249
250 Revision = Registers->ReadExtended32(Capability + XHCI_PROTOCOL_REVISION);
251 Name = Registers->ReadExtended32(Capability + XHCI_PROTOCOL_NAME);
252 Ports = Registers->ReadExtended32(Capability + XHCI_PROTOCOL_PORTS);
253
255 {
256 DPRINT1("Protocol capability at 0x%lx has name 0x%08lx, skipped\n", Capability, Name);
257 return STATUS_SUCCESS;
258 }
259
261 if (Major != 2 && Major != 3)
262 {
263 DPRINT1("USB protocol capability at 0x%lx with major revision %u, skipped\n", Capability, Major);
264 return STATUS_SUCCESS;
265 }
266
269 if (First == 0 || Count == 0 || First + Count - 1 > m_PortCount)
270 {
271 DPRINT1("USB %u protocol covers ports %lu+%lu, controller has %lu\n", Major, First, Count, m_PortCount);
273 }
274
275 *Usable = TRUE;
276
277 if (Major == 3)
279
280 for (Number = First; Number < First + Count; Number++)
281 {
282 Port* P = &m_Ports[Number - 1];
283
284 if (P->Major != 0)
285 {
286 DPRINT1("Port %lu claimed by USB %u and USB %u protocol capabilities\n", Number, P->Major, Major);
288 }
289
290 if (Major == 2)
292 else
294
295 P->Major = Major;
297 P->HighSpeedOnly = (Ports & XHCI_PROTOCOL_HSO) != 0;
298 P->IntegratedHub = (Ports & XHCI_PROTOCOL_IHI) != 0;
299 P->LpmCapabilities = 0;
301 P->LpmCapabilities |= 0x01;
303 P->LpmCapabilities |= 0x02;
305 P->SpeedCount = (UCHAR)(Ports >> XHCI_PROTOCOL_PSIC_SHIFT);
306 P->SpeedTable = Capability + XHCI_PROTOCOL_PSI;
307 P->Removable = (Registers->ReadPort32(Number, XHCI_PORT_SC) & XHCI_PORTSC_DR) == 0;
308 }
309
310 return STATUS_SUCCESS;
311}
WCHAR First[]
Definition: FormatMessage.c:11
_In_ ULONG const Usable
Definition: cdrom.h:1084
ULONG m_FirstUsb30Port
Definition: rootports.h:254
LPWSTR Name
Definition: desk.c:124
static PS2_PORT Ports[PS2_PORTS]
Definition: ps2.c:52
_In_ const GUID _In_ ULONG Revision
Definition: slotdev.cpp:85
USHORT Count
Definition: userreq.cpp:200
#define XHCI_PROTOCOL_NAME_USB
Definition: xhcihw.h:285
#define XHCI_PROTOCOL_HSO
Definition: xhcihw.h:290
#define XHCI_PROTOCOL_COUNT_MASK
Definition: xhcihw.h:289
#define XHCI_PROTOCOL_PORTS
Definition: xhcihw.h:280
#define XHCI_PROTOCOL_OFFSET_MASK
Definition: xhcihw.h:287
#define XHCI_PROTOCOL_PSIC_SHIFT
Definition: xhcihw.h:296
#define XHCI_PROTOCOL_NAME
Definition: xhcihw.h:279
#define XHCI_PORTSC_DR
Definition: xhcihw.h:231
#define XHCI_PROTOCOL_MHD_SHIFT
Definition: xhcihw.h:294
#define XHCI_PROTOCOL_BLC
Definition: xhcihw.h:293
#define XHCI_PROTOCOL_REVISION
Definition: xhcihw.h:278
#define XHCI_PROTOCOL_MHD_MASK
Definition: xhcihw.h:295
#define XHCI_PROTOCOL_PSI
Definition: xhcihw.h:281
#define XHCI_PROTOCOL_COUNT_SHIFT
Definition: xhcihw.h:288
#define XHCI_PROTOCOL_HLC
Definition: xhcihw.h:292
#define XHCI_PROTOCOL_IHI
Definition: xhcihw.h:291
#define XHCI_PROTOCOL_MAJOR_SHIFT
Definition: xhcihw.h:284
#define XHCI_PORT_SC
Definition: xhcihw.h:203
#define XHCI_PROTOCOL_MINOR_SHIFT
Definition: xhcihw.h:283

Referenced by Prepare().

◆ PortAt()

◆ PortCount()

ULONG XhciRootHub::PortCount ( ) const

Definition at line 965 of file rootports.cpp.

966{
967 return m_PortCount;
968}

◆ PostInterruptsEntry()

VOID XhciRootHub::PostInterruptsEntry ( )

Definition at line 867 of file rootports.cpp.

868{
870
871 /* A port already in Resume at power up may never raise an event of its own */
872 for (Number = 1; Number <= m_PortCount; Number++)
874}

Referenced by XhciController::D0EntryPostInterruptsEnabled().

◆ PostReset()

VOID XhciRootHub::PostReset ( )

Definition at line 914 of file rootports.cpp.

915{
916 /* Resume, LPM and U1/U2 bookkeeping deliberately survive the reset */
917 D0Entry();
918}
VOID D0Entry()
Definition: rootports.cpp:844

Referenced by XhciController::InternalReset().

◆ Prepare()

NTSTATUS XhciRootHub::Prepare ( )

Walks the supported protocol capabilities; needs the registers prepared.

Definition at line 314 of file rootports.cpp.

315{
317 BOOLEAN AnyUsable = FALSE;
320 ULONG Capability;
323
324 m_PortCount = Registers->MaxPorts();
327
328 Params = Registers->Hcsparams3();
331
332 Capability = Registers->FindExtendedCapability(XHCI_EXTCAP_DEBUG, 0);
333 if (Capability != 0)
334 m_DebugCapability = Capability;
335
336 Capability = Registers->FindExtendedCapability(XHCI_EXTCAP_USB4_TUNNELING, 0);
337 m_PortScTunnelValid = Capability != 0 &&
338 (Registers->ReadExtended32(Capability) & XHCI_USB4_CAP_PORTSC_TUNNEL_VALID) != 0;
340
341 if (m_PortCount == 0)
342 {
343 DPRINT1("Controller reports no root hub ports\n");
345 }
346
348 if (m_Ports == NULL)
349 {
350 DPRINT1("No memory for %lu root hub ports\n", m_PortCount);
351 m_PortCount = 0;
353 }
354
355 for (Capability = Registers->FindExtendedCapability(XHCI_EXTCAP_SUPPORTED_PROTOCOL, 0);
356 Capability != 0;
357 Capability = Registers->FindExtendedCapability(XHCI_EXTCAP_SUPPORTED_PROTOCOL, Capability))
358 {
359 Status = ParseProtocol(Capability, &Usable);
360 if (!NT_SUCCESS(Status))
361 break;
362
363 AnyUsable |= Usable;
364 }
365
366 if (NT_SUCCESS(Status) && !AnyUsable)
367 {
368 DPRINT1("No USB 2.x or 3.x protocol capability found\n");
370 }
371
372 if (!NT_SUCCESS(Status))
373 {
374 DPRINT1("Root hub prepare failed 0x%lx\n", Status);
376 m_Ports = NULL;
377 m_PortCount = 0;
380 return Status;
381 }
382
383 for (Number = 1; Number <= m_PortCount; Number++)
384 {
385 Port* P = &m_Ports[Number - 1];
386
387 KeInitializeSpinLock(&P->Lock);
388 P->Hub = this;
389 P->Number = Number;
390
391 if (P->Major == 2)
392 {
393 KeInitializeTimer(&P->ResumeTimer);
394 KeInitializeDpc(&P->ResumeDpc, ResumeTimerDpc, P);
395 P->TimerReady = TRUE;
396 }
397 }
398
399 DPRINT("Root hub: %lu ports, %u USB 2.x, %u USB 3.x\n", m_PortCount, m_Usb20PortCount, m_Usb30PortCount);
400 return STATUS_SUCCESS;
401}
ULONG MaxPorts() const
Definition: mmio.cpp:555
ULONG FindExtendedCapability(_In_ ULONG Id, _In_ ULONG Start) const
Definition: mmio.cpp:284
ULONG Hcsparams3() const
Definition: mmio.cpp:591
USHORT m_U1ExitLatency
Definition: rootports.h:250
static KDEFERRED_ROUTINE ResumeTimerDpc
Definition: rootports.h:124
BOOLEAN m_PortScTunnelValid
Definition: rootports.h:253
NTSTATUS ParseProtocol(_In_ ULONG Capability, _Out_ PBOOLEAN Usable)
Definition: rootports.cpp:235
USHORT m_U2ExitLatency
Definition: rootports.h:251
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:712
#define NonPagedPool
Definition: env_spec_w32.h:307
#define KeInitializeSpinLock(sl)
Definition: env_spec_w32.h:604
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
static PVOID ExAllocatePoolZero(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
Definition: precomp.h:45
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFIOTARGET _In_ PWDF_REQUEST_COMPLETION_PARAMS Params
Definition: wdfrequest.h:308
#define XHCI_EXTCAP_DEBUG
Definition: xhcihw.h:311
#define XHCI_EXTCAP_USB4_TUNNELING
Definition: xhcihw.h:645
#define XHCI_HCS3_U2_LATENCY_SHIFT
Definition: xhcihw.h:365
#define XHCI_EXTCAP_SUPPORTED_PROTOCOL
Definition: xhcihw.h:277
#define XHCI_USB4_CAP_PORTSC_TUNNEL_VALID
Definition: xhcihw.h:646
#define XHCI_HCS3_U1_LATENCY_MASK
Definition: xhcihw.h:364
#define XHCI_TAG_ROOTHUB
Definition: xhciutil.h:16

Referenced by XhciController::PrepareHardware().

◆ QueryTunnelState()

UCHAR XhciRootHub::QueryTunnelState ( _In_ ULONG  PortNumber) const

USB4 tunnel state of a root port, one of the UCXHUB_TUNNEL_STATE values.

Definition at line 1005 of file rootports.cpp.

1007{
1008 const XhciRegisters* Registers = &m_Controller->m_Registers;
1009 const Port* P = PortAt(PortNumber);
1010 ULONG Value;
1011 ULONG Mask;
1012
1013 if (P == NULL || P->Major != 3)
1015
1016 if (m_Controller->HasErrata(XhciErrata::Usb4TunnelFromVendorPortReg))
1017 {
1021 }
1022 else if (m_Controller->HasErrata(XhciErrata::Usb4TunnelFromVendorStatusReg))
1023 {
1026 }
1027 else if (m_PortScTunnelValid)
1028 {
1029 Value = ReadPortSc(P);
1031 }
1032 else
1033 {
1035 }
1036
1037 DPRINT("Root port %lu tunnel register 0x%08lx\n", PortNumber, Value);
1039}
unsigned int Mask
Definition: fpcontrol.c:82
#define UCXHUB_TUNNEL_STATE_TUNNELED
Definition: hubucx.h:539
#define UCXHUB_TUNNEL_STATE_UNKNOWN
Definition: hubucx.h:541
#define UCXHUB_TUNNEL_STATE_NATIVE
Definition: hubucx.h:540
#define XHCI_VENDOR_PORT_TUNNEL_STRIDE
Definition: xhcihw.h:651
#define XHCI_VENDOR_PORT_TUNNEL_BASE
Definition: xhcihw.h:650
#define XHCI_VENDOR_PORT_TUNNEL_ACTIVE
Definition: xhcihw.h:652
#define XHCI_PORTSC_TUNNELED
Definition: xhcihw.h:647
#define XHCI_VENDOR_TUNNEL_STATUS
Definition: xhcihw.h:653
#define XHCI_VENDOR_TUNNEL_STATUS_ACTIVE
Definition: xhcihw.h:654

Referenced by XhciUsbDevice::ApplyUpdate().

◆ ReadPortSc()

ULONG XhciRootHub::ReadPortSc ( _In_ const Port *  P) const
private

◆ Release()

VOID XhciRootHub::Release ( )

Definition at line 404 of file rootports.cpp.

405{
406 ULONG Index;
407
408 if (m_Ports == NULL)
409 return;
410
411 for (Index = 0; Index < m_PortCount; Index++)
412 {
413 if (m_Ports[Index].TimerReady)
415 }
416
417 /* Wait for a running resume timer callback before freeing the ports */
418 KeFlushQueuedDpcs();
419
421 m_Ports = NULL;
422 m_PortCount = 0;
425}

Referenced by XhciController::ReleaseHardware().

◆ ResuspendResumedPorts()

VOID XhciRootHub::ResuspendResumedPorts ( )
private

Puts every active, not suspended port back in U3 before power down.

Definition at line 775 of file rootports.cpp.

776{
778
779 for (Number = 1; Number <= m_PortCount; Number++)
780 {
781 Port* P = &m_Ports[Number - 1];
782 ULONG Remaining = XhciResumeWaitSteps;
783 ULONG PortSc;
784 ULONG Link;
785
786 if (P->Major == 2 && KeCancelTimer(&P->ResumeTimer))
787 {
788 /* Left in Resume with PLC set, which wakes the controller once it is down */
789 P->ResumeHandled = FALSE;
790 continue;
791 }
792
793 if (P->Major == 0)
794 continue;
795
796 for (;;)
797 {
798 PortSc = ReadPortSc(P);
799 Link = XhciLinkState(PortSc);
800
801 if (PortSc == XhciPortGone ||
802 !P->ResumeHandled ||
803 !XhciPortActive(PortSc) ||
805 {
806 break;
807 }
808
809 if (Remaining == 0)
810 {
811 DPRINT1("Port %lu: acknowledged resume not done after 12 ms\n", Number);
812 break;
813 }
814
815 Remaining--;
817 }
818
819 if (PortSc == XhciPortGone || !XhciPortActive(PortSc))
820 continue;
821
822 if (Link != PORT_LINK_STATE_U0 &&
826 {
827 continue;
828 }
829
830 if ((P->Major == 2 && m_Controller->HasErrata(XhciErrata::PortHighSpeedLpmOffForSuspend)) ||
831 (P->Major == 3 && m_Controller->HasErrata(XhciErrata::PortWakeToU0BeforeSuspend)))
832 {
833 if (!NT_SUCCESS(WaitU0(P)))
834 continue;
835 }
836
837 SuspendPort(P);
838 }
839}
NTSTATUS WaitU0(_In_ Port *P)
Definition: rootports.cpp:701
VOID SuspendPort(_In_ Port *P)
Definition: rootports.cpp:760
#define KeStallExecutionProcessor(MicroSeconds)
Definition: precomp.h:27
static const ULONG XhciResumeWaitSteps
Definition: rootports.cpp:52
FORCEINLINE BOOLEAN NTAPI XhciPortActive(_In_ ULONG PortSc)
Definition: rootports.cpp:95
#define PORT_LINK_STATE_U1
Definition: usb200.h:193

Referenced by D0Exit().

◆ SetPortFeature()

XhciRootHub::Outcome XhciRootHub::SetPortFeature ( _In_ PURB  Urb)
private

Definition at line 1603 of file rootports.cpp.

1605{
1608 Port* P;
1609
1610 if (!m_Controller->IsAccessible())
1611 {
1612 DPRINT1("SetPortFeature: controller not accessible\n");
1613 return Outcome::Gone;
1614 }
1615
1616 Result = CheckRunning();
1617 if (Result != Outcome::Ok)
1618 return Result;
1619
1620 P = PortAt(Setup->wIndex.LowByte);
1621 if (Setup->bmRequestType.B != HubRequestToPort ||
1622 Setup->bRequest != USB_REQUEST_SET_FEATURE ||
1623 P == NULL ||
1624 Setup->wLength != 0)
1625 {
1626 XhciTraceBadRequest("SetPortFeature", Urb);
1627 return Outcome::Stall;
1628 }
1629
1630 if (P->Major == 2)
1631 Result = SetUsb20PortFeature(P, Setup->wValue.W, Setup->wIndex.HiByte);
1632 else if (P->Major == 3)
1633 Result = SetUsb30PortFeature(P, Setup->wValue.W, Setup->wIndex.HiByte);
1634 else
1636
1637 if (Result == Outcome::Stall)
1638 XhciTraceBadRequest("SetPortFeature", Urb);
1639
1640 return Result;
1641}
Outcome SetUsb20PortFeature(_In_ Port *P, _In_ USHORT Feature, _In_ UCHAR Value)
Definition: rootports.cpp:1644
Outcome SetUsb30PortFeature(_In_ Port *P, _In_ USHORT Feature, _In_ UCHAR Value)
Definition: rootports.cpp:1710
#define USB_REQUEST_SET_FEATURE
Definition: usb100.h:80

◆ SetUsb20PortFeature()

XhciRootHub::Outcome XhciRootHub::SetUsb20PortFeature ( _In_ Port *  P,
_In_ USHORT  Feature,
_In_ UCHAR  Value 
)
private

Definition at line 1644 of file rootports.cpp.

1648{
1650 return Outcome::Stall;
1651
1652 switch (Feature)
1653 {
1654 case FeaturePortReset:
1655 {
1656 XhciSpinLockGuard Guard(&P->Lock);
1657
1658 /* LpmEnabled is kept on purpose, the resume timer may turn HLE back on */
1659 if (P->LpmDirty)
1661
1663 return Outcome::Ok;
1664 }
1665
1666 case FeaturePortSuspend:
1667 /* xHCI 4.15.1; some controllers only enter U3 from L0 */
1668 if (m_Controller->HasErrata(XhciErrata::PortHighSpeedLpmOffForSuspend) &&
1669 !NT_SUCCESS(WaitU0(P)))
1670 {
1671 return Outcome::Stall;
1672 }
1673
1674 SuspendPort(P);
1675 return Outcome::Ok;
1676
1677 case FeaturePortPower:
1679 return Outcome::Ok;
1680
1681 case FeaturePortTest:
1682 {
1683 if (Value > 5)
1684 return Outcome::Stall;
1685
1686 XhciSpinLockGuard Guard(&P->Lock);
1687
1688 /* No xHCI 4.19.6 preconditions are enforced */
1690 return Outcome::Ok;
1691 }
1692
1694 if (Value > 3)
1695 return Outcome::Stall;
1696
1697 /* Hub "off" (3) and "automatic" (0) both become xHCI off */
1698 if (Value == 3)
1699 Value = 0;
1700
1702 return Outcome::Ok;
1703
1704 default:
1705 return Outcome::Stall;
1706 }
1707}
@ FeaturePortReset
Definition: rootports.cpp:26
@ FeaturePortTest
Definition: rootports.cpp:34
#define XHCI_PORTSC_PIC_SHIFT
Definition: xhcihw.h:218
#define XHCI_PORTPMSC_TEST_SHIFT
Definition: xhcihw.h:259
#define XHCI_PORTPMSC_TEST_MASK
Definition: xhcihw.h:260

Referenced by SetPortFeature().

◆ SetUsb30LinkState()

XhciRootHub::Outcome XhciRootHub::SetUsb30LinkState ( _In_ Port *  P,
_In_ UCHAR  LinkState 
)
private

Definition at line 1783 of file rootports.cpp.

1786{
1787 if (LinkState > PORT_LINK_STATE_RX_DETECT)
1788 return Outcome::Stall;
1789
1790 /* Applies to every non U0 target, not only U3 */
1791 if (LinkState != PORT_LINK_STATE_U0 &&
1792 m_Controller->HasErrata(XhciErrata::PortWakeToU0BeforeSuspend) &&
1793 !NT_SUCCESS(WaitU0(P)))
1794 {
1795 return Outcome::Stall;
1796 }
1797
1798 /* A U3 request completes before the link gets there */
1799 if (LinkState == PORT_LINK_STATE_U0 && !NT_SUCCESS(WaitForU3(P, FALSE)))
1800 return Outcome::Stall;
1801
1802 {
1803 XhciSpinLockGuard Guard(&P->Lock);
1804
1805 if (LinkState == PORT_LINK_STATE_U3)
1806 P->ResumeHandled = FALSE;
1807
1808 /* SS.Disabled is entered through PED (xHCI 4.19.1.2) */
1809 if (LinkState == PORT_LINK_STATE_DISABLED)
1811 else
1813 }
1814
1815 if (LinkState == PORT_LINK_STATE_U3 &&
1816 m_Controller->HasErrata(XhciErrata::PortRetrySuspendEntry) &&
1818 {
1819 return Outcome::Stall;
1820 }
1821
1822 return Outcome::Ok;
1823}

Referenced by SetUsb30PortFeature().

◆ SetUsb30PortFeature()

XhciRootHub::Outcome XhciRootHub::SetUsb30PortFeature ( _In_ Port *  P,
_In_ USHORT  Feature,
_In_ UCHAR  Value 
)
private

Definition at line 1710 of file rootports.cpp.

1714{
1715 if (Value != 0 &&
1720 {
1721 return Outcome::Stall;
1722 }
1723
1724 switch (Feature)
1725 {
1726 case FeaturePortReset:
1728 return Outcome::Ok;
1729
1730 case FeatureWarmReset:
1732 return Outcome::Ok;
1733
1734 case FeaturePortPower:
1736 return Outcome::Ok;
1737
1738 case FeatureU1Timeout:
1739 {
1740 XhciSpinLockGuard Guard(&P->Lock);
1741
1743 P->U1Timeout = Value;
1744 return Outcome::Ok;
1745 }
1746
1747 case FeatureU2Timeout:
1748 {
1749 XhciSpinLockGuard Guard(&P->Lock);
1750
1755 P->U2Timeout = Value;
1756 return Outcome::Ok;
1757 }
1758
1760 return SetUsb30LinkState(P, Value);
1761
1763 if (Value & ~0x07)
1764 return Outcome::Stall;
1765
1767 return Outcome::Ok;
1768
1770 {
1771 XhciSpinLockGuard Guard(&P->Lock);
1772
1774 return Outcome::Ok;
1775 }
1776
1777 default:
1778 return Outcome::Stall;
1779 }
1780}
Outcome SetUsb30LinkState(_In_ Port *P, _In_ UCHAR LinkState)
Definition: rootports.cpp:1783
@ FeatureRemoteWakeMask
Definition: rootports.cpp:40
@ FeatureU2Timeout
Definition: rootports.cpp:37
@ FeatureU1Timeout
Definition: rootports.cpp:36
@ FeatureWarmReset
Definition: rootports.cpp:41
@ FeaturePortLinkState
Definition: rootports.cpp:27
#define XHCI_PORTSC_WAKE_SHIFT
Definition: xhcihw.h:229
#define XHCI_PORTSC_WPR
Definition: xhcihw.h:232

Referenced by SetPortFeature().

◆ SetWakeEnables()

VOID XhciRootHub::SetWakeEnables ( _In_ BOOLEAN  Arm)

Wake arm or disarm of every port for the controller.

Definition at line 936 of file rootports.cpp.

938{
940
941 if (!Arm && m_Controller->HasErrata(XhciErrata::PortHoldWakeMaskAwake))
942 return;
943
944 for (Number = 1; Number <= m_PortCount; Number++)
945 {
946 Port* P = &m_Ports[Number - 1];
947
948 if (Arm)
950 else
952 }
953}

Referenced by XhciController::SetPortWake().

◆ SignalPortChange()

VOID XhciRootHub::SignalPortChange ( )

Tells UCX a root port changed, for the controller's wake from S0 path.

Definition at line 956 of file rootports.cpp.

957{
958 if (m_Ucx != NULL)
959 UcxRootHubPortChanged(m_Ucx);
960}

Referenced by XhciEvtDeviceWakeFromS0Triggered().

◆ StartResumeTimer()

VOID XhciRootHub::StartResumeTimer ( _In_ Port *  P)
private

Definition at line 536 of file rootports.cpp.

538{
539 ULONG Milliseconds = XhciResumeSignalMs;
540
541 if (P->ResumeOverrideCount > 0)
542 Milliseconds = P->ResumeOverrideMs;
543
544 KeSetTimer(&P->ResumeTimer, XhciRelativeMs(Milliseconds), &P->ResumeDpc);
545}
static const ULONG XhciResumeSignalMs
Definition: rootports.cpp:47
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:282
FORCEINLINE LARGE_INTEGER NTAPI XhciRelativeMs(_In_ ULONG Milliseconds)
Definition: xhciutil.h:137

Referenced by AcknowledgeResume(), and ClearUsb20PortFeature().

◆ SuspendPort()

VOID XhciRootHub::SuspendPort ( _In_ Port *  P)
private

Requests U3 (USB 2.x suspend); the transition is not waited for.

Definition at line 760 of file rootports.cpp.

762{
763 XhciSpinLockGuard Guard(&P->Lock);
764 ULONG PortSc;
765
766 P->ResumeHandled = FALSE;
767
769 if (!(PortSc & XHCI_PORTSC_PED) || XhciLinkState(PortSc) >= PORT_LINK_STATE_U3)
770 DPRINT1("Port %lu: suspend requested with PORTSC 0x%08lx\n", P->Number, PortSc);
771}

Referenced by ResuspendResumedPorts(), and SetUsb20PortFeature().

◆ Update20HardwareLpm()

VOID XhciRootHub::Update20HardwareLpm ( _In_ ULONG  PortNumber,
_In_ ULONG  SlotId,
_In_ const USBDEVICE_UPDATE_20_HARDWARE_LPM_PARAMETERS *  Parameters 
)

Definition at line 1075 of file rootports.cpp.

1079{
1080 Port* P = PortAt(PortNumber);
1081 ULONG Value;
1082
1083 if (P == NULL)
1084 {
1085 DPRINT1("LPM update for bad root port %lu\n", PortNumber);
1086 return;
1087 }
1088
1089 NT_ASSERT(P->Major == 2);
1090
1091 XhciSpinLockGuard Guard(&P->Lock);
1092
1093 /* Parameters before the enable bit (xHCI 4.23.5.1.1.1) */
1094 Value = Parameters->HostInitiatedResumeDurationMode |
1096 (Parameters->BestEffortServiceLatencyDeep << XHCI_PORTHLPMC_BESLD_SHIFT);
1100 Value);
1101
1102 Value = (Parameters->BestEffortServiceLatency << XHCI_PORTPMSC_BESL_SHIFT) |
1104 if (Parameters->RemoteWakeEnable)
1106 if (Parameters->HardwareLpmEnable)
1111 Value);
1112
1113 P->LpmEnabled = Parameters->HardwareLpmEnable != 0;
1114 P->LpmDirty = TRUE;
1115}
_In_ HANDLE _In_ CONST PDXGKMDT_OPM_GET_INFO_PARAMETERS Parameters
Definition: dispmprt.h:321
#define NT_ASSERT
Definition: rtlfuncs.h:3334
#define XHCI_PORTHLPMC_L1_TIMEOUT_SHIFT
Definition: xhcihw.h:271
#define XHCI_PORTPMSC_BESL_SHIFT
Definition: xhcihw.h:254
#define XHCI_PORTHLPMC_BESLD_SHIFT
Definition: xhcihw.h:273

Referenced by XhciUsbDevice::ApplyUpdate().

◆ UpdatePortReg()

VOID XhciRootHub::UpdatePortReg ( _In_ Port *  P,
_In_ ULONG  Offset,
_In_ ULONG  Clear,
_In_ ULONG  Set 
)
private

Plain field replace for PORTPMSC and PORTHLPMC.

Definition at line 472 of file rootports.cpp.

477{
479 ULONG Value;
480
481 Value = Registers->ReadPort32(P->Number, Offset);
482 Registers->WritePort32(P->Number, Offset, (Value & ~Clear) | Set);
483}
VOID WritePort32(_In_ ULONG Port, _In_ ULONG Offset, _In_ ULONG Value)
Definition: mmio.cpp:528
static void Clear(void)
Definition: treeview.c:388
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
static BOOL Set
Definition: pageheap.c:10

Referenced by AcknowledgeResume(), ClearUsb20LpmLocked(), ClearUsb30PortFeature(), SetUsb20PortFeature(), SetUsb30PortFeature(), Update20HardwareLpm(), and WaitU0().

◆ UpdatePortSc()

ULONG XhciRootHub::UpdatePortSc ( _In_ Port *  P,
_In_ ULONG  Keep,
_In_ ULONG  Set 
)
private

◆ UpdatePortScLocked()

ULONG XhciRootHub::UpdatePortScLocked ( _In_ Port *  P,
_In_ ULONG  Keep,
_In_ ULONG  Set 
)
private

PORTSC read and write back keeping only the Keep bits, plus Set. Caller holds the port lock.

Definition at line 448 of file rootports.cpp.

452{
453 ULONG PortSc = ReadPortSc(P);
454
455 m_Controller->m_Registers.WritePort32(P->Number, XHCI_PORT_SC, (PortSc & Keep) | Set);
456 return PortSc;
457}

Referenced by AcknowledgeResume(), ClearUsb20PortFeature(), SetUsb20PortFeature(), SetUsb30LinkState(), SuspendPort(), UpdatePortSc(), and WaitU0().

◆ WaitForU3()

NTSTATUS XhciRootHub::WaitForU3 ( _In_ Port *  P,
_In_ BOOLEAN  RepeatRequest 
)
private

Waits up to 24 ms for a requested U3 to land.

Definition at line 650 of file rootports.cpp.

653{
654 ULONG LastSeen = XhciPortGone;
655 ULONG Step;
656
657 for (Step = 0; Step < XhciU3WaitSteps; Step++)
658 {
659 ULONG PortSc;
660 ULONG Link;
661
662 /* Some controllers drop the first U3 request; ask again every 30 us */
663 if (RepeatRequest && Step != 0 && (Step % 3) == 0)
665
666 PortSc = ReadPortSc(P);
667 if (PortSc != LastSeen)
668 {
669 LastSeen = PortSc;
670
671 if (P->Major == 0)
672 {
673 DPRINT1("Port %lu: U3 wait on a port with no protocol\n", P->Number);
674 return STATUS_SUCCESS;
675 }
676
677 Link = XhciLinkState(PortSc);
678 if (Link == PORT_LINK_STATE_U3 ||
679 !XhciPortActive(PortSc) ||
685 (PortSc & XHCI_PORTSC_PR) ||
686 P->ResumeHandled)
687 {
688 return STATUS_SUCCESS;
689 }
690 }
691
693 }
694
695 DPRINT1("Port %lu: U3 transition still pending after 24 ms, PORTSC 0x%08lx\n", P->Number, LastSeen);
696 return STATUS_UNSUCCESSFUL;
697}
static const ULONG XhciU3WaitSteps
Definition: rootports.cpp:50
#define PORT_LINK_STATE_HOT_RESET
Definition: usb200.h:201

Referenced by ClearUsb20PortFeature(), D0Exit(), and SetUsb30LinkState().

◆ WaitU0()

NTSTATUS XhciRootHub::WaitU0 ( _In_ Port *  P)
private

Brings the link to U0 first for controllers that cannot go to U3 from a low power state.

Definition at line 701 of file rootports.cpp.

703{
704 ULONG Remaining = XhciU0WaitSteps;
705
706 if (P->Major == 2)
707 {
708 if (!P->LpmEnabled)
709 return STATUS_SUCCESS;
710
711 XhciSpinLockGuard Guard(&P->Lock);
712
714 }
715 else if (P->Major == 3)
716 {
717 XhciSpinLockGuard Guard(&P->Lock);
718
721 }
722 else
723 {
724 return STATUS_SUCCESS;
725 }
726
727 for (;;)
728 {
729 ULONG PortSc = ReadPortSc(P);
730 ULONG Link = XhciLinkState(PortSc);
731
732 if (PortSc == XhciPortGone)
733 break;
735 return STATUS_SUCCESS;
739 !XhciPortActive(PortSc))
740 {
741 break;
742 }
744 {
745 DPRINT1("Port %lu: link state %lu while forcing U0\n", P->Number, Link);
746 break;
747 }
748 if ((PortSc & XHCI_PORTSC_PR) || Remaining == 0)
749 break;
750
751 Remaining--;
753 }
754
755 return STATUS_UNSUCCESSFUL;
756}
static const ULONG XhciU0WaitSteps
Definition: rootports.cpp:51

Referenced by ResuspendResumedPorts(), SetUsb20PortFeature(), and SetUsb30LinkState().

Member Data Documentation

◆ EvtClearHubFeature

VOID NTAPI XhciRootHub::EvtClearHubFeature
staticprivate

Definition at line 113 of file rootports.h.

Referenced by Create().

◆ EvtClearPortFeature

VOID NTAPI XhciRootHub::EvtClearPortFeature
staticprivate

Definition at line 114 of file rootports.h.

Referenced by Create().

◆ EvtGet20PortInfo

VOID NTAPI XhciRootHub::EvtGet20PortInfo
staticprivate

Definition at line 122 of file rootports.h.

Referenced by Create().

◆ EvtGet30PortInfo

VOID NTAPI XhciRootHub::EvtGet30PortInfo
staticprivate

Definition at line 123 of file rootports.h.

Referenced by Create().

◆ EvtGetHubStatus

VOID NTAPI XhciRootHub::EvtGetHubStatus
staticprivate

Definition at line 115 of file rootports.h.

Referenced by Create().

◆ EvtGetInfo

VOID NTAPI XhciRootHub::EvtGetInfo
staticprivate

Definition at line 121 of file rootports.h.

Referenced by Create().

◆ EvtGetPortErrorCount

VOID NTAPI XhciRootHub::EvtGetPortErrorCount
staticprivate

Definition at line 119 of file rootports.h.

Referenced by Create().

◆ EvtGetPortStatus

VOID NTAPI XhciRootHub::EvtGetPortStatus
staticprivate

Definition at line 116 of file rootports.h.

Referenced by Create().

◆ EvtInterruptTransfer

VOID NTAPI XhciRootHub::EvtInterruptTransfer
staticprivate

Definition at line 120 of file rootports.h.

Referenced by Create().

◆ EvtSetHubFeature

VOID NTAPI XhciRootHub::EvtSetHubFeature
staticprivate

Definition at line 117 of file rootports.h.

Referenced by Create().

◆ EvtSetPortFeature

VOID NTAPI XhciRootHub::EvtSetPortFeature
staticprivate

Definition at line 118 of file rootports.h.

Referenced by Create().

◆ m_AwaitingStatusRead

BOOLEAN XhciRootHub::m_AwaitingStatusRead
private

No interrupt transfer seen since D0 entry

Definition at line 252 of file rootports.h.

Referenced by Create(), D0Entry(), and InterruptTransfer().

◆ m_Controller

◆ m_DebugCapability

ULONG XhciRootHub::m_DebugCapability
private

Extended capability offset, 0 when absent

Definition at line 247 of file rootports.h.

Referenced by Create(), IsHiddenDebugPort(), and Prepare().

◆ m_FirstUsb30Port

ULONG XhciRootHub::m_FirstUsb30Port
private

Compatible Port Offset of the last USB 3 protocol capability

Definition at line 254 of file rootports.h.

Referenced by ParseProtocol(), Prepare(), and QueryTunnelState().

◆ m_PortCount

◆ m_Ports

◆ m_PortScTunnelValid

BOOLEAN XhciRootHub::m_PortScTunnelValid
private

PORTSC bit 2 reports USB4 tunneling

Definition at line 253 of file rootports.h.

Referenced by Prepare(), and QueryTunnelState().

◆ m_U1ExitLatency

USHORT XhciRootHub::m_U1ExitLatency
private

Definition at line 250 of file rootports.h.

Referenced by Prepare().

◆ m_U2ExitLatency

USHORT XhciRootHub::m_U2ExitLatency
private

Definition at line 251 of file rootports.h.

Referenced by Prepare().

◆ m_Ucx

UCXROOTHUB XhciRootHub::m_Ucx
private

Definition at line 244 of file rootports.h.

Referenced by Create(), D0Exit(), OnPortStatusChangeEvent(), and SignalPortChange().

◆ m_Usb20PortCount

USHORT XhciRootHub::m_Usb20PortCount
private

Definition at line 248 of file rootports.h.

Referenced by Create(), ParseProtocol(), Prepare(), and Release().

◆ m_Usb30PortCount

USHORT XhciRootHub::m_Usb30PortCount
private

Definition at line 249 of file rootports.h.

Referenced by Create(), ParseProtocol(), Prepare(), and Release().

◆ ResumeTimerDpc

VOID NTAPI XhciRootHub::ResumeTimerDpc
staticprivate

Ends USB 2.x resume signaling once TDRSMDN has passed.

Definition at line 124 of file rootports.h.

Referenced by Prepare().


The documentation for this class was generated from the following files: