ReactOS 0.4.17-dev-1281-g065abb3
XhciIsochRing Class Reference

#include <isoxfer.h>

Collaboration diagram for XhciIsochRing:

Static Public Member Functions

static NTSTATUS Initialize (_In_ XhciTransferRing *Ring)
 
static VOID Enable (_In_ XhciTransferRing *Ring)
 
static VOID Disable (_In_ XhciTransferRing *Ring)
 
static VOID ReleaseParkedMapping (_In_ XhciTransferRing *Ring)
 
static VOID Cleanup (_In_ XhciTransferRing *Ring)
 
static VOID ResumeRingFill (_In_ XhciTransferRing *Ring)
 
static VOID SuspendRingFill (_In_ XhciTransferRing *Ring)
 
static VOID OnClientPipeReset (_In_ XhciTransferRing *Ring)
 
static VOID AllowReclaimOnCancel (_In_ XhciTransferRing *Ring)
 
static VOID ConsumePendingEvents (_In_ XhciTransferRing *Ring)
 
static VOID RecoverTransfers (_In_ XhciTransferRing *Ring)
 
static BOOLEAN DoorbellRungSinceFill (_In_ const XhciTransferRing *Ring)
 
static BOOLEAN HasQueuedWork (_In_ const XhciTransferRing *Ring)
 
