ReactOS 0.4.17-dev-1281-g065abb3
ctrlxfer.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS xHCI Host Controller Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Control transfer ring: setup, data and status TDs on endpoint 0 style pipes
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8#include "xhcidrv.h"
9
10#define NDEBUG
11#include <debug.h>
12
13/* Event Data value layout: endpoint type in bits 1:0, status stage flag in bit 2 */
16
17static const ULONG XhciCtlTagSignature = 0x6C744358;
18
19/* Reason codes handed to the controller with a fatal error */
20static const ULONG XhciCtlReasonBadTrbPointer = 0x101F;
21static const ULONG XhciCtlReasonDuplicateEvent = 0x1020;
22
23static const ULONG XhciCtlMaxTransfer = 0x10000;
24static const ULONG XhciCtlMaxTrbLength = 0x10000;
27static const ULONG XhciCtlSetupBytes = 8;
28
29/* Setup, 17 data, a status TRB and two Event Data TRBs */
30static const ULONG XhciCtlWorstCaseTd = 21;
31
32enum class XhciCtlStep : ULONG
33{
34 Setup,
38 Status,
40 Done
41};
42
43static
48{
49 return &Ring->m_Type.Control;
50}
51
52static
56 _In_ const XhciTransferRing* Ring)
57{
58 return static_cast<XhciMapState>(Ring->m_MapState);
59}
60
61static
62VOID
67{
68 InterlockedExchange(&Ring->m_MapState, static_cast<LONG>(State));
69}
70
71static
76{
77 return static_cast<ULONG>(Type) << XHCI_TRB_TYPE_SHIFT;
78}
79
81static
86{
87 switch (static_cast<XhciCompletionCode>(Code))
88 {
97 return TRUE;
98 default:
99 return FALSE;
100 }
101}
102
103static
105NTAPI
108{
109 return Code == static_cast<ULONG>(XhciCompletionCode::Stopped) ||
112}
113
115static
117NTAPI
120{
121 switch (Status)
122 {
123 case STATUS_CANCELLED:
129 default:
131 }
132}
133
135static
136VOID
137NTAPI
140 _In_ BOOLEAN FirstOfTd,
141 _In_ BOOLEAN InDataStage)
142{
144 ULONG64 Base = Ring->SegmentBase();
145
146 Ring->BuildLinkTrb(&Link, FirstOfTd, InDataStage);
147 Link.Dword[0] = static_cast<ULONG>(Base);
148 Link.Dword[1] = static_cast<ULONG>(Base >> 32);
149 Link.Dword[3] |= XHCI_LINK_TOGGLE_CYCLE;
150
151 Ring->m_Trbs[Ring->m_EnqueueIndex] = Link;
152 Ring->m_Cycle ^= XHCI_TRB_CYCLE;
153 Ring->m_EnqueueIndex = 0;
154}
155
157static
158VOID
159NTAPI
162 _Inout_ PXHCI_TRB Trb,
163 _In_ BOOLEAN FirstOfTd)
164{
165 ULONG Cycle = Ring->m_Cycle & XHCI_TRB_CYCLE;
166
167 if (FirstOfTd)
168 Cycle ^= XHCI_TRB_CYCLE;
169
170 Trb->Dword[3] = (Trb->Dword[3] & ~XHCI_TRB_CYCLE) | Cycle;
171 Ring->m_Trbs[Ring->m_EnqueueIndex] = *Trb;
172 Ring->m_EnqueueIndex++;
173}
174
175/* Ring type entry points ****************************************************/
176
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}
228
229VOID
232{
234}
235
236VOID
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}
258
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}
284
285VOID
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}
302
303/* Request intake ************************************************************/
304
305VOID
307 _Out_ XhciControlTransfer* Transfer,
308 _In_ WDFREQUEST Request)
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}
335
336VOID
338 _In_ WDFQUEUE Queue,
339 _In_ WDFREQUEST Request)
340{
342 XhciControlRing* Self = XhciCtlOf(Ring);
343 XhciRequestData* Data = XhciGetRequestData(Request);
344 XhciControlTransfer* Transfer;
345 BOOLEAN Map = FALSE;
348
349 if (Data == NULL)
350 {
351 DPRINT1("Control request %p has no driver context\n", Request);
352 WdfRequestComplete(Request, STATUS_INVALID_DEVICE_STATE);
353 return;
354 }
355
356 Transfer = &Data->Control;
357 Self->InitTransfer(Transfer, Request);
358
360
361 ASSERT(Self->m_Current == NULL);
362 Self->m_Current = Transfer;
363
364 /* Cancelable before mapping, so a later reclaim can always finish it */
365 Transfer->CancelState = XhciControlCancel::Armed;
366 Status = WdfRequestMarkCancelableEx(Request, EvtRequestCancel);
367 if (!NT_SUCCESS(Status))
368 {
369 DPRINT1("Control request %p was canceled on arrival, status 0x%lx\n", Request, Status);
370 Transfer->CancelState = XhciControlCancel::Done;
371 Self->CompleteHeld();
372 }
373 else if (XhciCtlMapState(Ring) == XhciMapState::PausedFill)
374 {
375 XhciCtlSetMapState(Ring, XhciMapState::Filling);
376 Map = TRUE;
377 }
378
380
381 if (Map)
382 Self->BuildControlTd(Transfer);
383}
384
385/* Mapping *******************************************************************/
386
387VOID
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}
423
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}
528
529VOID
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}
605
606VOID
607NTAPI
610 _In_ PIRP Irp,
613{
614 XhciControlTransfer* Transfer = static_cast<XhciControlTransfer*>(Context);
615
618
619 Transfer->SgList = ScatterGather;
620 XhciCtlOf(Transfer->Ring)->WriteTd(Transfer);
621}
622
623VOID
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}
872
873/* Completion ****************************************************************/
874
875VOID
877{
878 WdfDpcEnqueue(m_Ring->m_CompletionDpc);
879}
880
881_Requires_lock_held_(m_Ring->m_Lock)
882VOID
883XhciControlRing::CopyIn(
886{
887 if (Transfer->Mechanism == XhciControlMechanism::DoubleBuffer && Transfer->DataIn && Bytes != 0)
888 RtlCopyMemory(Transfer->SystemBuffer, Transfer->DoubleBuffer->VirtualAddress, Bytes);
889}
890
892_Requires_lock_held_(m_Ring->m_Lock)
893VOID
894XhciControlRing::Finish(
896{
897 XhciTransferRing* Ring = m_Ring;
898 WDFREQUEST Request = Transfer->Request;
899 PURB Urb = Transfer->Urb;
902
903 if (Transfer->CompletionCode == static_cast<ULONG>(XhciCompletionCode::Invalid))
904 {
905 if (Transfer->CancelState == XhciControlCancel::Done ||
906 Transfer->TimeoutState == XhciControlTimeout::Expired)
907 {
908 Transfer->Status = STATUS_CANCELLED;
909 }
910 else if (Transfer->Status == STATUS_PENDING)
911 {
912 /* A request still marked pending completes as canceled */
913 Transfer->Status = STATUS_CANCELLED;
914 }
915
916 UsbdStatus = XhciCtlUsbdStatusFromNt(Transfer->Status);
917 }
918 else
919 {
922 }
923
924 Status = Transfer->Status;
925 Urb->UrbHeader.Status = UsbdStatus;
926 Urb->UrbControlTransfer.TransferBufferLength = Transfer->BytesTransferred;
927
928 DPRINT("Control request %p done, status 0x%lx, URB status 0x%lx, %lu of %lu bytes\n",
929 Request, Status, UsbdStatus, Transfer->BytesTransferred, Transfer->BytesTotal);
930
932
933 ReleaseResources(Transfer);
934 Transfer->Initialized = FALSE;
935 WdfRequestComplete(Request, Status);
936
938}
939
941_Requires_lock_held_(m_Ring->m_Lock)
943XhciControlRing::CompleteHeld()
944{
945 XhciControlTransfer* Transfer = m_Current;
947
948 if (Transfer->CancelState == XhciControlCancel::Armed)
949 {
950 Status = WdfRequestUnmarkCancelable(Transfer->Request);
951 if (!NT_SUCCESS(Status))
952 {
954 return STATUS_CANCELLED;
955 }
957 }
958
960 {
961 if (!WdfTimerStop(m_Timer, FALSE))
962 {
964 return STATUS_CANCELLED;
965 }
967 }
968
969 if (Transfer->TagArmed)
970 {
971 m_Tags[Transfer->TagIndex].Transfer = NULL;
972 Transfer->TagArmed = FALSE;
973 }
974
975 m_Current = NULL;
976 Finish(Transfer);
977 return STATUS_SUCCESS;
978}
979
980/* Cancel and timeout ********************************************************/
981
983VOID
986 _In_ BOOLEAN FromTimer)
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}
1033
1034VOID
1036 _In_ WDFREQUEST Request)
1037{
1038 XhciControlTransfer* Transfer = &XhciGetRequestData(Request)->Control;
1039
1040 DPRINT("Control request %p cancel\n", Request);
1041 XhciCtlOf(Transfer->Ring)->Abort(Transfer, FALSE);
1042}
1043
1044VOID
1046 _In_ WDFTIMER Timer)
1047{
1048 XhciTransferRing* Ring = XhciTransferRing::FromQueue(static_cast<WDFQUEUE>(WdfTimerGetParentObject(Timer)));
1049 XhciControlRing* Self = XhciCtlOf(Ring);
1050 XhciControlTransfer* Transfer;
1051 KIRQL OldIrql;
1052
1054 Transfer = Self->m_Current;
1056
1057 if (Transfer == NULL)
1058 return;
1059
1060 DPRINT("Control request %p timed out\n", Transfer->Request);
1061 Self->Abort(Transfer, TRUE);
1062}
1063
1064VOID
1066 _In_ WDFQUEUE Queue,
1067 _In_ WDFREQUEST Request)
1068{
1070 XhciControlRing* Self = XhciCtlOf(Ring);
1071 XhciControlTransfer* Transfer;
1072 KIRQL OldIrql;
1073
1074 if (XhciGetRequestData(Request) == NULL)
1075 {
1076 DPRINT1("Control request %p canceled on the queue has no driver context\n", Request);
1077 WdfRequestComplete(Request, STATUS_CANCELLED);
1078 return;
1079 }
1080
1081 Transfer = &XhciGetRequestData(Request)->Control;
1082 Self->InitTransfer(Transfer, Request);
1083 Transfer->CancelState = XhciControlCancel::Done;
1084
1086 InsertTailList(&Self->m_CanceledOnQueue, &Transfer->Link);
1088
1089 /* Requests canceled in the queue are completed from a DPC */
1090 WdfDpcEnqueue(Self->m_CanceledOnQueueDpc);
1091}
1092
1093VOID
1095 _In_ WDFDPC Dpc)
1096{
1097 XhciTransferRing* Ring = XhciTransferRing::FromQueue(static_cast<WDFQUEUE>(WdfDpcGetParentObject(Dpc)));
1098 XhciControlRing* Self = XhciCtlOf(Ring);
1099 XhciControlTransfer* Transfer;
1100 KIRQL OldIrql;
1101
1103
1104 if (!Self->m_CanceledDpcRunning)
1105 {
1106 Self->m_CanceledDpcRunning = TRUE;
1107
1108 while (!IsListEmpty(&Self->m_CanceledOnQueue))
1109 {
1111 XhciClearListEntry(&Transfer->Link);
1112 Self->Finish(Transfer);
1113 }
1114
1116 }
1117
1119}
1120
1121VOID
1123 _In_ WDFDPC Dpc)
1124{
1125 XhciTransferRing* Ring = XhciTransferRing::FromQueue(static_cast<WDFQUEUE>(WdfDpcGetParentObject(Dpc)));
1126 XhciControlRing* Self = XhciCtlOf(Ring);
1127 BOOLEAN Reclaimed = FALSE;
1128 KIRQL OldIrql;
1129
1131
1132 /* A failed completion is retried when the pending cancel or timer callback queues us again */
1133 if (Self->m_Current != NULL && NT_SUCCESS(Self->CompleteHeld()))
1134 Reclaimed = Self->m_ReclaimAndAcknowledge;
1135
1137
1138 if (Reclaimed)
1140}
1141
1142/* Endpoint machine directives ***********************************************/
1143
1144VOID
1146 _In_ XhciTransferRing* Ring)
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}
1192
1193VOID
1195 _In_ XhciTransferRing* Ring)
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}
1219
1220VOID
1222 _In_ XhciTransferRing* Ring)
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}
1238
1239VOID
1241 _In_ XhciTransferRing* Ring)
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}
1256
1257VOID
1259 _In_ XhciTransferRing* Ring)
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}
1276
1277BOOLEAN
1279 _In_ const XhciTransferRing* Ring)
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}
1293
1294BOOLEAN
1296 _In_ const XhciTransferRing* Ring)
1297{
1298 return Ring->m_Type.Control.m_Current != NULL;
1299}
1300
1301/* Transfer events ***********************************************************/
1302
1303XhciControlRing::EventTag*
1306 _In_ const XHCI_TRB* Event)
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}
1336
1337BOOLEAN
1341 _In_ const XHCI_TRB* Event)
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}
1373
1374BOOLEAN
1376 _In_ EventTag* Tag,
1377 _In_ const XHCI_TRB* Event)
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}
1482
1483BOOLEAN
1485 _In_ const XhciControlTransfer* Transfer,
1486 _In_ const XHCI_TRB* Event,
1488 _Out_ PULONG SkippedTds) const
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}
1570
1571BOOLEAN
1573 _In_ const XHCI_TRB* Event)
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}
#define PAGED_CODE()
WCHAR First[]
Definition: FormatMessage.c:11
Type
Definition: Type.h:7
unsigned char BOOLEAN
Definition: actypes.h:127
#define InterlockedExchange
Definition: armddk.h:54
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
PDMA_ADAPTER DmaAdapter() const
Definition: dmapool.cpp:738
static EventTag * TagFromEvent(_In_opt_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: ctrlxfer.cpp:1304
BOOLEAN m_CanceledDpcRunning
Definition: ctrlxfer.h:153
static VOID Enable(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:230
static VOID RecoverTransfers(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:1258
XhciTransferRing * m_Ring
Definition: ctrlxfer.h:141
static BOOLEAN HasQueuedWork(_In_ const XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:1295
BOOLEAN m_ReclaimOnCancelAllowed
Definition: ctrlxfer.h:152
static BOOLEAN OnTransferEvent(_In_opt_ XhciTransferRing *Ring, _In_ XhciController *Controller, _In_ const XHCI_TRB *Event)
Definition: ctrlxfer.cpp:1338
VOID QueueCompletion()
Definition: ctrlxfer.cpp:876
BOOLEAN OnEventDataEvent(_In_ EventTag *Tag, _In_ const XHCI_TRB *Event)
Definition: ctrlxfer.cpp:1375
EventTag m_Tags[TagCount]
Definition: ctrlxfer.h:140
static const ULONG TagCount
Definition: ctrlxfer.h:81
WDFDPC m_CanceledOnQueueDpc
Definition: ctrlxfer.h:144
static VOID Disable(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:237
static BOOLEAN DoorbellRungSinceFill(_In_ const XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:1278
static EVT_WDF_DPC EvtCanceledOnQueueDpc
Definition: ctrlxfer.h:84
VOID BuildControlTd(_Inout_ XhciControlTransfer *Transfer)
Definition: ctrlxfer.cpp:530
static EVT_WDF_REQUEST_CANCEL EvtRequestCancel
Definition: ctrlxfer.h:85
VOID Abort(_Inout_ XhciControlTransfer *Transfer, _In_ BOOLEAN FromTimer)
Definition: ctrlxfer.cpp:984
VOID ReleaseResources(_Inout_ XhciControlTransfer *Transfer)
Definition: ctrlxfer.cpp:388
static EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue
Definition: ctrlxfer.h:36
static EVT_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault
Definition: ctrlxfer.h:35
static NTSTATUS Initialize(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:178
VOID WriteTd(_Inout_ XhciControlTransfer *Transfer)
Definition: ctrlxfer.cpp:624
static EVT_WDF_TIMER EvtTimeout
Definition: ctrlxfer.h:83
static VOID SuspendRingFill(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:1194
VOID InitTransfer(_Out_ XhciControlTransfer *Transfer, _In_ WDFREQUEST Request)
Definition: ctrlxfer.cpp:306
BOOLEAN LocateTrb(_In_ const XhciControlTransfer *Transfer, _In_ const XHCI_TRB *Event, _Out_ PULONG Bytes, _Out_ PULONG SkippedTds) const
Definition: ctrlxfer.cpp:1484
BOOLEAN m_ReclaimAndAcknowledge
Definition: ctrlxfer.h:150
LONG m_Outstanding
Definition: ctrlxfer.h:147
WDFTIMER m_Timer
Definition: ctrlxfer.h:145
XhciControlTransfer * m_Current
Definition: ctrlxfer.h:142
ULONG m_NextTag
Definition: ctrlxfer.h:146
static DRIVER_LIST_CONTROL EvtDmaReady
Definition: ctrlxfer.h:86
static VOID ResumeRingFill(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:1145
volatile LONG m_ReservedMdlBusy
Definition: ctrlxfer.h:148
LIST_ENTRY m_CanceledOnQueue
Definition: ctrlxfer.h:143
BOOLEAN m_ImmediateAllowed
Definition: ctrlxfer.h:149
BOOLEAN m_AcknowledgeExpectedEvents
Definition: ctrlxfer.h:151
static VOID Cleanup(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:286
static EVT_WDF_DPC EvtCompletionDpc
Definition: ctrlxfer.h:37
static NTSTATUS EnableForwardProgress(_In_ XhciTransferRing *Ring, _In_ ULONG MaxTransferSize)
Definition: ctrlxfer.cpp:260
_In_ ULONG Bytes
Definition: ctrlxfer.h:120
BOOLEAN OnTrbEvent(_In_ const XHCI_TRB *Event)
Definition: ctrlxfer.cpp:1572
static VOID AllowReclaimOnCancel(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:1221
static VOID ConsumePendingEvents(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:1240
NTSTATUS PrepareTransfer(_Inout_ XhciControlTransfer *Transfer)
Definition: ctrlxfer.cpp:425
XhciCommonBuffer m_Buffers
Definition: hc.h:92
PDEVICE_OBJECT m_WdmDevice
Definition: hc.h:86
ULONG Dci() const
Definition: epctx.cpp:257
VOID OnStoppedEvent()
Definition: epctx.cpp:1217
VOID OnTransferCanceled()
Definition: epctx.cpp:1183
VOID OnMappingStopped()
Definition: epctx.cpp:1237
VOID OnHaltedCompletionCode(_In_ ULONG CompletionCode, _In_ BOOLEAN TransferFound)
Definition: epctx.cpp:1190
VOID OnExpectedEventsProcessed()
Definition: epctx.cpp:1231
BOOLEAN ShouldDropStoppedEvent() const
Definition: epctx.cpp:1211
VOID OnTransfersReclaimed()
Definition: epctx.cpp:1243
XhciDmaBuffer * BorrowBounceBuffer()
Definition: xferring.cpp:1014
static XhciTransferRing * FromQueue(_In_ WDFQUEUE Queue)
Definition: xferring.cpp:308
ULONG m_InterrupterTarget
Definition: xferring.h:179
static ULONG UrbProcessorIndex(_In_ PURB Urb)
Definition: xferring.cpp:1168
WDFDPC m_CompletionDpc
Definition: xferring.h:176
KSPIN_LOCK m_Lock
Definition: xferring.h:177
static NTSTATUS NtStatusFromUsbdStatus(_In_ USBD_STATUS UsbdStatus)
Definition: xferring.cpp:1237
XhciController * m_Controller
Definition: xferring.h:170
ULONG64 EnqueuePointer() const
Definition: xferring.cpp:664
VOID ReturnBounceBuffer(_In_ XhciDmaBuffer *Buffer)
Definition: xferring.cpp:1039
ULONG m_LastIndex
Definition: xferring.h:191
ULONG m_EnqueueIndex
Definition: xferring.h:190
ULONG TdSize(_In_ ULONG PacketCount, _In_ ULONG BytesMappedSoFar, _In_ BOOLEAN LastTrbOfTd) const
Definition: xferring.cpp:1126
ULONG64 SegmentBase() const
Definition: xferring.cpp:658
PMDL m_ReservedMdl
Definition: xferring.h:181
BOOLEAN m_DoorbellRung
Definition: xferring.h:180
XhciUsbDevice * m_Device
Definition: xferring.h:171
ULONG PacketCount(_In_ ULONG Bytes) const
Definition: xferring.cpp:1113
PXHCI_TRB m_Trbs
Definition: xferring.h:189
static USBD_STATUS UsbdStatusFromCompletionCode(_In_ ULONG CompletionCode)
Definition: xferring.cpp:1184
XhciEndpoint * m_Endpoint
Definition: xferring.h:172
ULONG m_MaxStageSize
Definition: xferring.h:185
VOID UpdateInterrupterTarget()
Definition: xferring.cpp:1147
ULONG SlotId() const
Definition: slotdev.cpp:335
#define _Requires_lock_held_(lock)
XhciCtlStep
Definition: ctrlxfer.cpp:33
static const ULONG XhciCtlMaxTrbLength
Definition: ctrlxfer.cpp:24
static const ULONG XhciCtlImmediateBytes
Definition: ctrlxfer.cpp:26
static const ULONG XhciCtlWorstCaseTd
Definition: ctrlxfer.cpp:30
static const ULONG_PTR XhciCtlValueFlagBits
Definition: ctrlxfer.cpp:15
static const ULONG XhciCtlReasonDuplicateEvent
Definition: ctrlxfer.cpp:21
static XhciControlRing *NTAPI XhciCtlOf(_In_ XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:46
static const ULONG XhciCtlTagSignature
Definition: ctrlxfer.cpp:17
static BOOLEAN NTAPI XhciCtlIsHaltCode(_In_ ULONG Code)
Definition: ctrlxfer.cpp:84
static const ULONG XhciCtlShortDataStageTrb
Definition: ctrlxfer.cpp:25
static XhciMapState NTAPI XhciCtlMapState(_In_ const XhciTransferRing *Ring)
Definition: ctrlxfer.cpp:55
static VOID NTAPI XhciCtlPut(_Inout_ XhciTransferRing *Ring, _Inout_ PXHCI_TRB Trb, _In_ BOOLEAN FirstOfTd)
Definition: ctrlxfer.cpp:160
static const ULONG XhciCtlReasonBadTrbPointer
Definition: ctrlxfer.cpp:20
static VOID NTAPI XhciCtlSetMapState(_Inout_ XhciTransferRing *Ring, _In_ XhciMapState State)
Definition: ctrlxfer.cpp:64
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 const ULONG_PTR XhciCtlStatusStageFlag
Definition: ctrlxfer.cpp:14
static const ULONG XhciCtlMaxTransfer
Definition: ctrlxfer.cpp:23
static USBD_STATUS NTAPI XhciCtlUsbdStatusFromNt(_In_ NTSTATUS Status)
Definition: ctrlxfer.cpp:118
static ULONG NTAPI XhciCtlTrbType(_In_ enum XhciTrbType Type)
Definition: ctrlxfer.cpp:74
static BOOLEAN NTAPI XhciCtlIsStopCode(_In_ ULONG Code)
Definition: ctrlxfer.cpp:106
#define STATUS_NOT_SUPPORTED
Definition: d3dkmdt.h:48
#define Code
Definition: deflate.h:80
PUCHAR Limit
Definition: desccheck.cpp:2230
Walk Base
Definition: desccheck.cpp:2270
_In_ ULONG Attributes
Definition: dispmprt.h:1077
_In_ HANDLE _In_ CONST PDXGKMDT_OPM_GET_INFO_PARAMETERS Parameters
Definition: dispmprt.h:321
_Check_return_ _In_ DXGK_EVENT_TYPE _In_ ULONG Event
Definition: dispmprt.h:1287
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define L(x)
Definition: resources.c:13
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
@ Stopped
Definition: fbtusb.h:81
@ Pending
Definition: fs_rec.h:186
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
Status
Definition: gdiplustypes.h:24
#define USB3_URB_RESERVED_RESOURCES
Definition: hubreq.cpp:15
#define InterlockedCompareExchange
Definition: interlocked.h:119
_In_ PIRP Irp
Definition: kse.h:79
_In_ PIRP _In_ PIO_COMPLETION_ROUTINE _In_ PVOID Context
Definition: kse.h:81
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:423
ULONG const BOOLEAN const _Out_ PBOOLEAN Writable
Definition: mmc.h:77
_In_ UINT Bytes
Definition: mmcopy.h:9
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 ULONG64
Definition: imports.h:198
@ NormalPagePriority
Definition: imports.h:54
#define min(a, b)
Definition: monoChain.cc:55
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1629
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
long LONG
Definition: pedump.c:60
static WCHAR Address[46]
Definition: ping.c:68
_In_ ULONG MaxTransferSize
Definition: pipe.h:72
XhciControlMechanism
Definition: reqctx.h:13
FORCEINLINE VOID KeMemoryBarrier(VOID)
Definition: ke.h:58
#define KeAcquireSpinLockAtDpcLevel(SpinLock)
Definition: ke.h:125
#define KeReleaseSpinLockFromDpcLevel(SpinLock)
Definition: ke.h:135
#define STATUS_SUCCESS
Definition: shellext.h:65
PACPI_METHOD_ARGUMENT Next
Definition: slotdev.cpp:96
#define DPRINT
Definition: sndvol32.h:73
BOOLEAN TagArmed
Definition: reqctx.h:60
WDFREQUEST Request
Definition: reqctx.h:40
XhciControlCancel CancelState
Definition: reqctx.h:50
XhciControlTimeout TimeoutState
Definition: reqctx.h:51
ULONG EventsReceived
Definition: reqctx.h:55
LIST_ENTRY Link
Definition: reqctx.h:39
XhciTransferRing * Ring
Definition: reqctx.h:42
ULONG CompletionCode
Definition: reqctx.h:53
ULONG BytesTransferred
Definition: reqctx.h:49
ULONG BytesTotal
Definition: reqctx.h:48
PSCATTER_GATHER_LIST SgList
Definition: reqctx.h:47
struct _DMA_OPERATIONS * DmaOperations
Definition: iotypes.h:2310
Definition: usb.h:565
ULONG Dword[4]
Definition: xhcihw.h:17
#define max(a, b)
Definition: svc.c:63
#define STATUS_PENDING
Definition: telnetd.h:14
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char UCHAR
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE _In_ PUCX_CONTROLLER_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ UCXCONTROLLER * Controller
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST Request
_Must_inspect_result_ _In_ UCXENDPOINT _In_ PVOID Tag
Definition: ucxendpoint.h:325
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
#define USB_ENDPOINT_TYPE_CONTROL
Definition: usb100.h:62
#define USBD_STATUS_CANCELED
Definition: usb.h:225
#define USBD_TRANSFER_DIRECTION_IN
Definition: usb.h:167
#define USBD_STATUS_NOT_SUPPORTED
Definition: usb.h:213
#define USBD_STATUS_INSUFFICIENT_RESOURCES
Definition: usb.h:215
#define USBD_STATUS_INVALID_PARAMETER
Definition: usb.h:203
LONG USBD_STATUS
Definition: usb.h:172
_In_opt_ PUSB_CONFIGURATION_DESCRIPTOR _Inout_ PUSBD_INTERFACE_LIST_ENTRY _Outptr_ PURB * Urb
Definition: usbdlib.h:333
_In_ WDFCOLLECTION _In_ ULONG Index
FORCEINLINE LONGLONG WDF_REL_TIMEOUT_IN_MS(_In_ ULONGLONG Time)
Definition: wdfcore.h:80
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
_Must_inspect_result_ _In_ WDFDEVICE _In_ PIRP _In_ WDFQUEUE Queue
Definition: wdfdevice.h:2231
_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
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
FORCEINLINE VOID WDF_DPC_CONFIG_INIT(_Out_ PWDF_DPC_CONFIG Config, _In_ PFN_WDF_DPC EvtDpcFunc)
Definition: wdfdpc.h:83
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
FORCEINLINE VOID WDF_OBJECT_ATTRIBUTES_INIT(_Out_ PWDF_OBJECT_ATTRIBUTES Attributes)
Definition: wdfobject.h:147
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
FORCEINLINE VOID WDF_REQUEST_PARAMETERS_INIT(_Out_ PWDF_REQUEST_PARAMETERS Parameters)
Definition: wdfrequest.h:211
_In_ WDFREQUEST _In_ PFN_WDF_REQUEST_CANCEL EvtRequestCancel
Definition: wdfrequest.h:730
FORCEINLINE VOID WDF_TIMER_CONFIG_INIT(_Out_ PWDF_TIMER_CONFIG Config, _In_ PFN_WDF_TIMER EvtTimerFunc)
Definition: wdftimer.h:111
_In_ NTSTATUS _In_ USBD_STATUS UsbdStatus
Definition: wdfusb.h:403
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
struct _SCATTER_GATHER_LIST * PSCATTER_GATHER_LIST
Definition: iotypes.h:2219
_In_ struct _IRP _In_ struct _SCATTER_GATHER_LIST * ScatterGather
Definition: iotypes.h:2390
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
#define MmGetMdlVirtualAddress(_Mdl)
#define MmInitializeMdl(_MemoryDescriptorList, _BaseVa, _Length)
#define MmGetSystemAddressForMdlSafe(_Mdl, _Priority)
XhciMapState
Definition: xferring.h:19
#define XHCI_TRB_LENGTH_MASK
Definition: xhcihw.h:621
#define XHCI_TRB_TRT_SHIFT
Definition: xhcihw.h:629
#define XHCI_TRB_ENDPOINT_MASK
Definition: xhcihw.h:27
#define XHCI_TRB_TYPE_SHIFT
Definition: xhcihw.h:23
FORCEINLINE ULONG64 NTAPI XhciTrbPointer(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:60
#define XHCI_TRANSFER_EVENT_ED
Definition: xhcihw.h:321
#define XHCI_LINK_TOGGLE_CYCLE
Definition: xhcihw.h:184
#define XHCI_TRB_ENT
Definition: xhcihw.h:623
#define XHCI_TRB_TD_SIZE_SHIFT
Definition: xhcihw.h:622
#define XHCI_TRB_ENDPOINT_SHIFT
Definition: xhcihw.h:26
#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_TRANSFER_EVENT_LENGTH_MASK
Definition: xhcihw.h:635
#define XHCI_TRB_IOC
Definition: xhcihw.h:624
XhciTrbType
Definition: xhcihw.h:68
#define XHCI_TRB_CYCLE
Definition: xhcihw.h:22
#define XHCI_TRB_CHAIN
Definition: xhcihw.h:609
XhciCompletionCode
Definition: xhcihw.h:110
FORCEINLINE ULONG NTAPI XhciTrbCompletionCode(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:42
#define XHCI_TRB_TRT_NO_DATA
Definition: xhcihw.h:630
FORCEINLINE ULONG NTAPI XhciTrbSlotId(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:51
FORCEINLINE VOID NTAPI XhciClearListEntry(_Out_ PLIST_ENTRY Entry)
Definition: xhciutil.h:117