ReactOS 0.4.17-dev-1281-g065abb3
XhciControlRing Class Reference

#include <ctrlxfer.h>

Collaboration diagram for XhciControlRing:

Static Public Member Functions

static NTSTATUS Initialize (_In_ XhciTransferRing *Ring)
 
static VOID Enable (_In_ XhciTransferRing *Ring)
 
static VOID Disable (_In_ XhciTransferRing *Ring)
 
static NTSTATUS EnableForwardProgress (_In_ XhciTransferRing *Ring, _In_ ULONG MaxTransferSize)
 
static VOID Cleanup (_In_ XhciTransferRing *Ring)
 
static VOID ResumeRingFill (_In_ XhciTransferRing *Ring)
 
static VOID SuspendRingFill (_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_opt_ XhciTransferRing *Ring, _In_ XhciController *Controller, _In_ const XHCI_TRB *Event)
 

Static Public Attributes

static EVT_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault
 
static EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue
 
static EVT_WDF_DPC EvtCompletionDpc
 

Private Member Functions

struct DECLSPEC_ALIGN (8) EventTag
 
VOID InitTransfer (_Out_ XhciControlTransfer *Transfer, _In_ WDFREQUEST Request)
 
NTSTATUS PrepareTransfer (_Inout_ XhciControlTransfer *Transfer)
 
VOID BuildControlTd (_Inout_ XhciControlTransfer *Transfer)
 
VOID WriteTd (_Inout_ XhciControlTransfer *Transfer)
 
VOID ReleaseResources (_Inout_ XhciControlTransfer *Transfer)
 
 _Requires_lock_held_ (m_Ring->m_Lock) NTSTATUS CompleteHeld()
 
 _Requires_lock_held_ (m_Ring->m_Lock) VOID Finish(_Inout_ XhciControlTransfer *Transfer)
 
VOID Abort (_Inout_ XhciControlTransfer *Transfer, _In_ BOOLEAN FromTimer)
 