static BOOLEAN OnTransferEvent (_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
 
static VOID SegmentsArrived (_In_ XhciTransferRing *Ring, _In_ NTSTATUS Status)
 

Static Public Attributes

static EVT_WDF_IO_QUEUE_STATE ReadyNotification
 
static EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue
 
static EVT_WDF_DPC EvtCompletionDpc
 

Private Types

enum class  Outcome : ULONG {
  Ready , Completed , WaitSegments , WaitDma ,
  Gap , Late , Failed
}
 

Static Private Member Functions

static VOID BuildTdsFromQueue (_In_ XhciTransferRing *Ring)
 
static VOID FillLoop (_In_ XhciTransferRing *Ring)
 
static VOID AwaitRingEmpty (_In_ XhciTransferRing *Ring)
 
static BOOLEAN LeaveRingEmptyWait (_In_ XhciTransferRing *Ring)
 
static VOID KickAfterStage (_In_ XhciTransferRing *Ring, _In_ ULONG InFlight)
 
static BOOLEAN ParkOnSegments (_In_ XhciTransferRing *Ring)
 
static XhciIsochStage * NextTdSlot (_In_ XhciTransferRing *Ring)
 
static BOOLEAN TakeRequest (_In_ XhciTransferRing *Ring, _In_ WDFREQUEST Request, _Out_ XhciIsochTransfer **Taken)
 
static BOOLEAN PacketsValid (_In_ const XhciIsochTransfer *Transfer)
 
static NTSTATUS ScheduleStartFrame (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer)
 
static VOID FlagMissedPackets (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer)
 
static VOID SkipUnmapped (_Inout_ XhciIsochTransfer *Transfer)
 
static XhciIsochStage * AcquireStage (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer)
 
static VOID FreeStage (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
 
static VOID PutScatterGather (_In_ XhciTransferRing *Ring, _In_opt_ PSCATTER_GATHER_LIST SgList)
 
static BOOLEAN TransferDone (_In_ const XhciIsochTransfer *Transfer)
 
static Outcome PrimeStage (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
 
static NTSTATUS AcquireStageMdl (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
 
static BOOLEAN SizeStage (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
 
static ULONG EstimateSegments (_In_ XhciTransferRing *Ring, _In_ const XhciIsochStage *Stage)
 
static Outcome FailStage (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
 
static Outcome EncodeStage (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
 
static VOID WriteStage (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
 
static ULONG LayoutStage (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage, _In_ BOOLEAN Commit)
 
static VOID InsertLink (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage, _In_ BOOLEAN FirstOfTd)
 
static VOID CompleteTd (_In_ XhciTransferRing *Ring, _In_ XhciIsochTransfer *Transfer, _In_ XhciIsochStage *Stage, _In_ ULONG Sequence, _In_ ULONG Code, _In_ ULONG Bytes, _In_ BOOLEAN CloseStage)
 
static VOID FinishExpiredIsoch (_In_ XhciTransferRing *Ring, _In_ const XhciIsochTransfer *Newest, _In_ ULONG Sequence)
 
static VOID RetireExpiredStages (_In_ XhciTransferRing *Ring, _In_ XhciIsochTransfer *Transfer, _In_ XhciIsochStage *Stage, _In_ ULONG Sequence)
 
static ULONG ReleaseAllStages (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer)
 
static VOID Finalize (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer, _In_ USBD_STATUS PacketStatus, _In_ USBD_STATUS HeaderStatus)
 
static VOID CompletePlain (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer, _In_ USBD_STATUS PacketStatus, _In_ USBD_STATUS HeaderStatus, _In_ BOOLEAN Async)
 
static VOID CompleteAfterUncancel (_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer, _In_ USBD_STATUS PacketStatus, _In_ USBD_STATUS HeaderStatus, _In_ BOOLEAN FinishCanceled, _In_ BOOLEAN Async)
 
static VOID CompleteBatch (_In_ XhciTransferRing *Ring, _Inout_ PLIST_ENTRY Batch)
 
static BOOLEAN OwnsRequests (_In_ const XhciTransferRing *Ring)
 
static VOID Ed1Event (_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
 
static VOID Ed0Event (_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
 
static BOOLEAN FindTrb (_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event, _Outptr_result_maybenull_ XhciIsochStage **Found, _Out_ PULONG Bytes)
 
static VOID OnRingStarved (_In_ XhciTransferRing *Ring)
 
static BOOLEAN FinishLostStages (_In_ XhciTransferRing *Ring)
 

Private Attributes

BOOLEAN m_FreshStream
 
BOOLEAN m_DoorbellAfterFirstTd
 
BOOLEAN m_DpcRunning
 
ULONG m_NextStartFrame
 
ULONG m_LastScheduledFrame
 
ULONG m_PacketsPerFrame
 
ULONG m_PendingStages
 
ULONG m_TrbsPerTd
 
ULONG m_BufferRetries
 
ULONG m_NextSequence
 
volatile LONG m_Flags
 
volatile LONG m_FillWanted
 
volatile LONG m_RingEmptySeen
 
volatile LONG m_FillAgain
 
volatile LONG m_LateStage
 
volatile LONG m_SegmentWait
 
XhciIsochStage * m_CurrentStage
 
LIST_ENTRY m_Pending
 
LIST_ENTRY m_WaitingForCancel
 
LIST_ENTRY m_Completion
 
WDFTIMER m_Watchdog
 
ULONG m_Transfers
 
ULONG m_FailedTransfers
 
ULONG64 m_Bytes
 
ULONG m_Tds
 
ULONG m_TdFailures
 
ULONG m_MissedServiceErrors
 
ULONG m_RingEmptyEvents
 

Static Private Attributes

static EVT_WDF_REQUEST_CANCEL EvtRequestCancel
 
static EVT_WDF_TIMER EvtWatchdog
 
static DRIVER_LIST_CONTROL DmaCallback
 

Detailed Description

Isochronous ring state and the entry points the transfer ring module calls.

Definition at line 79 of file isoxfer.h.

Member Enumeration Documentation

◆ Outcome

Enumerator
Ready 
Completed 
WaitSegments 
WaitDma 
Gap 
Late 
Failed 

Definition at line 142 of file isoxfer.h.

Member Function Documentation

◆ AcquireStage()

static XhciIsochStage * XhciIsochRing::AcquireStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochTransfer *  Transfer 
)
staticprivate

Referenced by NextTdSlot().

◆ AcquireStageMdl()

NTSTATUS XhciIsochRing::AcquireStageMdl ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage 
)
staticprivate

Definition at line 1465 of file isoxfer.cpp.

1468{
1469 XhciIsochTransfer* Transfer = Stage->Transfer;
1470 PMDL Mdl = Transfer->Mdl;
1471 ULONG Offset = Transfer->BytesQueued + Transfer->BytesDropped;
1472 PUCHAR Start;
1473 ULONG Length;
1474 PMDL Partial;
1475
1476 while (Mdl != NULL && Offset >= MmGetMdlByteCount(Mdl))
1477 {
1479 Mdl = Mdl->Next;
1480 }
1481
1482 if (Mdl == NULL)
1483 {
1484 DPRINT1("Isoch DCI %lu: MDL chain shorter than the transfer\n", Ring->m_Endpoint->Dci());
1486 }
1487
1488 if (Offset == 0)
1489 {
1490 Stage->Mdl = Mdl;
1491 return STATUS_SUCCESS;
1492 }
1493
1494 Start = static_cast<PUCHAR>(MmGetMdlVirtualAddress(Mdl)) + Offset;
1496
1497 Partial = IoAllocateMdl(Start, Length, FALSE, FALSE, NULL);
1498 if (Partial == NULL)
1499 {
1500 DPRINT1("Isoch DCI %lu: partial MDL allocation failed\n", Ring->m_Endpoint->Dci());
1502 }
1503
1504 IoBuildPartialMdl(Mdl, Partial, Start, Length);
1505 Partial->Next = Mdl->Next;
1506 Stage->Mdl = Partial;
1507 Stage->FreeMdl = TRUE;
1508 return STATUS_SUCCESS;
1509}
static _Out_opt_ PULONGLONG Start
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define IoAllocateMdl
Definition: fxmdl.h:88
VOID NTAPI IoBuildPartialMdl(IN PMDL SourceMdl, IN PMDL TargetMdl, IN PVOID VirtualAddress, IN ULONG Length)
Definition: iomdl.c:96
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define STATUS_SUCCESS
Definition: shellext.h:65
ULONG BytesDropped
Definition: isoxfer.h:66
ULONG BytesQueued
Definition: isoxfer.h:65
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
#define MmGetMdlByteCount(_Mdl)
#define MmGetMdlVirtualAddress(_Mdl)

Referenced by PrimeStage().

◆ AllowReclaimOnCancel()

VOID XhciIsochRing::AllowReclaimOnCancel ( _In_ XhciTransferRing *  Ring)
static

Definition at line 702 of file isoxfer.cpp.

704{
705 XhciIsochRing* Self = &Ring->m_Type.Isoch;
708
709 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
710 if (Self->m_Flags & XhciIsochCanceled)
711 {
713 Queue = TRUE;
714 }
715 else
716 {
718 }
719 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
720
721 if (Queue)
722 WdfDpcEnqueue(Ring->m_CompletionDpc);
723}
unsigned char BOOLEAN
Definition: actypes.h:127
volatile LONG m_Flags
Definition: isoxfer.h:344
LIST_ENTRY m_Pending
Definition: isoxfer.h:351
LIST_ENTRY m_Completion
Definition: isoxfer.h:353
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
#define InterlockedOr
Definition: interlocked.h:239
static const LONG XhciIsochOkToReclaim
Definition: isoxfer.cpp:36
static VOID NTAPI XhciIsochMoveList(_Inout_ PLIST_ENTRY Destination, _Inout_ PLIST_ENTRY Source)
Definition: isoxfer.cpp:170
static const LONG XhciIsochCanceled
Definition: isoxfer.cpp:37
_Must_inspect_result_ _In_ WDFDEVICE _In_ PIRP _In_ WDFQUEUE Queue
Definition: wdfdevice.h:2231
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

Referenced by XhciTransferRing::AllowReclaimOnCancel().

◆ AwaitRingEmpty()

VOID XhciIsochRing::AwaitRingEmpty ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 908 of file isoxfer.cpp.

910{
911 if (Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::AwaitingStarve) == XhciMapState::Filling)
912 WdfTimerStart(Ring->m_Type.Isoch.m_Watchdog, WDF_REL_TIMEOUT_IN_MS(XhciIsochWatchdogMs));
913}
static const ULONG XhciIsochWatchdogMs
Definition: isoxfer.cpp:22
FORCEINLINE LONGLONG WDF_REL_TIMEOUT_IN_MS(_In_ ULONGLONG Time)
Definition: wdfcore.h:80

Referenced by FillLoop().

◆ BuildTdsFromQueue()

VOID XhciIsochRing::BuildTdsFromQueue ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 824 of file isoxfer.cpp.

826{
827 XhciIsochRing* Self = &Ring->m_Type.Isoch;
828 LONG State;
830
832
833 for (;;)
834 {
835 FillLoop(Ring);
836
837 State = InterlockedCompareExchange(&Ring->m_MapState, 0, 0);
838
839 if (State == static_cast<LONG>(XhciMapState::PausedFill) && Self->m_FillWanted != 0)
840 {
841 if (Ring->ChangeMapState(FALSE, XhciMapState::PausedFill, XhciMapState::Filling) == XhciMapState::PausedFill)
842 continue;
843 }
844 else if (State == static_cast<LONG>(XhciMapState::AwaitingStarve) && Self->m_RingEmptySeen != 0)
845 {
846 if (LeaveRingEmptyWait(Ring))
847 continue;
848 }
849
850 break;
851 }
852
854}
static VOID FillLoop(_In_ XhciTransferRing *Ring)
Definition: isoxfer.cpp:857
volatile LONG m_FillWanted
Definition: isoxfer.h:345
volatile LONG m_RingEmptySeen
Definition: isoxfer.h:346
static BOOLEAN LeaveRingEmptyWait(_In_ XhciTransferRing *Ring)
Definition: isoxfer.cpp:916
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define InterlockedCompareExchange
Definition: interlocked.h:119
long LONG
Definition: pedump.c:60

Referenced by KickAfterStage(), OnRingStarved(), ResumeRingFill(), and SegmentsArrived().

◆ Cleanup()

VOID XhciIsochRing::Cleanup ( _In_ XhciTransferRing *  Ring)
static

Definition at line 518 of file isoxfer.cpp.

520{
521 BOOLEAN Owned;
523
524 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
525 Owned = OwnsRequests(Ring);
526 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
527
528 if (Owned)
529 {
530 DPRINT1("Isoch DCI %lu cleaned up with requests still owned\n", Ring->m_Endpoint->Dci());
532 }
533}
static BOOLEAN OwnsRequests(_In_ const XhciTransferRing *Ring)
#define NT_ASSERT
Definition: rtlfuncs.h:3334

Referenced by XhciTransferRing::Cleanup().

◆ CompleteAfterUncancel()

static VOID XhciIsochRing::CompleteAfterUncancel ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochTransfer *  Transfer,
_In_ USBD_STATUS  PacketStatus,
_In_ USBD_STATUS  HeaderStatus,
_In_ BOOLEAN  FinishCanceled,
_In_ BOOLEAN  Async 
)
staticprivate

◆ CompleteBatch()

VOID XhciIsochRing::CompleteBatch ( _In_ XhciTransferRing *  Ring,
_Inout_ PLIST_ENTRY  Batch 
)
staticprivate

Definition at line 2477 of file isoxfer.cpp.

2480{
2481 XhciIsochTransfer* Transfer;
2482 KIRQL OldIrql;
2483
2484 while (!IsListEmpty(Batch))
2485 {
2487 XhciClearListEntry(&Transfer->Link);
2488
2489 if (Transfer->Status != STATUS_PENDING)
2490 {
2491 WdfRequestComplete(Transfer->Request, Transfer->Status);
2492 continue;
2493 }
2494
2495 ReleaseAllStages(Ring, Transfer);
2496
2497 /* QUIRK: everything reclaimed reports canceled, canceled or not */
2498 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2500 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2501 }
2502}
static ULONG ReleaseAllStages(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer)
Definition: isoxfer.cpp:2269
static VOID CompleteAfterUncancel(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer, _In_ USBD_STATUS PacketStatus, _In_ USBD_STATUS HeaderStatus, _In_ BOOLEAN FinishCanceled, _In_ BOOLEAN Async)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
static const USBD_STATUS XhciIsochNotSet
Definition: isoxfer.cpp:25
@ Batch
Definition: ntsecapi.h:291
NTSTATUS Status
Definition: isoxfer.h:60
WDFREQUEST Request
Definition: isoxfer.h:57
LIST_ENTRY Link
Definition: isoxfer.h:52
#define STATUS_PENDING
Definition: telnetd.h:14
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
#define USBD_STATUS_CANCELED
Definition: usb.h:225
FORCEINLINE VOID NTAPI XhciClearListEntry(_Out_ PLIST_ENTRY Entry)
Definition: xhciutil.h:117

◆ CompletePlain()

static VOID XhciIsochRing::CompletePlain ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochTransfer *  Transfer,
_In_ USBD_STATUS  PacketStatus,
_In_ USBD_STATUS  HeaderStatus,
_In_ BOOLEAN  Async 
)
staticprivate

Referenced by TakeRequest().

◆ CompleteTd()

VOID XhciIsochRing::CompleteTd ( _In_ XhciTransferRing *  Ring,
_In_ XhciIsochTransfer *  Transfer,
_In_ XhciIsochStage *  Stage,
_In_ ULONG  Sequence,
_In_ ULONG  Code,
_In_ ULONG  Bytes,
_In_ BOOLEAN  CloseStage 
)
staticprivate

Accounts one TD event; closing the stage's last TD frees the stage.

Definition at line 2091 of file isoxfer.cpp.

2099{
2100 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2101 struct _URB_ISOCH_TRANSFER* Urb;
2103 ULONG Packet;
2104 ULONG Index;
2105 ULONG InFlight;
2106 KIRQL OldIrql;
2107
2108 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2109
2110 /* A reclaim or a stale pass may have taken the stage meanwhile */
2111 if (!XhciIsochIsActive(&Self->m_Pending, Transfer, Sequence) ||
2112 !Stage->InUse ||
2113 Stage->Transfer != Transfer)
2114 {
2115 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2116 return;
2117 }
2118
2119 Urb = Transfer->Urb;
2120 Packet = Stage->NextPacket - 1;
2121 if (Packet >= Transfer->PacketsInUrb)
2122 {
2123 DPRINT1("Isoch DCI %lu: event for packet %lu of %lu\n",
2124 Ring->m_Endpoint->Dci(), Packet, Transfer->PacketsInUrb);
2125 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2126 return;
2127 }
2128
2129 /* TDs the controller passed without a Missed Service event */
2130 for (Index = Packet; Index > 0 && Urb->IsoPacket[Index - 1].Status == XhciIsochNotSet; Index--)
2131 {
2132 DPRINT1("Isoch DCI %lu: packet %lu was skipped by the controller\n",
2133 Ring->m_Endpoint->Dci(), Index - 1);
2134 Urb->IsoPacket[Index - 1].Status = USBD_STATUS_ISO_TD_ERROR;
2135 }
2136
2137 if (Urb->IsoPacket[Packet].Status == XhciIsochNotSet && (!XhciIsochStoppedCode(Code) || Bytes != 0))
2138 {
2140 Transfer->BytesTransferred += Bytes;
2141 if (XhciIsochEndpointIn(Ring))
2142 Urb->IsoPacket[Packet].Length = Bytes;
2143 }
2144
2145 if (Packet != Stage->LastPacket || !CloseStage)
2146 {
2147 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2148 return;
2149 }
2150
2151 if (!Stage->OnHardware)
2152 {
2153 DPRINT1("Isoch DCI %lu: end of a stage still being written was reported\n", Ring->m_Endpoint->Dci());
2154 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2155 return;
2156 }
2157
2158 SgList = Stage->SgList;
2159 Stage->SgList = NULL;
2160 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2161
2162 PutScatterGather(Ring, SgList);
2163
2164 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2165 if (!XhciIsochIsActive(&Self->m_Pending, Transfer, Sequence) || !Stage->InUse)
2166 {
2167 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2168 return;
2169 }
2170
2171 FreeStage(Ring, Stage);
2172 Transfer->TdsRetired++;
2173 if (Self->m_PendingStages != 0)
2174 Self->m_PendingStages--;
2175 InFlight = Self->m_PendingStages;
2176
2177 /* Complete only once no stage is in use and every packet was queued or dropped */
2178 if (TransferDone(Transfer))
2180
2181 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2182
2183 KickAfterStage(Ring, InFlight);
2184}
static VOID FreeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
static VOID KickAfterStage(_In_ XhciTransferRing *Ring, _In_ ULONG InFlight)
Definition: isoxfer.cpp:931
static VOID PutScatterGather(_In_ XhciTransferRing *Ring, _In_opt_ PSCATTER_GATHER_LIST SgList)
ULONG m_PendingStages
Definition: isoxfer.h:340
static USBD_STATUS UsbdStatusFromCompletionCode(_In_ ULONG CompletionCode)
Definition: xferring.cpp:1184
static BOOLEAN NTAPI XhciIsochStoppedCode(_In_ ULONG Code)
Definition: isoxfer.cpp:54
static BOOLEAN NTAPI XhciIsochIsActive(_In_ const LIST_ENTRY *Pending, _In_ const XhciIsochTransfer *Transfer, _In_ ULONG Sequence)
Definition: isoxfer.cpp:182
static BOOLEAN NTAPI XhciIsochEndpointIn(_In_ const XhciTransferRing *Ring)
Definition: isoxfer.cpp:65
_In_ UINT Bytes
Definition: mmcopy.h:9
_In_ NDIS_HANDLE _In_ PNDIS_PACKET Packet
Definition: ndis.h:1549
#define USBD_STATUS_ISO_TD_ERROR
Definition: usb.h:227
_In_opt_ PUSB_CONFIGURATION_DESCRIPTOR _Inout_ PUSBD_INTERFACE_LIST_ENTRY _Outptr_ PURB * Urb
Definition: usbdlib.h:333
_In_ WDFCOLLECTION _In_ ULONG Index
_In_ UCHAR _In_ UCHAR _In_ ULONG Code
Definition: wdfdevice.h:1707
WDF_EXTERN_C_START typedef _In_ WDFDEVICE _In_ WDFCONTEXT _In_ WDF_DMA_DIRECTION _In_ PSCATTER_GATHER_LIST SgList
struct _SCATTER_GATHER_LIST * PSCATTER_GATHER_LIST
Definition: iotypes.h:2219

Referenced by Ed0Event(), Ed1Event(), FinishLostStages(), and RetireExpiredStages().

◆ ConsumePendingEvents()

VOID XhciIsochRing::ConsumePendingEvents ( _In_ XhciTransferRing *  Ring)
static

Definition at line 726 of file isoxfer.cpp.

728{
729 /* Lost Missed Service events mean there is nothing reliable to wait for; late ones are dropped */
730 Ring->m_Endpoint->OnExpectedEventsProcessed();
731}

Referenced by XhciTransferRing::ConsumePendingEvents().

◆ Disable()

VOID XhciIsochRing::Disable ( _In_ XhciTransferRing *  Ring)
static

Definition at line 479 of file isoxfer.cpp.

481{
482 XhciIsochRing* Self = &Ring->m_Type.Isoch;
484
486 WdfTimerStop(Self->m_Watchdog, FALSE);
487
488 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
489 if (OwnsRequests(Ring))
490 DPRINT1("Isoch DCI %lu disabled while it still owns requests\n", Ring->m_Endpoint->Dci());
491 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
492}
static VOID ReleaseParkedMapping(_In_ XhciTransferRing *Ring)
Definition: isoxfer.cpp:495
WDFTIMER m_Watchdog
Definition: isoxfer.h:354

◆ DoorbellRungSinceFill()

BOOLEAN XhciIsochRing::DoorbellRungSinceFill ( _In_ const XhciTransferRing *  Ring)
static

Definition at line 750 of file isoxfer.cpp.

752{
753 return (Ring->m_Type.Isoch.m_Flags & XhciIsochDoorbellRung) != 0;
754}
static const LONG XhciIsochDoorbellRung
Definition: isoxfer.cpp:35

Referenced by XhciTransferRing::DoorbellRungSinceFill().

◆ Ed0Event()

VOID XhciIsochRing::Ed0Event ( _In_ XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event 
)
staticprivate

Definition at line 2661 of file isoxfer.cpp.

2664{
2665 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2667 ULONG64 Pointer = XhciTrbPointer(Event);
2668 XhciIsochTransfer* Transfer = NULL;
2669 XhciIsochStage* Stage;
2670 ULONG Sequence = 0;
2671 ULONG Bytes;
2672 BOOLEAN Matched;
2673 KIRQL OldIrql;
2674
2675 switch (static_cast<XhciCompletionCode>(Code))
2676 {
2677 case XhciCompletionCode::RingUnderrun:
2678 case XhciCompletionCode::RingOverrun:
2679 OnRingStarved(Ring);
2680 return;
2681
2682 case XhciCompletionCode::MissedService:
2683 Self->m_MissedServiceErrors++;
2684
2685 /* A Missed Service event without a TRB pointer has nothing to complete */
2686 if (Pointer == 0)
2687 return;
2688 break;
2689
2690 case XhciCompletionCode::NoPingResponse:
2691 UcxEndpointNoPingResponseError(Ring->m_Endpoint->Handle());
2692
2693 /* The length is invalid without a TRB pointer */
2694 if (Pointer == 0)
2695 return;
2696 break;
2697
2698 case XhciCompletionCode::Stopped:
2699 case XhciCompletionCode::StoppedLengthInvalid:
2700 case XhciCompletionCode::StoppedShortPacket:
2701 case XhciCompletionCode::DataBufferError:
2702 case XhciCompletionCode::BabbleDetected:
2703 case XhciCompletionCode::IsochBufferOverrun:
2704 case XhciCompletionCode::UsbTransactionError:
2705 case XhciCompletionCode::StallError:
2706 case XhciCompletionCode::EventLost:
2707 case XhciCompletionCode::SplitTransactionError:
2708 break;
2709
2710 default:
2711 DPRINT1("Isoch DCI %lu: unexpected code %lu without Event Data\n", Ring->m_Endpoint->Dci(), Code);
2712 break;
2713 }
2714
2715 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2716
2717 if (Self->m_Flags & XhciIsochStoppedSeen)
2718 {
2719 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2720 return;
2721 }
2722
2723 Matched = FindTrb(Ring, Event, &Stage, &Bytes);
2724 if (Stage != NULL)
2725 {
2726 Transfer = Stage->Transfer;
2727 Sequence = Transfer->Sequence;
2728 }
2729
2731 {
2732 /* Also covers a stop at the enqueue pointer or on a Link TRB after the last stage */
2734 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2735
2736 if (Stage != NULL)
2737 CompleteTd(Ring, Transfer, Stage, Sequence, Code, Bytes, FALSE);
2738
2739 Ring->m_Endpoint->OnStoppedEvent();
2740 return;
2741 }
2742
2743 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2744
2745 if (Stage == NULL)
2746 {
2747 if (!Matched)
2748 {
2749 DPRINT("Isoch DCI %lu: event at 0x%I64x code %lu matched no stage, dropped\n",
2750 Ring->m_Endpoint->Dci(), Pointer, Code);
2751 }
2752 return;
2753 }
2754
2755 /* The following Event Data event or a later stale pass closes the stage */
2756 FinishExpiredIsoch(Ring, Transfer, Sequence);
2757 RetireExpiredStages(Ring, Transfer, Stage, Sequence);
2758 CompleteTd(Ring, Transfer, Stage, Sequence, Code, Bytes, FALSE);
2759}
static VOID OnRingStarved(_In_ XhciTransferRing *Ring)
Definition: isoxfer.cpp:2924
static VOID FinishExpiredIsoch(_In_ XhciTransferRing *Ring, _In_ const XhciIsochTransfer *Newest, _In_ ULONG Sequence)
Definition: isoxfer.cpp:2188
static VOID CompleteTd(_In_ XhciTransferRing *Ring, _In_ XhciIsochTransfer *Transfer, _In_ XhciIsochStage *Stage, _In_ ULONG Sequence, _In_ ULONG Code, _In_ ULONG Bytes, _In_ BOOLEAN CloseStage)
Definition: isoxfer.cpp:2091
ULONG m_MissedServiceErrors
Definition: isoxfer.h:362
static BOOLEAN FindTrb(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event, _Outptr_result_maybenull_ XhciIsochStage **Found, _Out_ PULONG Bytes)
static VOID RetireExpiredStages(_In_ XhciTransferRing *Ring, _In_ XhciIsochTransfer *Transfer, _In_ XhciIsochStage *Stage, _In_ ULONG Sequence)
Definition: isoxfer.cpp:2224
_Check_return_ _In_ DXGK_EVENT_TYPE _In_ ULONG Event
Definition: dispmprt.h:1287
static const LONG XhciIsochStoppedSeen
Definition: isoxfer.cpp:41
unsigned __int64 ULONG64
Definition: imports.h:198
#define DPRINT
Definition: sndvol32.h:73
XhciIsochTransfer * Transfer
Definition: isoxfer.h:30
ULONG Sequence
Definition: isoxfer.h:54
FORCEINLINE ULONG64 NTAPI XhciTrbPointer(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:60
XhciCompletionCode
Definition: xhcihw.h:110
FORCEINLINE ULONG NTAPI XhciTrbCompletionCode(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:42

Referenced by OnTransferEvent().

◆ Ed1Event()

VOID XhciIsochRing::Ed1Event ( _In_ XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event 
)
staticprivate

Definition at line 2564 of file isoxfer.cpp.

2567{
2568 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2572 ULONG Packet = (ULONG)(Value >> 16) & 0xFFFF;
2573 ULONG Frame = (ULONG)(Value >> 32);
2574 XhciIsochTransfer* Transfer = NULL;
2575 XhciIsochStage* Stage = NULL;
2576 ULONG Sequence = 0;
2578 ULONG Index;
2579 KIRQL OldIrql;
2580
2582 {
2583 DPRINT1("Isoch DCI %lu: Event Data 0x%I64x is not an isoch tag, resetting\n",
2584 Ring->m_Endpoint->Dci(), Value);
2585 Ring->m_Controller->RaiseControllerFault(XhciRecovery::ResetHost, XhciIsochReasonBadEventData);
2586 return;
2587 }
2588
2589 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2590
2591 if (Self->m_Flags & XhciIsochStoppedSeen)
2592 {
2593 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2594 return;
2595 }
2596
2597 /* QUIRK: found by start frame, so of two URBs with one start frame the older one matches */
2598 for (Entry = Self->m_Pending.Flink; Entry != &Self->m_Pending; Entry = Entry->Flink)
2599 {
2601
2602 if (Candidate->StartFrame == Frame)
2603 {
2604 Transfer = Candidate;
2605 break;
2606 }
2607 }
2608
2609 if (Transfer != NULL)
2610 {
2611 Sequence = Transfer->Sequence;
2612
2613 for (Index = 0; Index < Transfer->StageCount; Index++)
2614 {
2615 XhciIsochStage* Candidate = XhciIsochStageAt(Transfer, Index);
2616
2617 if (Packet <= Candidate->LastPacket)
2618 {
2619 Stage = Candidate;
2620 break;
2621 }
2622 }
2623
2624 if (Stage == NULL)
2625 {
2626 DPRINT1("Isoch DCI %lu: no stage holds packet %lu of request %p\n",
2627 Ring->m_Endpoint->Dci(), Packet, Transfer->Request);
2628 }
2629 else if (Packet == 0 || Packet > Stage->NextPacket - 1)
2630 {
2631 Stage->NextPacket = Packet + 1;
2632 Transfer->PacketsRetired = Packet + 1;
2633 }
2634 }
2635
2637 {
2638 /* Some controllers report the stop on the Event Data TRB */
2640 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2641
2642 if (Stage != NULL)
2643 CompleteTd(Ring, Transfer, Stage, Sequence, Code, Bytes, FALSE);
2644
2645 Ring->m_Endpoint->OnStoppedEvent();
2646 return;
2647 }
2648
2649 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2650
2651 /* A late event of a request that is gone already */
2652 if (Stage == NULL)
2653 return;
2654
2655 FinishExpiredIsoch(Ring, Transfer, Sequence);
2656 RetireExpiredStages(Ring, Transfer, Stage, Sequence);
2657 CompleteTd(Ring, Transfer, Stage, Sequence, Code, Bytes, TRUE);
2658}
PLIST_ENTRY Entry
Definition: devhcd.cpp:1262
static XhciIsochStage *NTAPI XhciIsochStageAt(_In_ XhciIsochTransfer *Transfer, _In_ ULONG Position)
Definition: isoxfer.cpp:98
static const ULONG XhciIsochReasonBadEventData
Definition: isoxfer.cpp:32
ULONG NextPacket
Definition: isoxfer.h:33
ULONG StartFrame
Definition: isoxfer.h:62
ULONG PacketsRetired
Definition: isoxfer.h:68
ULONG StageCount
Definition: isoxfer.h:74
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
static MOUSE_PACKET LastPacket
Definition: mouse.c:32
#define USB_ENDPOINT_TYPE_ISOCHRONOUS
Definition: usb100.h:63
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
#define XHCI_TRANSFER_EVENT_LENGTH_MASK
Definition: xhcihw.h:635
#define XHCI_EVENT_DATA_TYPE_MASK
Definition: xhcihw.h:324

Referenced by OnTransferEvent().

◆ Enable()

VOID XhciIsochRing::Enable ( _In_ XhciTransferRing *  Ring)
static

Definition at line 468 of file isoxfer.cpp.

470{
472
473 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
474 Ring->m_Type.Isoch.m_FreshStream = TRUE;
475 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
476}

Referenced by _IRQL_requires_max_().

◆ EncodeStage()

XhciIsochRing::Outcome XhciIsochRing::EncodeStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage 
)
staticprivate

Definition at line 1675 of file isoxfer.cpp.

1678{
1679 XhciIsochRing* Self = &Ring->m_Type.Isoch;
1680 PDMA_ADAPTER Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
1682 KIRQL OldIrql;
1683
1685
1687 Status = Adapter->DmaOperations->GetScatterGatherList(Adapter,
1688 WdfDeviceWdmGetDeviceObject(Ring->m_Controller->m_Device),
1689 Stage->Mdl,
1690 MmGetMdlVirtualAddress(Stage->Mdl),
1691 Stage->Size,
1693 Stage,
1694 !XhciIsochEndpointIn(Ring));
1696
1697 if (!NT_SUCCESS(Status))
1698 {
1699 DPRINT1("Isoch DCI %lu: GetScatterGatherList for %lu bytes failed, 0x%08lx\n",
1700 Ring->m_Endpoint->Dci(), Stage->Size, Status);
1701 (VOID)FailStage(Ring, Stage);
1702 return Outcome::Ready;
1703 }
1704
1705 /* Whichever of this context and the callback gets here second keeps mapping */
1706 if (InterlockedXor(&Self->m_FillAgain, 1) == 1)
1707 return (Self->m_LateStage != 0) ? Outcome::Late : Outcome::Ready;
1708
1709 return Outcome::WaitDma;
1710}
#define VOID
Definition: acefi.h:82
#define InterlockedExchange
Definition: armddk.h:54
LONG NTSTATUS
Definition: precomp.h:26
static Outcome FailStage(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
Definition: isoxfer.cpp:1643
static DRIVER_LIST_CONTROL DmaCallback
Definition: isoxfer.h:155
volatile LONG m_LateStage
Definition: isoxfer.h:348
volatile LONG m_FillAgain
Definition: isoxfer.h:347
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
Status
Definition: gdiplustypes.h:24
#define InterlockedXor
Definition: interlocked.h:281
struct _DMA_OPERATIONS * DmaOperations
Definition: iotypes.h:2310

Referenced by FillLoop().

◆ EstimateSegments()

ULONG XhciIsochRing::EstimateSegments ( _In_ XhciTransferRing *  Ring,
_In_ const XhciIsochStage *  Stage 
)
staticprivate

Definition at line 1601 of file isoxfer.cpp.

1604{
1605 XhciIsochRing* Self = &Ring->m_Type.Isoch;
1606 BOOLEAN Guard = XhciIsochNeedsLinkGuard(Ring);
1607 ULONG PerTd;
1608 ULONG Needed;
1609 ULONG Available;
1610 ULONG Usable;
1611 ULONG Segments = 0;
1612
1613 PerTd = 1 + ((XhciIsochEsitPayload(Ring) + 2 * PAGE_SIZE - 2) >> PAGE_SHIFT);
1614 if (Guard)
1615 PerTd += 1;
1616 if (MmGetMdlByteCount(Stage->Mdl) < Stage->Size)
1617 PerTd += 2;
1618
1619 /* A TD never needs more than one segment */
1620 if (PerTd > Ring->m_LastIndex)
1621 PerTd = Ring->m_LastIndex;
1622
1623 Self->m_TrbsPerTd = PerTd;
1624
1625 Needed = PerTd * (Stage->LastPacket - Stage->FirstPacket + 1);
1626 Available = Ring->m_LastIndex - Ring->m_EnqueueIndex;
1627 Available -= Available % PerTd;
1628
1629 if (Needed > Available)
1630 {
1631 Usable = Ring->m_LastIndex - (Ring->m_LastIndex % PerTd);
1632 Segments = (Needed - Available + Usable - 1) / Usable;
1633 }
1634
1635 if (Guard)
1636 Segments++;
1637
1638 return Segments;
1639}
_In_ ULONG const Usable
Definition: cdrom.h:1084
ULONG m_TrbsPerTd
Definition: isoxfer.h:341
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
static BOOLEAN NTAPI XhciIsochNeedsLinkGuard(_In_ const XhciTransferRing *Ring)
Definition: isoxfer.cpp:124
static ULONG NTAPI XhciIsochEsitPayload(_In_ const XhciTransferRing *Ring)
Definition: isoxfer.cpp:109

Referenced by PrimeStage().

◆ FailStage()

XhciIsochRing::Outcome XhciIsochRing::FailStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage 
)
staticprivate

Drops a stage that cannot be mapped; completes its request when nothing of it is on the ring.

Definition at line 1643 of file isoxfer.cpp.

1646{
1647 XhciIsochTransfer* Transfer = Stage->Transfer;
1648 PSCATTER_GATHER_LIST SgList = Stage->SgList;
1650 KIRQL OldIrql;
1651
1652 Stage->SgList = NULL;
1653 PutScatterGather(Ring, SgList);
1654
1655 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1656 FreeStage(Ring, Stage);
1657
1658 if (Transfer->TdsRetired == Transfer->TdsQueued)
1659 {
1662 }
1663 else
1664 {
1665 /* The request completes when its last mapped stage comes back */
1666 SkipUnmapped(Transfer);
1668 }
1669
1670 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1671 return Result;
1672}
static VOID SkipUnmapped(_Inout_ XhciIsochTransfer *Transfer)
Definition: isoxfer.cpp:1282
ULONG TdsRetired
Definition: isoxfer.h:71
ULONG TdsQueued
Definition: isoxfer.h:72
#define USBD_STATUS_INSUFFICIENT_RESOURCES
Definition: usb.h:215
_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

Referenced by EncodeStage(), PrimeStage(), and WriteStage().

◆ FillLoop()

VOID XhciIsochRing::FillLoop ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 857 of file isoxfer.cpp.

859{
860 XhciIsochRing* Self = &Ring->m_Type.Isoch;
861 XhciIsochStage* Stage;
863
864 for (;;)
865 {
868
869 Stage = NextTdSlot(Ring);
870 if (Stage == NULL)
871 {
872 Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::PausedFill);
873 return;
874 }
875
876 Result = PrimeStage(Ring, Stage);
878 continue;
880 return;
881 if (Result == Outcome::Gap)
882 {
883 AwaitRingEmpty(Ring);
884 return;
885 }
886 if (Result == Outcome::Failed)
887 {
888 Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::PausedFill);
889 return;
890 }
891
892 Result = EncodeStage(Ring, Stage);
894 return;
895 if (Result == Outcome::Late)
896 {
897 AwaitRingEmpty(Ring);
898 return;
899 }
900
901 /* Also completes a stop that raced in */
902 if (Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::Filling) != XhciMapState::Filling)
903 return;
904 }
905}
static Outcome EncodeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
Definition: isoxfer.cpp:1675
static VOID AwaitRingEmpty(_In_ XhciTransferRing *Ring)
Definition: isoxfer.cpp:908
static Outcome PrimeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
Definition: isoxfer.cpp:1393
static XhciIsochStage * NextTdSlot(_In_ XhciTransferRing *Ring)
Definition: isoxfer.cpp:966

Referenced by BuildTdsFromQueue().

◆ Finalize()

VOID XhciIsochRing::Finalize ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochTransfer *  Transfer,
_In_ USBD_STATUS  PacketStatus,
_In_ USBD_STATUS  HeaderStatus 
)
staticprivate

Fills in the URB from the transfer record and frees what intake built.

Definition at line 2312 of file isoxfer.cpp.

2317{
2318 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2319 struct _URB_ISOCH_TRANSFER* Urb = Transfer->Urb;
2321 ULONG Index;
2322
2323 NT_ASSERT(Transfer->StageCount == 0);
2324
2325 Urb->TransferBufferLength = Transfer->BytesTransferred;
2326
2327 for (Index = 0; Index < Transfer->PacketsInUrb; Index++)
2328 {
2329 if (PacketStatus != XhciIsochNotSet)
2330 Urb->IsoPacket[Index].Status = PacketStatus;
2331 else if (Urb->IsoPacket[Index].Status == XhciIsochNotSet)
2332 Urb->IsoPacket[Index].Status = USBD_STATUS_ISO_NOT_ACCESSED_BY_HW;
2333
2334 /* QUIRK: added to whatever the URB held, as the USB 2.0 stack does */
2335 if (Urb->IsoPacket[Index].Status != USBD_STATUS_SUCCESS)
2336 {
2337 Urb->ErrorCount++;
2338 Self->m_TdFailures++;
2339 }
2340 Self->m_Tds++;
2341 }
2342
2343 if (HeaderStatus != XhciIsochNotSet)
2344 Status = HeaderStatus;
2345 else if (Urb->ErrorCount == Transfer->PacketsInUrb)
2347 else
2349
2350 Urb->Hdr.Status = Status;
2352
2353 Self->m_Transfers++;
2354 Self->m_Bytes += Transfer->BytesTransferred;
2355 if (!NT_SUCCESS(Transfer->Status))
2356 {
2357 Self->m_FailedTransfers++;
2358
2359 if (Transfer->Status != STATUS_CANCELLED)
2360 {
2361 DPRINT1("Isoch DCI %lu request %p failed, 0x%08lx USBD 0x%08lx, %lu of %lu packets in error\n",
2362 Ring->m_Endpoint->Dci(), Transfer->Request, Transfer->Status, Status,
2363 Urb->ErrorCount, Transfer->PacketsInUrb);
2364 }
2365 }
2366
2367 if (Transfer->OwnMdl)
2368 {
2369 IoFreeMdl(Transfer->Mdl);
2370 Transfer->OwnMdl = FALSE;
2371 }
2372 Transfer->Mdl = NULL;
2373 Transfer->Initialized = 0;
2374}
ULONG64 m_Bytes
Definition: isoxfer.h:359
ULONG m_Tds
Definition: isoxfer.h:360
ULONG m_Transfers
Definition: isoxfer.h:357
ULONG m_TdFailures
Definition: isoxfer.h:361
ULONG m_FailedTransfers
Definition: isoxfer.h:358
static NTSTATUS NtStatusFromUsbdStatus(_In_ USBD_STATUS UsbdStatus)
Definition: xferring.cpp:1237
#define IoFreeMdl
Definition: fxmdl.h:89
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
#define USBD_STATUS_ISO_NOT_ACCESSED_BY_HW
Definition: usb.h:226
#define USBD_STATUS_SUCCESS
Definition: usb.h:177
LONG USBD_STATUS
Definition: usb.h:172
#define USBD_STATUS_ISOCH_REQUEST_FAILED
Definition: usb.h:210

◆ FindTrb()

static BOOLEAN XhciIsochRing::FindTrb ( _In_ XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event,
_Outptr_result_maybenull_ XhciIsochStage **  Found,
_Out_ PULONG  Bytes 
)
staticprivate

Referenced by Ed0Event().

◆ FinishExpiredIsoch()

VOID XhciIsochRing::FinishExpiredIsoch ( _In_ XhciTransferRing *  Ring,
_In_ const XhciIsochTransfer *  Newest,
_In_ ULONG  Sequence 
)
staticprivate

Completes every active transfer older than Newest; their events will not come.

Definition at line 2188 of file isoxfer.cpp.

2192{
2193 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2194 XhciIsochTransfer* Transfer;
2195 LIST_ENTRY Stale;
2196 KIRQL OldIrql;
2197
2198 InitializeListHead(&Stale);
2199
2200 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2201 if (XhciIsochIsActive(&Self->m_Pending, Newest, Sequence))
2202 {
2203 while (Self->m_Pending.Flink != &Newest->Link)
2204 InsertTailList(&Stale, RemoveHeadList(&Self->m_Pending));
2205 }
2206 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2207
2208 while (!IsListEmpty(&Stale))
2209 {
2211 XhciClearListEntry(&Transfer->Link);
2212
2213 DPRINT("Isoch DCI %lu: completing stale request %p\n", Ring->m_Endpoint->Dci(), Transfer->Request);
2214 ReleaseAllStages(Ring, Transfer);
2215
2216 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2218 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2219 }
2220}
#define InsertTailList(ListHead, Entry)
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944

Referenced by Ed0Event(), and Ed1Event().

◆ FinishLostStages()

BOOLEAN XhciIsochRing::FinishLostStages ( _In_ XhciTransferRing *  Ring)
staticprivate

Closes in flight stages as missed once every frame they were scheduled for has passed.

Definition at line 2960 of file isoxfer.cpp.

2962{
2963 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2964 ULONG Now = Ring->m_Controller->GetFrameNumber(XhciIsochBiasNow);
2965 XhciIsochTransfer* Transfer;
2966 XhciIsochStage* Stage;
2968 ULONG Sequence;
2969 ULONG Index;
2970 BOOLEAN Stuck;
2971 KIRQL OldIrql;
2972
2973 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2974 if ((Self->m_Flags & XhciIsochLastFrameValid) && (LONG)(Now - Self->m_LastScheduledFrame) <= 0)
2975 {
2976 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2977 return FALSE;
2978 }
2979 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2980
2981 for (;;)
2982 {
2983 Stage = NULL;
2984 Transfer = NULL;
2985 Sequence = 0;
2986
2987 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2988 for (Entry = Self->m_Pending.Flink; Entry != &Self->m_Pending && Stage == NULL; Entry = Entry->Flink)
2989 {
2991
2992 for (Index = 0; Index < Transfer->StageCount; Index++)
2993 {
2994 if (XhciIsochStageAt(Transfer, Index)->OnHardware)
2995 {
2996 Stage = XhciIsochStageAt(Transfer, Index);
2997 Stage->NextPacket = Stage->LastPacket + 1;
2998 Sequence = Transfer->Sequence;
2999 break;
3000 }
3001 }
3002 }
3003 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
3004
3005 if (Stage == NULL)
3006 break;
3007
3008 DPRINT1("Isoch DCI %lu: closing a stage whose events never came\n", Ring->m_Endpoint->Dci());
3009 CompleteTd(Ring, Transfer, Stage, Sequence, static_cast<ULONG>(XhciCompletionCode::MissedService), 0, TRUE);
3010
3011 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
3012 Stuck = Stage->InUse && Stage->OnHardware && Stage->Transfer == Transfer;
3013 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
3014
3015 if (Stuck)
3016 break;
3017 }
3018
3019 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
3021 if (Self->m_PendingStages == 0)
3023 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
3024
3025 return TRUE;
3026}
ULONG m_LastScheduledFrame
Definition: isoxfer.h:338
#define InterlockedAnd
Definition: interlocked.h:77
static const ULONG XhciIsochBiasNow
Definition: isoxfer.cpp:28
static const LONG XhciIsochLastFrameValid
Definition: isoxfer.cpp:40
static const LONG XhciIsochEmptyExpected
Definition: isoxfer.cpp:39
struct tm * Now
Definition: output.c:19
BOOLEAN OnHardware
Definition: isoxfer.h:27
ULONG LastPacket
Definition: isoxfer.h:32
BOOLEAN InUse
Definition: isoxfer.h:26

◆ FlagMissedPackets()

VOID XhciIsochRing::FlagMissedPackets ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochTransfer *  Transfer 
)
staticprivate

Marks the unmapped frames that are already due as late.

Definition at line 1253 of file isoxfer.cpp.

1256{
1257 ULONG PerFrame = Ring->m_Type.Isoch.m_PacketsPerFrame;
1258 ULONG First = Transfer->PacketsQueued + Transfer->PacketsDropped;
1259 ULONG Frame = Transfer->StartFrame + XhciIsochFrames(First, PerFrame);
1260 ULONG End = Frame + XhciIsochFrames(Transfer->PacketsInUrb - First, PerFrame);
1261 ULONG Now = Ring->m_Controller->GetFrameNumber(XhciIsochBiasLate);
1262 ULONG Packet;
1263 ULONG Index;
1264
1265 /* QUIRK: unsigned compares without wrap handling */
1266 while (Frame < End && Frame <= Now)
1267 {
1268 Packet = (Frame - Transfer->StartFrame) * PerFrame;
1269
1270 for (Index = 0; Index < PerFrame && Packet + Index < Transfer->PacketsInUrb; Index++)
1271 {
1272 Transfer->Urb->IsoPacket[Packet + Index].Status = USBD_STATUS_ISO_NOT_ACCESSED_LATE;
1273 Transfer->BytesDropped += XhciIsochPacketLength(Transfer, Packet + Index);
1274 Transfer->PacketsDropped++;
1275 }
1276
1277 Frame++;
1278 }
1279}
WCHAR First[]
Definition: FormatMessage.c:11
PUCHAR End
Definition: desccheck.cpp:2229
static ULONG NTAPI XhciIsochFrames(_In_ ULONG Packets, _In_ ULONG PerFrame)
Definition: isoxfer.cpp:74
static const ULONG XhciIsochBiasLate
Definition: isoxfer.cpp:29
static ULONG NTAPI XhciIsochPacketLength(_In_ const XhciIsochTransfer *Transfer, _In_ ULONG Packet)
Definition: isoxfer.cpp:84
#define USBD_STATUS_ISO_NOT_ACCESSED_LATE
Definition: usb.h:229

Referenced by NextTdSlot(), and TakeRequest().

◆ FreeStage()

static VOID XhciIsochRing::FreeStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage 
)
staticprivate

