ReactOS 0.4.17-dev-1281-g065abb3
urbroute.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS USB Host Controller Extension
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: USBPORT style URB validation and routing
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8#include "ucx01000.h"
9#include <pseh/pseh2.h>
10
11#define NDEBUG
12#include <debug.h>
13
14/* Status mapping, shared by the whole driver */
15
20{
21 switch (UsbdStatus)
22 {
25 return STATUS_SUCCESS;
26
29
35
38
41
43 return STATUS_CANCELLED;
44
45 default:
47 }
48}
49
50/* Any other code, success codes such as STATUS_PENDING included, becomes INVALID_PARAMETER */
55{
56 switch (Status)
57 {
58 case STATUS_SUCCESS:
60
63
66
69
72
73 default:
75 }
76}
77
78/* Buffers handed over without an MDL */
79
80VOID
84{
85 struct _URB_CONTROL_TRANSFER* Transfer = &Urb->UrbControlTransfer;
87 PMDL Mdl;
88
89 Urb->UrbHeader.UsbdFlags &= ~UCX_URB_FLAG_BUFFER_LOCKED;
90
91 /* At DISPATCH_LEVEL the buffer has to be resident already */
93 Transfer->TransferBufferMDL != NULL ||
94 Transfer->TransferBuffer == NULL ||
95 Transfer->TransferBufferLength == 0)
96 {
97 return;
98 }
99
101 if (Mdl == NULL)
102 {
103 DPRINT1("No MDL for the %lu byte buffer of URB %p\n", Transfer->TransferBufferLength, Urb);
104 return;
105 }
106
108
110 {
112 }
114 {
115 DPRINT1("Locking the buffer of URB %p failed 0x%lx\n", Urb, _SEH2_GetExceptionCode());
116 IoFreeMdl(Mdl);
117 Mdl = NULL;
118 }
119 _SEH2_END;
120
121 if (Mdl == NULL)
122 return;
123
124 Transfer->TransferBufferMDL = Mdl;
125 Urb->UrbHeader.UsbdFlags |= UCX_URB_FLAG_BUFFER_LOCKED;
126}
127
128VOID
129NTAPI
132{
133 struct _URB_CONTROL_TRANSFER* Transfer = &Urb->UrbControlTransfer;
134
135 if (!(Urb->UrbHeader.UsbdFlags & UCX_URB_FLAG_BUFFER_LOCKED))
136 return;
137
139 IoFreeMdl(Transfer->TransferBufferMDL);
140 Transfer->TransferBufferMDL = NULL;
141 Urb->UrbHeader.UsbdFlags &= ~UCX_URB_FLAG_BUFFER_LOCKED;
142}
143
144/* The function table */
145
147{
150 AbortPipe,
154 Isoch,
157 GetStatus,
162};
163
164/* Table flags; never written into the URB */
165#define UCX_URB_TRANSFER 0x01
166#define UCX_URB_DEFAULT_PIPE 0x02
167#define UCX_URB_NO_DATA 0x04
168#define UCX_URB_PIPE_REQUEST 0x08
169
170/* Setup packet fields the table supplies; Dir 2 means the client's direction bit decides */
171#define UCX_DIR_OUT 0
172#define UCX_DIR_IN 1
173#define UCX_DIR_CLIENT 2
174
176{
184};
185
186#define UCX_RT_STANDARD 0
187#define UCX_RT_CLASS 1
188#define UCX_RT_VENDOR 2
189
190#define UCX_TO_DEVICE 0
191#define UCX_TO_INTERFACE 1
192#define UCX_TO_ENDPOINT 2
193#define UCX_TO_OTHER 3
194
195#define UCX_PIPE_REQUEST_SIZE sizeof(struct _URB_PIPE_REQUEST)
196#define UCX_DESCRIPTOR_SIZE sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)
197#define UCX_FEATURE_SIZE sizeof(struct _URB_CONTROL_FEATURE_REQUEST)
198#define UCX_STATUS_SIZE sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST)
199#define UCX_VENDOR_SIZE sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)
200
201#define UCX_STD_TRANSFER (UCX_URB_TRANSFER | UCX_URB_DEFAULT_PIPE)
202#define UCX_STD_NO_DATA (UCX_URB_TRANSFER | UCX_URB_DEFAULT_PIPE | UCX_URB_NO_DATA)
203
204#define UCX_UNSUPPORTED(Length) { UcxUrbHandler::NotSupported, (USHORT)(Length), 0, 0, 0, 0, 0 }
205#define UCX_INVALID { UcxUrbHandler::InvalidFunction, 0, 0, 0, 0, 0, 0 }
206#define UCX_DESCRIPTOR(Dir, To, Req) { UcxUrbHandler::GetSetDescriptor, UCX_DESCRIPTOR_SIZE, UCX_STD_TRANSFER, Dir, UCX_RT_STANDARD, To, Req }
207#define UCX_FEATURE(To, Req) { UcxUrbHandler::SetClearFeature, UCX_FEATURE_SIZE, UCX_STD_NO_DATA, UCX_DIR_OUT, UCX_RT_STANDARD, To, Req }
208#define UCX_STATUS(To) { UcxUrbHandler::GetStatus, UCX_STATUS_SIZE, UCX_STD_TRANSFER, UCX_DIR_IN, UCX_RT_STANDARD, To, USB_REQUEST_GET_STATUS }
209#define UCX_VENDOR_CLASS(Type, To) { UcxUrbHandler::VendorClass, UCX_VENDOR_SIZE, UCX_STD_TRANSFER, UCX_DIR_CLIENT, Type, To, 0 }
210
212{
213 /* 0x00 */ UCX_UNSUPPORTED(0),
214 /* 0x01 */ UCX_UNSUPPORTED(0),
216 /* 0x03 */ UCX_UNSUPPORTED(sizeof(struct _URB_FRAME_LENGTH_CONTROL)),
217 /* 0x04 */ UCX_UNSUPPORTED(sizeof(struct _URB_FRAME_LENGTH_CONTROL)),
218 /* 0x05 */ UCX_UNSUPPORTED(sizeof(struct _URB_GET_FRAME_LENGTH)),
219 /* 0x06 */ UCX_UNSUPPORTED(sizeof(struct _URB_SET_FRAME_LENGTH)),
220 /* 0x07 */ { UcxUrbHandler::GetCurrentFrame, sizeof(struct _URB_GET_CURRENT_FRAME_NUMBER), 0, 0, 0, 0, 0 },
221 /* 0x08 */ { UcxUrbHandler::ControlTransfer, sizeof(struct _URB_CONTROL_TRANSFER), UCX_URB_TRANSFER, 0, 0, 0, 0 },
222 /* 0x09 */ { UcxUrbHandler::BulkOrInterrupt, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), UCX_URB_TRANSFER, 0, 0, 0, 0 },
223 /* 0x0A */ { UcxUrbHandler::Isoch, 0, UCX_URB_TRANSFER, 0, 0, 0, 0 },
232 /* 0x13 */ UCX_STATUS(UCX_TO_DEVICE),
233 /* 0x14 */ UCX_STATUS(UCX_TO_INTERFACE),
234 /* 0x15 */ UCX_STATUS(UCX_TO_ENDPOINT),
235 /* 0x16 */ UCX_INVALID,
242 /* 0x1D */ UCX_INVALID,
243 /* 0x1E */ { UcxUrbHandler::NotSupported, UCX_PIPE_REQUEST_SIZE, UCX_URB_PIPE_REQUEST, 0, 0, 0, 0 },
246 /* 0x21 */ UCX_STATUS(UCX_TO_OTHER),
251 /* 0x26 */ { UcxUrbHandler::GetConfiguration, sizeof(struct _URB_CONTROL_GET_CONFIGURATION_REQUEST), UCX_STD_TRANSFER,
253 /* 0x27 */ { UcxUrbHandler::GetInterface, sizeof(struct _URB_CONTROL_GET_INTERFACE_REQUEST), UCX_STD_TRANSFER,
257 /* 0x2A */ { UcxUrbHandler::MsFeatureDescriptor, UCX_DESCRIPTOR_SIZE, UCX_STD_TRANSFER, UCX_DIR_IN, UCX_RT_VENDOR, 0, 0 },
258 /* 0x2B */ UCX_INVALID,
259 /* 0x2C */ UCX_INVALID,
260 /* 0x2D */ UCX_INVALID,
261 /* 0x2E */ UCX_INVALID,
262 /* 0x2F */ UCX_INVALID,
263 /* 0x30 */ { UcxUrbHandler::NotSupported, UCX_PIPE_REQUEST_SIZE, UCX_URB_PIPE_REQUEST, 0, 0, 0, 0 },
264 /* 0x31 */ { UcxUrbHandler::NotSupported, UCX_PIPE_REQUEST_SIZE, UCX_URB_PIPE_REQUEST, 0, 0, 0, 0 },
265 /* 0x32 */ { UcxUrbHandler::ControlTransfer, sizeof(struct _URB_CONTROL_TRANSFER_EX), UCX_URB_TRANSFER, 0, 0, 0, 0 },
266 /* 0x33 */ UCX_INVALID,
267 /* 0x34 */ UCX_INVALID,
268};
269
270C_ASSERT(ARRAYSIZE(UcxUrbFunctions) == URB_FUNCTION_RESERVE_0X0034 + 1);
271
272static IO_COMPLETION_ROUTINE UcxLegacyTransferCompletion;
273
274/* Forwarding */
275
277static
278VOID
279NTAPI
281 _In_ WDFDEVICE RootHubPdo,
282 _In_ PIRP Irp,
283 _In_ PIO_COMPLETION_ROUTINE Completion,
285{
287
290
291 Status = IoSetCompletionRoutineEx(WdfDeviceWdmGetDeviceObject(RootHubPdo),
292 Irp,
293 Completion,
294 Context,
295 TRUE,
296 TRUE,
297 TRUE);
298 if (!NT_SUCCESS(Status))
299 {
300 DPRINT("IoSetCompletionRoutineEx failed 0x%lx for IRP %p, using the plain routine\n", Status, Irp);
302 }
303}
304
305/* A refused IRP still runs the completion routine, which cancels the URB */
307NTAPI
309 _In_ WDFDEVICE RootHubPdo,
310 _In_ PIRP Irp,
311 _In_ PIO_COMPLETION_ROUTINE Completion,
313 _In_ WDFQUEUE Queue)
314{
315 UcxSetCompletionOnNext(RootHubPdo, Irp, Completion, Context);
316
317 WdfDeviceWdmDispatchIrpToIoQueue(RootHubPdo, Irp, Queue, WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP);
318 return STATUS_PENDING;
319}
320
322NTAPI
324 _In_ WDFDEVICE RootHubPdo,
325 _In_ PIRP Irp,
326 _In_ PIO_COMPLETION_ROUTINE Completion,
328 _In_ WDFQUEUE Queue,
329 _In_ WDFREQUEST Request)
330{
333
334 UcxSetCompletionOnNext(RootHubPdo, Irp, Completion, Context);
336
338 Status = WdfRequestForwardToParentDeviceIoQueue(Request, Queue, &Options);
339 if (!NT_SUCCESS(Status))
340 {
341 /* A purging queue means a controller reset or a concurrent pipe reset */
342 if (Status == STATUS_WDF_BUSY)
344
345 DPRINT1("Forwarding request %p (IRP %p) to queue %p failed 0x%lx\n", Request, Irp, Queue, Status);
346 WdfRequestComplete(Request, Status);
347 }
348
349 return STATUS_PENDING;
350}
351
352/* Pipe handles */
353
355NTAPI
359{
363
364 if (Pipe != NULL && !Pipe->BelongsToStream)
365 {
366 if (Device->m_StalePipeIoAllowed)
367 {
368 SpinLockGuard Guard(&Device->m_TrackingLock);
369
370 for (Entry = Device->m_TrackingList.Flink; Entry != &Device->m_TrackingList; Entry = Entry->Flink)
371 {
372 if (&CONTAINING_RECORD(Entry, UcxEndpoint, m_TrackingLink)->m_Pipe == Pipe)
373 {
374 Valid = TRUE;
375 break;
376 }
377 }
378 }
379 else
380 {
381 Valid = Pipe->IsValid();
382 }
383 }
384
386 {
387 DPRINT1("Client used invalid pipe handle %p on device %p\n", Handle, Device);
390 }
391
392 return Valid;
393}
394
396static
398NTAPI
400 _In_ PMDL Mdl,
402{
403 ULONG Remaining;
404
405 if (Mdl->Next == NULL || Length <= MmGetMdlByteCount(Mdl))
406 return FALSE;
407
409 return TRUE;
410
411 Remaining = Length - MmGetMdlByteCount(Mdl);
412
413 for (Mdl = Mdl->Next; Mdl != NULL; Mdl = Mdl->Next)
414 {
415 if (MmGetMdlByteOffset(Mdl) != 0)
416 return TRUE;
417
418 if (Remaining <= MmGetMdlByteCount(Mdl))
419 return FALSE;
420
421 if (MmGetMdlByteCount(Mdl) % PAGE_SIZE != 0)
422 return TRUE;
423
424 Remaining -= MmGetMdlByteCount(Mdl);
425 }
426
427 return TRUE;
428}
429
430/* Handlers */
431
432static
433PUCHAR
434NTAPI
436 _In_ PURB Urb)
437{
438 return Urb->UrbControlTransfer.SetupPacket;
439}
440
441static
442UCHAR
443NTAPI
447 _In_ UCHAR Recipient)
448{
449 return (UCHAR)((Direction << 7) | (Type << 5) | Recipient);
450}
451
452static
453VOID
454NTAPI
456 _Out_writes_bytes_(2) PUCHAR Where,
458{
459 Where[0] = (UCHAR)(Value & 0xFF);
460 Where[1] = (UCHAR)(Value >> 8);
461}
462
463static
464USHORT
465NTAPI
467 _In_reads_bytes_(2) const UCHAR* Where)
468{
469 return (USHORT)(Where[0] | (Where[1] << 8));
470}
471
472/* Default pipe requests only ever reach the HCD as plain control transfers, as with USBPORT */
473static
475NTAPI
477 _In_ WDFDEVICE RootHubPdo,
478 _In_ PIRP Irp,
479 _In_ PURB Urb,
480 _In_ WDFQUEUE Queue)
481{
482 if (Urb->UrbControlTransfer.TransferFlags & USBD_DEFAULT_PIPE_TRANSFER)
483 Urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
484
487}
488
489static
491NTAPI
493 _In_ WDFDEVICE RootHubPdo,
494 _In_ PIRP Irp,
495 _In_ PURB Urb,
496 _In_ WDFQUEUE Queue,
498{
500 PULONG Flags = &Urb->UrbControlTransfer.TransferFlags;
502
504
505 switch (Function->Handler)
506 {
507 case UcxUrbHandler::GetSetDescriptor:
508 Setup[0] = UcxRequestType(Function->Direction, Function->Type, Function->Recipient);
509 Setup[1] = Function->Request;
510 break;
511
512 case UcxUrbHandler::SetClearFeature:
513 Urb->UrbControlTransfer.TransferBufferLength = 0;
514 Setup[0] = UcxRequestType(Function->Direction, Function->Type, Function->Recipient);
515 Setup[1] = Function->Request;
516 break;
517
518 case UcxUrbHandler::GetStatus:
519 case UcxUrbHandler::GetInterface:
520 Setup[0] = UcxRequestType(Function->Direction, Function->Type, Function->Recipient);
521 Setup[1] = Function->Request;
522 UcxSetWord(&Setup[2], 0);
523 break;
524
525 case UcxUrbHandler::GetConfiguration:
526 Setup[0] = UcxRequestType(Function->Direction, Function->Type, Function->Recipient);
527 Setup[1] = Function->Request;
528 UcxSetWord(&Setup[2], 0);
529 UcxSetWord(&Setup[4], 0);
530 break;
531
532 /* The client's direction bit and reserved request type bits are kept */
533 case UcxUrbHandler::VendorClass:
535 Function->Type,
536 Function->Recipient) |
537 (Setup[0] & 0x1C));
538 break;
539
540 /* The recipient comes from the client, the request code from the hub */
541 case UcxUrbHandler::MsFeatureDescriptor:
542 Setup[0] = (UCHAR)(UcxRequestType(UCX_DIR_IN, UCX_RT_VENDOR, 0) | (Setup[0] & 0x1F));
543 break;
544
545 default:
547 break;
548 }
549
550 if (Function->Handler != UcxUrbHandler::VendorClass)
551 {
552 if (Function->Direction == UCX_DIR_IN)
554 else
555 *Flags &= ~USBD_TRANSFER_DIRECTION_IN;
556 }
557
558 Length = (USHORT)Urb->UrbControlTransfer.TransferBufferLength;
559 UcxSetWord(&Setup[6], Length);
560
561 /* The setup bytes stay written even when this fails */
562 if (Function->Handler == UcxUrbHandler::GetStatus && UcxGetWord(&Setup[6]) != sizeof(USHORT))
563 {
564 DPRINT1("GET_STATUS URB %p has wLength %u, expected 2\n", Urb, UcxGetWord(&Setup[6]));
566 }
567
568 return UcxForwardDefaultPipeRequest(RootHubPdo, Irp, Urb, Queue);
569}
570
571static
573NTAPI
575 _In_ WDFDEVICE RootHubPdo,
576 _In_ PIRP Irp,
577 _In_ PURB Urb,
578 _In_ WDFQUEUE Queue,
580{
581 struct _URB_ISOCH_TRANSFER* Isoch = &Urb->UrbIsochronousTransfer;
582 ULONG Packets = Isoch->NumberOfPackets;
583
584 if (Isoch->TransferBufferLength == 0 && Isoch->TransferBufferMDL == NULL && Isoch->TransferBuffer == NULL)
585 {
586 DPRINT1("Isoch URB %p has no buffer\n", Urb);
588 }
589
590 if (Pipe->IsochPeriodMicroframes > 8)
591 {
592 DPRINT1("Isoch URB %p on pipe %p has period %lu microframes\n", Urb, Pipe, Pipe->IsochPeriodMicroframes);
593 Isoch->StartFrame = 0;
595 }
596
597 /* Only the frame alignment failure resets StartFrame */
598 if (Packets != 0 && (Packets * Pipe->IsochPeriodMicroframes) % 8 != 0)
599 {
600 DPRINT1("Isoch URB %p: %lu packets do not fill whole frames\n", Urb, Packets);
601 Isoch->StartFrame = 0;
603 }
604
605 if (Packets == 0 || Packets > Pipe->IsochPacketLimit)
606 {
607 DPRINT1("Isoch URB %p has bad packet count %lu, max %lu\n", Urb, Packets, Pipe->IsochPacketLimit);
609 }
610
614}
615
616static
618NTAPI
620 _In_ PIRP Irp,
621 _In_ PURB Urb,
623{
624 ULONG Frame = 0;
626
627 Status = Device->m_Controller->GetCurrentFrameNumber(&Frame);
628 if (!NT_SUCCESS(Status))
629 {
630 DPRINT1("Getting the current frame for URB %p failed 0x%lx\n", Urb, Status);
631 Frame = 0;
632 }
633
634 Urb->UrbGetCurrentFrameNumber.FrameNumber = Frame;
636}
637
639static
641NTAPI
643 _In_ PURB Urb,
644 _In_ const UcxPipe* Pipe)
645{
646 ULONG Length = Urb->UrbControlTransfer.TransferBufferLength;
647 BOOLEAN AllowLarge = (Urb->UrbHeader.UsbdFlags & UCXHUB_URB_FLAG_ALLOW_LARGE_TRANSFER) != 0;
649
650 switch (Urb->UrbHeader.Function)
651 {
653 case URB_FUNCTION_CONTROL_TRANSFER_EX:
654 if (Pipe->TransferType != UcxTransferType::Control)
656 if ((Length > Pipe->MaximumTransferSize && !AllowLarge) || Length > UCX_MAX_CONTROL_TRANSFER)
658 break;
659
661 if (Pipe->TransferType != UcxTransferType::Bulk && Pipe->TransferType != UcxTransferType::Interrupt)
663 if (Length > Pipe->MaximumTransferSize)
665 break;
666
668 if (Pipe->TransferType != UcxTransferType::Isochronous)
670 break;
671 }
672
673 return Error;
674}
675
677static
679NTAPI
681 _In_ PURB Urb,
684 _Outptr_ UcxPipe** TargetPipe)
685{
686 struct _URB_CONTROL_TRANSFER* Transfer = &Urb->UrbControlTransfer;
687 USHORT Code = Urb->UrbHeader.Function;
688 UcxPipe* Pipe;
690
691 *TargetPipe = NULL;
692
694
695 if (Function->Flags & UCX_URB_DEFAULT_PIPE)
696 {
697 Transfer->PipeHandle = Device->m_DefaultPipe->Handle();
699 }
700
701 if ((Transfer->TransferFlags & USBD_DEFAULT_PIPE_TRANSFER) &&
702 (Code == URB_FUNCTION_CONTROL_TRANSFER || Code == URB_FUNCTION_CONTROL_TRANSFER_EX))
703 {
704 Transfer->PipeHandle = Device->m_DefaultPipe->Handle();
705 }
706
707 /* UrbLink must be unused; the _EX form keeps its Timeout in the same slot */
708 if (Transfer->UrbLink != NULL && Code != URB_FUNCTION_CONTROL_TRANSFER_EX)
710
711 if (Function->Flags & UCX_URB_NO_DATA)
712 {
713 Transfer->TransferBuffer = NULL;
714 Transfer->TransferBufferMDL = NULL;
715 Transfer->TransferBufferLength = 0;
716 }
717
718 if (!UcxValidatePipeHandle(Device, Transfer->PipeHandle))
720
722
723 if (Pipe->Kind == UcxEndpointKind::ZeroBandwidth)
725
728 return Error;
729
730 /* A buffer with zero length is accepted, a length with no buffer is not */
731 if (Transfer->TransferBufferLength != 0 && Transfer->TransferBuffer == NULL && Transfer->TransferBufferMDL == NULL)
733
734 if (Transfer->TransferBufferLength == 0 && Transfer->TransferBufferMDL != NULL)
736
737 if (Pipe->TransferType == UcxTransferType::Control &&
738 ((Transfer->TransferBufferLength > Pipe->MaximumTransferSize &&
739 !(Urb->UrbHeader.UsbdFlags & UCXHUB_URB_FLAG_ALLOW_LARGE_TRANSFER)) ||
741 {
743 }
744
745 /* Only fatal under verifier; the HCD copes otherwise */
746 if (Transfer->TransferBufferMDL != NULL &&
748 Device->m_Controller->m_DriverVerifierEnabled)
749 {
750 DPRINT1("URB %p has an unaligned chained MDL %p\n", Urb, Transfer->TransferBufferMDL);
751 KeBugCheckEx(0x144, 0x807, (ULONG_PTR)Transfer->TransferBufferMDL, (ULONG_PTR)Urb, 0);
752 }
753
754 *TargetPipe = Pipe;
755 return USBD_STATUS_SUCCESS;
756}
757
759NTAPI
761 _In_ WDFDEVICE RootHubPdo,
762 _In_ PIRP Irp,
763 _In_ PURB Urb)
764{
767 UcxPipe* Pipe = NULL;
769 USHORT Code;
770
771 /* Short headers are not rejected */
772 Urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
773 Code = Urb->UrbHeader.Function;
774 Urb->UrbHeader.UsbdFlags &= UCX_URB_FLAGS_KEEP_HUB_BITS;
775
777 {
778 DPRINT1("URB %p has unknown function 0x%x\n", Urb, Code);
780 }
781
783
784 if (Function->Length != 0 && Function->Length != Urb->UrbHeader.Length)
785 {
786 DPRINT1("URB %p function 0x%x has length %u, expected %u\n", Urb, Code, Urb->UrbHeader.Length, Function->Length);
788 }
789
790 /* The hub fills in its UCXUSBDEVICE */
791 if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
792 {
793 DPRINT1("URB %p function 0x%x has no device handle\n", Urb, Code);
795 }
796
797 Device = UcxUsbDevice::FromHandle((UCXUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle);
798
799 if (Device->m_Disconnected)
800 {
801 DPRINT("URB %p function 0x%x for disconnected device %p\n", Urb, Code, Device);
803 }
804
805 if (Function->Flags & UCX_URB_TRANSFER)
806 {
809 {
810 DPRINT1("Transfer URB %p function 0x%x on device %p rejected, USBD status 0x%lx\n", Urb, Code, Device, Error);
812 }
813 }
814 else if (Function->Flags & UCX_URB_PIPE_REQUEST)
815 {
816 if (!UcxValidatePipeHandle(Device, Urb->UrbPipeRequest.PipeHandle))
817 {
818 DPRINT1("Pipe URB %p function 0x%x has invalid pipe %p\n", Urb, Code, Urb->UrbPipeRequest.PipeHandle);
820 }
821
822 Pipe = UcxPipe::FromHandle(Urb->UrbPipeRequest.PipeHandle);
823
824 /* Zero bandwidth pipes are not in the schedule; pipe requests on them just succeed */
825 if (Pipe->Kind == UcxEndpointKind::ZeroBandwidth)
827 }
828
829 /* Tells the completion routine whether the HCD ever saw it */
830 Urb->UrbHeader.Status = USBD_STATUS_PENDING;
831
832 switch (Function->Handler)
833 {
834 case UcxUrbHandler::NotSupported:
835 DPRINT1("URB %p function 0x%x is not supported\n", Urb, Code);
838
839 case UcxUrbHandler::InvalidFunction:
840 DPRINT1("URB %p has invalid function 0x%x\n", Urb, Code);
842
843 case UcxUrbHandler::AbortPipe:
844 return Pipe->Endpoint->AbortPipe(Irp, Urb);
845
846 case UcxUrbHandler::GetCurrentFrame:
848
849 case UcxUrbHandler::ControlTransfer:
851 return UcxForwardIrpToQueue(RootHubPdo, Irp, UcxLegacyTransferCompletion, Urb, Pipe->Queue);
852
853 case UcxUrbHandler::BulkOrInterrupt:
856 return UcxForwardIrpToQueue(RootHubPdo, Irp, UcxLegacyTransferCompletion, Urb, Pipe->Queue);
857
858 case UcxUrbHandler::Isoch:
859 return UcxHandleIsoch(RootHubPdo, Irp, Urb, Pipe->Queue, Pipe);
860
861 default:
862 return UcxHandleStandardRequest(RootHubPdo, Irp, Urb, Pipe->Queue, Function);
863 }
864}
865
866/* Completion of every transfer forwarded by this path */
867
868static
870NTAPI
873 _In_ PIRP Irp,
874 _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
875{
876 PURB Urb = (PURB)Context;
877 UcxUsbDevice* Device = UcxUsbDevice::FromHandle((UCXUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle);
878 USBD_STATUS UsbdStatus = Urb->UrbHeader.Status;
879 NTSTATUS Status = Irp->IoStatus.Status;
880 ULONG Index;
881
883
884 /* The byte count lives in the URB only */
885 Irp->IoStatus.Information = 0;
886
888 {
889 /* The HCD never saw it: purged, canceled while queued or refused */
890 DPRINT("URB %p function 0x%x canceled before reaching the HCD\n", Urb, Urb->UrbHeader.Function);
891 Urb->UrbHeader.Status = USBD_STATUS_CANCELED;
892 Irp->IoStatus.Status = STATUS_CANCELLED;
893 Urb->UrbControlTransfer.TransferBufferLength = 0;
894
895 if (Urb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER)
896 {
897 for (Index = 0; Index < Urb->UrbIsochronousTransfer.NumberOfPackets; Index++)
898 Urb->UrbIsochronousTransfer.IsoPacket[Index].Status = 0xFFFFFFFF;
899 Urb->UrbIsochronousTransfer.ErrorCount = 0;
900 }
901
902 Device->m_TransferFailureCount++;
903 }
904 else if (!USBD_SUCCESS(UsbdStatus))
905 {
906 DPRINT("URB %p function 0x%x on device %p failed, USBD status 0x%lx\n",
907 Urb, Urb->UrbHeader.Function, Device, UsbdStatus);
908 Device->m_TransferFailureCount++;
909 Device->ReportNoPingResponseIfPending();
910 Irp->IoStatus.Status = UcxUsbdStatusToNtStatus(UsbdStatus);
911 }
912 else if (!NT_SUCCESS(Status))
913 {
914 DPRINT1("URB %p succeeded but its IRP %p failed 0x%lx\n", Urb, Irp, Status);
916 Urb->UrbHeader.Status = UcxNtStatusToUsbdStatus(Status);
917 }
918
919 if (Irp->PendingReturned)
921
923
924 if (UcxIsXrbIrp(Irp, Urb))
926
928}
Type
Definition: Type.h:7
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn UINT32 *TableIdx UINT32 ACPI_TABLE_HEADER *OutTableHeader ACPI_TABLE_HEADER **OutTable ACPI_HANDLE UINT32 ACPI_WALK_CALLBACK ACPI_WALK_CALLBACK void void **ReturnValue UINT32 ACPI_BUFFER *RetPathPtr ACPI_OBJECT_HANDLER void *Data ACPI_OBJECT_HANDLER void **Data ACPI_STRING ACPI_OBJECT_LIST ACPI_BUFFER *ReturnObjectBuffer ACPI_DEVICE_INFO **ReturnBuffer ACPI_HANDLE ACPI_HANDLE ACPI_HANDLE *OutHandle ACPI_HANDLE *OutHandle void *Context void *Context ACPI_EVENT_HANDLER Handler UINT32 UINT32 ACPI_GPE_HANDLER void *Context UINT32 ACPI_NOTIFY_HANDLER void *Context ACPI_ADR_SPACE_TYPE ACPI_ADR_SPACE_HANDLER ACPI_ADR_SPACE_SETUP Setup
Definition: acpixf.h:834
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
BOOL Error
Definition: chkdsk.c:66
DECLSPEC_NORETURN VOID NTAPI KeBugCheckEx(IN ULONG BugCheckCode, IN ULONG_PTR BugCheckParameter1, IN ULONG_PTR BugCheckParameter2, IN ULONG_PTR BugCheckParameter3, IN ULONG_PTR BugCheckParameter4)
Definition: debug.c:485
#define ARRAYSIZE(a)
Definition: cat.c:25
_In_ CDROM_SCAN_FOR_SPECIAL_INFO _In_ PCDROM_SCAN_FOR_SPECIAL_HANDLER Function
Definition: cdrom.h:1156
BOOLEAN NTAPI UcxAnyUsbdHandleHasVerifier(_In_ UcxUsbDevice *Device)
Definition: clientif.cpp:646
NTSTATUS NTAPI UcxCompleteUrb(_In_ PIRP Irp, _In_ PURB Urb, _In_ NTSTATUS Status, _In_ USBD_STATUS UsbdStatus)
Definition: clientxrb.cpp:23
FORCEINLINE VOID NTAPI UcxXrbMarkInactive(_In_ PURB Urb)
Definition: clientxrb.h:90
FORCEINLINE BOOLEAN NTAPI UcxIsXrbIrp(_In_ PIRP Irp, _In_ PURB Urb)
Definition: clientxrb.h:79
#define STATUS_NOT_SUPPORTED
Definition: d3dkmdt.h:48
#define Code
Definition: deflate.h:80
BOOLEAN Valid
Definition: desccheck.cpp:2227
PLIST_ENTRY Entry
Definition: devhcd.cpp:1262
_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID _In_ ULONG _In_ ULONG Flags
Definition: dispmprt.h:245
#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 PAGE_SIZE
Definition: env_spec_w32.h:49
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
FP_OP Operation
Definition: fpcontrol.c:150
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
ULONG Handle
Definition: gdb_input.c:15
Status
Definition: gdiplustypes.h:24
_Must_inspect_result_ _In_ PUCXHUB_DEVICE_CREATE_INFO _Out_ UCXUSBDEVICE * Device
Definition: hubucx.h:258
#define UCXHUB_URB_FLAG_ALLOW_LARGE_TRANSFER
Definition: hubucx.h:101
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define C_ASSERT(e)
Definition: intsafe.h:73
NTSTATUS NTAPI IoSetCompletionRoutineEx(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context, IN BOOLEAN InvokeOnSuccess, IN BOOLEAN InvokeOnError, IN BOOLEAN InvokeOnCancel)
Definition: iocomp.c:220
IoMarkIrpPending(Irp)
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
BOOLEAN NTAPI KdRefreshDebuggerNotPresent(VOID)
Definition: kdapi.c:2679
_In_ PIRP Irp
Definition: kse.h:79
_In_ PIRP _In_ PIO_COMPLETION_ROUTINE _In_ PVOID Context
Definition: kse.h:81
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:928
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1432
#define KernelMode
Definition: asm.h:38
#define _In_reads_bytes_(s)
Definition: no_sal2.h:170
#define _Inout_
Definition: no_sal2.h:162
#define _Outptr_
Definition: no_sal2.h:262
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
#define _In_
Definition: no_sal2.h:158
#define _Out_writes_bytes_(s)
Definition: no_sal2.h:178
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define IoCopyCurrentIrpStackLocationToNext(Irp)
Definition: ntifs_ex.h:413
unsigned short USHORT
Definition: pedump.c:61
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:204
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:104
#define _SEH2_END
Definition: pseh2_64.h:194
#define _SEH2_TRY
Definition: pseh2_64.h:93
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
Definition: pipe.h:30
static UcxPipe * FromHandle(_In_ USBD_PIPE_HANDLE Handle)
Definition: pipe.h:53
UcxUrbHandler Handler
Definition: urbroute.cpp:177
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
PMDL TransferBufferMDL
Definition: usb.h:484
struct _URB * UrbLink
Definition: usb.h:485
USBD_PIPE_HANDLE PipeHandle
Definition: usb.h:480
ULONG TransferFlags
Definition: usb.h:481
ULONG TransferBufferLength
Definition: usb.h:482
PVOID TransferBuffer
Definition: usb.h:483
Definition: usb.h:565
#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
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_ WDFREQUEST Request
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
NTSTATUS NTAPI UcxUsbdStatusToNtStatus(_In_ USBD_STATUS UsbdStatus)
Definition: urbroute.cpp:18
#define UCX_URB_NO_DATA
Definition: urbroute.cpp:167
NTSTATUS NTAPI UcxProcessLegacyUrb(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PURB Urb)
Definition: urbroute.cpp:760
static VOID NTAPI UcxSetCompletionOnNext(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PIO_COMPLETION_ROUTINE Completion, _In_ PVOID Context)
Definition: urbroute.cpp:280
#define UCX_URB_PIPE_REQUEST
Definition: urbroute.cpp:168
#define UCX_STATUS(To)
Definition: urbroute.cpp:208
USBD_STATUS NTAPI UcxNtStatusToUsbdStatus(_In_ NTSTATUS Status)
Definition: urbroute.cpp:53
NTSTATUS NTAPI UcxForwardIrpToQueue(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PIO_COMPLETION_ROUTINE Completion, _In_ PVOID Context, _In_ WDFQUEUE Queue)
Definition: urbroute.cpp:308
#define UCX_URB_DEFAULT_PIPE
Definition: urbroute.cpp:166
static USBD_STATUS NTAPI UcxPrepareTransfer(_In_ PURB Urb, _In_ UcxUsbDevice *Device, _In_ const UcxUrbFunction *Function, _Outptr_ UcxPipe **TargetPipe)
Definition: urbroute.cpp:680
#define UCX_TO_ENDPOINT
Definition: urbroute.cpp:192
#define UCX_RT_VENDOR
Definition: urbroute.cpp:188
BOOLEAN NTAPI UcxValidatePipeHandle(_In_ UcxUsbDevice *Device, _In_ USBD_PIPE_HANDLE Handle)
Definition: urbroute.cpp:356
#define UCX_TO_DEVICE
Definition: urbroute.cpp:190
static NTSTATUS NTAPI UcxForwardDefaultPipeRequest(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PURB Urb, _In_ WDFQUEUE Queue)
Definition: urbroute.cpp:476
#define UCX_TO_INTERFACE
Definition: urbroute.cpp:191
#define UCX_UNSUPPORTED(Length)
Definition: urbroute.cpp:204
#define UCX_DESCRIPTOR_SIZE
Definition: urbroute.cpp:196
VOID NTAPI UcxUnlockTransferBuffer(_Inout_ PURB Urb)
Definition: urbroute.cpp:130
#define UCX_STD_TRANSFER
Definition: urbroute.cpp:201
static NTSTATUS NTAPI UcxHandleStandardRequest(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PURB Urb, _In_ WDFQUEUE Queue, _In_ const UcxUrbFunction *Function)
Definition: urbroute.cpp:492
static NTSTATUS NTAPI UcxHandleGetCurrentFrame(_In_ PIRP Irp, _In_ PURB Urb, _In_ UcxUsbDevice *Device)
Definition: urbroute.cpp:619
#define UCX_DIR_IN
Definition: urbroute.cpp:172
static BOOLEAN NTAPI UcxChainedMdlMisaligned(_In_ PMDL Mdl, _In_ ULONG Length)
Definition: urbroute.cpp:399
static NTSTATUS NTAPI UcxHandleIsoch(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PURB Urb, _In_ WDFQUEUE Queue, _In_ UcxPipe *Pipe)
Definition: urbroute.cpp:574
#define UCX_TO_OTHER
Definition: urbroute.cpp:193
NTSTATUS NTAPI UcxForwardIrpWithRequest(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PIO_COMPLETION_ROUTINE Completion, _In_ PVOID Context, _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request)
Definition: urbroute.cpp:323
static IO_COMPLETION_ROUTINE UcxLegacyTransferCompletion
Definition: urbroute.cpp:272
#define UCX_INVALID
Definition: urbroute.cpp:205
static VOID NTAPI UcxSetWord(_Out_writes_bytes_(2) PUCHAR Where, _In_ USHORT Value)
Definition: urbroute.cpp:455
static USBD_STATUS NTAPI UcxCheckTransferAgainstPipe(_In_ PURB Urb, _In_ const UcxPipe *Pipe)
Definition: urbroute.cpp:642
static USHORT NTAPI UcxGetWord(_In_reads_bytes_(2) const UCHAR *Where)
Definition: urbroute.cpp:466
VOID NTAPI UcxLockTransferBuffer(_Inout_ PURB Urb)
Definition: urbroute.cpp:82
#define UCX_URB_TRANSFER
Definition: urbroute.cpp:165
static UCHAR NTAPI UcxRequestType(_In_ UCHAR Direction, _In_ UCHAR Type, _In_ UCHAR Recipient)
Definition: urbroute.cpp:444
static const UcxUrbFunction UcxUrbFunctions[]
Definition: urbroute.cpp:211
static PUCHAR NTAPI UcxSetupPacket(_In_ PURB Urb)
Definition: urbroute.cpp:435
#define UCX_RT_STANDARD
Definition: urbroute.cpp:186
UcxUrbHandler
Definition: urbroute.cpp:147
#define UCX_DESCRIPTOR(Dir, To, Req)
Definition: urbroute.cpp:206
#define UCX_DIR_OUT
Definition: urbroute.cpp:171
#define UCX_PIPE_REQUEST_SIZE
Definition: urbroute.cpp:195
#define UCX_RT_CLASS
Definition: urbroute.cpp:187
#define UCX_FEATURE(To, Req)
Definition: urbroute.cpp:207
#define UCX_VENDOR_CLASS(Type, To)
Definition: urbroute.cpp:209
FORCEINLINE VOID NTAPI UcxSetTransferDirection(_Inout_ PURB Urb, _In_ const UcxPipe *Pipe)
Definition: urbroute.h:48
#define UCX_MAX_CONTROL_TRANSFER
Definition: urbroute.h:17
FORCEINLINE VOID NTAPI UcxStampProcessorNumber(_Inout_ PURB Urb)
Definition: urbroute.h:32
#define UCX_URB_FLAG_BUFFER_LOCKED
Definition: urbroute.h:14
#define UCX_URB_FLAGS_KEEP_HUB_BITS
Definition: urbroute.h:11
#define USB_REQUEST_GET_INTERFACE
Definition: usb100.h:86
#define USB_REQUEST_GET_CONFIGURATION
Definition: usb100.h:84
#define USB_REQUEST_GET_DESCRIPTOR
Definition: usb100.h:82
#define USB_REQUEST_SET_DESCRIPTOR
Definition: usb100.h:83
#define USB_REQUEST_SET_FEATURE
Definition: usb100.h:80
#define USB_REQUEST_CLEAR_FEATURE
Definition: usb100.h:79
#define USBD_STATUS_DEVICE_GONE
Definition: usb.h:222
struct _URB * PURB
#define USBD_STATUS_INVALID_PIPE_HANDLE
Definition: usb.h:205
#define USBD_STATUS_CANCELED
Definition: usb.h:225
#define USBD_STATUS_SUCCESS
Definition: usb.h:177
#define USBD_TRANSFER_DIRECTION_IN
Definition: usb.h:167
#define URB_FUNCTION_CONTROL_TRANSFER
Definition: usb.h:94
#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
#define USBD_SHORT_TRANSFER_OK
Definition: usb.h:161
#define USBD_STATUS_PORT_OPERATION_PENDING
Definition: usb.h:178
#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Definition: usb.h:95
#define USBD_SUCCESS(Status)
Definition: usb.h:174
LONG USBD_STATUS
Definition: usb.h:172
#define USBD_STATUS_PENDING
Definition: usb.h:179
#define USBD_DEFAULT_PIPE_TRANSFER
Definition: usb.h:163
#define USBD_STATUS_INVALID_URB_FUNCTION
Definition: usb.h:202
#define USBD_STATUS_BAD_START_FRAME
Definition: usb.h:209
#define URB_FUNCTION_ISOCH_TRANSFER
Definition: usb.h:96
_In_opt_ PUSB_CONFIGURATION_DESCRIPTOR _Inout_ PUSBD_INTERFACE_LIST_ENTRY _Outptr_ PURB * Urb
Definition: usbdlib.h:333
_In_ WDFCOLLECTION _In_ ULONG Index
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
@ WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP
Definition: wdfdevice.h:437
_Must_inspect_result_ _In_ WDFDEVICE _In_ PIRP _In_ WDFQUEUE Queue
Definition: wdfdevice.h:2231
_In_ PWDFDEVICE_INIT _In_ PWDF_REMOVE_LOCK_OPTIONS Options
Definition: wdfdevice.h:3540
_In_ UCHAR _In_ UCHAR _In_ ULONG Code
Definition: wdfdevice.h:1707
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
WDF_EXTERN_C_START typedef _In_ WDFDEVICE _In_ WDFCONTEXT _In_ WDF_DMA_DIRECTION Direction
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
FORCEINLINE VOID WDF_REQUEST_FORWARD_OPTIONS_INIT(_Out_ PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions)
Definition: wdfrequest.h:453
#define STATUS_WDF_BUSY
Definition: wdfstatus.h:126
_In_ NTSTATUS _In_ USBD_STATUS UsbdStatus
Definition: wdfusb.h:403
_In_ WDFUSBPIPE Pipe
Definition: wdfusb.h:1741
NTSYSAPI void WINAPI DbgBreakPoint(void)
FORCEINLINE VOID IoSetNextIrpStackLocation(_Inout_ PIRP Irp)
Definition: iofuncs.h:2706
#define STATUS_CONTINUE_COMPLETION
IO_COMPLETION_ROUTINE * PIO_COMPLETION_ROUTINE
Definition: iotypes.h:2850
enum _LOCK_OPERATION LOCK_OPERATION
@ IoReadAccess
Definition: ketypes.h:931
@ IoWriteAccess
Definition: ketypes.h:932
#define MmGetMdlByteOffset(_Mdl)
#define MmGetMdlByteCount(_Mdl)
#define NT_ASSERT
Definition: rtlfuncs.h:3334