ReactOS 0.4.17-dev-1281-g065abb3
bulkio.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: Bulk and interrupt transfer rings: staging, TD building, events and reclaim
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
13static const ULONG XhciBulkStageTag = 'gtSB';
14static const ULONG XhciBulkTransferTag = 'rTkB';
15
18static const ULONG XhciBulkTrbBytesMax = 0x10000;
20static const ULONG XhciBulkMinStageSize = 0x10000;
21static const ULONG XhciBulkNoOpCount = 8;
22static const USBD_STATUS XhciBulkStatusNotSet = (USBD_STATUS)0xFFFFFFFF;
23
24/* Reason codes handed to the controller with a fatal error */
25static const ULONG XhciBulkReasonEd0Invalid = 0x101F;
26static const ULONG XhciBulkReasonEd0Duplicate = 0x1020;
27
28/* m_Flags bits, all cleared when mapping starts */
29static const ULONG XhciBulkAckExpected = 0x01;
30static const ULONG XhciBulkHalted = 0x02;
31static const ULONG XhciBulkStoppedSeen = 0x04;
32static const ULONG XhciBulkCanceled = 0x08;
33static const ULONG XhciBulkOkToReclaim = 0x10;
34static const ULONG XhciBulkReclaimAck = 0x20;
35
36/* m_SegmentWait values */
37static const LONG XhciBulkWaitIdle = 0;
38static const LONG XhciBulkWaitParked = 1;
39static const LONG XhciBulkWaitArrived = 2;
40static const LONG XhciBulkWaitAbandoned = 3;
41
42enum class XhciBulkStep : ULONG
43{
44 Normal,
45 Pad,
47 Done
48};
49
50C_ASSERT((sizeof(XhciBulkStage) % 8) == 0);
51
52/* XhciBulkEventData keeps the endpoint type in the low bits of a stage address */
53C_ASSERT(alignof(XhciBulkStage) > XHCI_EVENT_DATA_TYPE_MASK);
54
55/* Small helpers that only use public state *********************************/
56
57static
62{
63 switch (static_cast<XhciCompletionCode>(Code))
64 {
73 return TRUE;
74 default:
75 return FALSE;
76 }
77}
78
79static
84{
85 return Code == static_cast<ULONG>(XhciCompletionCode::Stopped) ||
88}
89
90static
94 _In_ const XhciTransferRing* Ring)
95{
96 return (Ring->m_Endpoint->Descriptor()->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) != 0;
97}
98
99static
101NTAPI
103 _In_ const XhciBulkTransfer* Transfer)
104{
105 return (Transfer->Urb->TransferFlags & USBD_TRANSFER_DIRECTION_IN) != 0;
106}
107
108static
110NTAPI
112 _In_ const XhciBulkTransfer* Transfer)
113{
114 return Transfer->Urb->TransferBufferMDL != NULL &&
115 Transfer->Urb->TransferBufferMDL->Next != NULL;
116}
117
119static
120ULONG
121NTAPI
124{
125 return (Bytes + 2 * (PAGE_SIZE - 1)) / PAGE_SIZE;
126}
127
128static
130NTAPI
134 _In_ ULONG OnePastEnd,
136{
137 ULONG64 Base = (ULONG64)Segment->LogicalAddress.QuadPart;
138 ULONG Slots = Segment->Size / sizeof(XHCI_TRB);
140
141 Limit = (OnePastEnd >= Slots) ? Segment->Size : (ULONG64)OnePastEnd * sizeof(XHCI_TRB);
142 return Address >= Base + (ULONG64)Start * sizeof(XHCI_TRB) && Address < Base + Limit;
143}
144
145static
147NTAPI
149 _In_ const XhciTransferRing* Ring)
150{
151 return Ring->m_Controller->HasErrata(XhciErrata::XferPadSsBulkInTail) &&
152 Ring->m_Device->Speed() == UsbSuperSpeed &&
153 Ring->m_TransferType == USB_ENDPOINT_TYPE_BULK &&
154 XhciBulkEndpointIn(Ring);
155}
156
158static
159ULONG
160NTAPI
162 _In_ const XhciTransferRing* Ring,
164{
165 const XHCI_SLOT_CONTEXT* Slot;
166 USB_DEVICE_SPEED Speed = Ring->m_Device->Speed();
167 ULONG MaxPacket = Ring->m_Endpoint->MaxPacketSize();
168
169 if (!Ring->m_Controller->HasErrata(XhciErrata::XferPacketAlignChunks) ||
170 !XhciBulkEndpointIn(Ring) ||
171 (Speed != UsbLowSpeed && Speed != UsbFullSpeed) ||
172 MaxPacket == 0 ||
173 (Size % MaxPacket) == 0)
174 {
175 return 0;
176 }
177
178 Slot = static_cast<const XHCI_SLOT_CONTEXT*>(Ring->m_Device->OutputContext(0));
179 if (Slot == NULL || Slot->TTHubSlotId == 0)
180 return 0;
181
182 return MaxPacket - (Size % MaxPacket);
183}
184
185static
186VOID
187NTAPI
189 _In_ const XhciBulkTransfer* Transfer,
190 _In_ const XhciBulkStage* Stage,
192{
193 if (Bytes != 0 &&
194 Transfer->Mechanism == XhciBulkMechanism::DoubleBuffer &&
195 XhciBulkTransferIn(Transfer))
196 {
197 RtlCopyMemory(Stage->Buffer, Stage->DoubleBuffer->VirtualAddress, Bytes);
198 }
199}
200
201static
202VOID
203NTAPI
207{
208 while (!IsListEmpty(Source))
210}
211
216static
218NTAPI
222 _In_ const XHCI_TRB* Event,
224{
225 const XHCI_TRB* Trbs = static_cast<const XHCI_TRB*>(Segment->VirtualAddress);
226 ULONG Slots = Segment->Size / sizeof(XHCI_TRB);
227 ULONG64 Pointer = XhciTrbPointer(Event);
228 ULONG Residual = Event->Dword[2] & XHCI_TRANSFER_EVENT_LENGTH_MASK;
230 ULONG64 Address = (ULONG64)Segment->LogicalAddress.QuadPart + (ULONG64)Start * sizeof(XHCI_TRB);
231 ULONG Index;
232
233 for (Index = Start; Index < Slots; Index++, Address += sizeof(XHCI_TRB))
234 {
235 BOOLEAN Match = (Address == Pointer);
237
238 switch (XhciTrbType(&Trbs[Index]))
239 {
240 case static_cast<ULONG>(XhciTrbType::Normal):
241 if (!Match)
242 {
243 *Bytes += Length;
244 break;
245 }
246
247 switch (static_cast<XhciCompletionCode>(Code))
248 {
255 if (Residual <= Length)
256 *Bytes += Length - Residual;
257 break;
259 *Bytes = Residual;
260 break;
261 default:
262 break;
263 }
264 break;
265
266 case static_cast<ULONG>(XhciTrbType::EventData):
267 if (!Match)
268 *Bytes = 0;
269 break;
270
271 case static_cast<ULONG>(XhciTrbType::Link):
272 return Match;
273
274 default:
275 break;
276 }
277
278 if (Match)
279 return TRUE;
280 }
281
282 return FALSE;
283}
284
285static
286ULONG
287NTAPI
289 _In_ const XhciBulkStage* Stage,
290 _In_ const XHCI_TRB* Event)
291{
292 const LIST_ENTRY* Entry;
293 ULONG Bytes = 0;
294 ULONG Start = Stage->FirstIndex;
295
296 for (Entry = Stage->UsedSegments.Flink; Entry != &Stage->UsedSegments; Entry = Entry->Flink)
297 {
299 return Bytes;
300 Start = 0;
301 }
302
303 if (!XhciBulkScanSegment(Stage->LastSegment, Start, Event, &Bytes))
304 DPRINT1("Event TRB 0x%I64x not found while sizing its stage\n", XhciTrbPointer(Event));
305
306 return Bytes;
307}
308
309static
311NTAPI
313 _In_ const XhciBulkStage* Stage,
315{
316 const LIST_ENTRY* Entry;
317 ULONG Start = Stage->FirstIndex;
318
319 for (Entry = Stage->UsedSegments.Flink; Entry != &Stage->UsedSegments; Entry = Entry->Flink)
320 {
322 return TRUE;
323 Start = 0;
324 }
325
326 return XhciBulkSegmentHas(Stage->LastSegment, Start, Stage->EndIndex, Address);
327}
328
330static
332NTAPI
334 _In_ const XhciTransferRing* Ring,
335 _In_ const XhciBulkStage* Stage)
336{
337 ULONG64 Value = (ULONG_PTR)Stage | (Ring->m_TransferType & XHCI_EVENT_DATA_TYPE_MASK);
338
339#ifndef _WIN64
340 Value |= (ULONG64)Stage->Generation << 32;
341#endif
342 return Value;
343}
344
345static
346XhciBulkStage*
347NTAPI
350{
351 return reinterpret_cast<XhciBulkStage*>((ULONG_PTR)Value & ~(ULONG_PTR)XHCI_EVENT_DATA_TYPE_MASK);
352}
353
354/* Ring type entry points ****************************************************/
355
359{
360 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
361 XhciController* Controller = Ring->m_Controller;
362 ULONG Index;
363
364 RtlZeroMemory(Bulk, sizeof(*Bulk));
365 InitializeListHead(&Bulk->m_Pending);
366 InitializeListHead(&Bulk->m_WaitingForCancel);
367 InitializeListHead(&Bulk->m_Completion);
368
369 for (Index = 0; Index < StageSlots; Index++)
370 {
371 XhciBulkStage* Stage = &Bulk->m_Stages[Index];
372
373 Stage->Signature = XhciBulkStageTag;
374 Stage->Ring = Ring;
375 InitializeListHead(&Stage->FreeSegments);
376 InitializeListHead(&Stage->UsedSegments);
377 }
378
379 Bulk->m_ImmediateData = !Controller->HasErrata(XhciErrata::XferNoInlineData) &&
380 Ring->m_Endpoint->MaxPacketSize() >= XhciBulkImmediateBytes &&
381 !XhciBulkEndpointIn(Ring);
382
383 if (Controller->HasErrata(XhciErrata::XferOneAsyncTdAtATime) ||
384 Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment))
385 {
386 Bulk->m_MaxPendingStages = 1;
387 }
388 else
389 {
390 Bulk->m_MaxPendingStages = XhciBulkPendingStagesMax;
391 }
392
393 /* A TD has to fit one segment, less the Link, Event Data and pad slots */
394 if (Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment))
395 Ring->m_MaxStageSize = (Ring->m_SegmentSize / sizeof(XHCI_TRB) - 4) * PAGE_SIZE;
396
397 return STATUS_SUCCESS;
398}
399
400VOID
403{
404 ULONG Burst;
405
406 NT_ASSERT(Ring->m_MaxStageSize >= XhciBulkMinStageSize);
407
408 if (Ring->m_Device->Speed() != UsbSuperSpeed)
409 return;
410
411 Burst = Ring->m_Endpoint->MaxPacketSize() * (Ring->m_Endpoint->MaxBurst() + 1);
412 if (Burst == 0 || (Ring->m_MaxStageSize % Burst) == 0)
413 return;
414
415 Ring->m_MaxStageSize -= Ring->m_MaxStageSize % Burst;
416 Ring->m_MapRegisterCount = (Ring->m_MaxStageSize + PAGE_SIZE - 1) / PAGE_SIZE;
417 DPRINT("Bulk DCI %lu stream %lu stage size cut to %lu\n",
418 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Ring->m_MaxStageSize);
419}
420
421VOID
424{
426
428
429 InterlockedCompareExchange(&Ring->m_MapState,
430 static_cast<LONG>(XhciMapState::Halted),
431 static_cast<LONG>(XhciMapState::PausedFill));
432
433 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
434 if (OwnsRequests(Ring))
435 {
436 DPRINT1("Bulk DCI %lu stream %lu disabled while it still owns requests\n",
437 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
438 }
439 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
440}
441
442VOID
445{
446 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
447
448 /* A loop parked on a segment wait only resumes from a PASSIVE work item; let it go */
451 {
452 DPRINT1("Bulk DCI %lu stream %lu disabled while waiting for segments\n",
453 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
454
455 if (Ring->ChangeMapState(FALSE, XhciMapState::Halting, XhciMapState::Halted) !=
456 XhciMapState::Halting)
457 {
458 InterlockedCompareExchange(&Ring->m_MapState,
459 static_cast<LONG>(XhciMapState::PausedFill),
460 static_cast<LONG>(XhciMapState::Filling));
461 }
462 }
463}
464
469{
471 ULONG PerBurst = XhciBulkWorstPages(Ring->m_Endpoint->MaxEsitPayload()) + 1;
472 ULONG PerSegment = Ring->m_SegmentSize / sizeof(XHCI_TRB) - 1;
473 ULONG Usable = PerSegment - (PerSegment % PerBurst);
474 ULONG Segments;
476
477 if (Usable == 0)
478 {
479 DPRINT1("Bulk DCI %lu: a burst of %lu TRBs does not fit a segment\n",
480 Ring->m_Endpoint->Dci(), PerBurst);
482 }
483
484 Segments = (Needed + Usable - 1) / Usable;
485 if (Segments == 0)
486 Segments = 1;
487
488 Status = Ring->EnsureFreeSegments(Segments, FALSE);
489 if (!NT_SUCCESS(Status))
490 {
491 DPRINT1("Bulk DCI %lu: %lu forward progress segments not available, 0x%08lx\n",
492 Ring->m_Endpoint->Dci(), Segments, Status);
493 return Status;
494 }
495
496 Ring->m_DoubleBufferSize = 0;
497 Ring->m_Type.Bulk.m_ImmediateData = FALSE;
498 return STATUS_SUCCESS;
499}
500
501VOID
504{
505 BOOLEAN Owned;
507
508 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
509 Owned = OwnsRequests(Ring);
510 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
511
512 if (Owned)
513 {
514 DPRINT1("Bulk DCI %lu stream %lu cleaned up with requests still owned\n",
515 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
517 }
518}
519
520VOID
521NTAPI
523 _In_ WDFQUEUE Queue,
525{
527
529
530 if (Ring->ChangeMapState(FALSE, XhciMapState::PausedFill, XhciMapState::Filling) == XhciMapState::PausedFill)
531 {
532 BuildTdsFromQueue(Ring);
533 return;
534 }
535
536 /* A loop that is about to pause sees this and goes round once more */
537 KickFill(Ring);
538}
539
540VOID
541NTAPI
543 _In_ WDFQUEUE Queue,
544 _In_ WDFREQUEST Request)
545{
547 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
548 XhciBulkTransfer* Transfer = &XhciGetRequestData(Request)->Bulk;
550
551 if (Transfer->Initialized != XhciBulkTransferTag)
552 InitTransfer(Ring, Transfer, Request);
553
555 Transfer->CancelState = XhciBulkCancel::Done;
556 InsertTailList(&Bulk->m_Completion, &Transfer->Link);
558
559 QueueCompletionDpc(Ring);
560}
561
562VOID
563NTAPI
565 _In_ WDFDPC Dpc)
566{
567 XhciTransferRing* Ring = XhciTransferRing::FromQueue(static_cast<WDFQUEUE>(WdfDpcGetParentObject(Dpc)));
568 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
570 BOOLEAN Acknowledge = FALSE;
572
574 if (Bulk->m_DpcRunning)
575 {
577 return;
578 }
579 Bulk->m_DpcRunning = TRUE;
580
581 while (!IsListEmpty(&Bulk->m_Completion))
582 {
584 XhciBulkMoveList(&Batch, &Bulk->m_Completion);
586
587 CompleteBatch(Ring, &Batch);
588
590 }
591
592 if ((Bulk->m_Flags & XhciBulkReclaimAck) && !OwnsRequests(Ring))
593 {
594 Bulk->m_Flags &= ~XhciBulkReclaimAck;
595 Acknowledge = TRUE;
596 }
597
598 Bulk->m_DpcRunning = FALSE;
600
601 if (Acknowledge)
603}
604
605VOID
608{
609 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
612
613 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
614 Bulk->m_Flags = 0;
615 Bulk->m_OutstandingEvents = 0;
616 Ring->m_DoorbellRung = FALSE;
617 NT_ASSERT(Bulk->m_PendingStages == 0);
618 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
619
620 Previous = Ring->ChangeMapState(TRUE, XhciMapState::Halted, XhciMapState::Filling);
621 if (Previous == XhciMapState::Halted)
622 {
623 BuildTdsFromQueue(Ring);
624 return;
625 }
626
627 DPRINT1("Bulk DCI %lu stream %lu started mapping from map state %ld\n",
628 Ring->m_Endpoint->Dci(), Ring->m_StreamId, static_cast<LONG>(Previous));
629}
630
631VOID
634{
636
637 Previous = Ring->ChangeMapState(TRUE, XhciMapState::Halted, XhciMapState::Halting);
638
639 /* QUIRK: a loop parked on a segment wait acknowledges only when the segments arrive */
640 if (Previous == XhciMapState::PausedFill)
641 Ring->ChangeMapState(FALSE, XhciMapState::Halting, XhciMapState::Halted);
642}
643
644/* Runs the stream stop or halt handling once per Flag (XhciBulkHalted or XhciBulkStoppedSeen) */
645VOID
649{
650 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
652
653 if (Ring->m_StreamId == 0)
654 return;
655
656 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
657 if (!(Bulk->m_Flags & Flag))
658 {
659 StreamStopOrHalt(Ring);
660 Bulk->m_Flags |= Flag;
661 }
662 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
663}
664
665VOID
668{
670}
671
672VOID
675{
677}
678
679VOID
682{
683 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
686
687 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
688 if (Bulk->m_Flags & XhciBulkCanceled)
689 {
690 /* QUIRK: the "OK to reclaim" flag stays clear when a cancel already happened */
691 XhciBulkMoveList(&Bulk->m_Completion, &Bulk->m_Pending);
692 Queue = TRUE;
693 }
694 else
695 {
696 Bulk->m_Flags |= XhciBulkOkToReclaim;
697 }
698 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
699
700 if (Queue)
701 QueueCompletionDpc(Ring);
702}
703
704VOID
707{
708 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
709 BOOLEAN Acknowledge = FALSE;
711
712 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
713 if (Bulk->m_OutstandingEvents == 0)
714 Acknowledge = TRUE;
715 else
716 Bulk->m_Flags |= XhciBulkAckExpected;
717 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
718
719 if (Acknowledge)
720 Ring->m_Endpoint->OnExpectedEventsProcessed();
721}
722
723VOID
726{
727 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
729
730 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
731 XhciBulkMoveList(&Bulk->m_Completion, &Bulk->m_Pending);
732 Bulk->m_Flags |= XhciBulkReclaimAck;
733 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
734
735 /* Only the DPC can tell that nothing is owned anymore */
736 QueueCompletionDpc(Ring);
737}
738
741 _In_ const XhciTransferRing* Ring)
742{
743 return Ring->m_DoorbellRung;
744}
745
748 _In_ const XhciTransferRing* Ring)
749{
750 PKSPIN_LOCK Lock = const_cast<PKSPIN_LOCK>(&Ring->m_Lock);
753
755 Pending = !IsListEmpty(&Ring->m_Type.Bulk.m_Pending);
757
758 return Pending;
759}
760
763 _In_ const XhciTransferRing* Ring,
764 _In_ const XHCI_TRB* Event)
765{
766 PKSPIN_LOCK Lock = const_cast<PKSPIN_LOCK>(&Ring->m_Lock);
768 BOOLEAN Likely;
770
772 Likely = LikelyDuplicate(Ring, XhciTrbPointer(Event), &NoOp);
774
775 return Likely;
776}
777
782 _In_ const XHCI_TRB* Event)
783{
785
786 if (Ring == NULL)
787 {
788 DPRINT1("Bulk transfer event 0x%I64x without a ring, dropped\n", XhciTrbPointer(Event));
789 return FALSE;
790 }
791
792 if (Event->Dword[3] & XHCI_TRANSFER_EVENT_ED)
793 return Ed1Event(Ring, Event);
794
795 return Ed0Event(Ring, Event);
796}
797
798VOID
802{
803 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
804
805 if (!NT_SUCCESS(Status))
806 {
807 DPRINT1("Bulk DCI %lu stream %lu segment growth failed, 0x%08lx\n",
808 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Status);
809 }
810
811 for (;;)
812 {
813 /* The loop already left: resume it here, whatever the map state */
816 {
817 Bulk->m_SegmentWaits++;
818 BuildTdsFromQueue(Ring);
819 return;
820 }
821
822 /* The ring was disabled while waiting */
825 {
826 return;
827 }
828
829 /* The loop has not left yet; it sees this and retries the stage itself */
832 {
833 Bulk->m_SegmentWaits++;
834 return;
835 }
836 }
837}
838
839/* Mapping loop **************************************************************/
840
841VOID
844{
845 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
847
849
850 for (;;)
851 {
852 FillLoop(Ring);
853
854 if (Ring->m_MapState != static_cast<LONG>(XhciMapState::PausedFill) ||
855 Bulk->m_FillWanted == 0)
856 {
857 break;
858 }
859
860 if (Ring->ChangeMapState(FALSE, XhciMapState::PausedFill, XhciMapState::Filling) != XhciMapState::PausedFill)
861 break;
862 }
863
865}
866
867VOID
870{
871 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
872 XhciBulkStage* Stage;
874 BOOLEAN Pause = FALSE;
875
876 for (;;)
877 {
878 InterlockedExchange(&Bulk->m_FillWanted, 0);
879
880 Stage = NextTdSlot(Ring);
881 if (Stage == NULL)
882 {
883 Pause = TRUE;
884 break;
885 }
886
887 Result = PrimeStage(Ring, Stage);
889 continue;
891 break;
892 if (Result == Outcome::Failed)
893 {
894 Pause = TRUE;
895 break;
896 }
897
898 Result = EncodeStage(Ring, Stage);
900 continue;
902 break;
903 if (Result == Outcome::Failed)
904 {
905 Pause = TRUE;
906 break;
907 }
908
909 /* Also completes a stop that raced in */
910 if (Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::Filling) != XhciMapState::Filling)
911 break;
912 }
913
914 if (Pause)
915 Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::PausedFill);
916}
917
918VOID
921{
922 InterlockedExchange(&Ring->m_Type.Bulk.m_FillWanted, 1);
923
924 if (Ring->ChangeMapState(FALSE, XhciMapState::PausedFill, XhciMapState::Filling) == XhciMapState::PausedFill)
925 BuildTdsFromQueue(Ring);
926}
927
928XhciBulkStage*
931{
932 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
933 XhciBulkTransfer* Transfer;
934 XhciBulkStage* Stage;
935 WDFREQUEST Request;
939
940 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
941
942 if (Bulk->m_PendingStages >= Bulk->m_MaxPendingStages)
943 {
944 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
945 return NULL;
946 }
947
948 if (!IsListEmpty(&Bulk->m_Pending))
949 {
950 Transfer = CONTAINING_RECORD(Bulk->m_Pending.Blink, XhciBulkTransfer, Link);
951
952 /* A zero length request has not mapped yet even though its byte count is met */
953 if (Transfer->BytesQueued < Transfer->BytesTotal || !Transfer->MappedOnce)
954 {
955 if (Bulk->m_SegmentWaits != XhciBulkSegmentWaitLimit)
956 {
957 Stage = AcquireStage(Ring, Transfer);
958 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
959 return Stage;
960 }
961
962 if (Transfer->TdsQueued != Transfer->TdsRetired)
963 {
964 /* QUIRK: completes later with the partial length and the hardware status */
965 Transfer->BytesQueued = Transfer->BytesTotal;
966 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
967 return NULL;
968 }
969
970 DPRINT1("Bulk DCI %lu stream %lu gave up waiting for segments\n",
971 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
973
974 /* Reset the count so the next split request waits again */
975 Bulk->m_SegmentWaits = 0;
976 }
977 }
978
979 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
980
981 for (;;)
982 {
983 Status = WdfIoQueueRetrieveNextRequest(Ring->m_Queue, &Request);
984 if (!NT_SUCCESS(Status))
985 return NULL;
986
987 if (XhciGetRequestData(Request) == NULL)
988 {
989 DPRINT1("Bulk request %p has no driver context\n", Request);
990 WdfRequestComplete(Request, STATUS_INVALID_DEVICE_STATE);
991 continue;
992 }
993
994 Transfer = &XhciGetRequestData(Request)->Bulk;
995 InitTransfer(Ring, Transfer, Request);
996 Transfer->MappedOnce = FALSE;
997 ChooseMechanism(Ring, Transfer);
998
999 Status = ArrangeBuffer(Ring, Transfer);
1000 if (!NT_SUCCESS(Status))
1001 {
1002 DPRINT1("Bulk DCI %lu stream %lu request %p has no usable buffer, 0x%08lx\n",
1003 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Request, Status);
1005 continue;
1006 }
1007
1008 Transfer->CancelState = XhciBulkCancel::Armed;
1009 Status = WdfRequestMarkCancelableEx(Request, EvtRequestCancel);
1010 if (!NT_SUCCESS(Status))
1011 {
1012 DPRINT1("Bulk DCI %lu stream %lu request %p canceled before mapping, 0x%08lx\n",
1013 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Request, Status);
1014 Transfer->CancelState = XhciBulkCancel::Done;
1015 Complete(Ring, Transfer, USBD_STATUS_CANCELED);
1016 continue;
1017 }
1018
1019 break;
1020 }
1021
1022 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1023 Idle = (Bulk->m_PendingStages == 0);
1024 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1025
1026 /* Every stage on the ring shares one event ring so its events stay in order */
1027 if (Idle)
1028 Ring->UpdateInterrupterTarget(XhciTransferRing::UrbProcessorIndex((PURB)Transfer->Urb));
1029
1030 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1031 Stage = AcquireStage(Ring, Transfer);
1032 InsertTailList(&Bulk->m_Pending, &Transfer->Link);
1033 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1034
1035 return Stage;
1036}
1037
1039XhciBulkStage*
1040XhciBulkRing::AcquireStage(
1041 _In_ XhciTransferRing* Ring,
1042 _Inout_ XhciBulkTransfer* Transfer)
1043{
1044 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1045 XhciBulkStage* Stage;
1046 ULONG Index;
1047
1048 if (Transfer->Stage != NULL)
1049 return NULL;
1050
1051 for (Index = 0; Index < StageSlots; Index++)
1052 {
1053 Stage = &Bulk->m_Stages[Index];
1054 if (Stage->InUse)
1055 continue;
1056
1057 Stage->InUse = TRUE;
1058 Stage->OnHardware = FALSE;
1059 Stage->FreeMdl = FALSE;
1060 Stage->Generation++;
1061 Stage->Transfer = Transfer;
1062 InitializeListHead(&Stage->FreeSegments);
1063 InitializeListHead(&Stage->UsedSegments);
1064 Stage->Size = 0;
1065 Stage->Mdl = NULL;
1066 Stage->SgList = NULL;
1067 Stage->Buffer = NULL;
1068 Stage->DoubleBuffer = NULL;
1069 Stage->BurstTrbBudget = 0;
1070 Stage->TrbsReserved = 0;
1071 Stage->TrbsWritten = 0;
1072 Stage->FirstSegment = Ring->m_Segment;
1073 Stage->FirstIndex = Ring->m_EnqueueIndex;
1074 Stage->LastSegment = Ring->m_Segment;
1075 Stage->EndIndex = Ring->m_EnqueueIndex;
1076
1077 Transfer->Stage = Stage;
1078 return Stage;
1079 }
1080
1081 DPRINT1("Bulk DCI %lu stream %lu ran out of stage records\n",
1082 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1083 return NULL;
1084}
1085
1087VOID
1088XhciBulkRing::ReleaseStage(
1089 _In_ XhciTransferRing* Ring,
1090 _Inout_ XhciBulkStage* Stage)
1091{
1092 NT_ASSERT(Stage->SgList == NULL);
1093
1094 if (Stage->FreeMdl)
1095 {
1096 IoFreeMdl(Stage->Mdl);
1097 Stage->FreeMdl = FALSE;
1098 }
1099 Stage->Mdl = NULL;
1100
1101 Ring->ReturnSegments(&Stage->FreeSegments, TRUE);
1102 Ring->ReturnSegments(&Stage->UsedSegments, FALSE);
1103 InitializeListHead(&Stage->FreeSegments);
1104 InitializeListHead(&Stage->UsedSegments);
1105
1106 if (Stage->Transfer != NULL)
1107 Stage->Transfer->Stage = NULL;
1108
1109 Stage->Transfer = NULL;
1110 Stage->OnHardware = FALSE;
1111 Stage->InUse = FALSE;
1112}
1113
1115VOID
1116XhciBulkRing::PutScatterGather(
1117 _In_ XhciTransferRing* Ring,
1118 _Inout_ XhciBulkStage* Stage)
1119{
1120 PDMA_ADAPTER Adapter;
1121 KIRQL OldIrql;
1122
1123 if (Stage->SgList == NULL)
1124 return;
1125
1126 /* Never under the ring lock: the HAL may run another DMA callback of this ring */
1127 Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
1129 Adapter->DmaOperations->PutScatterGatherList(Adapter,
1130 Stage->SgList,
1131 !XhciBulkTransferIn(Stage->Transfer));
1133 Stage->SgList = NULL;
1134}
1135
1136/* Request records ***********************************************************/
1137
1138VOID
1140 _In_ XhciTransferRing* Ring,
1141 _Inout_ XhciBulkTransfer* Transfer,
1142 _In_ WDFREQUEST Request)
1143{
1146
1147 /* A requeued request is already set up; keep its progress instead of starting over */
1148 if (Transfer->Initialized == XhciBulkTransferTag)
1149 {
1150 NT_ASSERT(Transfer->CancelState == XhciBulkCancel::Idle);
1151 NT_ASSERT(Transfer->Status == STATUS_PENDING);
1152 NT_ASSERT(!XhciIsListEntryLinked(&Transfer->Link));
1153 NT_ASSERT(Transfer->TdsQueued == Transfer->TdsRetired);
1154 return;
1155 }
1156
1158 WdfRequestGetParameters(Request, &Parameters);
1159 Urb = static_cast<struct _URB_BULK_OR_INTERRUPT_TRANSFER*>(Parameters.Parameters.Others.Arg1);
1160
1161 RtlZeroMemory(Transfer, sizeof(*Transfer));
1162 XhciClearListEntry(&Transfer->Link);
1163 Transfer->Initialized = XhciBulkTransferTag;
1164 Transfer->Request = Request;
1165 Transfer->Urb = Urb;
1166 Transfer->Ring = Ring;
1167 Transfer->CancelState = XhciBulkCancel::Idle;
1168 Transfer->Status = STATUS_PENDING;
1169 Transfer->Mechanism = XhciBulkMechanism::NoData;
1170 Transfer->BytesTotal = Urb->TransferBufferLength;
1171
1172 /* QUIRK: the length reads 0 until completion, as the USB 2.0 stack does */
1173 Urb->TransferBufferLength = 0;
1174}
1175
1176VOID
1178 _In_ XhciTransferRing* Ring,
1179 _Inout_ XhciBulkTransfer* Transfer)
1180{
1181 if (Transfer->BytesTotal == 0)
1182 {
1183 Transfer->Mechanism = XhciBulkMechanism::NoData;
1184 return;
1185 }
1186
1187 if (Ring->m_Type.Bulk.m_ImmediateData && Transfer->BytesTotal <= XhciBulkImmediateBytes)
1188 {
1189 Transfer->Mechanism = XhciBulkMechanism::Immediate;
1190 return;
1191 }
1192
1193 if (!XhciBulkChainedMdl(Transfer) && Transfer->BytesTotal <= Ring->m_DoubleBufferSize)
1194 {
1195 Transfer->DoubleBuffer = Ring->BorrowBounceBuffer();
1196 if (Transfer->DoubleBuffer != NULL)
1197 {
1198 Transfer->Mechanism = XhciBulkMechanism::DoubleBuffer;
1199 return;
1200 }
1201 }
1202
1203 Transfer->Mechanism = XhciBulkMechanism::Dma;
1204}
1205
1208 _In_ XhciTransferRing* Ring,
1209 _Inout_ XhciBulkTransfer* Transfer)
1210{
1211 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1212 struct _URB_BULK_OR_INTERRUPT_TRANSFER* Urb = Transfer->Urb;
1213
1214 switch (Transfer->Mechanism)
1215 {
1216 case XhciBulkMechanism::Immediate:
1217 case XhciBulkMechanism::DoubleBuffer:
1218 if (Urb->TransferBuffer != NULL)
1219 {
1220 Transfer->Buffer = static_cast<PUCHAR>(Urb->TransferBuffer);
1221 }
1222 else if (Urb->TransferBufferMDL != NULL)
1223 {
1224 Transfer->Buffer = static_cast<PUCHAR>(
1226 }
1227
1228 if (Transfer->Buffer == NULL)
1229 {
1230 DPRINT1("Bulk DCI %lu stream %lu: no system address for the buffer\n",
1231 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1233 }
1234 return STATUS_SUCCESS;
1235
1236 case XhciBulkMechanism::Dma:
1237 if (Urb->TransferBufferMDL != NULL)
1238 {
1239 Transfer->Mdl = Urb->TransferBufferMDL;
1240 return STATUS_SUCCESS;
1241 }
1242
1243 Transfer->Mdl = IoAllocateMdl(Urb->TransferBuffer, Transfer->BytesTotal, FALSE, FALSE, NULL);
1244 if (Transfer->Mdl == NULL)
1245 {
1246 if (!(Urb->TransferFlags & USB3_URB_RESERVED_RESOURCES) ||
1247 Ring->m_ReservedMdl == NULL)
1248 {
1249 DPRINT1("Bulk DCI %lu stream %lu: MDL allocation failed\n",
1250 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1252 }
1253
1254 /* The reserved MDL serves one request at a time */
1255 if (InterlockedCompareExchange(&Bulk->m_ForwardProgressBusy, 1, 0) != 0)
1256 {
1257 DPRINT1("Bulk DCI %lu stream %lu: forward progress MDL already in use\n",
1258 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1260 }
1261
1262 Transfer->Mdl = Ring->m_ReservedMdl;
1263 Transfer->UsesReservedMdl = TRUE;
1264 MmInitializeMdl(Transfer->Mdl, Urb->TransferBuffer, Transfer->BytesTotal);
1265 }
1266
1267 MmBuildMdlForNonPagedPool(Transfer->Mdl);
1268 return STATUS_SUCCESS;
1269
1270 default:
1271 return STATUS_SUCCESS;
1272 }
1273}
1274
1275VOID
1277 _In_ XhciTransferRing* Ring,
1278 _Inout_ XhciBulkTransfer* Transfer)
1279{
1280 if (Transfer->Mdl == NULL)
1281 return;
1282
1283 if (Transfer->UsesReservedMdl)
1284 {
1285 Transfer->UsesReservedMdl = FALSE;
1286 InterlockedExchange(&Ring->m_Type.Bulk.m_ForwardProgressBusy, 0);
1287 }
1288 else if (Transfer->Mdl != Transfer->Urb->TransferBufferMDL)
1289 {
1290 IoFreeMdl(Transfer->Mdl);
1291 }
1292
1293 Transfer->Mdl = NULL;
1294}
1295
1296VOID
1298 _In_ XhciTransferRing* Ring,
1299 _Inout_ XhciBulkTransfer* Transfer)
1300{
1301 NT_ASSERT(Transfer->Stage == NULL);
1302
1303 if (Transfer->DoubleBuffer != NULL)
1304 {
1305 Ring->ReturnBounceBuffer(Transfer->DoubleBuffer);
1306 Transfer->DoubleBuffer = NULL;
1307 }
1308
1309 DropMdl(Ring, Transfer);
1310 Transfer->Buffer = NULL;
1311 Transfer->Initialized = 0;
1312}
1313
1314/* Stage preparation *********************************************************/
1315
1318 _In_ XhciTransferRing* Ring,
1319 _Inout_ XhciBulkStage* Stage)
1320{
1321 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1322 XhciBulkTransfer* Transfer = Stage->Transfer;
1323 ULONG Segments;
1325 KIRQL OldIrql;
1326
1327 switch (Transfer->Mechanism)
1328 {
1329 case XhciBulkMechanism::Immediate:
1330 Stage->Buffer = Transfer->Buffer + Transfer->BytesQueued;
1331 break;
1332
1333 case XhciBulkMechanism::DoubleBuffer:
1334 Stage->Buffer = Transfer->Buffer + Transfer->BytesQueued;
1335 Stage->DoubleBuffer = Transfer->DoubleBuffer;
1336 break;
1337
1338 case XhciBulkMechanism::Dma:
1339 if (!NT_SUCCESS(AcquireStageMdl(Ring, Stage)))
1340 return FailStage(Ring, Stage);
1341 break;
1342
1343 default:
1344 break;
1345 }
1346
1347 SizeStage(Ring, Stage);
1348 EstimateTrbs(Ring, Stage);
1349
1350 if (!EstimateSegments(Ring, Stage, &Segments))
1351 return FailStage(Ring, Stage);
1352
1353 if (Segments == 0)
1354 return Outcome::Ready;
1355
1356 Status = Ring->TakeSegments(Segments, &Stage->FreeSegments);
1357 if (Status == STATUS_PENDING)
1358 {
1359 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1360 ReleaseStage(Ring, Stage);
1361 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1362
1363 if (ParkOnSegments(Ring))
1364 return Outcome::WaitSegments;
1365
1366 /* The segments already arrived; map the request again from the top */
1367 return Outcome::Completed;
1368 }
1369
1370 if (!NT_SUCCESS(Status))
1371 {
1372 DPRINT1("Bulk DCI %lu stream %lu: %lu segments not available, 0x%08lx\n",
1373 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Segments, Status);
1374 return FailStage(Ring, Stage);
1375 }
1376
1377 Bulk->m_SegmentWaits = 0;
1378 return Outcome::Ready;
1379}
1380
1381BOOLEAN
1383 _In_ XhciTransferRing* Ring)
1384{
1385 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1386 LONG Previous;
1387
1390 return TRUE;
1391
1392 InterlockedExchange(&Bulk->m_SegmentWait, XhciBulkWaitIdle);
1393 return FALSE;
1394}
1395
1398 _In_ XhciTransferRing* Ring,
1399 _Inout_ XhciBulkStage* Stage)
1400{
1401 XhciBulkTransfer* Transfer = Stage->Transfer;
1402 PMDL Mdl = Transfer->Mdl;
1403 ULONG Offset = Transfer->BytesQueued;
1404 PUCHAR Start;
1405 ULONG Length;
1406 PMDL Partial;
1407
1408 while (Mdl != NULL && Offset >= MmGetMdlByteCount(Mdl))
1409 {
1411 Mdl = Mdl->Next;
1412 }
1413
1414 if (Mdl == NULL)
1415 {
1416 DPRINT1("Bulk DCI %lu stream %lu: MDL chain shorter than the transfer\n",
1417 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1419 }
1420
1421 if (Offset == 0)
1422 {
1423 Stage->Mdl = Mdl;
1424 return STATUS_SUCCESS;
1425 }
1426
1427 Start = static_cast<PUCHAR>(MmGetMdlVirtualAddress(Mdl)) + Offset;
1429
1430 Partial = IoAllocateMdl(Start, Length, FALSE, FALSE, NULL);
1431 if (Partial == NULL)
1432 {
1433 DPRINT1("Bulk DCI %lu stream %lu: partial MDL allocation failed\n",
1434 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1436 }
1437
1438 IoBuildPartialMdl(Mdl, Partial, Start, Length);
1439 Partial->Next = Mdl->Next;
1440 Stage->Mdl = Partial;
1441 Stage->FreeMdl = TRUE;
1442 return STATUS_SUCCESS;
1443}
1444
1445VOID
1447 _In_ XhciTransferRing* Ring,
1448 _Inout_ XhciBulkStage* Stage)
1449{
1450 XhciBulkTransfer* Transfer = Stage->Transfer;
1451 ULONG Remaining = Transfer->BytesTotal - Transfer->BytesQueued;
1452 ULONG Limit = Ring->m_MaxStageSize;
1453 ULONG Registers = 0;
1454 PDMA_ADAPTER Adapter;
1456 PMDL Mdl;
1457 ULONG Left;
1458
1459 if (Transfer->Mechanism != XhciBulkMechanism::Dma)
1460 {
1461 Stage->Size = Remaining;
1462 return;
1463 }
1464
1465 Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
1466 if (Adapter->Version >= DEVICE_DESCRIPTION_VERSION3 &&
1467 Adapter->DmaOperations->Size > FIELD_OFFSET(DMA_OPERATIONS, GetDmaTransferInfo) &&
1468 Adapter->DmaOperations->GetDmaTransferInfo != NULL)
1469 {
1470 RtlZeroMemory(&Info, sizeof(Info));
1472 if (NT_SUCCESS(Adapter->DmaOperations->GetDmaTransferInfo(Adapter,
1473 Stage->Mdl,
1474 0,
1475 Remaining,
1476 !XhciBulkTransferIn(Transfer),
1477 &Info)))
1478 {
1479 Registers = Info.V1.MapRegisterCount;
1480 }
1481 }
1482
1483 if (Registers == 0)
1484 {
1485 /* Without the HAL query count the pages the chain spans */
1486 for (Mdl = Stage->Mdl, Left = Remaining; Mdl != NULL && Left != 0; Mdl = Mdl->Next)
1487 {
1488 ULONG Chunk = min(Left, MmGetMdlByteCount(Mdl));
1489
1491 Left -= Chunk;
1492 }
1493 }
1494
1495 if (Registers > Ring->m_MapRegisterCount && Ring->m_MapRegisterCount > 1)
1496 Limit = min(Limit, (Ring->m_MapRegisterCount - 1) * PAGE_SIZE);
1497
1498 Stage->Size = min(Remaining, Limit);
1499}
1500
1501VOID
1503 _In_ XhciTransferRing* Ring,
1504 _Inout_ XhciBulkStage* Stage)
1505{
1506 XhciBulkTransfer* Transfer = Stage->Transfer;
1507 ULONG Burst;
1508 ULONG Carry = 0;
1509 ULONG CarryTrbs = 0;
1510 ULONG Left;
1511 PMDL Mdl;
1512
1513 if (Transfer->Mechanism != XhciBulkMechanism::Dma)
1514 {
1515 /* One Normal and one Event Data TRB */
1516 Stage->TrbsReserved = 2;
1517 Stage->BurstTrbBudget = 2;
1518 }
1519 else
1520 {
1521 Burst = min(Ring->m_Endpoint->MaxEsitPayload(), Stage->Size);
1522 if (Burst == 0)
1523 Burst = 1;
1524
1525 Stage->BurstTrbBudget = XhciBulkWorstPages(Burst) + 1;
1526 Stage->TrbsReserved = 0;
1527
1528 if (!XhciBulkChainedMdl(Transfer))
1529 {
1530 Stage->TrbsReserved = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Stage->Mdl),
1531 Stage->Size);
1532 }
1533 else
1534 {
1535 /* QUIRK: per burst sized fragment estimate; a carried fragment is counted twice */
1536 for (Mdl = Stage->Mdl, Left = Stage->Size; Mdl != NULL && Left != 0; Mdl = Mdl->Next)
1537 {
1538 ULONG Chunk = min(Left, MmGetMdlByteCount(Mdl));
1539 ULONG Offset = 0;
1540
1541 Left -= Chunk;
1542 while (Offset < Chunk)
1543 {
1544 PUCHAR Va = static_cast<PUCHAR>(MmGetMdlVirtualAddress(Mdl)) + Offset;
1545 ULONG Piece = Chunk - Offset;
1546 ULONG Span;
1547
1548 if (Piece + Carry >= Burst)
1549 {
1550 Span = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Va, Burst - Carry) + CarryTrbs;
1551 Offset += Burst - Carry;
1552 Carry = 0;
1553 CarryTrbs = 0;
1554 }
1555 else
1556 {
1557 Span = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Va, Piece);
1558 Carry = Piece;
1559 CarryTrbs = Span;
1560 Offset = Chunk;
1561 }
1562
1563 Stage->TrbsReserved += Span;
1564
1565 if (Span >= Ring->m_LastIndex)
1566 {
1567 DPRINT1("Bulk DCI %lu stream %lu: a %lu TRB fragment needs a whole segment\n",
1568 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Span);
1569 }
1570
1571 if (Span > Stage->BurstTrbBudget)
1572 Stage->BurstTrbBudget = Span;
1573 }
1574 }
1575 }
1576
1577 Stage->TrbsReserved += 1;
1578 }
1579
1580 if (XhciBulkPadSize(Ring, Stage->Size) != 0)
1581 {
1582 Stage->BurstTrbBudget += 1;
1583 Stage->TrbsReserved += 1;
1584 }
1585}
1586
1587BOOLEAN
1589 _In_ XhciTransferRing* Ring,
1590 _In_ const XhciBulkStage* Stage,
1591 _Out_ PULONG Segments)
1592{
1593 ULONG Available;
1594 ULONG Usable;
1595
1596 *Segments = 0;
1597
1598 if (Ring->m_Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment))
1599 {
1600 /* The TD always starts in a fresh segment */
1601 *Segments = 1;
1602 }
1603 else
1604 {
1605 Available = Ring->m_LastIndex - Ring->m_EnqueueIndex;
1606 Available -= Available % Stage->BurstTrbBudget;
1607
1608 if (Stage->TrbsReserved > Available)
1609 {
1610 Usable = Ring->m_LastIndex - (Ring->m_LastIndex % Stage->BurstTrbBudget);
1611
1612 /* One burst can need more TRBs than a segment holds */
1613 if (Usable == 0)
1614 {
1615 DPRINT1("Bulk DCI %lu stream %lu: a %lu TRB burst does not fit a segment\n",
1616 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Stage->BurstTrbBudget);
1617 return FALSE;
1618 }
1619
1620 *Segments = (Stage->TrbsReserved - Available + Usable - 1) / Usable;
1621 }
1622 }
1623
1624 if (XhciBulkNeedsNoOps(Ring))
1625 *Segments += 1;
1626
1627 return TRUE;
1628}
1629
1633 _In_ XhciTransferRing* Ring,
1634 _Inout_ XhciBulkStage* Stage)
1635{
1636 XhciBulkTransfer* Transfer = Stage->Transfer;
1638 KIRQL OldIrql;
1639
1640 PutScatterGather(Ring, Stage);
1641
1642 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1643 ReleaseStage(Ring, Stage);
1644
1645 if (Transfer->TdsQueued == Transfer->TdsRetired)
1646 {
1649 }
1650 else
1651 {
1652 Transfer->BytesQueued = Transfer->BytesTotal;
1654 }
1655
1656 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1657 return Result;
1658}
1659
1662 _In_ XhciTransferRing* Ring,
1663 _Inout_ XhciBulkStage* Stage)
1664{
1665 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1666 PDMA_ADAPTER Adapter;
1668 KIRQL OldIrql;
1669
1670 if (Stage->Transfer->Mechanism != XhciBulkMechanism::Dma)
1671 {
1672 if (!BuildTd(Ring, Stage))
1673 return FailStage(Ring, Stage);
1674 return Outcome::Ready;
1675 }
1676
1677 Adapter = Ring->m_Controller->m_Buffers.DmaAdapter();
1678
1680 Status = Adapter->DmaOperations->GetScatterGatherList(Adapter,
1681 WdfDeviceWdmGetDeviceObject(Ring->m_Controller->m_Device),
1682 Stage->Mdl,
1683 MmGetMdlVirtualAddress(Stage->Mdl),
1684 Stage->Size,
1686 Stage,
1687 !XhciBulkTransferIn(Stage->Transfer));
1689
1690 if (!NT_SUCCESS(Status))
1691 {
1692 DPRINT1("Bulk DCI %lu stream %lu: GetScatterGatherList failed, 0x%08lx\n",
1693 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Status);
1694 return FailStage(Ring, Stage);
1695 }
1696
1697 /* Whichever of this context and the callback gets here second keeps mapping */
1698 if (InterlockedXor(&Bulk->m_FillAgain, 1) == 1)
1699 return Outcome::Ready;
1700
1701 return Outcome::WaitDma;
1702}
1703
1704VOID
1705NTAPI
1708 _In_ PIRP Irp,
1711{
1712 XhciBulkStage* Stage = static_cast<XhciBulkStage*>(Context);
1713 XhciTransferRing* Ring = Stage->Ring;
1714
1717
1718 Stage->SgList = ScatterGather;
1719 if (!BuildTd(Ring, Stage))
1720 (VOID)FailStage(Ring, Stage);
1721
1722 if (InterlockedXor(&Ring->m_Type.Bulk.m_FillAgain, 1) == 1)
1723 {
1724 if (Ring->ChangeMapState(FALSE, XhciMapState::Filling, XhciMapState::Filling) == XhciMapState::Filling)
1725 BuildTdsFromQueue(Ring);
1726 }
1727}
1728
1729/* TD building ***************************************************************/
1730
1735BOOLEAN
1737 _In_ XhciTransferRing* Ring,
1738 _Inout_ XhciBulkStage* Stage)
1739{
1740 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
1741 XhciBulkTransfer* Transfer = Stage->Transfer;
1742 XhciDmaBuffer* PadBuffer = Ring->m_Controller->m_SplitPadBuffer;
1743 PSCATTER_GATHER_LIST SgList = Stage->SgList;
1744 ULONG PadBytes = XhciBulkPadSize(Ring, Stage->Size);
1745 BOOLEAN NoOps = XhciBulkNeedsNoOps(Ring);
1746 ULONG Packets = Ring->PacketCount(Stage->Size);
1747 ULONG Pending = Stage->BurstTrbBudget;
1748 ULONG Mapped = 0;
1749 ULONG Element = 0;
1750 ULONG64 ElementAddress = 0;
1751 ULONG ElementLeft = 0;
1752 XhciBulkStep Step = XhciBulkStep::Normal;
1753 PXHCI_TRB First = &Ring->m_Trbs[Ring->m_EnqueueIndex];
1754 volatile UCHAR* CycleByte;
1755 XHCI_TRB Trb;
1756 ULONG64 Value;
1757 ULONG Chunk;
1758 ULONG Index;
1759 BOOLEAN IsFirst;
1760 KIRQL OldIrql;
1761
1762 Stage->TrbsWritten = 0;
1763
1764 if (Ring->m_Controller->HasErrata(XhciErrata::RingKeepTdInOneSegment) && !InsertLink(Ring, Stage, TRUE))
1765 {
1766 UndoTd(Ring, Stage);
1767 return FALSE;
1768 }
1769
1770 while (Step != XhciBulkStep::Done)
1771 {
1772 IsFirst = (&Ring->m_Trbs[Ring->m_EnqueueIndex] == First);
1773
1774 /* Keep each burst sized piece of the TD inside one segment (xHCI 4.11.7.1) */
1775 if (Pending + Ring->m_EnqueueIndex > Ring->m_LastIndex ||
1776 (NoOps && Step == XhciBulkStep::EventData &&
1777 Ring->m_EnqueueIndex + XhciBulkNoOpCount + 1 > Ring->m_LastIndex))
1778 {
1779 /* A failed insert fails the TD instead of retrying */
1780 if (!InsertLink(Ring, Stage, IsFirst))
1781 {
1782 UndoTd(Ring, Stage);
1783 return FALSE;
1784 }
1785 continue;
1786 }
1787
1788 RtlZeroMemory(&Trb, sizeof(Trb));
1789
1790 if (Step == XhciBulkStep::Normal)
1791 {
1792 Trb.Dword[3] = static_cast<ULONG>(XhciTrbType::Normal) << XHCI_TRB_TYPE_SHIFT;
1793
1794 switch (Transfer->Mechanism)
1795 {
1796 case XhciBulkMechanism::Immediate:
1797 RtlCopyMemory(&Trb.Dword[0], Stage->Buffer, Stage->Size);
1798 Trb.Dword[3] |= XHCI_TRB_IDT;
1799 Chunk = Stage->Size;
1800 Step = XhciBulkStep::EventData;
1801 break;
1802
1803 case XhciBulkMechanism::DoubleBuffer:
1804 if (!XhciBulkTransferIn(Transfer))
1805 RtlCopyMemory(Stage->DoubleBuffer->VirtualAddress, Stage->Buffer, Stage->Size);
1806 Trb.Dword[0] = Stage->DoubleBuffer->LogicalAddress.LowPart;
1807 Trb.Dword[1] = (ULONG)Stage->DoubleBuffer->LogicalAddress.HighPart;
1808 Chunk = Stage->Size;
1809 Step = XhciBulkStep::EventData;
1810 break;
1811
1812 case XhciBulkMechanism::Dma:
1813 if (ElementLeft == 0)
1814 {
1815 ElementAddress = (ULONG64)SgList->Elements[Element].Address.QuadPart;
1816 ElementLeft = SgList->Elements[Element].Length;
1817 Element++;
1818 }
1819
1820 /* A TRB buffer may not cross a 64 KB boundary (xHCI 6.4.1.1) */
1821 Chunk = min(ElementLeft, XhciBulkTrbBytesMax - (ULONG)(ElementAddress & 0xFFFF));
1822 Trb.Dword[0] = (ULONG)ElementAddress;
1823 Trb.Dword[1] = (ULONG)(ElementAddress >> 32);
1824 ElementAddress += Chunk;
1825 ElementLeft -= Chunk;
1826
1827 if (ElementLeft == 0 && Element >= SgList->NumberOfElements)
1828 Step = XhciBulkStep::EventData;
1829 break;
1830
1831 default:
1832 Chunk = 0;
1833 Step = XhciBulkStep::EventData;
1834 break;
1835 }
1836
1837 Mapped += Chunk;
1838 Trb.Dword[2] = Chunk |
1839 (Ring->TdSize(Packets, Mapped, Step == XhciBulkStep::EventData) << XHCI_TRB_TD_SIZE_SHIFT);
1840 Trb.Dword[3] |= XHCI_TRB_CHAIN;
1841 Pending--;
1842 }
1843 else if (Step == XhciBulkStep::Pad)
1844 {
1845 Trb.Dword[0] = PadBuffer->LogicalAddress.LowPart;
1846 Trb.Dword[1] = (ULONG)PadBuffer->LogicalAddress.HighPart;
1847 Trb.Dword[2] = PadBytes;
1848 Trb.Dword[3] = (static_cast<ULONG>(XhciTrbType::Normal) << XHCI_TRB_TYPE_SHIFT) | XHCI_TRB_CHAIN;
1849 Pending--;
1850 PadBytes = 0;
1851 Step = XhciBulkStep::EventData;
1852 }
1853 else
1854 {
1855 Value = XhciBulkEventData(Ring, Stage);
1856 Trb.Dword[0] = (ULONG)Value;
1857 Trb.Dword[1] = (ULONG)(Value >> 32);
1858 Trb.Dword[3] = (static_cast<ULONG>(XhciTrbType::EventData) << XHCI_TRB_TYPE_SHIFT) | XHCI_TRB_IOC;
1859 Step = XhciBulkStep::Done;
1860 }
1861
1862 Stage->TrbsWritten++;
1863
1864 if (Step == XhciBulkStep::EventData)
1865 {
1866 if (PadBytes != 0 && PadBuffer != NULL)
1867 {
1868 Trb.Dword[2] += 1 << XHCI_TRB_TD_SIZE_SHIFT;
1869 Step = XhciBulkStep::Pad;
1870
1871 /* The pad still needs a slot when the burst is used up */
1872 if (Pending == 0)
1873 Pending = 1;
1874 }
1875 else
1876 {
1877 /* xHCI 4.12.3: let a flow controlled ring reach the Event Data TRB */
1878 Trb.Dword[3] |= XHCI_TRB_ENT;
1879 Pending = 1;
1880 }
1881 }
1882 else if (Step == XhciBulkStep::Normal && Pending == 0)
1883 {
1884 Pending = (Stage->TrbsReserved > Stage->TrbsWritten) ?
1885 min(Stage->BurstTrbBudget, Stage->TrbsReserved - Stage->TrbsWritten) :
1886 Stage->BurstTrbBudget;
1887 }
1888
1889 /* The first slot stays invalid until the whole TD is written */
1890 Trb.Dword[3] |= IsFirst ? (Ring->m_Cycle ^ XHCI_TRB_CYCLE) : Ring->m_Cycle;
1891 Trb.Dword[2] |= Ring->m_InterrupterTarget << XHCI_TRB_INTERRUPTER_SHIFT;
1892
1893 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1894 Ring->m_EnqueueIndex++;
1895
1896 if (Step == XhciBulkStep::Done && NoOps)
1897 {
1898 for (Index = 0; Index < XhciBulkNoOpCount; Index++)
1899 {
1900 RtlZeroMemory(&Trb, sizeof(Trb));
1901 Trb.Dword[3] = (static_cast<ULONG>(XhciTrbType::NoOp) << XHCI_TRB_TYPE_SHIFT) | Ring->m_Cycle;
1902 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1903 Ring->m_EnqueueIndex++;
1904 }
1905 }
1906 }
1907
1908 NT_ASSERT(Stage->TrbsWritten <= Stage->TrbsReserved);
1909
1910 /* Recycled segments are not cleared, so the slot after the TD must be */
1911 Stage->LastSegment = Ring->m_Segment;
1912 Stage->EndIndex = Ring->m_EnqueueIndex;
1913 RtlZeroMemory(&Ring->m_Trbs[Ring->m_EnqueueIndex], sizeof(XHCI_TRB));
1914
1915 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1916 Transfer->TdsQueued++;
1917 Transfer->BytesQueued += Stage->Size;
1918 Transfer->MappedOnce = TRUE;
1919 Bulk->m_PendingStages++;
1920 Stage->OnHardware = TRUE;
1921 Ring->m_DoorbellRung = TRUE;
1922 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1923
1924 /* A one byte register write publishes the TD after every store above */
1926 CycleByte = reinterpret_cast<volatile UCHAR*>(&First->Dword[3]);
1927 WRITE_REGISTER_UCHAR(const_cast<PUCHAR>(CycleByte), (UCHAR)(*CycleByte ^ XHCI_TRB_CYCLE));
1929
1930 Ring->RingDoorbell();
1931 return TRUE;
1932}
1933
1935BOOLEAN
1937 _In_ XhciTransferRing* Ring,
1938 _Inout_ XhciBulkStage* Stage,
1939 _In_ BOOLEAN FirstOfTd)
1940{
1942 XHCI_TRB Trb;
1943 KIRQL OldIrql;
1944
1945 if (IsListEmpty(&Stage->FreeSegments))
1946 {
1947 DPRINT1("Bulk DCI %lu stream %lu: no reserved segment left for a Link TRB\n",
1948 Ring->m_Endpoint->Dci(), Ring->m_StreamId);
1949 return FALSE;
1950 }
1951
1952 Next = CONTAINING_RECORD(RemoveHeadList(&Stage->FreeSegments), XhciDmaBuffer, Link);
1953 XhciClearListEntry(&Next->Link);
1954
1955 /* Chained even ahead of the pad TRB */
1956 Ring->BuildLinkTrb(&Trb, FirstOfTd, TRUE);
1957 Trb.Dword[0] = Next->LogicalAddress.LowPart;
1958 Trb.Dword[1] = (ULONG)Next->LogicalAddress.HighPart;
1959 Ring->m_Trbs[Ring->m_EnqueueIndex] = Trb;
1960
1961 /* The ring never toggles its cycle state: it is an endless forward chain of segments */
1962 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1963 InsertTailList(&Stage->UsedSegments, &Ring->m_Segment->Link);
1964 Ring->m_Segment = Next;
1965 Ring->m_Trbs = static_cast<PXHCI_TRB>(Next->VirtualAddress);
1966 Ring->m_EnqueueIndex = 0;
1967 Stage->LastSegment = Next;
1968 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1969
1970 return TRUE;
1971}
1972
1974VOID
1976 _In_ XhciTransferRing* Ring,
1977 _Inout_ XhciBulkStage* Stage)
1978{
1979 KIRQL OldIrql;
1980
1981 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
1982
1983 if (Ring->m_Segment != Stage->FirstSegment)
1984 {
1985 RemoveEntryList(&Stage->FirstSegment->Link);
1986 XhciClearListEntry(&Stage->FirstSegment->Link);
1987 InsertTailList(&Stage->FreeSegments, &Ring->m_Segment->Link);
1988 Ring->m_Segment = Stage->FirstSegment;
1989 Ring->m_Trbs = static_cast<PXHCI_TRB>(Stage->FirstSegment->VirtualAddress);
1990 }
1991
1992 /* The first slot never became valid, so the controller cannot be past it */
1993 Ring->m_EnqueueIndex = Stage->FirstIndex;
1994 RtlZeroMemory(&Ring->m_Trbs[Stage->FirstIndex], sizeof(XHCI_TRB));
1995 Stage->LastSegment = Stage->FirstSegment;
1996 Stage->EndIndex = Stage->FirstIndex;
1997
1998 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
1999}
2000
2001/* Completion ****************************************************************/
2002
2004VOID
2005XhciBulkRing::CompleteAfterUncancel(
2006 _In_ XhciTransferRing* Ring,
2007 _Inout_ XhciBulkTransfer* Transfer,
2009 _In_ BOOLEAN FinishCanceled)
2010{
2011 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2013
2014 switch (Transfer->CancelState)
2015 {
2017 break;
2018
2020 if (XhciIsListEntryLinked(&Transfer->Link))
2021 {
2022 RemoveEntryList(&Transfer->Link);
2023 XhciClearListEntry(&Transfer->Link);
2024 }
2025
2026 Status = WdfRequestUnmarkCancelable(Transfer->Request);
2027 if (!NT_SUCCESS(Status))
2028 {
2029 /* The cancel callback is about to run and finishes the job */
2030 Transfer->CancelState = XhciBulkCancel::CancelRoutinePending;
2031 InsertTailList(&Bulk->m_WaitingForCancel, &Transfer->Link);
2032 return;
2033 }
2034 Transfer->CancelState = XhciBulkCancel::Idle;
2035 break;
2036
2038 if (!FinishCanceled)
2039 return;
2042 break;
2043
2044 default:
2046 return;
2047 }
2048
2049 if (XhciIsListEntryLinked(&Transfer->Link))
2050 {
2051 RemoveEntryList(&Transfer->Link);
2052 XhciClearListEntry(&Transfer->Link);
2053 }
2054
2055 KeReleaseSpinLockFromDpcLevel(&Ring->m_Lock);
2056 Complete(Ring, Transfer, Default);
2057 KeAcquireSpinLockAtDpcLevel(&Ring->m_Lock);
2058}
2059
2060_Requires_lock_not_held_(Ring->m_Lock)
2061VOID
2063 _In_ XhciTransferRing* Ring,
2064 _Inout_ XhciBulkTransfer* Transfer,
2066{
2067 struct _URB_BULK_OR_INTERRUPT_TRANSFER* Urb = Transfer->Urb;
2068 WDFREQUEST Request = Transfer->Request;
2071
2072 NT_ASSERT(Transfer->CancelState == XhciBulkCancel::Idle ||
2073 Transfer->CancelState == XhciBulkCancel::Done);
2074
2076 if (Transfer->CompletionCode == 0 || UsbdStatus == XhciBulkStatusNotSet)
2078
2079 Urb->TransferBufferLength = Transfer->BytesTransferred;
2080 Urb->Hdr.Status = UsbdStatus;
2082 Transfer->Status = Status;
2083
2085 {
2086 DPRINT1("Bulk DCI %lu stream %lu request %p failed, 0x%08lx USBD 0x%08lx code %lu, %lu bytes\n",
2087 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Request, Status, UsbdStatus,
2088 Transfer->CompletionCode, Transfer->BytesTransferred);
2089 }
2090
2091 FreeTransferResources(Ring, Transfer);
2092 WdfRequestComplete(Request, Status);
2093}
2094
2095VOID
2097 _In_ XhciTransferRing* Ring,
2099{
2100 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2101 XhciBulkTransfer* Transfer;
2102 XhciBulkStage* Stage;
2103 LIST_ENTRY Canceled;
2104 LIST_ENTRY Finished;
2106 BOOLEAN OnHardware;
2108 KIRQL OldIrql;
2109
2110 InitializeListHead(&Canceled);
2111 InitializeListHead(&Finished);
2113
2114 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2115
2116 while (!IsListEmpty(Batch))
2117 {
2119 XhciClearListEntry(&Transfer->Link);
2120
2121 Stage = Transfer->Stage;
2122 if (Stage != NULL)
2123 {
2124 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2125 PutScatterGather(Ring, Stage);
2126 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2127
2128 OnHardware = Stage->OnHardware;
2129 ReleaseStage(Ring, Stage);
2130 if (OnHardware)
2131 {
2132 Transfer->TdsRetired++;
2133 Bulk->m_PendingStages--;
2134 }
2135 }
2136
2137 if (Transfer->CancelState == XhciBulkCancel::Done)
2138 {
2139 InsertTailList(&Canceled, &Transfer->Link);
2140 continue;
2141 }
2142
2143 if (Transfer->CancelState == XhciBulkCancel::Armed)
2144 {
2145 Status = WdfRequestUnmarkCancelable(Transfer->Request);
2146 if (!NT_SUCCESS(Status))
2147 {
2148 Transfer->CancelState = XhciBulkCancel::CancelRoutinePending;
2149 InsertTailList(&Bulk->m_WaitingForCancel, &Transfer->Link);
2150 continue;
2151 }
2152 Transfer->CancelState = XhciBulkCancel::Idle;
2153 }
2154
2155 if (Transfer->CompletionCode == static_cast<ULONG>(XhciCompletionCode::Success) ||
2156 Transfer->CompletionCode == static_cast<ULONG>(XhciCompletionCode::StoppedShortPacket))
2157 {
2158 InsertTailList(&Finished, &Transfer->Link);
2159 }
2160 else
2161 {
2162 InsertTailList(&Requeue, &Transfer->Link);
2163 }
2164 }
2165
2166 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2167
2168 while (!IsListEmpty(&Canceled))
2169 {
2170 Transfer = CONTAINING_RECORD(RemoveHeadList(&Canceled), XhciBulkTransfer, Link);
2171 XhciClearListEntry(&Transfer->Link);
2172
2173 if (Ring->m_StreamId != 0 && Transfer->CompletionCode == 0)
2174 Transfer->CompletionCode = Ring->m_Endpoint->StreamHaltedCode();
2175
2176 Complete(Ring, Transfer, USBD_STATUS_CANCELED);
2177 }
2178
2179 while (!IsListEmpty(&Finished))
2180 {
2181 Transfer = CONTAINING_RECORD(RemoveHeadList(&Finished), XhciBulkTransfer, Link);
2182 XhciClearListEntry(&Transfer->Link);
2183 Complete(Ring, Transfer, XhciBulkStatusNotSet);
2184 }
2185
2186 /* From the tail, so the oldest request ends up at the head of the queue */
2187 while (!IsListEmpty(&Requeue))
2188 {
2190 XhciClearListEntry(&Transfer->Link);
2191
2192 /* It resumes where the hardware stopped */
2193 Transfer->BytesQueued = Transfer->BytesTransferred;
2194
2195 if (Transfer->DoubleBuffer != NULL)
2196 {
2197 Ring->ReturnBounceBuffer(Transfer->DoubleBuffer);
2198 Transfer->DoubleBuffer = NULL;
2199 }
2200 DropMdl(Ring, Transfer);
2201
2202 Status = WdfRequestRequeue(Transfer->Request);
2203 if (!NT_SUCCESS(Status))
2204 {
2205 DPRINT1("Bulk DCI %lu stream %lu could not requeue request %p, 0x%08lx\n",
2206 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Transfer->Request, Status);
2207 Complete(Ring, Transfer, USBD_STATUS_CANCELED);
2208 }
2209 }
2210}
2211
2212VOID
2214 _In_ XhciTransferRing* Ring)
2215{
2216 WdfDpcEnqueue(Ring->m_CompletionDpc);
2217}
2218
2219_Requires_lock_held_(Ring->m_Lock)
2220BOOLEAN
2221XhciBulkRing::OwnsRequests(
2223{
2224 const XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2225
2226 return !IsListEmpty(&Bulk->m_Pending) ||
2227 !IsListEmpty(&Bulk->m_WaitingForCancel) ||
2228 !IsListEmpty(&Bulk->m_Completion);
2229}
2230
2231VOID
2232NTAPI
2234 _In_ WDFREQUEST Request)
2235{
2236 XhciBulkTransfer* Transfer = &XhciGetRequestData(Request)->Bulk;
2237 XhciTransferRing* Ring = Transfer->Ring;
2238 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2241 KIRQL OldIrql;
2242
2244 if (Transfer->CancelState == XhciBulkCancel::Armed)
2245 {
2246 if (Bulk->m_Flags & XhciBulkOkToReclaim)
2247 {
2248 /* QUIRK: everything pending goes; requests that were not canceled get requeued */
2249 XhciBulkMoveList(&Bulk->m_Completion, &Bulk->m_Pending);
2250 Queue = TRUE;
2251 }
2252 else
2253 {
2254 Bulk->m_Flags |= XhciBulkCanceled;
2255 Report = TRUE;
2256 }
2257 }
2259
2260 if (Report)
2262
2264 if (Transfer->CancelState == XhciBulkCancel::CancelRoutinePending)
2265 {
2266 RemoveEntryList(&Transfer->Link);
2267 InsertTailList(&Bulk->m_Completion, &Transfer->Link);
2268 Queue = TRUE;
2269 }
2270 Transfer->CancelState = XhciBulkCancel::Done;
2272
2273 if (Queue)
2274 QueueCompletionDpc(Ring);
2275}
2276
2277/* Transfer events ***********************************************************/
2278
2280BOOLEAN
2281XhciBulkRing::IsLiveStage(
2283 _In_ const XhciBulkStage* Stage,
2285{
2286 const XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2287 const LIST_ENTRY* Entry;
2288 ULONG Index;
2289
2291
2292 for (Index = 0; Index < StageSlots; Index++)
2293 {
2294 if (&Bulk->m_Stages[Index] == Stage)
2295 break;
2296 }
2297
2298 if (Index == StageSlots || !Stage->InUse || !Stage->OnHardware || Stage->Transfer == NULL)
2299 return FALSE;
2300
2301#ifndef _WIN64
2302 if ((ULONG)(EventData >> 32) != Stage->Generation)
2303 return FALSE;
2304#endif
2305
2306 /* Any pending request's stage qualifies, not only the oldest */
2307 for (Entry = Bulk->m_Pending.Flink; Entry != &Bulk->m_Pending; Entry = Entry->Flink)
2308 {
2309 if (CONTAINING_RECORD(Entry, XhciBulkTransfer, Link)->Stage == Stage)
2310 return TRUE;
2311 }
2312
2313 return FALSE;
2314}
2315
2316BOOLEAN
2318 _In_ XhciTransferRing* Ring,
2319 _In_ const XHCI_TRB* Event)
2320{
2321 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2323 XhciBulkStage* Stage = XhciBulkStageFromEventData(Value);
2324 XhciBulkTransfer* Transfer;
2325 XhciBulkStage* Match;
2328 ULONG EndpointId = (Event->Dword[3] & XHCI_TRB_ENDPOINT_MASK) >> XHCI_TRB_ENDPOINT_SHIFT;
2329 BOOLEAN Acknowledge = FALSE;
2330 BOOLEAN Live;
2332 ULONG Skipped;
2333 KIRQL OldIrql;
2334
2335 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2336 Live = IsLiveStage(Ring, Stage, Value);
2337 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2338
2339 if (!Live)
2340 {
2341 /* A stale or unknown Event Data pointer is dropped, never dereferenced */
2342 if (Ring->m_StreamId == 0)
2343 {
2344 DPRINT1("Bulk DCI %lu: stale or unknown Event Data 0x%I64x code %lu, dropped\n",
2345 Ring->m_Endpoint->Dci(), Value, Code);
2346 }
2347
2348 KickFill(Ring);
2349 return (Ring->m_StreamId == 0);
2350 }
2351
2352 Transfer = Stage->Transfer;
2353
2354 if (EndpointId != Ring->m_Endpoint->Dci() || XhciTrbSlotId(Event) != Ring->m_Device->SlotId())
2355 {
2356 DPRINT1("Bulk event for slot %lu DCI %lu reached slot %lu DCI %lu\n",
2357 XhciTrbSlotId(Event), EndpointId, Ring->m_Device->SlotId(), Ring->m_Endpoint->Dci());
2358 }
2359
2360 if (Bytes > Stage->Size)
2361 {
2362 DPRINT1("Bulk DCI %lu stream %lu: %lu bytes reported for a %lu byte stage\n",
2363 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Bytes, Stage->Size);
2364 Bytes = 0;
2365 }
2366
2368 {
2369 DPRINT1("Bulk DCI %lu stream %lu: halted code %lu reported through Event Data\n",
2370 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Code);
2371 HaltedEvent(Ring, Stage, Code, Bytes);
2372 }
2373 else if (XhciBulkIsStoppedCode(Code))
2374 {
2375 /* QUIRK: the drop stopped event flag is not consulted for Event Data events */
2376 Address = (ULONG64)Stage->FirstSegment->LogicalAddress.QuadPart +
2377 (ULONG64)Stage->FirstIndex * sizeof(XHCI_TRB);
2378
2379 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2380 if (LookupStage(Ring, Address, &Match, &Skipped) && Match == Stage)
2381 StoppedEvent(Ring, Stage, Code, Bytes, Skipped);
2382 else
2384 Bulk->m_Flags |= XhciBulkStoppedSeen;
2385 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2386
2387 Ring->m_Endpoint->OnStoppedEvent();
2388 }
2389 else
2390 {
2391 /* Only a short packet or a fully queued request records the code, so a reclaim cannot finish a partial one as Success */
2392 if (Code == static_cast<ULONG>(XhciCompletionCode::ShortPacket) ||
2393 Transfer->BytesQueued == Transfer->BytesTotal)
2394 {
2395 Transfer->CompletionCode = Code;
2396 }
2397
2398 Transfer->BytesTransferred += Bytes;
2399 XhciBulkCopyIn(Transfer, Stage, Bytes);
2400 PutScatterGather(Ring, Stage);
2401
2402 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2403 ReleaseStage(Ring, Stage);
2404 Transfer->TdsRetired++;
2405
2406 if (Code == static_cast<ULONG>(XhciCompletionCode::ShortPacket) ||
2407 Transfer->BytesQueued == Transfer->BytesTotal)
2408 {
2410 }
2411
2412 Bulk->m_PendingStages--;
2413 if (Bulk->m_OutstandingEvents != 0)
2414 {
2415 Bulk->m_OutstandingEvents--;
2416 if (Bulk->m_OutstandingEvents == 0 && (Bulk->m_Flags & XhciBulkAckExpected))
2417 Acknowledge = TRUE;
2418 }
2419 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2420
2421 if (Acknowledge)
2422 Ring->m_Endpoint->OnExpectedEventsProcessed();
2423 }
2424
2425 /* A slot on the ring freed up */
2426 KickFill(Ring);
2427 return TRUE;
2428}
2429
2430BOOLEAN
2432 _In_ XhciTransferRing* Ring,
2433 _In_ const XHCI_TRB* Event)
2434{
2435 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2437 XhciBulkStage* Stage;
2438 ULONG Skipped;
2439 ULONG Bytes = 0;
2440 KIRQL OldIrql;
2441
2442 if (XhciBulkIsStoppedCode(Code) && Ring->m_Endpoint->ShouldDropStoppedEvent())
2443 return TRUE;
2444
2445 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2446
2447 if (!LookupStage(Ring, XhciTrbPointer(Event), &Stage, &Skipped))
2448 {
2449 if (Ring->m_StreamId == 0)
2450 Ed0Mismatch(Ring, Event);
2451 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2452 return FALSE;
2453 }
2454
2455 if (Stage != NULL)
2456 {
2457 Bytes = XhciBulkStageBytes(Stage, Event);
2458 if (Bytes > Stage->Size)
2459 {
2460 DPRINT1("Bulk DCI %lu stream %lu: %lu bytes found in a %lu byte stage\n",
2461 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Bytes, Stage->Size);
2462 Bytes = 0;
2463 }
2464 }
2465
2467 {
2468 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2469
2470 /* QUIRK: old controllers report a halt one past the last TRB; that event is dropped */
2471 if (Stage != NULL)
2472 HaltedEvent(Ring, Stage, Code, Bytes);
2473 else
2474 DPRINT("Bulk DCI %lu: halt reported at the enqueue pointer, dropped\n", Ring->m_Endpoint->Dci());
2475
2476 return TRUE;
2477 }
2478
2480 {
2481 StoppedEvent(Ring, Stage, Code, Bytes, Skipped);
2482 Bulk->m_Flags |= XhciBulkStoppedSeen;
2483 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2484
2485 Ring->m_Endpoint->OnStoppedEvent();
2486 return TRUE;
2487 }
2488
2489 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2490 DPRINT1("Bulk DCI %lu stream %lu: unexpected code %lu without Event Data\n",
2491 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Code);
2492 return FALSE;
2493}
2494
2496_Requires_lock_held_(Ring->m_Lock)
2497BOOLEAN
2498XhciBulkRing::LookupStage(
2501 _Outptr_result_maybenull_ XhciBulkStage** Stage,
2502 _Out_ PULONG Skipped)
2503{
2504 const XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2505 const LIST_ENTRY* Entry;
2506 ULONG Count = 0;
2507
2508 *Stage = NULL;
2509 *Skipped = 0;
2510
2511 if (Address == 0)
2512 return FALSE;
2513
2514 if (Address == Ring->EnqueuePointer())
2515 {
2516 *Skipped = Bulk->m_PendingStages;
2517 return TRUE;
2518 }
2519
2520 for (Entry = Bulk->m_Pending.Flink; Entry != &Bulk->m_Pending; Entry = Entry->Flink)
2521 {
2522 XhciBulkStage* Candidate = CONTAINING_RECORD(Entry, XhciBulkTransfer, Link)->Stage;
2523
2524 if (Candidate == NULL || !Candidate->OnHardware)
2525 continue;
2526
2527 if (XhciBulkStageContains(Candidate, Address))
2528 {
2529 *Stage = Candidate;
2530 *Skipped = Count;
2531 return TRUE;
2532 }
2533
2534 Count++;
2535 }
2536
2537 return FALSE;
2538}
2539
2540VOID
2542 _In_ XhciTransferRing* Ring,
2543 _Inout_ XhciBulkStage* Stage,
2544 _In_ ULONG Code,
2546{
2547 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2548 XhciBulkTransfer* Transfer = Stage->Transfer;
2549 BOOLEAN Acknowledge = FALSE;
2550 KIRQL OldIrql;
2551
2552 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2553 Bulk->m_Flags |= XhciBulkHalted;
2554 Bulk->m_OutstandingEvents = 1;
2555 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2556
2557 /* The machine must see the halt before the client sees the failed request */
2558 Ring->m_Endpoint->OnHaltedCompletionCode(Code, TRUE);
2559
2560 Transfer->CompletionCode = Code;
2561 Transfer->BytesTransferred += Bytes;
2562 XhciBulkCopyIn(Transfer, Stage, Bytes);
2563 PutScatterGather(Ring, Stage);
2564
2565 KeAcquireSpinLock(&Ring->m_Lock, &OldIrql);
2566 ReleaseStage(Ring, Stage);
2567 Transfer->TdsRetired++;
2569 Bulk->m_PendingStages--;
2570 if (Bulk->m_OutstandingEvents != 0)
2571 Bulk->m_OutstandingEvents--;
2572 if (Bulk->m_Flags & XhciBulkAckExpected)
2573 Acknowledge = TRUE;
2574 KeReleaseSpinLock(&Ring->m_Lock, OldIrql);
2575
2576 if (Acknowledge)
2577 Ring->m_Endpoint->OnExpectedEventsProcessed();
2578}
2579
2580_Requires_lock_held_(Ring->m_Lock)
2581VOID
2582XhciBulkRing::StoppedEvent(
2583 _In_ XhciTransferRing* Ring,
2584 _Inout_opt_ XhciBulkStage* Stage,
2585 _In_ ULONG Code,
2587 _In_ ULONG Skipped)
2588{
2589 XhciBulkTransfer* Transfer;
2590
2591 if (Stage != NULL)
2592 {
2593 Transfer = Stage->Transfer;
2594 Transfer->BytesTransferred += Bytes;
2595 XhciBulkCopyIn(Transfer, Stage, Bytes);
2596
2597 if (Transfer->BytesTransferred == Transfer->BytesTotal)
2598 Transfer->CompletionCode = static_cast<ULONG>(XhciCompletionCode::Success);
2599 else if (Code == static_cast<ULONG>(XhciCompletionCode::StoppedShortPacket))
2600 Transfer->CompletionCode = Code;
2601 }
2602
2603 /* Earlier stages finished but their events are still on the way */
2604 Ring->m_Type.Bulk.m_OutstandingEvents = Skipped;
2605}
2606
2607_Requires_lock_held_(Ring->m_Lock)
2608BOOLEAN
2609XhciBulkRing::LikelyDuplicate(
2612 _Out_ PBOOLEAN PointsToNoOp)
2613{
2614 const XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2615 const XhciDmaBuffer* Segment = NULL;
2616 const XhciDmaBuffer* Candidate;
2617 const LIST_ENTRY* Entry;
2618 const XHCI_TRB* Trb;
2619
2620 *PointsToNoOp = FALSE;
2621
2622 /* The segment most recently given back to the pool */
2623 if (!IsListEmpty(&Ring->m_FreeSegments))
2624 {
2625 Candidate = CONTAINING_RECORD(Ring->m_FreeSegments.Blink, XhciDmaBuffer, Link);
2626 if (XhciBulkSegmentHas(Candidate, 0, MAXULONG, Address))
2627 Segment = Candidate;
2628 }
2629
2630 if (Segment == NULL)
2631 {
2632 Candidate = Ring->m_Segment;
2633 for (Entry = Bulk->m_Pending.Flink; Entry != &Bulk->m_Pending; Entry = Entry->Flink)
2634 {
2635 const XhciBulkStage* Oldest = CONTAINING_RECORD(Entry, XhciBulkTransfer, Link)->Stage;
2636
2637 if (Oldest != NULL)
2638 {
2639 Candidate = Oldest->FirstSegment;
2640 break;
2641 }
2642 }
2643
2644 if (XhciBulkSegmentHas(Candidate, 0, MAXULONG, Address))
2645 Segment = Candidate;
2646 }
2647
2648 if (Segment == NULL)
2649 return FALSE;
2650
2651 Trb = static_cast<const XHCI_TRB*>(Segment->VirtualAddress) +
2652 (ULONG)((Address - (ULONG64)Segment->LogicalAddress.QuadPart) / sizeof(XHCI_TRB));
2653 *PointsToNoOp = (XhciTrbType(Trb) == static_cast<ULONG>(XhciTrbType::NoOp));
2654 return TRUE;
2655}
2656
2657_Requires_lock_held_(Ring->m_Lock)
2658VOID
2659XhciBulkRing::Ed0Mismatch(
2660 _In_ XhciTransferRing* Ring,
2662{
2663 ULONG64 Pointer = XhciTrbPointer(Event);
2665 BOOLEAN NoOp;
2666
2667 if (!LikelyDuplicate(Ring, Pointer, &NoOp))
2668 {
2669 DPRINT1("Bulk DCI %lu: event TRB pointer 0x%I64x is not on the ring, resetting\n",
2670 Ring->m_Endpoint->Dci(), Pointer);
2671 Ring->m_Controller->RaiseControllerFault(XhciRecovery::ResetHost, XhciBulkReasonEd0Invalid);
2672 return;
2673 }
2674
2675 if (Ring->m_Controller->HasErrata(XhciErrata::EvtDiscardRepeatedEd0))
2676 {
2677 DPRINT1("Bulk DCI %lu: likely duplicate event at 0x%I64x dropped\n",
2678 Ring->m_Endpoint->Dci(), Pointer);
2679 return;
2680 }
2681
2683 {
2684 DPRINT1("Bulk DCI %lu: stopped event on a No Op TRB at 0x%I64x dropped\n",
2685 Ring->m_Endpoint->Dci(), Pointer);
2686 return;
2687 }
2688
2689 DPRINT1("Bulk DCI %lu: likely duplicate event at 0x%I64x code %lu, resetting\n",
2690 Ring->m_Endpoint->Dci(), Pointer, Code);
2691 Ring->m_Controller->RaiseControllerFault(XhciRecovery::ResetHost, XhciBulkReasonEd0Duplicate);
2692}
2693
2695_Requires_lock_held_(Ring->m_Lock)
2696VOID
2697XhciBulkRing::StreamStopOrHalt(
2698 _In_ XhciTransferRing* Ring)
2699{
2700 XhciBulkRing* Bulk = &Ring->m_Type.Bulk;
2701 XhciBulkStage* Stage;
2702 ULONG64 Dequeue;
2703 ULONG Skipped;
2704 ULONG Bytes;
2705
2706 NT_ASSERT(Ring->m_StreamId != 0);
2707
2708 Dequeue = Ring->m_Endpoint->StreamDequeuePointer(Ring->m_StreamId) & ~XHCI_DEQUEUE_FLAGS_MASK;
2709
2710 if (!LookupStage(Ring, Dequeue, &Stage, &Skipped))
2711 {
2712 DPRINT1("Bulk DCI %lu stream %lu: stream dequeue pointer 0x%I64x is not on the ring\n",
2713 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Dequeue);
2714 Stage = NULL;
2715 }
2716
2717 if (Stage == NULL)
2718 {
2719 Bulk->m_OutstandingEvents = Bulk->m_PendingStages;
2720 return;
2721 }
2722
2723 Bytes = Ring->m_Endpoint->StreamTransferLength(Ring->m_StreamId);
2724 if (Bytes > Stage->Size)
2725 {
2726 DPRINT1("Bulk DCI %lu stream %lu: context reports %lu bytes for a %lu byte stage\n",
2727 Ring->m_Endpoint->Dci(), Ring->m_StreamId, Bytes, Stage->Size);
2728 Bytes = 0;
2729 }
2730
2731 Stage->Transfer->BytesTransferred += Bytes;
2732 XhciBulkCopyIn(Stage->Transfer, Stage, Bytes);
2733 Bulk->m_OutstandingEvents = Skipped;
2734}
WCHAR First[]
Definition: FormatMessage.c:11
static _Out_opt_ PULONGLONG Start
#define VOID
Definition: acefi.h:82
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
static const ULONG XhciBulkOkToReclaim
Definition: bulkio.cpp:33
static const ULONG XhciBulkImmediateBytes
Definition: bulkio.cpp:19
static const ULONG XhciBulkPendingStagesMax
Definition: bulkio.cpp:16
static const USBD_STATUS XhciBulkStatusNotSet
Definition: bulkio.cpp:22
static const ULONG XhciBulkReclaimAck
Definition: bulkio.cpp:34
static BOOLEAN NTAPI XhciBulkNeedsNoOps(_In_ const XhciTransferRing *Ring)
Definition: bulkio.cpp:148
static const LONG XhciBulkWaitArrived
Definition: bulkio.cpp:39
XhciBulkStep
Definition: bulkio.cpp:43
static const LONG XhciBulkWaitParked
Definition: bulkio.cpp:38
static const ULONG XhciBulkHalted
Definition: bulkio.cpp:30
static BOOLEAN NTAPI XhciBulkIsHaltedCode(_In_ ULONG Code)
Definition: bulkio.cpp:60
static const ULONG XhciBulkReasonEd0Invalid
Definition: bulkio.cpp:25
static BOOLEAN NTAPI XhciBulkEndpointIn(_In_ const XhciTransferRing *Ring)
Definition: bulkio.cpp:93
static XhciBulkStage *NTAPI XhciBulkStageFromEventData(_In_ ULONG64 Value)
Definition: bulkio.cpp:348
static ULONG NTAPI XhciBulkWorstPages(_In_ ULONG Bytes)
Definition: bulkio.cpp:122
static ULONG64 NTAPI XhciBulkEventData(_In_ const XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage)
Definition: bulkio.cpp:333
static const LONG XhciBulkWaitIdle
Definition: bulkio.cpp:37
static ULONG NTAPI XhciBulkStageBytes(_In_ const XhciBulkStage *Stage, _In_ const XHCI_TRB *Event)
Definition: bulkio.cpp:288
static BOOLEAN NTAPI XhciBulkScanSegment(_In_ const XhciDmaBuffer *Segment, _In_ ULONG Start, _In_ const XHCI_TRB *Event, _Inout_ PULONG Bytes)
Definition: bulkio.cpp:219
static BOOLEAN NTAPI XhciBulkIsStoppedCode(_In_ ULONG Code)
Definition: bulkio.cpp:82
static BOOLEAN NTAPI XhciBulkStageContains(_In_ const XhciBulkStage *Stage, _In_ ULONG64 Address)
Definition: bulkio.cpp:312
static VOID NTAPI XhciBulkMoveList(_Inout_ PLIST_ENTRY Destination, _Inout_ PLIST_ENTRY Source)
Definition: bulkio.cpp:204
static const ULONG XhciBulkAckExpected
Definition: bulkio.cpp:29
static VOID NTAPI XhciBulkCopyIn(_In_ const XhciBulkTransfer *Transfer, _In_ const XhciBulkStage *Stage, _In_ ULONG Bytes)
Definition: bulkio.cpp:188
static const ULONG XhciBulkReasonEd0Duplicate
Definition: bulkio.cpp:26
static ULONG NTAPI XhciBulkPadSize(_In_ const XhciTransferRing *Ring, _In_ ULONG Size)
Definition: bulkio.cpp:161
static const ULONG XhciBulkStageTag
Definition: bulkio.cpp:13
static const ULONG XhciBulkCanceled
Definition: bulkio.cpp:32
static BOOLEAN NTAPI XhciBulkSegmentHas(_In_ const XhciDmaBuffer *Segment, _In_ ULONG Start, _In_ ULONG OnePastEnd, _In_ ULONG64 Address)
Definition: bulkio.cpp:131
static const ULONG XhciBulkNoOpCount
Definition: bulkio.cpp:21
static const ULONG XhciBulkMinStageSize
Definition: bulkio.cpp:20
static const LONG XhciBulkWaitAbandoned
Definition: bulkio.cpp:40
static const ULONG XhciBulkStoppedSeen
Definition: bulkio.cpp:31
static BOOLEAN NTAPI XhciBulkTransferIn(_In_ const XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:102
static BOOLEAN NTAPI XhciBulkChainedMdl(_In_ const XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:111
static const ULONG XhciBulkSegmentWaitLimit
Definition: bulkio.cpp:17
static const ULONG XhciBulkTrbBytesMax
Definition: bulkio.cpp:18
static const ULONG XhciBulkTransferTag
Definition: bulkio.cpp:14
_In_ ULONG const Usable
Definition: cdrom.h:1084
static BOOLEAN BuildTd(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1736
static VOID Cleanup(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:502
static VOID DropMdl(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:1276
static VOID FreeTransferResources(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:1297
static NTSTATUS EnableForwardProgress(_In_ XhciTransferRing *Ring, _In_ ULONG MaxTransferSize)
Definition: bulkio.cpp:466
static VOID RecoverTransfers(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:724
static VOID EstimateTrbs(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1502
static VOID ResumeRingFill(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:606
static VOID StreamStopOrHaltOnce(_In_ XhciTransferRing *Ring, _In_ ULONG Flag)
Definition: bulkio.cpp:646
static VOID InitTransfer(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ WDFREQUEST Request)
Definition: bulkio.cpp:1139
static NTSTATUS Initialize(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:357
static EVT_WDF_DPC EvtCompletionDpc
Definition: bulkio.h:115
static BOOLEAN Ed0Event(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: bulkio.cpp:2431
static VOID KickFill(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:919
static BOOLEAN DoorbellRungSinceFill(_In_ const XhciTransferRing *Ring)
Definition: bulkio.cpp:740
static VOID Ed0Mismatch(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
static XhciBulkStage * NextTdSlot(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:929
static BOOLEAN OnTransferEvent(_In_opt_ XhciTransferRing *Ring, _In_ XhciController *Controller, _In_ const XHCI_TRB *Event)
Definition: bulkio.cpp:779
static VOID Complete(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ USBD_STATUS Default)
static BOOLEAN OwnsRequests(_In_ const XhciTransferRing *Ring)
static const ULONG StageSlots
Definition: bulkio.h:164
static VOID StoppedEvent(_In_ XhciTransferRing *Ring, _Inout_opt_ XhciBulkStage *Stage, _In_ ULONG Code, _In_ ULONG Bytes, _In_ ULONG Skipped)
static EVT_WDF_IO_QUEUE_STATE ReadyNotification
Definition: bulkio.h:113
static VOID CompleteAfterUncancel(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer, _In_ USBD_STATUS Default, _In_ BOOLEAN FinishCanceled)
static BOOLEAN EstimateSegments(_In_ XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage, _Out_ PULONG Segments)
Definition: bulkio.cpp:1588
static VOID SegmentsArrived(_In_ XhciTransferRing *Ring, _In_ NTSTATUS Status)
Definition: bulkio.cpp:799
static VOID StreamStopOrHalt(_In_ XhciTransferRing *Ring)
static EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue
Definition: bulkio.h:114
volatile LONG m_FillAgain
Definition: bulkio.h:350
static BOOLEAN IsLikelyDuplicate(_In_ const XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: bulkio.cpp:762
static VOID QueueCompletionDpc(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:2213
static NTSTATUS ArrangeBuffer(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:1207
static VOID CompleteBatch(_In_ XhciTransferRing *Ring, _Inout_ PLIST_ENTRY Batch)
Definition: bulkio.cpp:2096
static VOID SizeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1446
static VOID Enable(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:401
static BOOLEAN HasQueuedWork(_In_ const XhciTransferRing *Ring)
Definition: bulkio.cpp:747
static Outcome EncodeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1661
static VOID ConsumePendingEvents(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:705
static VOID HaltedEvent(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage, _In_ ULONG Code, _In_ ULONG Bytes)
Definition: bulkio.cpp:2541
static VOID FillLoop(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:868
static DRIVER_LIST_CONTROL DmaCallback
Definition: bulkio.h:176
static BOOLEAN Ed1Event(_In_ XhciTransferRing *Ring, _In_ const XHCI_TRB *Event)
Definition: bulkio.cpp:2317
static VOID Disable(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:422
static VOID PutScatterGather(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
static VOID SuspendRingFill(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:632
static Outcome FailStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1632
static VOID OnPipeHalted(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:666
static VOID UndoTd(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1975
static Outcome PrimeStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1317
static BOOLEAN ParkOnSegments(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:1382
static VOID ChooseMechanism(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
Definition: bulkio.cpp:1177
static BOOLEAN LikelyDuplicate(_In_ const XhciTransferRing *Ring, _In_ ULONG64 Address, _Out_ PBOOLEAN PointsToNoOp)
static VOID AllowReclaimOnCancel(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:680
static BOOLEAN IsLiveStage(_In_ const XhciTransferRing *Ring, _In_ const XhciBulkStage *Stage, _In_ ULONG64 EventData)
static XhciBulkStage * AcquireStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkTransfer *Transfer)
static EVT_WDF_REQUEST_CANCEL EvtRequestCancel
Definition: bulkio.h:175
static BOOLEAN LookupStage(_In_ const XhciTransferRing *Ring, _In_ ULONG64 Address, _Outptr_result_maybenull_ XhciBulkStage **Stage, _Out_ PULONG Skipped)
static VOID BuildTdsFromQueue(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:842
static NTSTATUS AcquireStageMdl(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
Definition: bulkio.cpp:1397
static VOID StoppedEventReceived(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:673
static BOOLEAN InsertLink(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage, _In_ BOOLEAN FirstOfTd)
Definition: bulkio.cpp:1936
static VOID ReleaseParkedMapping(_In_ XhciTransferRing *Ring)
Definition: bulkio.cpp:443
static VOID ReleaseStage(_In_ XhciTransferRing *Ring, _Inout_ XhciBulkStage *Stage)
VOID OnTransferCanceled()
Definition: epctx.cpp:1183
VOID OnTransfersReclaimed()
Definition: epctx.cpp:1243
static XhciTransferRing * FromQueue(_In_ WDFQUEUE Queue)
Definition: xferring.cpp:308
XhciMapState ChangeMapState(_In_ BOOLEAN FromAny, _In_ XhciMapState From, _In_ XhciMapState To)
Definition: xferring.cpp:1048
static ULONG UrbProcessorIndex(_In_ PURB Urb)
Definition: xferring.cpp:1168
KSPIN_LOCK m_Lock
Definition: xferring.h:177
static NTSTATUS NtStatusFromUsbdStatus(_In_ USBD_STATUS UsbdStatus)
Definition: xferring.cpp:1237
XhciBulkRing Bulk
Definition: xferring.h:199
union XhciTransferRing::@1691 m_Type
static USBD_STATUS UsbdStatusFromCompletionCode(_In_ ULONG CompletionCode)
Definition: xferring.cpp:1184
XhciEndpoint * m_Endpoint
Definition: xferring.h:172
#define _Requires_lock_held_(lock)
#define _Requires_lock_not_held_(lock)
#define Code
Definition: deflate.h:80
PUCHAR Limit
Definition: desccheck.cpp:2230
Walk Base
Definition: desccheck.cpp:2270
_Inout_ HubConfiguration ** Slot
Definition: devhcd.cpp:1260
PLIST_ENTRY Entry
Definition: devhcd.cpp:1262
_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 ULONG_PTR
Definition: config.h:101
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#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
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
#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 RemoveTailList(ListHead)
Definition: env_spec_w32.h:975
#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
@ Pending
Definition: fs_rec.h:186
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
pRequest Complete(RequestStatus)
Status
Definition: gdiplustypes.h:24
static void Report(const char *msg)
Definition: glmodeswitch.c:58
Previous
#define USB3_URB_RESERVED_RESOURCES
Definition: hubreq.cpp:15
#define InterlockedCompareExchange
Definition: interlocked.h:119
#define InterlockedXor
Definition: interlocked.h:281
#define C_ASSERT(e)
Definition: intsafe.h:73
VOID NTAPI IoBuildPartialMdl(IN PMDL SourceMdl, IN PMDL TargetMdl, IN PVOID VirtualAddress, IN ULONG Length)
Definition: iomdl.c:96
_In_ PIRP Irp
Definition: kse.h:79
_In_ PIRP _In_ PIO_COMPLETION_ROUTINE _In_ PVOID Context
Definition: kse.h:81
if(dx< 0)
Definition: linetemp.h:194
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:423
_In_ UINT Bytes
Definition: mmcopy.h:9
unsigned __int64 ULONG64
Definition: imports.h:198
@ NormalPagePriority
Definition: imports.h:54
#define min(a, b)
Definition: monoChain.cc:55
_In_ UINT _In_ UINT _In_ PNDIS_PACKET Source
Definition: ndis.h:3169
_In_ PUNICODE_STRING _Inout_ PUNICODE_STRING Destination
Definition: rtlfuncs.h:3051
#define _Inout_
Definition: no_sal2.h:162
#define _Outptr_result_maybenull_
Definition: no_sal2.h:266
#define _Inout_opt_
Definition: no_sal2.h:216
#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
@ Batch
Definition: ntsecapi.h:291
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
Definition: xml2sdb.h:103
ULONG TdsRetired
Definition: bulkio.h:81
WDFREQUEST Request
Definition: bulkio.h:70
XhciTransferRing * Ring
Definition: bulkio.h:72
BOOLEAN MappedOnce
Definition: bulkio.h:66
XhciBulkStage * Stage
Definition: bulkio.h:83
XhciBulkMechanism Mechanism
Definition: bulkio.h:68
XhciBulkCancel CancelState
Definition: bulkio.h:69
ULONG BytesQueued
Definition: bulkio.h:80
PUCHAR Buffer
Definition: bulkio.h:76
ULONG TdsQueued
Definition: bulkio.h:82
struct _URB_BULK_OR_INTERRUPT_TRANSFER * Urb
Definition: bulkio.h:71
XhciDmaBuffer * DoubleBuffer
Definition: bulkio.h:77
ULONG Initialized
Definition: bulkio.h:65
ULONG BytesTransferred
Definition: bulkio.h:79
ULONG BytesTotal
Definition: bulkio.h:78
ULONG CompletionCode
Definition: bulkio.h:73
LIST_ENTRY Link
Definition: bulkio.h:64
PHYSICAL_ADDRESS LogicalAddress
Definition: dmapool.h:17
struct _DMA_OPERATIONS * DmaOperations
Definition: iotypes.h:2310
USHORT Version
Definition: iotypes.h:2308
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: usb.h:565
ULONG Dword[4]
Definition: xhcihw.h:17
#define STATUS_PENDING
Definition: telnetd.h:14
#define MAXULONG
Definition: typedefs.h:251
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char UCHAR
Definition: typedefs.h:53
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
unsigned char * PBOOLEAN
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
#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
ULONG LowPart
Definition: typedefs.h:106
#define USB_ENDPOINT_DIRECTION_MASK
Definition: usb100.h:73
#define USB_ENDPOINT_TYPE_BULK
Definition: usb100.h:64
@ UsbSuperSpeed
Definition: usb200.h:45
@ UsbLowSpeed
Definition: usb200.h:42
@ UsbFullSpeed
Definition: usb200.h:43
enum _USB_DEVICE_SPEED USB_DEVICE_SPEED
#define USBD_STATUS_CANCELED
Definition: usb.h:225
#define USBD_TRANSFER_DIRECTION_IN
Definition: usb.h:167
#define USBD_STATUS_INSUFFICIENT_RESOURCES
Definition: usb.h:215
LONG USBD_STATUS
Definition: usb.h:172
#define USBD_STATUS(Status)
Definition: usbdi.h:52
_In_opt_ PUSB_CONFIGURATION_DESCRIPTOR _Inout_ PUSBD_INTERFACE_LIST_ENTRY _Outptr_ PURB * Urb
Definition: usbdlib.h:333
USHORT Count
Definition: userreq.cpp:200
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
_In_ WDFCOLLECTION _In_ ULONG Index
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
_Must_inspect_result_ _In_ WDFDEVICE _In_ PIRP _In_ WDFQUEUE Queue
Definition: wdfdevice.h:2231
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539
_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
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
FORCEINLINE VOID WDF_REQUEST_PARAMETERS_INIT(_Out_ PWDF_REQUEST_PARAMETERS Parameters)
Definition: wdfrequest.h:211
_In_ WDFREQUEST _In_ BOOLEAN Requeue
Definition: wdfrequest.h:1654
_In_ WDFREQUEST _In_ PFN_WDF_REQUEST_CANCEL EvtRequestCancel
Definition: wdfrequest.h:730
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127
_In_ NTSTATUS _In_ USBD_STATUS UsbdStatus
Definition: wdfusb.h:403
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Inout_ PVOID Segment
Definition: exfuncs.h:1101
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
#define DMA_TRANSFER_INFO_VERSION1
Definition: iotypes.h:2116
struct _SCATTER_GATHER_LIST * PSCATTER_GATHER_LIST
Definition: iotypes.h:2219
_In_ struct _IRP _In_ struct _SCATTER_GATHER_LIST * ScatterGather
Definition: iotypes.h:2390
#define DEVICE_DESCRIPTION_VERSION3
Definition: iotypes.h:2066
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
#define MmGetMdlByteCount(_Mdl)
#define MmGetMdlVirtualAddress(_Mdl)
#define MmInitializeMdl(_MemoryDescriptorList, _BaseVa, _Length)
#define MmGetSystemAddressForMdlSafe(_Mdl, _Priority)
#define ADDRESS_AND_SIZE_TO_SPAN_PAGES(_Va, _Size)
#define NT_ASSERT
Definition: rtlfuncs.h:3334
XhciMapState
Definition: xferring.h:19
@ EvtDiscardRepeatedEd0
@ XferPacketAlignChunks
@ XferPadSsBulkInTail
#define XHCI_TRB_LENGTH_MASK
Definition: xhcihw.h:621
#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_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_IDT
Definition: xhcihw.h:625
#define XHCI_TRB_INTERRUPTER_SHIFT
Definition: xhcihw.h:610
#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_EVENT_DATA_TYPE_MASK
Definition: xhcihw.h:324
#define XHCI_TRB_CYCLE
Definition: xhcihw.h:22
struct _XHCI_TRB XHCI_TRB
#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
FORCEINLINE ULONG NTAPI XhciTrbSlotId(_In_ const XHCI_TRB *Trb)
Definition: xhcihw.h:51
FORCEINLINE BOOLEAN NTAPI XhciIsListEntryLinked(_In_ const LIST_ENTRY *Entry)
Definition: xhciutil.h:127
FORCEINLINE VOID NTAPI XhciClearListEntry(_Out_ PLIST_ENTRY Entry)
Definition: xhciutil.h:117
#define const
Definition: zconf.h:233