◆ HasQueuedWork()

BOOLEAN XhciIsochRing::HasQueuedWork ( _In_ const XhciTransferRing *  Ring)
static

Definition at line 757 of file isoxfer.cpp.

759{
760 PKSPIN_LOCK Lock = const_cast<PKSPIN_LOCK>(&Ring->m_Lock);
763
765 Pending = !IsListEmpty(&Ring->m_Type.Isoch.m_Pending);
767
768 return Pending;
769}
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
@ Pending
Definition: fs_rec.h:186
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127

Referenced by XhciTransferRing::HasQueuedWork().

◆ Initialize()

NTSTATUS XhciIsochRing::Initialize ( _In_ XhciTransferRing *  Ring)
static

Definition at line 422 of file isoxfer.cpp.

424{
425 XhciIsochRing* Self = &Ring->m_Type.Isoch;
426 USB_DEVICE_SPEED Speed = Ring->m_Device->Speed();
427 ULONG Interval = Ring->m_Endpoint->Descriptor()->bInterval;
428 WDF_TIMER_CONFIG TimerConfig;
432
433 RtlZeroMemory(Self, sizeof(*Self));
437
438 if (Speed >= UsbHighSpeed)
439 {
440 /* QUIRK: the raw bInterval is used, and 0 behaves as an 8 microframe period */
441 Period = (Interval == 0 || Interval > 4) ? 8 : (1UL << (Interval - 1));
442 Self->m_PacketsPerFrame = 8 / Period;
443 }
444 else
445 {
446 NT_ASSERT(Speed == UsbFullSpeed);
447 Self->m_PacketsPerFrame = 1;
448 }
449
450 WDF_TIMER_CONFIG_INIT(&TimerConfig, EvtWatchdog);
451 TimerConfig.TolerableDelay = 0;
453 Attributes.ParentObject = Ring->m_Queue;
454
455 Status = WdfTimerCreate(&TimerConfig, &Attributes, &Self->m_Watchdog);
456 if (!NT_SUCCESS(Status))
457 {
458 DPRINT1("Isoch DCI %lu: ring empty watchdog not created, 0x%08lx\n",
459 Ring->m_Endpoint->Dci(), Status);
460 return Status;
461 }
462
463 DPRINT("Isoch DCI %lu: %lu packets per frame\n", Ring->m_Endpoint->Dci(), Self->m_PacketsPerFrame);
464 return STATUS_SUCCESS;
465}
static EVT_WDF_TIMER EvtWatchdog
Definition: isoxfer.h:154
LIST_ENTRY m_WaitingForCancel
Definition: isoxfer.h:352
ULONG m_PacketsPerFrame
Definition: isoxfer.h:339
_In_ ULONG Attributes
Definition: dispmprt.h:1077
DWORD Interval
Definition: netstat.c:28
ULONG TolerableDelay
Definition: wdftimer.h:95
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
@ UsbHighSpeed
Definition: usb200.h:44
@ UsbFullSpeed
Definition: usb200.h:43
enum _USB_DEVICE_SPEED USB_DEVICE_SPEED
FORCEINLINE VOID WDF_OBJECT_ATTRIBUTES_INIT(_Out_ PWDF_OBJECT_ATTRIBUTES Attributes)
Definition: wdfobject.h:147
FORCEINLINE VOID WDF_TIMER_CONFIG_INIT(_Out_ PWDF_TIMER_CONFIG Config, _In_ PFN_WDF_TIMER EvtTimerFunc)
Definition: wdftimer.h:111
_In_ LARGE_INTEGER _In_ ULONG Period
Definition: kefuncs.h:1304