VOID QueueCompletion ()
 
 _Requires_lock_held_ (m_Ring->m_Lock) VOID CopyIn(_Inout_ XhciControlTransfer *Transfer
 
BOOLEAN OnEventDataEvent (_In_ EventTag *Tag, _In_ const XHCI_TRB *Event)
 
BOOLEAN OnTrbEvent (_In_ const XHCI_TRB *Event)
 
BOOLEAN LocateTrb (_In_ const XhciControlTransfer *Transfer, _In_ const XHCI_TRB *Event, _Out_ PULONG Bytes, _Out_ PULONG SkippedTds) const
 

Static Private Member Functions

static EventTag * TagFromEvent (_In_opt_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
 

Private Attributes

_In_ ULONG Bytes
 
EventTag m_Tags [TagCount]
 
XhciTransferRing * m_Ring
 
XhciControlTransfer * m_Current
 
LIST_ENTRY m_CanceledOnQueue
 
WDFDPC m_CanceledOnQueueDpc
 
WDFTIMER m_Timer
 
ULONG m_NextTag
 
LONG m_Outstanding
 
volatile LONG m_ReservedMdlBusy
 
BOOLEAN m_ImmediateAllowed
 
BOOLEAN m_ReclaimAndAcknowledge
 
BOOLEAN m_AcknowledgeExpectedEvents
 
BOOLEAN m_ReclaimOnCancelAllowed
 
BOOLEAN m_CanceledDpcRunning
 

Static Private Attributes

static const ULONG TagCount = 4
 
static EVT_WDF_TIMER EvtTimeout
 
static EVT_WDF_DPC EvtCanceledOnQueueDpc
 
static EVT_WDF_REQUEST_CANCEL EvtRequestCancel
 
static DRIVER_LIST_CONTROL EvtDmaReady
 

Detailed Description

Control ring state and the entry points the transfer ring calls for it.

Definition at line 15 of file ctrlxfer.h.

Member Function Documentation

◆ _Requires_lock_held_() [1/3]

XhciControlRing::_Requires_lock_held_ ( m_Ring->  m_Lock)
private

◆ _Requires_lock_held_() [2/3]

XhciControlRing::_Requires_lock_held_ ( m_Ring->  m_Lock)
private

◆ _Requires_lock_held_() [3/3]

XhciControlRing::_Requires_lock_held_ ( m_Ring->  m_Lock)
private

◆ Abort()

VOID XhciControlRing::Abort ( _Inout_ XhciControlTransfer *  Transfer,
_In_ BOOLEAN  FromTimer 
)
private

Shared by the cancel callback and the timeout timer; both act like a cancel.

Definition at line 984 of file ctrlxfer.cpp.

987{
988 XhciTransferRing* Ring = m_Ring;
989 BOOLEAN Reported = FALSE;
992 BOOLEAN Lost;
994
996 if (FromTimer)
997 Pending = (Transfer->TimeoutState == XhciControlTimeout::Armed);
998 else
999 Pending = (Transfer->CancelState == XhciControlCancel::Armed);
1000
1001 if (Pending)
1002 {
1004 Queue = TRUE;
1005 else
1006 Reported = TRUE;
1007 }
1009
1010 if (Reported)
1012
1014 if (FromTimer)
1015 Lost = (Transfer->TimeoutState == XhciControlTimeout::TimerRoutinePending);
1016 else
1017 Lost = (Transfer->CancelState == XhciControlCancel::CancelRoutinePending);
1018
1019 /* A completion left this request to us. After a reported cancel it waits for reclaim, or that permission would complete the next request */
1020 if (Lost && (!Reported || m_ReclaimAndAcknowledge || m_ReclaimOnCancelAllowed))
1021 Queue = TRUE;
1022
1023 /* Last, so nothing completes the request while this callback still uses it */
1024 if (FromTimer)
1025 Transfer->TimeoutState = XhciControlTimeout::Expired;
1026 else
1027 Transfer->CancelState = XhciControlCancel::Done;
1029
1030 if (Queue)
1032}
unsigned char BOOLEAN
Definition: actypes.h:127
XhciTransferRing * m_Ring
Definition: ctrlxfer.h:141
BOOLEAN m_ReclaimOnCancelAllowed
Definition: ctrlxfer.h:152
VOID QueueCompletion()
Definition: ctrlxfer.cpp:876
BOOLEAN m_ReclaimAndAcknowledge
Definition: ctrlxfer.h:150
VOID OnTransferCanceled()
Definition: epctx.cpp:1183
KSPIN_LOCK m_Lock
Definition: xferring.h:177
XhciEndpoint * m_Endpoint
Definition: xferring.h:172
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
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
@ Pending
Definition: fs_rec.h:186
_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

◆ AllowReclaimOnCancel()

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

Definition at line 1221 of file ctrlxfer.cpp.

1223{
1224 XhciControlRing* Self = XhciCtlOf(Ring);
1225 BOOLEAN Queue;
1226 KIRQL OldIrql;
1227
1228 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1229 Queue = (Self->m_Current != NULL &&
1230 (Self->m_Current->CancelState == XhciControlCancel::Done ||
1231 Self->m_Current->TimeoutState == XhciControlTimeout::Expired));
1233 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1234
1235 if (Queue)
1236 Self->QueueCompletion();
1237}
XhciControlTransfer * m_Current
Definition: ctrlxfer.h:142
static XhciControlRing *NTAPI XhciCtlOf(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:46
#define NULL
Definition: types.h:112
XhciControlCancel CancelState
Definition: reqctx.h:50
XhciControlTimeout TimeoutState
Definition: reqctx.h:51

Referenced by XhciTransferRing::AllowReclaimOnCancel().

◆ BuildControlTd()

VOID XhciControlRing::BuildControlTd ( _Inout_ XhciControlTransfer *  Transfer)
private

Definition at line 530 of file ctrlxfer.cpp.

532{
533 XhciTransferRing* Ring = m_Ring;
534 PURB Urb = Transfer->Urb;
535 PDMA_ADAPTER Adapter;
536 BOOLEAN Acknowledge = FALSE;
539
540 Status = PrepareTransfer(Transfer);
541 if (NT_SUCCESS(Status))
542 {
543 if (Urb->UrbHeader.Function == URB_FUNCTION_CONTROL_TRANSFER_EX &&
544 Urb->UrbControlTransferEx.Timeout != 0)
545 {
547 if (Transfer->TimeoutState == XhciControlTimeout::Idle ||
548 Transfer->TimeoutState == XhciControlTimeout::Armed)
549 {
550 Transfer->TimeoutState = XhciControlTimeout::Armed;
551 WdfTimerStart(m_Timer, WDF_REL_TIMEOUT_IN_MS(Urb->UrbControlTransferEx.Timeout));
552 }
554 }
555
557
558 if (Transfer->Mechanism != XhciControlMechanism::Dma)
559 {
560 WriteTd(Transfer);
561 return;
562 }
563
564 Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
566 Status = Adapter->DmaOperations->GetScatterGatherList(Adapter,
568 Transfer->Mdl,
569 MmGetMdlVirtualAddress(Transfer->Mdl),
570 Transfer->BytesTotal,
572 Transfer,
573 !Transfer->DataIn);
575
576 if (NT_SUCCESS(Status))
577 return;
578
579 DPRINT1("Control request %p: scatter gather list not built, status 0x%lx\n",
580 Transfer->Request, Status);
581 }
582
584
585 Transfer->Status = Status;
586
587 if (XhciCtlMapState(Ring) == XhciMapState::Filling)
588 {
589 XhciCtlSetMapState(Ring, XhciMapState::PausedFill);
590 if (m_Current == Transfer)
591 CompleteHeld();
592 }
593 else if (XhciCtlMapState(Ring) == XhciMapState::Halting)
594 {
595 /* The request stays held; reclaim completes it with the stored status */
596 XhciCtlSetMapState(Ring, XhciMapState::Halted);
597 Acknowledge = TRUE;
598 }
599
601
602 if (Acknowledge)
604}
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
PDMA_ADAPTER DmaAdapter() const
Definition: dmapool.cpp:738
VOID WriteTd(_Inout_ XhciControlTransfer *Transfer)
Definition: ctrlxfer.cpp:624
WDFTIMER m_Timer
Definition: ctrlxfer.h:145
static DRIVER_LIST_CONTROL EvtDmaReady
Definition: ctrlxfer.h:86
NTSTATUS PrepareTransfer(_Inout_ XhciControlTransfer *Transfer)
Definition: ctrlxfer.cpp:425
XhciCommonBuffer m_Buffers
Definition: hc.h:92
PDEVICE_OBJECT m_WdmDevice
Definition: hc.h:86
VOID OnMappingStopped()
Definition: epctx.cpp:1237
static ULONG UrbProcessorIndex(_In_ PURB Urb)
Definition: xferring.cpp:1168
XhciController * m_Controller
Definition: xferring.h:170
VOID UpdateInterrupterTarget()
Definition: xferring.cpp:1147
static XhciMapState NTAPI XhciCtlMapState(_In_ const XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:55
static VOID NTAPI XhciCtlSetMapState(_Inout_ XhciTransferRing *Ring, _In_ XhciMapState State)
Definition: ctrlxfer.cpp:64
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#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
Status
Definition: gdiplustypes.h:24
struct _DMA_OPERATIONS * DmaOperations
Definition: iotypes.h:2310
Definition: usb.h:565
_In_opt_ PUSB_CONFIGURATION_DESCRIPTOR _Inout_ PUSBD_INTERFACE_LIST_ENTRY _Outptr_ PURB * Urb
Definition: usbdlib.h:333
FORCEINLINE LONGLONG WDF_REL_TIMEOUT_IN_MS(_In_ ULONGLONG Time)
Definition: wdfcore.h:80
#define MmGetMdlVirtualAddress(_Mdl)

Referenced by ResumeRingFill().

◆ Cleanup()

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

Definition at line 286 of file ctrlxfer.cpp.

288{
289 XhciControlRing* Self = XhciCtlOf(Ring);
290 ULONG Index;
291
292 if (Self->m_Current != NULL)
293 DPRINT1("Control ring %p cleaned up while it holds request %p\n", Ring, Self->m_Current->Request);
294
295 /* A late fast path event must not take freed ring memory for a live tag */
296 for (Index = 0; Index < TagCount; Index++)
297 {
298 Self->m_Tags[Index].Signature = 0;
299 Self->m_Tags[Index].Transfer = NULL;
300 }
301}
EventTag m_Tags[TagCount]
Definition: ctrlxfer.h:140
static const ULONG TagCount
Definition: ctrlxfer.h:81
WDFREQUEST Request
Definition: reqctx.h:40
uint32_t ULONG
Definition: typedefs.h:59
_In_ WDFCOLLECTION _In_ ULONG Index

Referenced by XhciTransferRing::Cleanup().

◆ ConsumePendingEvents()

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

Definition at line 1240 of file ctrlxfer.cpp.

1242{
1243 XhciControlRing* Self = XhciCtlOf(Ring);
1244 BOOLEAN Drained;
1245 KIRQL OldIrql;
1246
1247 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1248 Drained = (Self->m_Outstanding == 0);
1249 if (!Drained)
1251 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1252
1253 if (Drained)
1254 Ring->m_Endpoint->OnExpectedEventsProcessed();
1255}
LONG m_Outstanding
Definition: ctrlxfer.h:147
BOOLEAN m_AcknowledgeExpectedEvents
Definition: ctrlxfer.h:151

Referenced by XhciTransferRing::ConsumePendingEvents().

◆ DECLSPEC_ALIGN()

struct XhciControlRing::DECLSPEC_ALIGN ( 8  )
inlineprivate

What an Event Data TRB points at. Tags live in the ring, not in the request, so a late or duplicate event never reads freed request memory.

Definition at line 63 of file ctrlxfer.h.

74 {
77 XhciTransferRing* Ring;
78 XhciControlTransfer* Transfer;
79 };
static const WCHAR Signature[]
Definition: parser.c:141

◆ Disable()

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

Definition at line 237 of file ctrlxfer.cpp.

239{
240 XhciControlRing* Self = XhciCtlOf(Ring);
243
244 /* The common ring already waited, with a limit, for the last mapping context to unwind */
245 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
246
247 State = XhciCtlMapState(Ring);
248 if (State == XhciMapState::PausedFill)
249 XhciCtlSetMapState(Ring, XhciMapState::Halted);
250 else if (State == XhciMapState::Filling || State == XhciMapState::Halting)
251 DPRINT1("Control ring %p disabled in map state %ld\n", Ring, static_cast<LONG>(State));
252
253 if (Self->m_Current != NULL)
254 DPRINT1("Control ring %p disabled while it holds request %p\n", Ring, Self->m_Current->Request);
255
256 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
257}
long LONG
Definition: pedump.c:60
XhciMapState
Definition: xferring.h:19

◆ DoorbellRungSinceFill()

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

Definition at line 1278 of file ctrlxfer.cpp.

1280{
1281 XhciTransferRing* Writable = const_cast<XhciTransferRing*>(Ring);
1282 BOOLEAN Rung;
1283 KIRQL OldIrql;
1284
1285 ASSERT(XhciCtlMapState(Ring) == XhciMapState::Halted);
1286
1288 Rung = Writable->m_DoorbellRung;
1290
1291 return Rung;
1292}
ULONG const BOOLEAN const _Out_ PBOOLEAN Writable
Definition: mmc.h:77
#define ASSERT(a)
Definition: mode.c:44

Referenced by XhciTransferRing::DoorbellRungSinceFill().

◆ Enable()

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

Definition at line 230 of file ctrlxfer.cpp.

232{
234}
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329

Referenced by _IRQL_requires_max_().

◆ EnableForwardProgress()

NTSTATUS XhciControlRing::EnableForwardProgress ( _In_ XhciTransferRing *  Ring,
_In_ ULONG  MaxTransferSize 
)
static

Definition at line 260 of file ctrlxfer.cpp.

263{
264 XhciControlRing* Self = XhciCtlOf(Ring);
265 ULONG Pages;
266 ULONG Trbs;
268
269 PAGED_CODE();
270
271 /* Worst case page span of the buffer, then setup, two Event Data, status and a link */
272 Pages = (PAGE_SIZE - 1 + MaxTransferSize + PAGE_SIZE - 1) / PAGE_SIZE;
273 Trbs = Pages + 5;
274 if (Trbs > Ring->m_LastIndex + 1)
275 DPRINT1("Control ring %p: %lu TRBs for a forward progress transfer exceed the segment\n", Ring, Trbs);
276
277 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
278 Ring->m_DoubleBufferSize = 0;
280 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
281
282 return STATUS_SUCCESS;
283}
#define PAGED_CODE()
BOOLEAN m_ImmediateAllowed
Definition: ctrlxfer.h:149
#define PAGE_SIZE
Definition: env_spec_w32.h:49
_In_ ULONG MaxTransferSize
Definition: pipe.h:72
#define STATUS_SUCCESS
Definition: shellext.h:65

◆ HasQueuedWork()

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

Definition at line 1295 of file ctrlxfer.cpp.

1297{
1298 return Ring->m_Type.Control.m_Current != NULL;
1299}

Referenced by XhciTransferRing::HasQueuedWork().

◆ Initialize()

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

Definition at line 178 of file ctrlxfer.cpp.

180{
181 XhciControlRing* Self = XhciCtlOf(Ring);
182 WDF_TIMER_CONFIG TimerConfig;
183 WDF_DPC_CONFIG DpcConfig;
186 ULONG Index;
187
188 PAGED_CODE();
189
190 RtlZeroMemory(Self, sizeof(*Self));
191 Self->m_Ring = Ring;
193
194 for (Index = 0; Index < TagCount; Index++)
195 {
196 Self->m_Tags[Index].Signature = XhciCtlTagSignature;
197 Self->m_Tags[Index].Index = Index;
198 Self->m_Tags[Index].Ring = Ring;
199 }
200
201 /* xHCI 6.4.1.1: immediate data needs a max packet size of at least 8 */
202 Self->m_ImmediateAllowed = !Ring->m_Controller->HasErrata(XhciErrata::XferNoInlineData) &&
203 Ring->m_Endpoint->MaxPacketSize() >= XhciCtlImmediateBytes;
204
205 WDF_TIMER_CONFIG_INIT(&TimerConfig, EvtTimeout);
207 Attributes.ParentObject = Ring->m_Queue;
208 Status = WdfTimerCreate(&TimerConfig, &Attributes, &Self->m_Timer);
209 if (!NT_SUCCESS(Status))
210 {
211 DPRINT1("Control ring %p: no timeout timer, status 0x%lx\n", Ring, Status);
212 return Status;
213 }
214
217 Attributes.ParentObject = Ring->m_Queue;
218 Status = WdfDpcCreate(&DpcConfig, &Attributes, &Self->m_CanceledOnQueueDpc);
219 if (!NT_SUCCESS(Status))
220 {
221 DPRINT1("Control ring %p: no DPC for requests canceled in the queue, status 0x%lx\n",
222 Ring, Status);
223 return Status;
224 }
225
226 return STATUS_SUCCESS;
227}
WDFDPC m_CanceledOnQueueDpc
Definition: ctrlxfer.h:144
static EVT_WDF_DPC EvtCanceledOnQueueDpc
Definition: ctrlxfer.h:84
static EVT_WDF_TIMER EvtTimeout
Definition: ctrlxfer.h:83
LIST_ENTRY m_CanceledOnQueue
Definition: ctrlxfer.h:143
static const ULONG XhciCtlImmediateBytes
Definition: ctrlxfer.cpp:26
static const ULONG XhciCtlTagSignature
Definition: ctrlxfer.cpp:17
_In_ ULONG Attributes
Definition: dispmprt.h:1077
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
FORCEINLINE VOID WDF_DPC_CONFIG_INIT(_Out_ PWDF_DPC_CONFIG Config, _In_ PFN_WDF_DPC EvtDpcFunc)
Definition: wdfdpc.h:83
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

Referenced by _IRQL_requires_().

◆ InitTransfer()

VOID XhciControlRing::InitTransfer ( _Out_ XhciControlTransfer *  Transfer,
_In_ WDFREQUEST  Request 
)
private

Definition at line 306 of file ctrlxfer.cpp.

309{
311 PURB Urb;
312
314 WdfRequestGetParameters(Request, &Parameters);
315 Urb = static_cast<PURB>(Parameters.Parameters.Others.Arg1);
316
317 RtlZeroMemory(Transfer, sizeof(*Transfer));
318 Transfer->Request = Request;
319 Transfer->Urb = Urb;
320 Transfer->Ring = m_Ring;
321 Transfer->Mechanism = XhciControlMechanism::NoData;
322 Transfer->BytesTotal = Urb->UrbControlTransfer.TransferBufferLength;
323 Transfer->DataIn = (Urb->UrbControlTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN) != 0;
324 Transfer->CancelState = XhciControlCancel::Idle;
325 Transfer->TimeoutState = XhciControlTimeout::Idle;
326 Transfer->Status = STATUS_PENDING;
327 Transfer->CompletionCode = static_cast<ULONG>(XhciCompletionCode::Invalid);
328 Transfer->FirstIndex = m_Ring->m_EnqueueIndex;
329 Transfer->EndIndex = m_Ring->m_EnqueueIndex;
330 Transfer->Initialized = TRUE;
331
332 /* QUIRK: the length reads 0 until completion, as it did on the USB 2.0 stack */
333 Urb->UrbControlTransfer.TransferBufferLength = 0;
334}
ULONG m_EnqueueIndex
Definition: xferring.h:190
_In_ HANDLE _In_ CONST PDXGKMDT_OPM_GET_INFO_PARAMETERS Parameters
Definition: dispmprt.h:321
#define STATUS_PENDING
Definition: telnetd.h:14
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST Request
#define USBD_TRANSFER_DIRECTION_IN
Definition: usb.h:167
FORCEINLINE VOID WDF_REQUEST_PARAMETERS_INIT(_Out_ PWDF_REQUEST_PARAMETERS Parameters)
Definition: wdfrequest.h:211

◆ LocateTrb()

BOOLEAN XhciControlRing::LocateTrb ( _In_ const XhciControlTransfer *  Transfer,
_In_ const XHCI_TRB *  Event,
_Out_ PULONG  Bytes,
_Out_ PULONG  SkippedTds 
) const
private

Definition at line 1484 of file ctrlxfer.cpp.

1489{
1490 const XhciTransferRing* Ring = m_Ring;
1491 ULONG64 Pointer = XhciTrbPointer(Event);
1492 ULONG64 Base = Ring->SegmentBase();
1493 ULONG EventLength = Event->Dword[2] & XHCI_TRANSFER_EVENT_LENGTH_MASK;
1495 const XHCI_TRB* Trb;
1496 ULONG Index = Transfer->FirstIndex;
1497 ULONG Visited;
1498 ULONG Length;
1499 ULONG Type;
1500 BOOLEAN Match;
1501
1502 *Bytes = 0;
1503 *SkippedTds = 0;
1504
1505 if (Pointer == 0)
1506 return FALSE;
1507
1508 /* Stopped on an empty ring: every TD of the request already ran */
1509 if (Pointer == Ring->EnqueuePointer())
1510 {
1511 *SkippedTds = Transfer->TdCount;
1512 return TRUE;
1513 }
1514
1515 /* Walk the TD from its first slot to its end slot, wrapping at the Link slot */
1516 for (Visited = 0; Visited <= Ring->m_LastIndex; Visited++)
1517 {
1518 Trb = &Ring->m_Trbs[Index];
1519 Type = XhciTrbType(Trb);
1520 Length = Trb->Dword[2] & XHCI_TRB_LENGTH_MASK;
1521 Match = (Base + static_cast<ULONG64>(Index) * sizeof(*Trb) == Pointer);
1522
1523 /* A link written in mid-segment jumps to the start, skipping the stale slots after it */
1524 if (Type == static_cast<ULONG>(XhciTrbType::Link) && !Match && Index != Transfer->EndIndex)
1525 {
1526 Index = 0;
1527 continue;
1528 }
1529
1530 if (Type == static_cast<ULONG>(XhciTrbType::Normal) || Type == static_cast<ULONG>(XhciTrbType::DataStage))
1531 {
1532 if (!Match)
1533 {
1534 *Bytes += Length;
1535 }
1536 else if (Code == XhciCompletionCode::StoppedShortPacket)
1537 {
1538 *Bytes = EventLength;
1539 }
1540 else if (Code == XhciCompletionCode::Stopped ||
1541 Code == XhciCompletionCode::DataBufferError ||
1542 Code == XhciCompletionCode::BabbleDetected ||
1543 Code == XhciCompletionCode::StallError ||
1544 Code == XhciCompletionCode::UsbTransactionError ||
1545 Code == XhciCompletionCode::SplitTransactionError)
1546 {
1547 /* The event carries the residual of this TRB */
1548 if (EventLength <= Length)
1549 *Bytes += Length - EventLength;
1550 }
1551 }
1552 else if (Type == static_cast<ULONG>(XhciTrbType::EventData) && !Match)
1553 {
1554 /* That TD finished and reported its own byte count */
1555 *Bytes = 0;
1556 (*SkippedTds)++;
1557 }
1558
1559 if (Match)
1560 return TRUE;
1561
1562 if (Index == Transfer->EndIndex)
1563 break;
1564
1565 Index = (Index >= Ring->m_LastIndex) ? 0 : Index + 1;
1566 }
1567
1568 return FALSE;
1569}
Type
Definition: Type.h:7
_In_ ULONG Bytes
Definition: ctrlxfer.h:120
ULONG64 EnqueuePointer() const
Definition: xferring.cpp:664
ULONG m_LastIndex
Definition: xferring.h:191
ULONG64 SegmentBase() const
Definition: xferring.cpp:658
PXHCI_TRB m_Trbs
Definition: xferring.h:189
Walk Base
Definition: desccheck.cpp:2270
_Check_return_ _In_ DXGK_EVENT_TYPE _In_ ULONG Event
Definition: dispmprt.h:1287
unsigned __int64 ULONG64
Definition: imports.h:198
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
ULONG Dword[4]
Definition: xhcihw.h:17
_In_ UCHAR _In_ UCHAR _In_ ULONG Code
Definition: wdfdevice.h:1707
#define XHCI_TRB_LENGTH_MASK
Definition: xhcihw.h:621
FORCEINLINE ULONG64 NTAPI XhciTrbPointer(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:60
#define XHCI_TRANSFER_EVENT_LENGTH_MASK
Definition: xhcihw.h:635
XhciTrbType
Definition: xhcihw.h:68
XhciCompletionCode
Definition: xhcihw.h:110
FORCEINLINE ULONG NTAPI XhciTrbCompletionCode(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:42

Referenced by OnTrbEvent().

◆ OnEventDataEvent()

BOOLEAN XhciControlRing::OnEventDataEvent ( _In_ EventTag *  Tag,
_In_ const XHCI_TRB *  Event 
)
private

Definition at line 1375 of file ctrlxfer.cpp.

1378{
1379 XhciTransferRing* Ring = m_Ring;
1380 XhciControlTransfer* Transfer;
1383 ULONG EndpointId = (Event->Dword[3] & XHCI_TRB_ENDPOINT_MASK) >> XHCI_TRB_ENDPOINT_SHIFT;
1387 BOOLEAN Drained = FALSE;
1388 KIRQL OldIrql;
1389
1391
1392 Transfer = Tag->Transfer;
1393 if (Transfer == NULL || Transfer != m_Current)
1394 {
1396
1397 DPRINT1("Control ring %p: stale Event Data event, code %lu, dropped\n", Ring, Code);
1398 return TRUE;
1399 }
1400
1401 if (EndpointId != Ring->m_Endpoint->Dci() || XhciTrbSlotId(Event) != Ring->m_Device->SlotId())
1402 {
1403 DPRINT1("Control ring %p: event for slot %lu endpoint %lu, ring is slot %lu endpoint %lu\n",
1404 Ring, XhciTrbSlotId(Event), EndpointId, Ring->m_Device->SlotId(), Ring->m_Endpoint->Dci());
1405 }
1406
1407 if (Bytes > Transfer->BytesTotal)
1408 {
1409 DPRINT1("Control ring %p: %lu bytes reported for a %lu byte request\n",
1410 Ring, Bytes, Transfer->BytesTotal);
1411 Bytes = 0;
1412 }
1413
1414 if (!StatusStage)
1415 {
1416 Transfer->BytesTransferred = Bytes;
1417 CopyIn(Transfer, Bytes);
1418 }
1419
1421 {
1422 /* The endpoint resets the pipe, then reclaim completes the request */
1423 Transfer->CompletionCode = Code;
1424 Halted = TRUE;
1425 }
1426 else if (XhciCtlIsStopCode(Code))
1427 {
1428 Transfer->EventsReceived++;
1429
1430 if (StatusStage)
1431 {
1432 if (Transfer->BytesTransferred == Transfer->BytesTotal)
1433 Transfer->CompletionCode = static_cast<ULONG>(XhciCompletionCode::Success);
1434 else if (Code == static_cast<ULONG>(XhciCompletionCode::StoppedShortPacket))
1435 Transfer->CompletionCode = Code;
1436
1437 m_Outstanding = max(static_cast<LONG>(Transfer->TdCount) - static_cast<LONG>(Transfer->EventsReceived), 0L);
1438 }
1439 else
1440 {
1441 /* QUIRK: a stop on the data stage expects no further events */
1442 m_Outstanding = 0;
1443 }
1444
1445 Stopped = TRUE;
1446 }
1447 else
1448 {
1449 Transfer->EventsReceived++;
1450
1451 if (StatusStage)
1452 {
1453 Transfer->CompletionCode = Code;
1454 if (Transfer->CancelState != XhciControlCancel::Done &&
1455 Transfer->TimeoutState != XhciControlTimeout::Expired)
1456 {
1457 CompleteHeld();
1458 }
1459 }
1460
1461 if (m_Outstanding > 0)
1462 {
1463 m_Outstanding--;
1464 Drained = (m_Outstanding == 0 && m_AcknowledgeExpectedEvents);
1465 }
1466 }
1467
1469
1470 if (Halted)
1472
1473 /* QUIRK: the drop stopped event flag is only consulted for events without Event Data */
1474 if (Stopped)
1475 Ring->m_Endpoint->OnStoppedEvent();
1476
1477 if (Drained)
1479
1480 return TRUE;
1481}
ULONG Dci() const
Definition: epctx.cpp:257
VOID OnStoppedEvent()
Definition: epctx.cpp:1217
VOID OnHaltedCompletionCode(_In_ ULONG CompletionCode, _In_ BOOLEAN TransferFound)
Definition: epctx.cpp:1190
VOID OnExpectedEventsProcessed()
Definition: epctx.cpp:1231
XhciUsbDevice * m_Device
Definition: xferring.h:171
ULONG SlotId() const
Definition: slotdev.cpp:335
static BOOLEAN NTAPI XhciCtlIsHaltCode(_In_ ULONG Code)
Definition: ctrlxfer.cpp:84
static const ULONG_PTR XhciCtlStatusStageFlag
Definition: ctrlxfer.cpp:14
static BOOLEAN NTAPI XhciCtlIsStopCode(_In_ ULONG Code)
Definition: ctrlxfer.cpp:106
#define Code
Definition: deflate.h:80
#define L(x)
Definition: resources.c:13
@ Stopped
Definition: fbtusb.h:81
ULONG EventsReceived
Definition: reqctx.h:55
ULONG CompletionCode
Definition: reqctx.h:53
ULONG BytesTransferred
Definition: reqctx.h:49
ULONG BytesTotal
Definition: reqctx.h:48
#define max(a, b)
Definition: svc.c:63
_Must_inspect_result_ _In_ UCXENDPOINT _In_ PVOID Tag
Definition: ucxendpoint.h:325
#define XHCI_TRB_ENDPOINT_MASK
Definition: xhcihw.h:27
#define XHCI_TRB_ENDPOINT_SHIFT
Definition: xhcihw.h:26
FORCEINLINE ULONG NTAPI XhciTrbSlotId(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:51

Referenced by OnTransferEvent().

◆ OnTransferEvent()

BOOLEAN XhciControlRing::OnTransferEvent ( _In_opt_ XhciTransferRing *  Ring,
_In_ XhciController *  Controller,
_In_ const XHCI_TRB *  Event 
)
static

The ring is always known; the NULL ring form is kept only for callers without one.

Definition at line 1338 of file ctrlxfer.cpp.

1342{
1343 EventTag* Tag;
1344
1346
1347 if (!(Event->Dword[3] & XHCI_TRANSFER_EVENT_ED))
1348 {
1349 /* Events without Event Data only come through the endpoint, with the ring known */
1350 if (Ring == NULL)
1351 return FALSE;
1352
1353 return XhciCtlOf(Ring)->OnTrbEvent(Event);
1354 }
1355
1356 Tag = TagFromEvent(Ring, Event);
1357 if (Tag == NULL)
1358 {
1359 if (Ring == NULL)
1360 {
1361 DPRINT1("Control Event Data value 0x%I64x names no live transfer, dropped\n",
1363 return FALSE;
1364 }
1365
1366 DPRINT1("Control ring %p: Event Data value 0x%I64x is not one of its own, dropped\n",
1367 Ring, XhciTrbPointer(Event));
1368 return FALSE;
1369 }
1370
1371 return XhciCtlOf(Tag->Ring)->OnEventDataEvent(Tag, Event);
1372}
static EventTag * TagFromEvent(_In_opt_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: ctrlxfer.cpp:1304
BOOLEAN OnEventDataEvent(_In_ EventTag *Tag, _In_ const XHCI_TRB *Event)
Definition: ctrlxfer.cpp:1375
BOOLEAN OnTrbEvent(_In_ const XHCI_TRB *Event)
Definition: ctrlxfer.cpp:1572
_Must_inspect_result_ _In_ WDFDEVICE _In_ PUCX_CONTROLLER_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ UCXCONTROLLER * Controller
#define XHCI_TRANSFER_EVENT_ED
Definition: xhcihw.h:321

Referenced by XhciTransferRing::OnTransferEvent().

◆ OnTrbEvent()

BOOLEAN XhciControlRing::OnTrbEvent ( _In_ const XHCI_TRB *  Event)
private

Definition at line 1572 of file ctrlxfer.cpp.

1574{
1575 XhciTransferRing* Ring = m_Ring;
1577 XhciControlTransfer* Transfer;
1579 ULONG64 Pointer = XhciTrbPointer(Event);
1580 ULONG64 Base;
1581 ULONG Bytes;
1582 ULONG Skipped;
1583 LONG Outstanding;
1584 KIRQL OldIrql;
1585
1587 return TRUE;
1588
1590
1591 Transfer = m_Current;
1592 if (Transfer == NULL)
1593 {
1595 DPRINT("Control ring %p: event code %lu with no request held\n", Ring, Code);
1596 return FALSE;
1597 }
1598
1599 if (!LocateTrb(Transfer, Event, &Bytes, &Skipped))
1600 {
1602
1603 Base = Ring->SegmentBase();
1604 if (Pointer >= Base && Pointer < Base + Ring->m_SegmentSize)
1605 {
1606 if (Controller->HasErrata(XhciErrata::EvtDiscardRepeatedEd0))
1607 {
1608 DPRINT1("Control ring %p: TRB 0x%I64x is outside the request, likely a duplicate, dropped\n",
1609 Ring, Pointer);
1610 }
1611 else
1612 {
1613 DPRINT1("Control ring %p: TRB 0x%I64x is outside the request, likely a duplicate, resetting\n",
1614 Ring, Pointer);
1615 Controller->RaiseControllerFault(XhciRecovery::ResetHost, XhciCtlReasonDuplicateEvent);
1616 }
1617 }
1618 else
1619 {
1620 DPRINT1("Control ring %p: TRB 0x%I64x is not on the ring, resetting\n", Ring, Pointer);
1621 Controller->RaiseControllerFault(XhciRecovery::ResetHost, XhciCtlReasonBadTrbPointer);
1622 }
1623 return FALSE;
1624 }
1625
1626 if (Bytes > Transfer->BytesTotal)
1627 {
1628 DPRINT1("Control ring %p: %lu bytes found for a %lu byte request\n", Ring, Bytes, Transfer->BytesTotal);
1629 Bytes = 0;
1630 }
1631
1632 /* Zero keeps a count an earlier data stage event already reported */
1633 if (Bytes != 0)
1634 {
1635 Transfer->BytesTransferred = Bytes;
1636 CopyIn(Transfer, Bytes);
1637 }
1638
1640 {
1641 Transfer->CompletionCode = Code;
1643
1645 return TRUE;
1646 }
1647
1649 {
1650 if (Transfer->BytesTransferred == Transfer->BytesTotal)
1651 Transfer->CompletionCode = static_cast<ULONG>(XhciCompletionCode::Success);
1652 else if (Code == static_cast<ULONG>(XhciCompletionCode::StoppedShortPacket))
1653 Transfer->CompletionCode = Code;
1654
1655 Transfer->EventsReceived++;
1656 Outstanding = static_cast<LONG>(Skipped + 1) - static_cast<LONG>(Transfer->EventsReceived);
1657 m_Outstanding = max(Outstanding, 0L);
1659
1660 Ring->m_Endpoint->OnStoppedEvent();
1661 return TRUE;
1662 }
1663
1665
1666 DPRINT1("Control ring %p: unexpected code %lu for TRB 0x%I64x\n", Ring, Code, Pointer);
1667 return FALSE;
1668}
BOOLEAN LocateTrb(_In_ const XhciControlTransfer *Transfer, _In_ const XHCI_TRB *Event, _Out_ PULONG Bytes, _Out_ PULONG SkippedTds) const
Definition: ctrlxfer.cpp:1484
BOOLEAN ShouldDropStoppedEvent() const
Definition: epctx.cpp:1211
static const ULONG XhciCtlReasonDuplicateEvent
Definition: ctrlxfer.cpp:21
static const ULONG XhciCtlReasonBadTrbPointer
Definition: ctrlxfer.cpp:20
#define DPRINT
Definition: sndvol32.h:73

Referenced by OnTransferEvent().

◆ PrepareTransfer()

NTSTATUS XhciControlRing::PrepareTransfer ( _Inout_ XhciControlTransfer *  Transfer)
private

Definition at line 425 of file ctrlxfer.cpp.

427{
428 XhciTransferRing* Ring = m_Ring;
429 struct _URB_CONTROL_TRANSFER* Urb = &Transfer->Urb->UrbControlTransfer;
430 PMDL UrbMdl = Urb->TransferBufferMDL;
431 ULONG Bytes = Transfer->BytesTotal;
432 XhciControlMechanism Mechanism;
433 PMDL Mdl;
434
435 /* A transfer mapped again after a stop starts over */
436 ReleaseResources(Transfer);
437
438 if (Bytes == 0)
439 return STATUS_SUCCESS;
440
441 if (m_ImmediateAllowed && Bytes <= XhciCtlImmediateBytes && !Transfer->DataIn)
442 {
443 Mechanism = XhciControlMechanism::Immediate;
444 }
445 else
446 {
447 Mechanism = XhciControlMechanism::Dma;
448
449 if ((UrbMdl == NULL || UrbMdl->Next == NULL) && Bytes <= Ring->m_DoubleBufferSize)
450 {
451 Transfer->DoubleBuffer = Ring->BorrowBounceBuffer();
452 if (Transfer->DoubleBuffer != NULL)
453 Mechanism = XhciControlMechanism::DoubleBuffer;
454 }
455 }
456
457 Transfer->Mechanism = Mechanism;
458
459 if (Mechanism != XhciControlMechanism::Dma)
460 {
461 Transfer->SystemBuffer = Urb->TransferBuffer;
462 if (Transfer->SystemBuffer == NULL && UrbMdl != NULL)
463 Transfer->SystemBuffer = MmGetSystemAddressForMdlSafe(UrbMdl, NormalPagePriority);
464
465 if (Transfer->SystemBuffer == NULL)
466 {
467 DPRINT1("Control request %p: no system address for its buffer\n", Transfer->Request);
469 }
470 }
471 else if (UrbMdl != NULL)
472 {
473 Transfer->Mdl = UrbMdl;
474 }
475 else
476 {
477 Mdl = IoAllocateMdl(Urb->TransferBuffer, Bytes, FALSE, FALSE, NULL);
478 if (Mdl == NULL)
479 {
480 /* The reserve MDL serves one request at a time */
481 if (!(Urb->TransferFlags & USB3_URB_RESERVED_RESOURCES) ||
482 Ring->m_ReservedMdl == NULL ||
484 {
485 DPRINT1("Control request %p: no MDL for %lu bytes\n", Transfer->Request, Bytes);
487 }
488
489 Mdl = Ring->m_ReservedMdl;
490 MmInitializeMdl(Mdl, Urb->TransferBuffer, Bytes);
491 }
492
494 Transfer->Mdl = Mdl;
495 }
496
497 /* QUIRK: one TD per request, never split */
499 {
500 DPRINT1("Control request %p: %lu bytes is more than 64 KB\n", Transfer->Request, Bytes);
502 }
503
504 if (Bytes > Ring->m_MaxStageSize)
505 {
506 DPRINT1("Control request %p: %lu bytes is more than the DMA stage size %lu\n",
507 Transfer->Request, Bytes, Ring->m_MaxStageSize);
509 }
510
511 /* QUIRK: the system buffer is NULL for Dma, so this never fires there */
512 if (Bytes == Ring->m_MaxStageSize &&
513 (reinterpret_cast<ULONG_PTR>(Transfer->SystemBuffer) & (PAGE_SIZE - 1)) != 0)
514 {
515 DPRINT1("Control request %p: stage sized buffer %p is not page aligned\n",
516 Transfer->Request, Transfer->SystemBuffer);
518 }
519
520 if (Mechanism == XhciControlMechanism::Dma && Transfer->Mdl->Next != NULL)
521 {
522 DPRINT1("Control request %p: chained MDLs are not supported\n", Transfer->Request);
524 }
525
526 return STATUS_SUCCESS;
527}
VOID ReleaseResources(_Inout_ XhciControlTransfer *Transfer)
Definition: ctrlxfer.cpp:388
volatile LONG m_ReservedMdlBusy
Definition: ctrlxfer.h:148
XhciDmaBuffer * BorrowBounceBuffer()
Definition: xferring.cpp:1014
PMDL m_ReservedMdl
Definition: xferring.h:181
ULONG m_MaxStageSize
Definition: xferring.h:185
static const ULONG XhciCtlMaxTransfer
Definition: ctrlxfer.cpp:23
#define STATUS_NOT_SUPPORTED
Definition: d3dkmdt.h:48
#define IoAllocateMdl
Definition: fxmdl.h:88
#define USB3_URB_RESERVED_RESOURCES
Definition: hubreq.cpp:15
#define InterlockedCompareExchange
Definition: interlocked.h:119
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:423
@ NormalPagePriority
Definition: imports.h:54
XhciControlMechanism
Definition: reqctx.h:13
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
#define MmInitializeMdl(_MemoryDescriptorList, _BaseVa, _Length)
#define MmGetSystemAddressForMdlSafe(_Mdl, _Priority)

Referenced by BuildControlTd().

◆ QueueCompletion()

VOID XhciControlRing::QueueCompletion ( )
private

Definition at line 876 of file ctrlxfer.cpp.

877{
878 WdfDpcEnqueue(m_Ring->m_CompletionDpc);
879}
WDFDPC m_CompletionDpc
Definition: xferring.h:176

Referenced by Abort(), AllowReclaimOnCancel(), RecoverTransfers(), and ResumeRingFill().

◆ RecoverTransfers()

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

Definition at line 1258 of file ctrlxfer.cpp.

1260{
1261 XhciControlRing* Self = XhciCtlOf(Ring);
1262 BOOLEAN Held;
1263 KIRQL OldIrql;
1264
1265 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1266 Held = (Self->m_Current != NULL);
1267 if (Held)
1269 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1270
1271 if (Held)
1272 Self->QueueCompletion();
1273 else
1274 Ring->m_Endpoint->OnTransfersReclaimed();
1275}

Referenced by XhciTransferRing::RecoverTransfers().

◆ ReleaseResources()

VOID XhciControlRing::ReleaseResources ( _Inout_ XhciControlTransfer *  Transfer)
private

Definition at line 388 of file ctrlxfer.cpp.

390{
391 XhciTransferRing* Ring = m_Ring;
392 PDMA_ADAPTER Adapter;
394
395 if (Transfer->DoubleBuffer != NULL)
396 {
397 Ring->ReturnBounceBuffer(Transfer->DoubleBuffer);
398 Transfer->DoubleBuffer = NULL;
399 }
400
401 if (Transfer->SgList != NULL)
402 {
403 Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
405 Adapter->DmaOperations->PutScatterGatherList(Adapter, Transfer->SgList, !Transfer->DataIn);
407 Transfer->SgList = NULL;
408 }
409
410 if (Transfer->Mdl != NULL && Transfer->Mdl == Ring->m_ReservedMdl)
411 {
413 }
414 else if (Transfer->Mdl != NULL && Transfer->Mdl != Transfer->Urb->UrbControlTransfer.TransferBufferMDL)
415 {
416 IoFreeMdl(Transfer->Mdl);
417 }
418
419 Transfer->Mdl = NULL;
420 Transfer->SystemBuffer = NULL;
421 Transfer->Mechanism = XhciControlMechanism::NoData;
422}
#define InterlockedExchange
Definition: armddk.h:54
VOID ReturnBounceBuffer(_In_ XhciDmaBuffer *Buffer)
Definition: xferring.cpp:1039
#define IoFreeMdl
Definition: fxmdl.h:89

Referenced by PrepareTransfer().

◆ ResumeRingFill()

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

Definition at line 1145 of file ctrlxfer.cpp.

1147{
1148 XhciControlRing* Self = XhciCtlOf(Ring);
1149 XhciControlTransfer* Transfer;
1151 BOOLEAN Map = FALSE;
1152 KIRQL OldIrql;
1153
1154 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1155
1156 Ring->m_DoorbellRung = FALSE;
1160 Self->m_Outstanding = 0;
1161
1162 if (XhciCtlMapState(Ring) != XhciMapState::Halted)
1163 DPRINT1("Control ring %p: mapping started in map state %ld\n", Ring, Ring->m_MapState);
1164
1165 Transfer = Self->m_Current;
1166 if (Transfer == NULL)
1167 {
1168 XhciCtlSetMapState(Ring, XhciMapState::PausedFill);
1169 }
1170 else if (Transfer->CancelState == XhciControlCancel::Done ||
1171 Transfer->TimeoutState == XhciControlTimeout::Expired)
1172 {
1173 /* Its cancel or timeout was reported before this start and the endpoint dropped that report */
1174 XhciCtlSetMapState(Ring, XhciMapState::PausedFill);
1175 Queue = TRUE;
1176 }
1177 else
1178 {
1179 XhciCtlSetMapState(Ring, XhciMapState::Filling);
1180 Map = TRUE;
1181 }
1182
1183 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1184
1185 if (Queue)
1186 Self->QueueCompletion();
1187
1188 /* QUIRK: a held request is mapped from scratch, which only happens if it never reached the hardware */
1189 if (Map)
1190 Self->BuildControlTd(Transfer);
1191}
VOID BuildControlTd(_Inout_ XhciControlTransfer *Transfer)
Definition: ctrlxfer.cpp:530

Referenced by XhciTransferRing::ResumeRingFill().

◆ SuspendRingFill()

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

Definition at line 1194 of file ctrlxfer.cpp.

1196{
1197 BOOLEAN Acknowledge = FALSE;
1198 KIRQL OldIrql;
1199
1200 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1201
1202 if (XhciCtlMapState(Ring) == XhciMapState::Filling)
1203 {
1204 /* The mapping context acknowledges once it is done */
1205 XhciCtlSetMapState(Ring, XhciMapState::Halting);
1206 }
1207 else
1208 {
1209 ASSERT(XhciCtlMapState(Ring) == XhciMapState::PausedFill);
1210 XhciCtlSetMapState(Ring, XhciMapState::Halted);
1211 Acknowledge = TRUE;
1212 }
1213
1214 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1215
1216 if (Acknowledge)
1217 Ring->m_Endpoint->OnMappingStopped();
1218}

Referenced by XhciTransferRing::SuspendRingFill().

◆ TagFromEvent()

XhciControlRing::EventTag * XhciControlRing::TagFromEvent ( _In_opt_ XhciTransferRing *  Ring,
_In_ const XHCI_TRB *  Event 
)
staticprivate

The tag an Event Data value names, or NULL when it is not a live tag (of Ring, when given).

Definition at line 1304 of file ctrlxfer.cpp.

1307{
1309 EventTag* Tag = reinterpret_cast<EventTag*>(Address);
1311 ULONG Index;
1312
1313 if (Address == 0)
1314 return NULL;
1315
1316 /* With the ring known, only compare addresses; nothing is read through the value */
1317 if (Ring != NULL)
1318 {
1319 Owner = XhciCtlOf(Ring);
1320 for (Index = 0; Index < TagCount; Index++)
1321 {
1322 if (Tag == &Owner->m_Tags[Index])
1323 return Tag;
1324 }
1325 return NULL;
1326 }
1327
1328 if (Tag->Signature != XhciCtlTagSignature || Tag->Index >= TagCount || Tag->Ring == NULL)
1329 return NULL;
1330
1331 if (&XhciCtlOf(Tag->Ring)->m_Tags[Tag->Index] != Tag)
1332 return NULL;
1333
1334 return Tag;
1335}
static const ULONG_PTR XhciCtlValueFlagBits
Definition: ctrlxfer.cpp:15
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1629
static WCHAR Address[46]
Definition: ping.c:68

Referenced by OnTransferEvent().

◆ WriteTd()

VOID XhciControlRing::WriteTd ( _Inout_ XhciControlTransfer *  Transfer)
private

Definition at line 624 of file ctrlxfer.cpp.

626{
627 XhciTransferRing* Ring = m_Ring;
629 struct _URB_CONTROL_TRANSFER* Urb = &Transfer->Urb->UrbControlTransfer;
630 PSCATTER_GATHER_LIST SgList = Transfer->SgList;
631 BOOLEAN Short512 = Controller->HasErrata(XhciErrata::CtlSplitDataAt512);
632 XhciCtlStep Next = XhciCtlStep::Setup;
633 XhciCtlStep Step;
634 EventTag* Tag;
635 ULONG_PTR TagValue;
637 XHCI_TRB Trb;
639 ULONG Packets;
640 ULONG Mapped = 0;
641 ULONG Element = 0;
642 ULONG Offset = 0;
643 ULONG Chunk;
644 ULONG Limit;
645 ULONG Remaining;
646 ULONG TdCount = 0;
647 ULONG FirstSlot;
648 ULONG Trt;
650 BOOLEAN DirOnNormal = FALSE;
651 BOOLEAN LastData;
652 BOOLEAN Acknowledge = FALSE;
653 volatile UCHAR* CycleByte;
655
656 Packets = Ring->PacketCount(Transfer->BytesTotal);
658
660 m_NextTag++;
661 ASSERT((reinterpret_cast<ULONG_PTR>(Tag) & XhciCtlValueFlagBits) == 0);
662 TagValue = reinterpret_cast<ULONG_PTR>(Tag) | USB_ENDPOINT_TYPE_CONTROL;
663
664 FirstSlot = Ring->m_EnqueueIndex;
665
666 /* Keep the whole TD inside the segment when Link TRBs inside a TD are not allowed */
667 if (Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment) &&
669 {
670 XhciCtlWrap(Ring, TRUE, FALSE);
671 First = FALSE;
672 }
673
674 while (Next != XhciCtlStep::Done)
675 {
676 Step = Next;
677
678 if (Ring->m_EnqueueIndex >= Ring->m_LastIndex)
679 {
680 XhciCtlWrap(Ring,
681 First,
682 Step == XhciCtlStep::MoreData ||
683 Step == XhciCtlStep::DataEventData ||
684 Step == XhciCtlStep::StatusEventData);
685 First = FALSE;
686 continue;
687 }
688
689 RtlZeroMemory(&Trb, sizeof(Trb));
690 Trb.Dword[2] = Target;
691
692 switch (Step)
693 {
694 case XhciCtlStep::Setup:
695 {
696 if (Transfer->BytesTotal == 0)
698 else
699 Trt = Transfer->DataIn ? XHCI_TRB_TRT_IN : XHCI_TRB_TRT_OUT;
700
701 RtlCopyMemory(&Trb.Dword[0], Urb->SetupPacket, XhciCtlSetupBytes);
702 Trb.Dword[2] |= XhciCtlSetupBytes;
703 Trb.Dword[3] = XhciCtlTrbType(XhciTrbType::SetupStage) | XHCI_TRB_IDT |
704 (Trt << XHCI_TRB_TRT_SHIFT);
705 Next = Transfer->BytesTotal ? XhciCtlStep::FirstData : XhciCtlStep::Status;
706 break;
707 }
708
709 case XhciCtlStep::FirstData:
710 case XhciCtlStep::MoreData:
711 {
712 if (Step == XhciCtlStep::FirstData)
713 {
714 Trb.Dword[3] = XhciCtlTrbType(XhciTrbType::DataStage);
715 if (Transfer->DataIn)
716 Trb.Dword[3] |= XHCI_TRB_DIR_IN;
717 }
718 else
719 {
720 Trb.Dword[3] = XhciCtlTrbType(XhciTrbType::Normal);
721 if (DirOnNormal)
722 Trb.Dword[3] |= XHCI_TRB_DIR_IN;
723 }
724 Trb.Dword[3] |= XHCI_TRB_CHAIN;
725
726 if (Transfer->Mechanism == XhciControlMechanism::Immediate)
727 {
728 RtlCopyMemory(&Trb.Dword[0], Transfer->SystemBuffer, Transfer->BytesTotal);
729 Trb.Dword[3] |= XHCI_TRB_IDT;
730 Chunk = Transfer->BytesTotal;
731 LastData = TRUE;
732 }
733 else if (Transfer->Mechanism == XhciControlMechanism::DoubleBuffer)
734 {
735 if (!Transfer->DataIn)
736 {
737 RtlCopyMemory(Transfer->DoubleBuffer->VirtualAddress,
738 Transfer->SystemBuffer,
739 Transfer->BytesTotal);
740 }
741
742 Address = Transfer->DoubleBuffer->LogicalAddress.QuadPart;
743 Trb.Dword[0] = static_cast<ULONG>(Address);
744 Trb.Dword[1] = static_cast<ULONG>(Address >> 32);
745 Chunk = Transfer->BytesTotal;
746 LastData = TRUE;
747 }
748 else
749 {
750 Remaining = SgList->Elements[Element].Length - Offset;
752
753 /* These parts want a short first Data Stage TRB; IN marks what follows */
754 if (Short512 && Step == XhciCtlStep::FirstData && Remaining > XhciCtlShortDataStageTrb)
755 {
757 DirOnNormal = Transfer->DataIn;
758 }
759
760 Address = SgList->Elements[Element].Address.QuadPart + Offset;
761
762 /* A TRB buffer may not cross a 64 KB boundary (xHCI 6.4.1.1) */
763 Limit = min(Limit, 0x10000 - static_cast<ULONG>(Address & 0xFFFF));
764
765 Chunk = min(Remaining, Limit);
766 Trb.Dword[0] = static_cast<ULONG>(Address);
767 Trb.Dword[1] = static_cast<ULONG>(Address >> 32);
768
769 Offset += Chunk;
770 if (Offset >= SgList->Elements[Element].Length)
771 {
772 Element++;
773 Offset = 0;
774 }
775 LastData = (Element >= SgList->NumberOfElements);
776 }
777
778 Mapped += Chunk;
779 Trb.Dword[2] |= (Chunk & XHCI_TRB_LENGTH_MASK) |
780 (Ring->TdSize(Packets, Mapped, LastData) << XHCI_TRB_TD_SIZE_SHIFT);
781
782 if (LastData)
783 {
784 Trb.Dword[3] |= XHCI_TRB_ENT;
785 Next = XhciCtlStep::DataEventData;
786 }
787 else
788 {
789 Next = XhciCtlStep::MoreData;
790 }
791 break;
792 }
793
794 case XhciCtlStep::DataEventData:
795 case XhciCtlStep::StatusEventData:
796 {
797 Address = TagValue;
798 if (Step == XhciCtlStep::StatusEventData)
800
801 Trb.Dword[0] = static_cast<ULONG>(Address);
802 Trb.Dword[1] = static_cast<ULONG>(Address >> 32);
803 Trb.Dword[3] = XhciCtlTrbType(XhciTrbType::EventData) | XHCI_TRB_IOC;
804 TdCount++;
805 Next = (Step == XhciCtlStep::DataEventData) ? XhciCtlStep::Status : XhciCtlStep::Done;
806 break;
807 }
808
809 case XhciCtlStep::Status:
810 {
811 /* QUIRK: the direction comes from the flags alone, even with no data stage */
812 Trb.Dword[3] = XhciCtlTrbType(XhciTrbType::StatusStage) | XHCI_TRB_CHAIN | XHCI_TRB_ENT;
813 if (!Transfer->DataIn)
814 Trb.Dword[3] |= XHCI_TRB_DIR_IN;
815 Next = XhciCtlStep::StatusEventData;
816 break;
817 }
818
819 default:
820 {
821 Next = XhciCtlStep::Done;
822 continue;
823 }
824 }
825
826 XhciCtlPut(Ring, &Trb, First);
827 First = FALSE;
828 }
829
830 Transfer->FirstIndex = FirstSlot;
831 Transfer->EndIndex = Ring->m_EnqueueIndex;
832
833 /* Invalid TRB after the TD so the controller stops there */
834 RtlZeroMemory(&Trb, sizeof(Trb));
835 Trb.Dword[3] = (Ring->m_Cycle & XHCI_TRB_CYCLE) ^ XHCI_TRB_CYCLE;
836 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
837
839
840 if (Transfer->TagArmed)
841 m_Tags[Transfer->TagIndex].Transfer = NULL;
842 Tag->Transfer = Transfer;
843 Transfer->TagIndex = Tag->Index;
844 Transfer->TagArmed = TRUE;
845
846 Transfer->TdCount = TdCount;
847 Ring->m_DoorbellRung = TRUE;
848
849 if (XhciCtlMapState(Ring) == XhciMapState::Filling)
850 {
851 XhciCtlSetMapState(Ring, XhciMapState::PausedFill);
852 }
853 else if (XhciCtlMapState(Ring) == XhciMapState::Halting)
854 {
855 XhciCtlSetMapState(Ring, XhciMapState::Halted);
856 Acknowledge = TRUE;
857 }
858
860
861 /* The byte write is the barrier that publishes the TD before its first TRB turns valid */
863 CycleByte = reinterpret_cast<volatile UCHAR*>(&Ring->m_Trbs[FirstSlot]) + 12;
864 WRITE_REGISTER_UCHAR(const_cast<PUCHAR>(CycleByte), *CycleByte ^ XHCI_TRB_CYCLE);
866
867 Ring->RingDoorbell();
868
869 if (Acknowledge)
871}
WCHAR First[]
Definition: FormatMessage.c:11
ULONG m_NextTag
Definition: ctrlxfer.h:146
ULONG m_InterrupterTarget
Definition: xferring.h:179
ULONG TdSize(_In_ ULONG PacketCount, _In_ ULONG BytesMappedSoFar, _In_ BOOLEAN LastTrbOfTd) const
Definition: xferring.cpp:1126
BOOLEAN m_DoorbellRung
Definition: xferring.h:180
ULONG PacketCount(_In_ ULONG Bytes) const
Definition: xferring.cpp:1113
XhciCtlStep
Definition: ctrlxfer.cpp:33
static const ULONG XhciCtlMaxTrbLength
Definition: ctrlxfer.cpp:24
static const ULONG XhciCtlWorstCaseTd
Definition: ctrlxfer.cpp:30
static const ULONG XhciCtlShortDataStageTrb
Definition: ctrlxfer.cpp:25
static VOID NTAPI XhciCtlPut(_Inout_ XhciTransferRing *Ring, _Inout_ PXHCI_TRB Trb, _In_ BOOLEAN FirstOfTd)
Definition: ctrlxfer.cpp:160
static VOID NTAPI XhciCtlWrap(_Inout_ XhciTransferRing *Ring, _In_ BOOLEAN FirstOfTd, _In_ BOOLEAN InDataStage)
Definition: ctrlxfer.cpp:138
static const ULONG XhciCtlSetupBytes
Definition: ctrlxfer.cpp:27
static ULONG NTAPI XhciCtlTrbType(_In_ enum XhciTrbType Type)
Definition: ctrlxfer.cpp:74
PUCHAR Limit
Definition: desccheck.cpp:2230
#define min(a, b)
Definition: monoChain.cc:55
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
FORCEINLINE VOID KeMemoryBarrier(VOID)
Definition: ke.h:58
PACPI_METHOD_ARGUMENT Next
Definition: slotdev.cpp:96
unsigned char UCHAR
Definition: typedefs.h:53
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
unsigned char * PUCHAR
Definition: typedefs.h:53
#define USB_ENDPOINT_TYPE_CONTROL
Definition: usb100.h:62
WDF_EXTERN_C_START typedef _In_ WDFDEVICE _In_ WDFCONTEXT _In_ WDF_DMA_DIRECTION _In_ PSCATTER_GATHER_LIST SgList
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
struct _SCATTER_GATHER_LIST * PSCATTER_GATHER_LIST
Definition: iotypes.h:2219
#define XHCI_TRB_TRT_SHIFT
Definition: xhcihw.h:629
#define XHCI_TRB_ENT
Definition: xhcihw.h:623
#define XHCI_TRB_TD_SIZE_SHIFT
Definition: xhcihw.h:622
#define XHCI_TRB_TRT_IN
Definition: xhcihw.h:632
#define XHCI_TRB_INTERRUPTER_MASK
Definition: xhcihw.h:611
#define XHCI_TRB_IDT
Definition: xhcihw.h:625
#define XHCI_TRB_INTERRUPTER_SHIFT
Definition: xhcihw.h:610
#define XHCI_TRB_TRT_OUT
Definition: xhcihw.h:631
#define XHCI_TRB_DIR_IN
Definition: xhcihw.h:626
#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_TRB_TRT_NO_DATA
Definition: xhcihw.h:630

Referenced by BuildControlTd().

Member Data Documentation

◆ Bytes

_In_ ULONG XhciControlRing::Bytes
private

Definition at line 120 of file ctrlxfer.h.

Referenced by LocateTrb(), OnEventDataEvent(), OnTrbEvent(), and PrepareTransfer().

◆ EvtCanceledOnQueueDpc

VOID XhciControlRing::EvtCanceledOnQueueDpc
staticprivate

Definition at line 84 of file ctrlxfer.h.

Referenced by Initialize().

◆ EvtCompletionDpc

VOID XhciControlRing::EvtCompletionDpc
static

Definition at line 37 of file ctrlxfer.h.

Referenced by _IRQL_requires_().

◆ EvtDmaReady

VOID NTAPI XhciControlRing::EvtDmaReady
staticprivate

Definition at line 86 of file ctrlxfer.h.

Referenced by BuildControlTd().

◆ EvtIoCanceledOnQueue

VOID XhciControlRing::EvtIoCanceledOnQueue
static

Definition at line 36 of file ctrlxfer.h.

Referenced by _IRQL_requires_().

◆ EvtIoDefault

VOID XhciControlRing::EvtIoDefault
static

Definition at line 35 of file ctrlxfer.h.

Referenced by _IRQL_requires_().

◆ EvtRequestCancel

VOID XhciControlRing::EvtRequestCancel
staticprivate

Definition at line 85 of file ctrlxfer.h.

◆ EvtTimeout

VOID XhciControlRing::EvtTimeout
staticprivate

Definition at line 83 of file ctrlxfer.h.

Referenced by Initialize().

◆ m_AcknowledgeExpectedEvents

BOOLEAN XhciControlRing::m_AcknowledgeExpectedEvents
private

Definition at line 151 of file ctrlxfer.h.

Referenced by ConsumePendingEvents(), OnEventDataEvent(), and ResumeRingFill().

◆ m_CanceledDpcRunning

BOOLEAN XhciControlRing::m_CanceledDpcRunning
private

Definition at line 153 of file ctrlxfer.h.

◆ m_CanceledOnQueue

LIST_ENTRY XhciControlRing::m_CanceledOnQueue
private

Definition at line 143 of file ctrlxfer.h.

Referenced by Initialize().

◆ m_CanceledOnQueueDpc

WDFDPC XhciControlRing::m_CanceledOnQueueDpc
private

Definition at line 144 of file ctrlxfer.h.

Referenced by Initialize().

◆ m_Current

XhciControlTransfer* XhciControlRing::m_Current
private

The one request on this ring, or NULL

Definition at line 142 of file ctrlxfer.h.

Referenced by AllowReclaimOnCancel(), BuildControlTd(), Cleanup(), Disable(), OnEventDataEvent(), OnTrbEvent(), RecoverTransfers(), and ResumeRingFill().

◆ m_ImmediateAllowed

BOOLEAN XhciControlRing::m_ImmediateAllowed
private

Definition at line 149 of file ctrlxfer.h.

Referenced by EnableForwardProgress(), Initialize(), and PrepareTransfer().

◆ m_NextTag

ULONG XhciControlRing::m_NextTag
private

Definition at line 146 of file ctrlxfer.h.

Referenced by WriteTd().

◆ m_Outstanding

LONG XhciControlRing::m_Outstanding
private

Events still expected after a stop

Definition at line 147 of file ctrlxfer.h.

Referenced by ConsumePendingEvents(), OnEventDataEvent(), OnTrbEvent(), and ResumeRingFill().

◆ m_ReclaimAndAcknowledge

BOOLEAN XhciControlRing::m_ReclaimAndAcknowledge
private

Definition at line 150 of file ctrlxfer.h.

Referenced by Abort(), RecoverTransfers(), and ResumeRingFill().

◆ m_ReclaimOnCancelAllowed

BOOLEAN XhciControlRing::m_ReclaimOnCancelAllowed
private

Definition at line 152 of file ctrlxfer.h.

Referenced by Abort(), AllowReclaimOnCancel(), and ResumeRingFill().

◆ m_ReservedMdlBusy

volatile LONG XhciControlRing::m_ReservedMdlBusy
private

Definition at line 148 of file ctrlxfer.h.

Referenced by PrepareTransfer(), and ReleaseResources().

◆ m_Ring

◆ m_Tags

EventTag XhciControlRing::m_Tags[TagCount]
private

Definition at line 140 of file ctrlxfer.h.

Referenced by Cleanup(), Initialize(), TagFromEvent(), and WriteTd().

◆ m_Timer

WDFTIMER XhciControlRing::m_Timer
private

Definition at line 145 of file ctrlxfer.h.

Referenced by BuildControlTd(), and Initialize().

◆ TagCount

const ULONG XhciControlRing::TagCount = 4
staticprivate

Definition at line 81 of file ctrlxfer.h.

Referenced by Cleanup(), Initialize(), TagFromEvent(), and WriteTd().


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