Referenced by _IRQL_requires_().

◆ InsertLink()

VOID XhciIsochRing::InsertLink ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage,
_In_ BOOLEAN  FirstOfTd 
)
staticprivate

Ends the current segment with a Link TRB into the stage's next reserved segment.

Definition at line 2056 of file isoxfer.cpp.

2060{
2062 XHCI_TRB Trb;
2063 KIRQL OldIrql;
2064
2065 /* The layout pass made sure a reserved segment is there */
2066 NT_ASSERT(!IsListEmpty(&Stage->FreeSegments));
2067
2068 Next = CONTAINING_RECORD(RemoveHeadList(&Stage->FreeSegments), XhciDmaBuffer, Link);
2069 XhciClearListEntry(&Next->Link);
2070
2071 Ring->BuildLinkTrb(&Trb, FirstOfTd, !FirstOfTd);
2072 Trb.Dword[0] = Next->LogicalAddress.LowPart;
2073 Trb.Dword[1] = (ULONG)Next->LogicalAddress.HighPart;
2074 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
2075
2076 /* Never Toggle Cycle: the ring is an endless forward chain of fresh segments */
2077 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2078 InsertTailList(&Stage->UsedSegments, &Ring->m_Segment->Link);
2079 Ring->m_Segment = Next;
2080 Ring->m_Trbs = static_cast<PXHCI_TRB>(Next->VirtualAddress);
2081 Ring->m_EnqueueIndex = 0;
2082 Stage->LastSegment = Next;
2083 Stage->EndIndex = 0;
2084 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2085}
PACPI_METHOD_ARGUMENT Next
Definition: slotdev.cpp:96
ULONG Dword[4]
Definition: xhcihw.h:17

Referenced by LayoutStage().

◆ KickAfterStage()

VOID XhciIsochRing::KickAfterStage ( _In_ XhciTransferRing *  Ring,
_In_ ULONG  InFlight 
)
staticprivate

A stage left the ring: map more, or leave the ring empty wait once nothing is in flight.

Definition at line 931 of file isoxfer.cpp.

934{
935 InterlockedExchange(&Ring->m_Type.Isoch.m_FillWanted, 1);
936
937 if (Ring->ChangeMapState(FALSE, XhciMapState::PausedFill, XhciMapState::Filling) == XhciMapState::PausedFill)
938 {
939 BuildTdsFromQueue(Ring);
940 return;
941 }
942
943 if (InFlight == 0 && LeaveRingEmptyWait(Ring))
944 BuildTdsFromQueue(Ring);
945}
static VOID BuildTdsFromQueue(_In_ XhciTransferRing *Ring)
Definition: isoxfer.cpp:824

Referenced by CompleteTd().

◆ LayoutStage()

ULONG XhciIsochRing::LayoutStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage,
_In_ BOOLEAN  Commit 
)
staticprivate

Lays the stage's TDs out on the ring. Without Commit it only counts how many TDs fit the current segment and the reserved ones, the last of them still able to end the stage.

Definition at line 1823 of file isoxfer.cpp.

1827{
1828 XhciIsochRing* Self = &Ring->m_Type.Isoch;
1829 XhciIsochTransfer* Transfer = Stage->Transfer;
1830 const SCATTER_GATHER_LIST* SgList = Stage->SgList;
1831 ULONG LastSlot = Ring->m_LastIndex;
1832 ULONG LastPacket = Stage->LastPacket;
1833 ULONG PerFrame = Self->m_PacketsPerFrame;
1834 BOOLEAN Guard = XhciIsochNeedsLinkGuard(Ring);
1835 BOOLEAN AllowBei = !Ring->m_Controller->HasErrata(XhciErrata::IsochInterruptEveryTd);
1836 ULONG Hcc2 = Ring->m_Controller->m_Registers.Hccparams2();
1837 BOOLEAN ExtendedTbc = (Hcc2 & XHCI_HCC2_LEC) && (Hcc2 & XHCI_HCC2_ETC);
1838 ULONG Esit = XhciIsochEsitPayload(Ring);
1839 ULONG MaxPacket = Ring->m_Endpoint->MaxPacketSize();
1840 ULONG BurstSize = Ring->m_Endpoint->MaxBurst() + 1;
1841 ULONG Target = (Ring->m_InterrupterTarget & XHCI_TRB_INTERRUPTER_MASK) << XHCI_TRB_INTERRUPTER_SHIFT;
1842 ULONG Spares = XhciIsochCountList(&Stage->FreeSegments);
1843 ULONG Index = Ring->m_EnqueueIndex;
1844 ULONG Element = 0;
1845 ULONG Offset = 0;
1846 ULONG Placed = 0;
1847 ULONG Fit = 0;
1848 ULONG Packet;
1849 KIRQL OldIrql;
1850
1851 if (Commit)
1852 {
1853 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1854 Stage->FirstSegment = Ring->m_Segment;
1855 Stage->LastSegment = Ring->m_Segment;
1856 Stage->ScanSegment = Ring->m_Segment;
1857 Stage->FirstIndex = Ring->m_EnqueueIndex;
1858 Stage->EndIndex = Ring->m_EnqueueIndex;
1859 Stage->ScanIndex = Ring->m_EnqueueIndex;
1860 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1861 }
1862
1863 for (Packet = Stage->FirstPacket; Packet <= LastPacket; Packet++)
1864 {
1866 ULONG Carried = min(Length, Esit);
1867 ULONG Pieces = XhciIsochCountPieces(SgList, Element, Offset, Carried);
1868 BOOLEAN IsLast = (Packet == LastPacket);
1869 ULONG Frame = Transfer->StartFrame + Packet / PerFrame;
1871 volatile UCHAR* CycleByte;
1872 BOOLEAN Tail;
1873 BOOLEAN Bei;
1874 XHCI_TRB Trb;
1875 ULONG Tdpc;
1876 ULONG Tbc;
1877 ULONG Tlbpc;
1878 ULONG Mapped = 0;
1879 ULONG Piece;
1880 ULONG64 Value;
1881
1882 if (Commit)
1883 Index = Ring->m_EnqueueIndex;
1884
1885 /* The data TRBs and the Event Data TRB of a TD stay in front of the Link slot */
1886 if (Index + Pieces + 1 > LastSlot)
1887 {
1888 if (!Commit)
1889 {
1890 if (Spares == 0 || Pieces + 1 > LastSlot)
1891 break;
1892 Spares--;
1893 }
1894 else
1895 {
1896 First = &Ring->m_Trbs[Ring->m_EnqueueIndex];
1897 InsertLink(Ring, Stage, TRUE);
1898 }
1899 Index = 0;
1900 }
1901
1902 /* A full speed TD behind a TT ends in a new segment instead of meeting a Link first */
1903 Tail = Guard && (IsLast || LastSlot - (Index + Pieces) < Self->m_TrbsPerTd);
1904
1905 if (!Commit)
1906 {
1907 if (!Guard || Spares != 0)
1908 Fit = Placed + 1;
1909
1910 if (Tail)
1911 {
1912 if (Spares == 0)
1913 break;
1914 Spares--;
1915 Index = 1;
1916 }
1917 else
1918 {
1919 Index += Pieces + 1;
1920 }
1921
1922 Placed++;
1923 XhciIsochAdvance(SgList, &Element, &Offset, Length);
1924 continue;
1925 }
1926
1927 /* Burst fields (xHCI 4.11.2.3) */
1928 Tdpc = (MaxPacket != 0) ? (Carried + MaxPacket - 1) / MaxPacket : 1;
1929 if (Tdpc == 0)
1930 Tdpc = 1;
1931 Tbc = (Tdpc + BurstSize - 1) / BurstSize - 1;
1932 Tlbpc = (Tdpc % BurstSize) ? (Tdpc % BurstSize) - 1 : BurstSize - 1;
1933
1934 if (First == NULL)
1935 First = &Ring->m_Trbs[Ring->m_EnqueueIndex];
1936
1937 for (Piece = 0; Piece < Pieces; Piece++)
1938 {
1939 BOOLEAN LastData = (Piece + 1 == Pieces);
1940 PXHCI_TRB Slot = &Ring->m_Trbs[Ring->m_EnqueueIndex];
1942 ULONG Chunk;
1943 ULONG SizeField;
1944
1945 /* QUIRK: bytes beyond the max ESIT payload of a packet are never sent */
1946 XhciIsochTakePiece(SgList, &Element, &Offset, Carried - Mapped, &Address, &Chunk);
1947 Mapped += Chunk;
1948
1949 RtlZeroMemory(&Trb, sizeof(Trb));
1950 Trb.Dword[0] = (ULONG)Address;
1951 Trb.Dword[1] = (ULONG)(Address >> 32);
1952
1953 if (Piece == 0 && ExtendedTbc)
1954 SizeField = Tbc;
1955 else
1956 SizeField = Ring->TdSize(Ring->PacketCount(Carried), Mapped, LastData);
1957
1958 Trb.Dword[2] = Chunk | (SizeField << XHCI_TRB_TD_SIZE_SHIFT) | Target;
1959 Trb.Dword[3] = XHCI_TRB_CHAIN | (LastData ? XHCI_TRB_ENT : 0);
1960
1961 if (Piece == 0)
1962 {
1963 /* QUIRK: every TD carries its Frame ID, SIA is never used */
1964 Trb.Dword[3] |= (static_cast<ULONG>(XhciTrbType::Isoch) << XHCI_TRB_TYPE_SHIFT) |
1965 (Tlbpc << XHCI_ISOCH_TLBPC_SHIFT) |
1967 if (!ExtendedTbc)
1968 Trb.Dword[3] |= Tbc << XHCI_ISOCH_TBC_SHIFT;
1969 }
1970 else
1971 {
1972 Trb.Dword[3] |= static_cast<ULONG>(XhciTrbType::Normal) << XHCI_TRB_TYPE_SHIFT;
1973 }
1974
1975 /* The first slot of the TD stays invalid until the whole TD is written */
1976 Trb.Dword[3] |= (Slot == First) ? (Ring->m_Cycle ^ XHCI_TRB_CYCLE) : Ring->m_Cycle;
1977
1978 *Slot = Trb;
1979 Ring->m_EnqueueIndex++;
1980 }
1981
1982 XhciIsochAdvance(SgList, &Element, &Offset, Length - Mapped);
1983
1984 if (Tail)
1985 {
1986 RtlZeroMemory(&Trb, sizeof(Trb));
1987 Trb.Dword[3] = (static_cast<ULONG>(XhciTrbType::Normal) << XHCI_TRB_TYPE_SHIFT) |
1988 XHCI_TRB_CHAIN | XHCI_TRB_ENT | Ring->m_Cycle;
1989 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1990 Ring->m_EnqueueIndex++;
1991
1992 InsertLink(Ring, Stage, FALSE);
1993 }
1994
1995 /* An interrupt at least every 128 packets and at every stage end */
1996 Bei = AllowBei &&
1997 !IsLast &&
1998 Packet + 1 != Transfer->PacketsInUrb &&
1999 ((Packet + 1) & XhciIsochInterruptEvery) != 0;
2000
2001 Value = USB_ENDPOINT_TYPE_ISOCHRONOUS | ((ULONG64)Packet << 16) | ((ULONG64)Transfer->StartFrame << 32);
2002 RtlZeroMemory(&Trb, sizeof(Trb));
2003 Trb.Dword[0] = (ULONG)Value;
2004 Trb.Dword[1] = (ULONG)(Value >> 32);
2005 Trb.Dword[2] = Target;
2006 Trb.Dword[3] = (static_cast<ULONG>(XhciTrbType::EventData) << XHCI_TRB_TYPE_SHIFT) |
2007 XHCI_TRB_IOC | (Bei ? XHCI_TRB_BEI : 0) | Ring->m_Cycle;
2008 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
2009 Ring->m_EnqueueIndex++;
2010
2011 /* Recycled segments are not cleared, and a stale TRB could look valid */
2012 Stage->EndIndex = Ring->m_EnqueueIndex;
2013 RtlZeroMemory(&Ring->m_Trbs[Ring->m_EnqueueIndex], sizeof(XHCI_TRB));
2014
2015 if (IsLast || Self->m_DoorbellAfterFirstTd)
2016 {
2017 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2018 if (IsLast)
2019 {
2020 Transfer->PacketsQueued = Packet + 1 - Transfer->PacketsDropped;
2021 Transfer->TdsQueued++;
2022 Transfer->BytesQueued += Stage->Size;
2023 Stage->OnHardware = TRUE;
2024 Self->m_PendingStages++;
2025 Self->m_LastScheduledFrame = Frame;
2027
2028 /* A cut stage leaves the rest of the URB to skip */
2029 if (Stage->Truncated)
2030 SkipUnmapped(Transfer);
2031 }
2033 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2034 }
2035
2036 /* A one byte register write publishes the TD after every store above */
2038 CycleByte = reinterpret_cast<volatile UCHAR*>(&First->Dword[3]);
2039 WRITE_REGISTER_UCHAR(const_cast<PUCHAR>(CycleByte), (UCHAR)(*CycleByte ^ XHCI_TRB_CYCLE));
2041
2042 if (Self->m_DoorbellAfterFirstTd)
2043 {
2045 Ring->RingDoorbell();
2046 }
2047
2048 Placed++;
2049 }
2050
2051 return Commit ? Placed : Fit;
2052}
BOOLEAN m_DoorbellAfterFirstTd
Definition: isoxfer.h:335
static VOID InsertLink(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage, _In_ BOOLEAN FirstOfTd)
Definition: isoxfer.cpp:2056
_Inout_ HubConfiguration ** Slot
Definition: devhcd.cpp:1260
const UCHAR * Tail
Definition: hubmsos.cpp:145
static VOID NTAPI XhciIsochTakePiece(_In_ const SCATTER_GATHER_LIST *SgList, _Inout_ PULONG Element, _Inout_ PULONG Offset, _In_ ULONG Bytes, _Out_ PULONG64 Address, _Out_ PULONG Chunk)
Definition: isoxfer.cpp:222
static ULONG NTAPI XhciIsochCountPieces(_In_ const SCATTER_GATHER_LIST *SgList, _In_ ULONG Element, _In_ ULONG Offset, _In_ ULONG Bytes)
Definition: isoxfer.cpp:255
static const ULONG XhciIsochInterruptEvery
Definition: isoxfer.cpp:21
static ULONG NTAPI XhciIsochCountList(_In_ const LIST_ENTRY *Head)
Definition: isoxfer.cpp:155
static VOID NTAPI XhciIsochAdvance(_In_ const SCATTER_GATHER_LIST *SgList, _Inout_ PULONG Element, _Inout_ PULONG Offset, _In_ ULONG Bytes)
Definition: isoxfer.cpp:281
#define min(a, b)
Definition: monoChain.cc:55
static WCHAR Address[46]
Definition: ping.c:68
FORCEINLINE VOID KeMemoryBarrier(VOID)
Definition: ke.h:58
ULONG PacketsQueued
Definition: isoxfer.h:69
ULONG PacketsDropped
Definition: isoxfer.h:70
ULONG PacketsInUrb
Definition: isoxfer.h:67
unsigned char UCHAR
Definition: typedefs.h:53
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
struct _SCATTER_GATHER_LIST SCATTER_GATHER_LIST
Definition: iotypes.h:2219
#define XHCI_TRB_BEI
Definition: xhcihw.h:638
#define XHCI_TRB_TYPE_SHIFT
Definition: xhcihw.h:23
#define XHCI_TRB_ENT
Definition: xhcihw.h:623
#define XHCI_TRB_TD_SIZE_SHIFT
Definition: xhcihw.h:622
#define XHCI_TRB_INTERRUPTER_MASK
Definition: xhcihw.h:611
#define XHCI_ISOCH_FRAME_ID_MASK
Definition: xhcihw.h:642
#define XHCI_TRB_INTERRUPTER_SHIFT
Definition: xhcihw.h:610
#define XHCI_ISOCH_FRAME_ID_SHIFT
Definition: xhcihw.h:641
#define XHCI_ISOCH_TLBPC_SHIFT
Definition: xhcihw.h:640
#define XHCI_TRB_IOC
Definition: xhcihw.h:624
#define XHCI_TRB_CYCLE
Definition: xhcihw.h:22
#define XHCI_TRB_CHAIN
Definition: xhcihw.h:609
#define XHCI_ISOCH_TBC_SHIFT
Definition: xhcihw.h:639
#define XHCI_HCC2_ETC
Definition: xhcihw.h:378
#define XHCI_HCC2_LEC
Definition: xhcihw.h:377

Referenced by WriteStage().

◆ LeaveRingEmptyWait()

BOOLEAN XhciIsochRing::LeaveRingEmptyWait ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 916 of file isoxfer.cpp.

918{
919 if (Ring->ChangeMapState(FALSE, XhciMapState::AwaitingStarve, XhciMapState::Filling) !=
920 XhciMapState::AwaitingStarve)
921 {
922 return FALSE;
923 }
924
925 WdfTimerStop(Ring->m_Type.Isoch.m_Watchdog, FALSE);
926 return TRUE;
927}

Referenced by BuildTdsFromQueue(), KickAfterStage(), and OnRingStarved().

◆ NextTdSlot()

XhciIsochStage * XhciIsochRing::NextTdSlot ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 966 of file isoxfer.cpp.

968{
969 XhciIsochRing* Self = &Ring->m_Type.Isoch;
970 XhciIsochTransfer* Transfer;
971 XhciIsochStage* Stage = NULL;
972 WDFREQUEST Request;
976
977 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
978 Self->m_CurrentStage = NULL;
979
981 {
982 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
983 return NULL;
984 }
985
986 if (!IsListEmpty(&Self->m_Pending))
987 {
989
991 {
992 /* QUIRK: nothing counts the retries up, so this is never reached */
993 DPRINT1("Isoch DCI %lu gave up waiting for segments\n", Ring->m_Endpoint->Dci());
994
995 if (Transfer->TdsRetired != Transfer->TdsQueued)
996 {
997 SkipUnmapped(Transfer);
998 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
999 return NULL;
1000 }
1001
1003 }
1004 else if (Transfer->PacketsQueued + Transfer->PacketsDropped < Transfer->PacketsInUrb)
1005 {
1006 FlagMissedPackets(Ring, Transfer);
1007
1008 if (Transfer->Urb->IsoPacket[Transfer->PacketsInUrb - 1].Status != USBD_STATUS_ISO_NOT_ACCESSED_LATE)
1009 {
1010 Stage = AcquireStage(Ring, Transfer);
1011 Self->m_CurrentStage = Stage;
1012 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1013 return Stage;
1014 }
1015
1016 if (Transfer->TdsRetired != Transfer->TdsQueued)
1017 {
1018 SkipUnmapped(Transfer);
1019 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1020 return NULL;
1021 }
1022
1023 /* QUIRK: like the USB 2.0 stack, a URB that ran late reports success, even when canceled */
1025 }
1026 }
1027
1028 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1029
1030 for (;;)
1031 {
1032 Status = WdfIoQueueRetrieveNextRequest(Ring->m_Queue, &Request);
1033 if (!NT_SUCCESS(Status))
1034 {
1035 if (Self->m_PendingStages == 0)
1036 DPRINT("Isoch DCI %lu has nothing queued, the stream may starve\n", Ring->m_Endpoint->Dci());
1037 return NULL;
1038 }
1039
1040 if (TakeRequest(Ring, Request, &Transfer))
1041 break;
1042 }
1043
1044 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1045 Idle = (Self->m_PendingStages == 0);
1046 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1047
1048 /* Every TD on the ring reports to one event ring so its events stay in order */
1049 if (Idle)
1050 Ring->UpdateInterrupterTarget(XhciTransferRing::UrbProcessorIndex((PURB)Transfer->Urb));
1051
1052 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1053 Stage = AcquireStage(Ring, Transfer);
1054 InsertTailList(&Self->m_Pending, &Transfer->Link);
1055 Self->m_CurrentStage = Stage;
1056 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1057
1058 return Stage;
1059}
static XhciIsochStage * AcquireStage(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer)
static BOOLEAN TakeRequest(_In_ XhciTransferRing *Ring, _In_ WDFREQUEST Request, _Out_ XhciIsochTransfer **Taken)
Definition: isoxfer.cpp:1063
XhciIsochStage * m_CurrentStage
Definition: isoxfer.h:350
ULONG m_BufferRetries
Definition: isoxfer.h:342
static VOID FlagMissedPackets(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer)
Definition: isoxfer.cpp:1253
static ULONG UrbProcessorIndex(_In_ PURB Urb)
Definition: xferring.cpp:1168
static const ULONG XhciIsochMaxInFlight
Definition: isoxfer.cpp:15
static const ULONG XhciIsochBufferRetryLimit
Definition: isoxfer.cpp:16
struct _URB_ISOCH_TRANSFER * Urb
Definition: isoxfer.h:58
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
Definition: usb.h:565
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST Request

Referenced by FillLoop().

◆ OnClientPipeReset()

VOID XhciIsochRing::OnClientPipeReset ( _In_ XhciTransferRing *  Ring)
static

Definition at line 691 of file isoxfer.cpp.

693{
695
696 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
697 Ring->m_Type.Isoch.m_FreshStream = TRUE;
698 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
699}

Referenced by XhciTransferRing::OnClientPipeReset().

◆ OnRingStarved()

VOID XhciIsochRing::OnRingStarved ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 2924 of file isoxfer.cpp.

2926{
2927 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2928 ULONG Now = Ring->m_Controller->GetFrameNumber(XhciIsochBiasNow);
2929 BOOLEAN Abort;
2930 KIRQL OldIrql;
2931
2932 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2933 Self->m_RingEmptyEvents++;
2935 if (Self->m_PendingStages == 0)
2937
2938 Abort = Ring->m_Controller->HasErrata(XhciErrata::IsochMissedServiceSilent) &&
2939 Self->m_PendingStages != 0 &&
2940 (Self->m_Flags & XhciIsochLastFrameValid) &&
2941 (LONG)(Now - Self->m_LastScheduledFrame) >= 0;
2942 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2943
2944 if (Abort)
2945 {
2946 /* The controller ran past TDs without a word. Their events may still sit
2947 * on a secondary event ring, so the endpoint stops and reclaims instead. */
2948 DPRINT1("Isoch DCI %lu: ring empty with stages unreported, reclaiming\n", Ring->m_Endpoint->Dci());
2949 Ring->m_Endpoint->OnTransferCanceled();
2950 return;
2951 }
2952
2954 if (LeaveRingEmptyWait(Ring))
2955 BuildTdsFromQueue(Ring);
2956}
ULONG m_RingEmptyEvents
Definition: isoxfer.h:363

Referenced by Ed0Event().

◆ OnTransferEvent()

BOOLEAN XhciIsochRing::OnTransferEvent ( _In_ XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event 
)
static

Definition at line 772 of file isoxfer.cpp.

775{
776 if (Event->Dword[3] & XHCI_TRANSFER_EVENT_ED)
777 Ed1Event(Ring, Event);
778 else
779 Ed0Event(Ring, Event);
780
781 return TRUE;
782}
static VOID Ed0Event(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: isoxfer.cpp:2661
static VOID Ed1Event(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: isoxfer.cpp:2564
#define XHCI_TRANSFER_EVENT_ED
Definition: xhcihw.h:321

Referenced by XhciTransferRing::OnTransferEvent().

◆ OwnsRequests()

static BOOLEAN XhciIsochRing::OwnsRequests ( _In_ const XhciTransferRing *  Ring)
staticprivate

Referenced by Cleanup(), and Disable().

◆ PacketsValid()

BOOLEAN XhciIsochRing::PacketsValid ( _In_ const XhciIsochTransfer *  Transfer)
staticprivate

Definition at line 1170 of file isoxfer.cpp.

1172{
1173 const struct _URB_ISOCH_TRANSFER* Urb = Transfer->Urb;
1174 ULONG Index;
1175
1176 if (Transfer->PacketsInUrb == 0)
1177 return FALSE;
1178
1179 for (Index = 0; Index + 1 < Transfer->PacketsInUrb; Index++)
1180 {
1181 if (Urb->IsoPacket[Index].Offset > Urb->IsoPacket[Index + 1].Offset)
1182 return FALSE;
1183 }
1184
1185 return Urb->IsoPacket[Transfer->PacketsInUrb - 1].Offset <= Transfer->BytesTotal;
1186}

Referenced by TakeRequest().

◆ ParkOnSegments()

BOOLEAN XhciIsochRing::ParkOnSegments ( _In_ XhciTransferRing *  Ring)
staticprivate

Definition at line 948 of file isoxfer.cpp.

950{
951 XhciIsochRing* Self = &Ring->m_Type.Isoch;
952
955 {
956 return TRUE;
957 }
958
960 return FALSE;
961}
volatile LONG m_SegmentWait
Definition: isoxfer.h:349
static const LONG XhciIsochWaitIdle
Definition: isoxfer.cpp:44
static const LONG XhciIsochWaitParked
Definition: isoxfer.cpp:45

Referenced by PrimeStage().

◆ PrimeStage()

XhciIsochRing::Outcome XhciIsochRing::PrimeStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage 
)
staticprivate

Definition at line 1393 of file isoxfer.cpp.

1396{
1397 XhciIsochRing* Self = &Ring->m_Type.Isoch;
1398 XhciIsochTransfer* Transfer = Stage->Transfer;
1399 ULONG Frame;
1400 ULONG Segments;
1401 BOOLEAN Gap = FALSE;
1403 KIRQL OldIrql;
1404
1405 Stage->FirstPacket = Transfer->PacketsQueued + Transfer->PacketsDropped;
1406 Frame = Transfer->StartFrame + XhciIsochFrames(Stage->FirstPacket, Self->m_PacketsPerFrame);
1407
1408 /* Without contiguous Frame IDs the controller must run dry before a jump (xHCI 4.11.2.5) */
1409 if (!Ring->m_Controller->m_Registers.ContiguousFrameId())
1410 {
1411 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1412 if ((Self->m_Flags & XhciIsochLastFrameValid) &&
1413 Frame != Self->m_LastScheduledFrame + 1 &&
1414 ((Self->m_Flags & XhciIsochEmptyExpected) || Self->m_PendingStages != 0))
1415 {
1416 FreeStage(Ring, Stage);
1417 Gap = TRUE;
1418 }
1419 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1420
1421 if (Gap)
1422 {
1423 DPRINT("Isoch DCI %lu: frame 0x%lx does not follow 0x%lx, waiting for the ring to drain\n",
1424 Ring->m_Endpoint->Dci(), Frame, Self->m_LastScheduledFrame);
1425 return Outcome::Gap;
1426 }
1427 }
1428
1429 if (!NT_SUCCESS(AcquireStageMdl(Ring, Stage)))
1430 return FailStage(Ring, Stage);
1431
1432 if (!SizeStage(Ring, Stage))
1433 return FailStage(Ring, Stage);
1434
1435 Segments = EstimateSegments(Ring, Stage);
1436 if (Segments == 0)
1437 return Outcome::Ready;
1438
1439 Status = Ring->TakeSegments(Segments, &Stage->FreeSegments);
1440 if (Status == STATUS_PENDING)
1441 {
1442 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1443 FreeStage(Ring, Stage);
1444 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1445
1446 if (ParkOnSegments(Ring))
1447 return Outcome::WaitSegments;
1448
1449 /* The segments already arrived; take the stage again from the top */
1450 return Outcome::Completed;
1451 }
1452
1453 if (!NT_SUCCESS(Status))
1454 {
1455 DPRINT1("Isoch DCI %lu: %lu segments not available, 0x%08lx\n",
1456 Ring->m_Endpoint->Dci(), Segments, Status);
1457 return FailStage(Ring, Stage);
1458 }
1459
1460 Self->m_BufferRetries = 0;
1461 return Outcome::Ready;
1462}
static ULONG EstimateSegments(_In_ XhciTransferRing *Ring, _In_ const XhciIsochStage *Stage)
Definition: isoxfer.cpp:1601
static NTSTATUS AcquireStageMdl(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
Definition: isoxfer.cpp:1465
static BOOLEAN SizeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage)
Definition: isoxfer.cpp:1513
static BOOLEAN ParkOnSegments(_In_ XhciTransferRing *Ring)
Definition: isoxfer.cpp:948

Referenced by FillLoop().

◆ PutScatterGather()

static VOID XhciIsochRing::PutScatterGather ( _In_ XhciTransferRing *  Ring,
_In_opt_ PSCATTER_GATHER_LIST  SgList 
)
staticprivate

◆ RecoverTransfers()

VOID XhciIsochRing::RecoverTransfers ( _In_ XhciTransferRing *  Ring)
static

Definition at line 734 of file isoxfer.cpp.

736{
737 XhciIsochRing* Self = &Ring->m_Type.Isoch;
739
740 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
743 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
744
745 /* Only the DPC can tell that nothing is owned anymore */
746 WdfDpcEnqueue(Ring->m_CompletionDpc);
747}
static const LONG XhciIsochReclaimAck
Definition: isoxfer.cpp:38

Referenced by XhciTransferRing::RecoverTransfers().

◆ ReleaseAllStages()

ULONG XhciIsochRing::ReleaseAllStages ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochTransfer *  Transfer 
)
staticprivate

Returns the lists and frees every stage of a transfer nobody else can reach anymore.

Definition at line 2269 of file isoxfer.cpp.

2272{
2273 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2274 XhciIsochStage* Stage;
2276 ULONG Freed = 0;
2277 KIRQL OldIrql;
2278
2279 for (;;)
2280 {
2281 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2282 if (Transfer->StageCount == 0)
2283 {
2284 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2285 break;
2286 }
2287
2288 Stage = XhciIsochStageAt(Transfer, 0);
2289 SgList = Stage->SgList;
2290 Stage->SgList = NULL;
2291 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2292
2293 PutScatterGather(Ring, SgList);
2294
2295 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2296 if (Stage->OnHardware)
2297 {
2298 Freed++;
2299 Transfer->TdsRetired++;
2300 if (Self->m_PendingStages != 0)
2301 Self->m_PendingStages--;
2302 }
2303 FreeStage(Ring, Stage);
2304 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2305 }
2306
2307 return Freed;
2308}
PSCATTER_GATHER_LIST SgList
Definition: isoxfer.h:36

Referenced by CompleteBatch(), and FinishExpiredIsoch().

◆ ReleaseParkedMapping()

VOID XhciIsochRing::ReleaseParkedMapping ( _In_ XhciTransferRing *  Ring)
static

Lets a mapping pass parked on a segment wait go, so a disable never waits on it.

Definition at line 495 of file isoxfer.cpp.

497{
498 XhciIsochRing* Self = &Ring->m_Type.Isoch;
499
500 /* A pass parked on a segment wait only resumes from a PASSIVE work item; let it go */
503 {
504 return;
505 }
506
507 DPRINT1("Isoch DCI %lu disabled while waiting for segments\n", Ring->m_Endpoint->Dci());
508
509 if (Ring->ChangeMapState(FALSE, XhciMapState::Halting, XhciMapState::Halted) != XhciMapState::Halting)
510 {
511 InterlockedCompareExchange(&Ring->m_MapState,
512 static_cast<LONG>(XhciMapState::PausedFill),
513 static_cast<LONG>(XhciMapState::Filling));
514 }
515}
static const LONG XhciIsochWaitAbandoned
Definition: isoxfer.cpp:47

Referenced by Disable().

◆ ResumeRingFill()

VOID XhciIsochRing::ResumeRingFill ( _In_ XhciTransferRing *  Ring)
static

Definition at line 636 of file isoxfer.cpp.

638{
639 XhciIsochRing* Self = &Ring->m_Type.Isoch;
642
643 InterlockedExchange(&Self->m_Flags, 0);
644
645 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
646 Self->m_PendingStages = 0;
647 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
648
649 Previous = Ring->ChangeMapState(TRUE, XhciMapState::Halted, XhciMapState::Filling);
650 if (Previous == XhciMapState::Halted)
651 {
652 BuildTdsFromQueue(Ring);
653 return;
654 }
655
656 DPRINT1("Isoch DCI %lu started mapping from map state %ld\n",
657 Ring->m_Endpoint->Dci(), static_cast<LONG>(Previous));
658}
Previous
XhciMapState
Definition: xferring.h:19

Referenced by XhciTransferRing::ResumeRingFill().

◆ RetireExpiredStages()

VOID XhciIsochRing::RetireExpiredStages ( _In_ XhciTransferRing *  Ring,
_In_ XhciIsochTransfer *  Transfer,
_In_ XhciIsochStage *  Stage,
_In_ ULONG  Sequence 
)
staticprivate

Closes the stages of Transfer older than Stage as missed.

Definition at line 2224 of file isoxfer.cpp.

2229{
2230 XhciIsochRing* Self = &Ring->m_Type.Isoch;
2231 XhciIsochStage* Oldest;
2232 BOOLEAN Progress;
2233 KIRQL OldIrql;
2234
2235 for (;;)
2236 {
2237 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2238 if (!XhciIsochIsActive(&Self->m_Pending, Transfer, Sequence) ||
2239 !Stage->InUse ||
2240 Transfer->StageCount == 0)
2241 {
2242 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2243 return;
2244 }
2245
2246 Oldest = XhciIsochStageAt(Transfer, 0);
2247 if (Oldest == Stage)
2248 {
2249 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2250 return;
2251 }
2252
2253 Oldest->NextPacket = Oldest->LastPacket + 1;
2254 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2255
2256 CompleteTd(Ring, Transfer, Oldest, Sequence, static_cast<ULONG>(XhciCompletionCode::MissedService), 0, TRUE);
2257
2258 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2259 Progress = !Oldest->InUse || XhciIsochStageAt(Transfer, 0) != Oldest;
2260 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2261
2262 if (!Progress)
2263 return;
2264 }
2265}

Referenced by Ed0Event(), and Ed1Event().

◆ ScheduleStartFrame()

NTSTATUS XhciIsochRing::ScheduleStartFrame ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochTransfer *  Transfer 
)
staticprivate

Definition at line 1189 of file isoxfer.cpp.

1192{
1193 XhciIsochRing* Self = &Ring->m_Type.Isoch;
1194 struct _URB_ISOCH_TRANSFER* Urb = Transfer->Urb;
1195 ULONG Threshold;
1196 ULONG StartFrame;
1197 ULONG Now = 0;
1198 ULONG Index;
1199 LONG Distance;
1200 KIRQL OldIrql;
1201
1202 Threshold = (Ring->m_Device->Speed() >= UsbHighSpeed) ? XhciIsochRestartFast : XhciIsochRestartSlow;
1203
1204 if (Urb->TransferFlags & USBD_START_ISO_TRANSFER_ASAP)
1205 Now = Ring->m_Controller->GetFrameNumber(XhciIsochBiasNow);
1206
1207 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1208
1209 if (Urb->TransferFlags & USBD_START_ISO_TRANSFER_ASAP)
1210 {
1211 StartFrame = Self->m_NextStartFrame;
1212
1213 /* QUIRK: unsigned and without wrap handling, and the threshold is really a packet count */
1214 if (Self->m_FreshStream || (Now > StartFrame && Now - StartFrame > Threshold))
1215 {
1216 StartFrame = Now + XhciIsochAsapDelay;
1218 }
1219
1220 Urb->StartFrame = StartFrame;
1221 }
1222 else
1223 {
1224 StartFrame = Urb->StartFrame;
1225 }
1226
1227 Self->m_NextStartFrame = StartFrame + XhciIsochFrames(Transfer->PacketsInUrb, Self->m_PacketsPerFrame);
1228 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1229
1230 Transfer->StartFrame = StartFrame;
1231 Urb->TransferBufferLength = 0;
1232 Urb->ErrorCount = 0;
1233 for (Index = 0; Index < Transfer->PacketsInUrb; Index++)
1234 Urb->IsoPacket[Index].Status = XhciIsochNotSet;
1235
1236 Distance = (LONG)(StartFrame - Ring->m_Controller->GetFrameNumber(XhciIsochBiasLate));
1237 if (Distance > XhciIsochFrameWindow || Distance < -XhciIsochFrameWindow)
1238 {
1239 DPRINT1("Isoch DCI %lu: start frame 0x%lx is %ld frames away\n",
1240 Ring->m_Endpoint->Dci(), StartFrame, Distance);
1241 return STATUS_UNSUCCESSFUL;
1242 }
1243
1244 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1245 Self->m_FreshStream = FALSE;
1246 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1247
1248 return STATUS_SUCCESS;
1249}
BOOLEAN m_FreshStream
Definition: isoxfer.h:334
ULONG m_NextStartFrame
Definition: isoxfer.h:337
static const ULONG XhciIsochAsapDelay
Definition: isoxfer.cpp:17
static const ULONG XhciIsochRestartFast
Definition: isoxfer.cpp:19
static const LONG XhciIsochFrameWindow
Definition: isoxfer.cpp:18
static const ULONG XhciIsochRestartSlow
Definition: isoxfer.cpp:20
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define USBD_START_ISO_TRANSFER_ASAP
Definition: usb.h:162

Referenced by TakeRequest().

◆ SegmentsArrived()

VOID XhciIsochRing::SegmentsArrived ( _In_ XhciTransferRing *  Ring,
_In_ NTSTATUS  Status 
)
static

Common buffer callback for asynchronous segment growth.

Definition at line 785 of file isoxfer.cpp.

788{
789 XhciIsochRing* Self = &Ring->m_Type.Isoch;
790
791 if (!NT_SUCCESS(Status))
792 DPRINT1("Isoch DCI %lu segment growth failed, 0x%08lx\n", Ring->m_Endpoint->Dci(), Status);
793
794 Self->m_BufferRetries = 0;
795
796 for (;;)
797 {
798 /* QUIRK: the pass runs even when a stop came in meanwhile, so one more stage can go out */
801 {
802 BuildTdsFromQueue(Ring);
803 return;
804 }
805
808 {
809 return;
810 }
811
812 /* The pass has not left yet; it sees this and retries the stage itself */
815 {
816 return;
817 }
818 }
819}
static const LONG XhciIsochWaitArrived
Definition: isoxfer.cpp:46

◆ SizeStage()

BOOLEAN XhciIsochRing::SizeStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage 
)
staticprivate

Picks the last packet and byte count of a stage; FALSE when not even one frame fits.

Definition at line 1513 of file isoxfer.cpp.

1516{
1517 XhciIsochTransfer* Transfer = Stage->Transfer;
1518 ULONG PerFrame = Ring->m_Type.Isoch.m_PacketsPerFrame;
1519 ULONG Used = Transfer->BytesQueued + Transfer->BytesDropped;
1520 ULONG Remaining = (Transfer->BytesTotal > Used) ? Transfer->BytesTotal - Used : 0;
1521 ULONG Limit = Ring->m_MaxStageSize;
1522 ULONG Registers = 0;
1523 PDMA_ADAPTER Adapter;
1525 ULONG Packet;
1526 ULONG Total = 0;
1527 PMDL Mdl;
1528 ULONG Left;
1529
1530 Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
1531 if (Adapter->Version >= DEVICE_DESCRIPTION_VERSION3 &&
1532 Adapter->DmaOperations->Size > FIELD_OFFSET(DMA_OPERATIONS, GetDmaTransferInfo) &&
1533 Adapter->DmaOperations->GetDmaTransferInfo != NULL)
1534 {
1535 RtlZeroMemory(&Info, sizeof(Info));
1537 if (NT_SUCCESS(Adapter->DmaOperations->GetDmaTransferInfo(Adapter,
1538 Stage->Mdl,
1539 0,
1540 Remaining,
1541 !XhciIsochEndpointIn(Ring),
1542 &Info)))
1543 {
1544 Registers = Info.V1.MapRegisterCount;
1545 }
1546 }
1547
1548 if (Registers == 0)
1549 {
1550 /* Without the HAL query count the pages the chain spans */
1551 for (Mdl = Stage->Mdl, Left = Remaining; Mdl != NULL && Left != 0; Mdl = Mdl->Next)
1552 {
1553 ULONG Chunk = min(Left, MmGetMdlByteCount(Mdl));
1554
1556 Left -= Chunk;
1557 }
1558 }
1559
1560 if (Registers > Ring->m_MapRegisterCount && Ring->m_MapRegisterCount > 1)
1561 Limit = min(Limit, (Ring->m_MapRegisterCount - 1) * PAGE_SIZE);
1562
1563 if (Remaining <= Limit)
1564 {
1565 Stage->LastPacket = Transfer->PacketsInUrb - 1;
1566 Stage->Size = Remaining;
1567 return TRUE;
1568 }
1569
1570 /* Whole frames only */
1571 Packet = Stage->FirstPacket;
1572 while (Packet < Transfer->PacketsInUrb)
1573 {
1574 ULONG FrameBytes = 0;
1575 ULONG Count;
1576
1577 for (Count = 0; Count < PerFrame && Packet + Count < Transfer->PacketsInUrb; Count++)
1578 FrameBytes += XhciIsochPacketLength(Transfer, Packet + Count);
1579
1580 if (Total + FrameBytes > Limit)
1581 break;
1582
1583 Total += FrameBytes;
1584 Packet += Count;
1585 }
1586
1587 /* Fail instead of building an empty stage when one frame exceeds the limit */
1588 if (Packet == Stage->FirstPacket)
1589 {
1590 DPRINT1("Isoch DCI %lu: one frame needs more than %lu bytes of mapping\n",
1591 Ring->m_Endpoint->Dci(), Limit);
1592 return FALSE;
1593 }
1594
1595 Stage->LastPacket = Packet - 1;
1596 Stage->Size = Total;
1597 return TRUE;
1598}
PUCHAR Limit
Definition: desccheck.cpp:2230
ULONG Total
Definition: hubwmi.cpp:548
ULONG BytesTotal
Definition: isoxfer.h:63
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
USHORT Count
Definition: userreq.cpp:200
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
#define DMA_TRANSFER_INFO_VERSION1
Definition: iotypes.h:2116
#define DEVICE_DESCRIPTION_VERSION3
Definition: iotypes.h:2066
#define ADDRESS_AND_SIZE_TO_SPAN_PAGES(_Va, _Size)

Referenced by PrimeStage().

◆ SkipUnmapped()

VOID XhciIsochRing::SkipUnmapped ( _Inout_ XhciIsochTransfer *  Transfer)
staticprivate

Definition at line 1282 of file isoxfer.cpp.

1284{
1285 Transfer->PacketsDropped = Transfer->PacketsInUrb - Transfer->PacketsQueued;
1286 Transfer->BytesDropped = (Transfer->BytesTotal > Transfer->BytesQueued) ?
1287 Transfer->BytesTotal - Transfer->BytesQueued : 0;
1288}

Referenced by FailStage(), LayoutStage(), and NextTdSlot().

◆ SuspendRingFill()

VOID XhciIsochRing::SuspendRingFill ( _In_ XhciTransferRing *  Ring)
static

Definition at line 661 of file isoxfer.cpp.

663{
665
666 Previous = Ring->ChangeMapState(TRUE, XhciMapState::Halted, XhciMapState::Halting);
667
668 switch (Previous)
669 {
670 case XhciMapState::AwaitingStarve:
671 WdfTimerStop(Ring->m_Type.Isoch.m_Watchdog, FALSE);
672 Ring->ChangeMapState(FALSE, XhciMapState::Halting, XhciMapState::Halted);
673 break;
674
675 case XhciMapState::PausedFill:
676 Ring->ChangeMapState(FALSE, XhciMapState::Halting, XhciMapState::Halted);
677 break;
678
679 case XhciMapState::Filling:
680 /* The context that owns mapping acknowledges the stop */
681 break;
682
683 default:
684 DPRINT1("Isoch DCI %lu stopped mapping from map state %ld\n",
685 Ring->m_Endpoint->Dci(), static_cast<LONG>(Previous));
686 break;
687 }
688}

Referenced by XhciTransferRing::SuspendRingFill().

◆ TakeRequest()

BOOLEAN XhciIsochRing::TakeRequest ( _In_ XhciTransferRing *  Ring,
_In_ WDFREQUEST  Request,
_Out_ XhciIsochTransfer **  Taken 
)
staticprivate

Sets up a request taken from the queue; FALSE when it was completed instead.

Definition at line 1063 of file isoxfer.cpp.

1067{
1068 XhciIsochRing* Self = &Ring->m_Type.Isoch;
1069 XhciRequestData* Data = XhciGetRequestData(Request);
1070 struct _URB_ISOCH_TRANSFER* Urb;
1071 XhciIsochTransfer* Transfer;
1073
1074 *Taken = NULL;
1075
1076 if (Data == NULL)
1077 {
1078 DPRINT1("Isoch request %p has no driver context\n", Request);
1079 WdfRequestComplete(Request, STATUS_INVALID_DEVICE_STATE);
1080 return FALSE;
1081 }
1082
1084 Transfer = &Data->Isoch;
1085
1086 /* UCX reuses requests, so the record starts from zero every time */
1087 RtlZeroMemory(Transfer, sizeof(*Transfer));
1088 XhciClearListEntry(&Transfer->Link);
1090 Transfer->Sequence = ++Self->m_NextSequence;
1091 Transfer->Request = Request;
1092 Transfer->Urb = Urb;
1093 Transfer->Ring = Ring;
1094 Transfer->CancelState = XhciIsochCancel::Idle;
1095 Transfer->Status = STATUS_PENDING;
1096 Transfer->BytesTotal = Urb->TransferBufferLength;
1097 Transfer->PacketsInUrb = (Urb->NumberOfPackets <= XhciIsochMaxPackets) ? Urb->NumberOfPackets : 0;
1098
1099 if (Urb->TransferBufferMDL != NULL)
1100 {
1101 Transfer->Mdl = Urb->TransferBufferMDL;
1102 }
1103 else if (Transfer->BytesTotal != 0)
1104 {
1105 if (Urb->TransferBuffer != NULL)
1106 Transfer->Mdl = IoAllocateMdl(Urb->TransferBuffer, Transfer->BytesTotal, FALSE, FALSE, NULL);
1107
1108 if (Transfer->Mdl == NULL)
1109 {
1110 DPRINT1("Isoch DCI %lu request %p: no MDL for a %lu byte buffer\n",
1111 Ring->m_Endpoint->Dci(), Request, Transfer->BytesTotal);
1112
1113 /* QUIRK: the caller's packet statuses and error count are kept */
1115 return FALSE;
1116 }
1117
1118 Transfer->OwnMdl = TRUE;
1119 MmBuildMdlForNonPagedPool(Transfer->Mdl);
1120 }
1121
1122 /* Packet offsets must lie inside the buffer before the MDL chain is walked */
1123 if (!PacketsValid(Transfer))
1124 {
1125 DPRINT1("Isoch DCI %lu request %p: %lu packets with bad offsets for %lu bytes\n",
1126 Ring->m_Endpoint->Dci(), Request, Urb->NumberOfPackets, Transfer->BytesTotal);
1127 Urb->ErrorCount = 0;
1129 return FALSE;
1130 }
1131
1132 Status = ScheduleStartFrame(Ring, Transfer);
1133 if (!NT_SUCCESS(Status))
1134 {
1136 return FALSE;
1137 }
1138
1139 FlagMissedPackets(Ring, Transfer);
1140 if (Urb->IsoPacket[Transfer->PacketsInUrb - 1].Status == USBD_STATUS_ISO_NOT_ACCESSED_LATE)
1141 {
1142 DPRINT("Isoch DCI %lu request %p is late in full\n", Ring->m_Endpoint->Dci(), Request);
1144 return FALSE;
1145 }
1146
1147 if (Transfer->BytesTotal == 0)
1148 {
1149 DPRINT("Isoch DCI %lu request %p has no data\n", Ring->m_Endpoint->Dci(), Request);
1151 return FALSE;
1152 }
1153
1154 Transfer->CancelState = XhciIsochCancel::Armed;
1155 Status = WdfRequestMarkCancelableEx(Request, EvtRequestCancel);
1156 if (!NT_SUCCESS(Status))
1157 {
1158 DPRINT1("Isoch DCI %lu request %p canceled before mapping, 0x%08lx\n",
1159 Ring->m_Endpoint->Dci(), Request, Status);
1160 Transfer->CancelState = XhciIsochCancel::Done;
1162 return FALSE;
1163 }
1164
1165 *Taken = Transfer;
1166 return TRUE;
1167}
static VOID CompletePlain(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer, _In_ USBD_STATUS PacketStatus, _In_ USBD_STATUS HeaderStatus, _In_ BOOLEAN Async)
static BOOLEAN PacketsValid(_In_ const XhciIsochTransfer *Transfer)
Definition: isoxfer.cpp:1170
ULONG m_NextSequence
Definition: isoxfer.h:343
static NTSTATUS ScheduleStartFrame(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochTransfer *Transfer)
Definition: isoxfer.cpp:1189
static const ULONG XhciIsochTransferTag
Definition: isoxfer.cpp:13
static const ULONG XhciIsochMaxPackets
Definition: isoxfer.cpp:24
static struct _URB_ISOCH_TRANSFER *NTAPI XhciIsochUrbOf(_In_ WDFREQUEST Request)
Definition: isoxfer.cpp:142
if(dx< 0)
Definition: linetemp.h:194
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:423
BOOLEAN OwnMdl
Definition: isoxfer.h:56
XhciIsochCancel CancelState
Definition: isoxfer.h:55
XhciTransferRing * Ring
Definition: isoxfer.h:59
ULONG Initialized
Definition: isoxfer.h:53
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
#define USBD_STATUS_INVALID_PARAMETER
Definition: usb.h:203
#define USBD_STATUS_BAD_START_FRAME
Definition: usb.h:209
_In_ WDFREQUEST _In_ PFN_WDF_REQUEST_CANCEL EvtRequestCancel
Definition: wdfrequest.h:730

Referenced by NextTdSlot().

◆ TransferDone()

BOOLEAN XhciIsochRing::TransferDone ( _In_ const XhciIsochTransfer *  Transfer)
staticprivate

Every stage is back and every packet is mapped or skipped.

Definition at line 1382 of file isoxfer.cpp.

1384{
1385 return Transfer->StageCount == 0 &&
1386 Transfer->TdsRetired == Transfer->TdsQueued &&
1387 Transfer->PacketsQueued + Transfer->PacketsDropped >= Transfer->PacketsInUrb;
1388}

◆ WriteStage()

VOID XhciIsochRing::WriteStage ( _In_ XhciTransferRing *  Ring,
_Inout_ XhciIsochStage *  Stage 
)
staticprivate

Writes a mapped stage into the ring, or drops it when it is late or nothing fits.

Definition at line 1747 of file isoxfer.cpp.

1750{
1751 XhciIsochRing* Self = &Ring->m_Type.Isoch;
1752 XhciIsochTransfer* Transfer = Stage->Transfer;
1754 ULONG Frame;
1755 ULONG Now;
1756 ULONG Fit;
1757 ULONG Packet;
1758 ULONG Size = 0;
1759 KIRQL OldIrql;
1760
1761 if (Ring->m_Controller->HasErrata(XhciErrata::IsochSkipPastFrames))
1762 {
1763 Frame = Transfer->StartFrame + Stage->FirstPacket / Self->m_PacketsPerFrame;
1764 Now = Ring->m_Controller->GetFrameNumber(XhciIsochBiasLate);
1765
1766 if ((LONG)(Now - Frame) >= 0)
1767 {
1768 DPRINT1("Isoch DCI %lu: stage for frame 0x%lx is late at 0x%lx\n",
1769 Ring->m_Endpoint->Dci(), Frame, Now);
1770
1771 SgList = Stage->SgList;
1772 Stage->SgList = NULL;
1773 PutScatterGather(Ring, SgList);
1774
1775 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1776 FreeStage(Ring, Stage);
1778 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1779
1780 /* The controller runs off the end and reports the ring empty */
1781 Ring->RingDoorbell();
1783 return;
1784 }
1785 }
1786
1787 Fit = LayoutStage(Ring, Stage, FALSE);
1788 if (Fit == 0)
1789 {
1790 DPRINT1("Isoch DCI %lu: packet %lu does not fit the reserved segments\n",
1791 Ring->m_Endpoint->Dci(), Stage->FirstPacket);
1792 (VOID)FailStage(Ring, Stage);
1793 return;
1794 }
1795
1796 /* End the stage at the last TD that fits in the segment */
1797 if (Stage->FirstPacket + Fit - 1 != Stage->LastPacket)
1798 {
1799 DPRINT1("Isoch DCI %lu: stage cut after %lu of %lu packets\n",
1800 Ring->m_Endpoint->Dci(), Fit, Stage->LastPacket - Stage->FirstPacket + 1);
1801
1802 for (Packet = Stage->FirstPacket; Packet < Stage->FirstPacket + Fit; Packet++)
1803 Size += XhciIsochPacketLength(Transfer, Packet);
1804
1805 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1806 Stage->LastPacket = Stage->FirstPacket + Fit - 1;
1807 Stage->Size = Size;
1808 Stage->Truncated = TRUE;
1809 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1810 }
1811
1812 (VOID)LayoutStage(Ring, Stage, TRUE);
1813
1814 /* The stage may be gone already; only the ring is used from here */
1815 Ring->RingDoorbell();
1816}
static ULONG LayoutStage(_In_ XhciTransferRing *Ring, _Inout_ XhciIsochStage *Stage, _In_ BOOLEAN Commit)
Definition: isoxfer.cpp:1823
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539

Member Data Documentation

◆ DmaCallback

VOID NTAPI XhciIsochRing::DmaCallback
staticprivate

Definition at line 155 of file isoxfer.h.

Referenced by EncodeStage().

◆ EvtCompletionDpc

VOID NTAPI XhciIsochRing::EvtCompletionDpc
static

Definition at line 103 of file isoxfer.h.

Referenced by _IRQL_requires_().

◆ EvtIoCanceledOnQueue

VOID NTAPI XhciIsochRing::EvtIoCanceledOnQueue
static

Definition at line 102 of file isoxfer.h.

Referenced by _IRQL_requires_().

◆ EvtRequestCancel

VOID NTAPI XhciIsochRing::EvtRequestCancel
staticprivate

Definition at line 153 of file isoxfer.h.

◆ EvtWatchdog

VOID NTAPI XhciIsochRing::EvtWatchdog
staticprivate

Definition at line 154 of file isoxfer.h.

Referenced by Initialize().

◆ m_BufferRetries

ULONG XhciIsochRing::m_BufferRetries
private

Definition at line 342 of file isoxfer.h.

Referenced by NextTdSlot(), PrimeStage(), and SegmentsArrived().

◆ m_Bytes

ULONG64 XhciIsochRing::m_Bytes
private

Definition at line 359 of file isoxfer.h.

Referenced by Finalize().

◆ m_Completion

LIST_ENTRY XhciIsochRing::m_Completion
private

Definition at line 353 of file isoxfer.h.

Referenced by AllowReclaimOnCancel(), Initialize(), and RecoverTransfers().

◆ m_CurrentStage

XhciIsochStage* XhciIsochRing::m_CurrentStage
private

Definition at line 350 of file isoxfer.h.

Referenced by NextTdSlot().

◆ m_DoorbellAfterFirstTd

BOOLEAN XhciIsochRing::m_DoorbellAfterFirstTd
private

Mapping context only

Definition at line 335 of file isoxfer.h.

Referenced by LayoutStage(), and ScheduleStartFrame().

◆ m_DpcRunning

BOOLEAN XhciIsochRing::m_DpcRunning
private

Definition at line 336 of file isoxfer.h.

◆ m_FailedTransfers

ULONG XhciIsochRing::m_FailedTransfers
private

Definition at line 358 of file isoxfer.h.

Referenced by Finalize().

◆ m_FillAgain

volatile LONG XhciIsochRing::m_FillAgain
private

Interlocked DMA callback handoff

Definition at line 347 of file isoxfer.h.

Referenced by EncodeStage().

◆ m_FillWanted

volatile LONG XhciIsochRing::m_FillWanted
private

Interlocked

Definition at line 345 of file isoxfer.h.

Referenced by BuildTdsFromQueue(), and FillLoop().

◆ m_Flags

volatile LONG XhciIsochRing::m_Flags
private

◆ m_FreshStream

BOOLEAN XhciIsochRing::m_FreshStream
private

Definition at line 334 of file isoxfer.h.

Referenced by ScheduleStartFrame().

◆ m_LastScheduledFrame

ULONG XhciIsochRing::m_LastScheduledFrame
private

Definition at line 338 of file isoxfer.h.

Referenced by FinishLostStages(), LayoutStage(), OnRingStarved(), and PrimeStage().

◆ m_LateStage

volatile LONG XhciIsochRing::m_LateStage
private

Interlocked

Definition at line 348 of file isoxfer.h.

Referenced by EncodeStage(), and WriteStage().

◆ m_MissedServiceErrors

ULONG XhciIsochRing::m_MissedServiceErrors
private

Definition at line 362 of file isoxfer.h.

Referenced by Ed0Event().

◆ m_NextSequence

ULONG XhciIsochRing::m_NextSequence
private

Definition at line 343 of file isoxfer.h.

Referenced by TakeRequest().

◆ m_NextStartFrame

ULONG XhciIsochRing::m_NextStartFrame
private

Definition at line 337 of file isoxfer.h.

Referenced by ScheduleStartFrame().

◆ m_PacketsPerFrame

ULONG XhciIsochRing::m_PacketsPerFrame
private

Definition at line 339 of file isoxfer.h.

Referenced by Initialize(), LayoutStage(), PrimeStage(), ScheduleStartFrame(), and WriteStage().

◆ m_Pending

◆ m_PendingStages

ULONG XhciIsochRing::m_PendingStages
private

◆ m_RingEmptyEvents

ULONG XhciIsochRing::m_RingEmptyEvents
private

Definition at line 363 of file isoxfer.h.

Referenced by OnRingStarved().

◆ m_RingEmptySeen

volatile LONG XhciIsochRing::m_RingEmptySeen
private

Interlocked

Definition at line 346 of file isoxfer.h.

Referenced by BuildTdsFromQueue(), FillLoop(), and OnRingStarved().

◆ m_SegmentWait

volatile LONG XhciIsochRing::m_SegmentWait
private

Interlocked segment callback handoff

Definition at line 349 of file isoxfer.h.

Referenced by ParkOnSegments(), ReleaseParkedMapping(), and SegmentsArrived().

◆ m_TdFailures

ULONG XhciIsochRing::m_TdFailures
private

Definition at line 361 of file isoxfer.h.

Referenced by Finalize().

◆ m_Tds

ULONG XhciIsochRing::m_Tds
private

Definition at line 360 of file isoxfer.h.

Referenced by Finalize().

◆ m_Transfers

ULONG XhciIsochRing::m_Transfers
private

Definition at line 357 of file isoxfer.h.

Referenced by Finalize().

◆ m_TrbsPerTd

ULONG XhciIsochRing::m_TrbsPerTd
private

Definition at line 341 of file isoxfer.h.

Referenced by EstimateSegments(), and LayoutStage().

◆ m_WaitingForCancel

LIST_ENTRY XhciIsochRing::m_WaitingForCancel
private

Definition at line 352 of file isoxfer.h.

Referenced by Initialize().

◆ m_Watchdog

WDFTIMER XhciIsochRing::m_Watchdog
private

Definition at line 354 of file isoxfer.h.

Referenced by Disable(), and Initialize().

◆ ReadyNotification

VOID NTAPI XhciIsochRing::ReadyNotification
static

Definition at line 101 of file isoxfer.h.

Referenced by _IRQL_requires_().


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