ReactOS 0.4.17-dev-1281-g065abb3
clientxrb.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: XRB submission, the fast transfer path and URB completion helpers
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8#include "ucx01000.h"
9
10#define NDEBUG
11#include <debug.h>
12
13/* KMDF 1.11 reuse flag; the ReactOS wdfrequest.h does not list it yet */
14#define UCX_REQUEST_REUSE_MUST_COMPLETE 0x00000002
15
16static IO_COMPLETION_ROUTINE UcxXrbTransferCompletion;
17static IO_COMPLETION_ROUTINE UcxXrbStreamsCompletion;
18
19/* Completion helpers */
20
28{
29 if (UcxIsXrbIrp(Irp, Urb))
31
32 Urb->UrbHeader.Status = UsbdStatus;
33 Irp->IoStatus.Status = Status;
34 Irp->IoStatus.Information = 0;
36
37 return Status;
38}
39
40VOID
47{
48 if (UcxIsXrbIrp(Irp, Urb))
49 {
51 return;
52 }
53
56}
57
58/* By now the current location is the root hub PDO's again, so the XRB test works */
59VOID
63{
65
66 if (UcxIsXrbIrp(Irp, Urb))
68
70}
71
72/* Submission */
73
75static
76VOID
81{
83
84 if (Xrb->Signature != UCX_XRB_SIGNATURE)
85 {
86 DPRINT1("IRP %p submitted corrupted XRB for URB %p\n", Irp, Urb);
92 }
93
94 if (Xrb->State != UCX_XRB_IDLE)
95 {
96 DPRINT1("IRP %p resubmitted URB %p while it is still active\n", Irp, Urb);
100 (ULONG_PTR)Urb,
102 }
103
105}
106
107/* Clients on the 0x602 contract skip every legacy check */
108static
110NTAPI
112 _In_ WDFDEVICE RootHubPdo,
113 _In_ PIRP Irp,
114 _In_ PURB Urb)
115{
117 UcxPipe* Pipe;
119
120 Urb->UrbHeader.Status = USBD_STATUS_PENDING;
121
122 Pipe = UcxPipe::FromHandle(Urb->UrbBulkOrInterruptTransfer.PipeHandle);
126
127 if (Xrb->Request == NULL)
128 return UcxForwardIrpToQueue(RootHubPdo, Irp, UcxXrbTransferCompletion, Urb, Pipe->Queue);
129
130 /* The preallocated request saves a KMDF allocation per transfer */
133 WdfRequestReuse(Xrb->Request, &Reuse);
134
135 return UcxForwardIrpWithRequest(RootHubPdo, Irp, UcxXrbTransferCompletion, Urb, Pipe->Queue, Xrb->Request);
136}
137
138static
140NTAPI
142 _In_ WDFDEVICE RootHubPdo,
143 _In_ PIRP Irp,
144 _In_ PURB Urb)
145{
147
148 if (!Handle->m_ChainedMdlGranted)
149 {
150 DPRINT1("Chained MDL URB %p from handle %p without the capability\n", Urb, Handle);
151
152 if (Handle->m_VerifierEnabled)
153 {
156 (ULONG_PTR)Irp,
157 (ULONG_PTR)Urb,
158 (ULONG_PTR)Handle->m_ClientDeviceObject);
159 }
160
162 }
163
164 return UcxXrbSubmitTransfer(RootHubPdo, Irp, Urb);
165}
166
168NTAPI
170 _In_ WDFDEVICE RootHubPdo,
171 _In_ PIRP Irp)
172{
174
175 if (!UcxIsXrbIrp(Irp, Urb))
176 return UcxProcessLegacyUrb(RootHubPdo, Irp, Urb);
177
179
180 /* Older contracts take the legacy path; its completions reset the state */
181 if (UcxXrbFromUrb(Urb)->ContractVersion < USBD_CLIENT_CONTRACT_VERSION_602)
182 return UcxProcessLegacyUrb(RootHubPdo, Irp, Urb);
183
184 switch (Urb->UrbHeader.Function)
185 {
188 return UcxXrbSubmitTransfer(RootHubPdo, Irp, Urb);
189
192 return UcxXrbSubmitChainedMdlTransfer(RootHubPdo, Irp, Urb);
193
195 return UcxEndpoint::FromPipe(Urb->UrbOpenStaticStreams.PipeHandle)->OpenStaticStreams(Irp, Urb);
196
197 /* The pipe handle sits at the same offset in both stream URBs */
199 return UcxEndpoint::FromPipe(Urb->UrbOpenStaticStreams.PipeHandle)->CloseStaticStreams(Irp, Urb);
200
201 /* Only XRBs reach this; a plain URB with this function is invalid */
203 return UcxEndpoint::FromPipe(Urb->UrbGetIsochPipeTransferPathDelays.PipeHandle)->GetIsochPathDelays(Irp, Urb);
204
205 default:
206 return UcxProcessLegacyUrb(RootHubPdo, Irp, Urb);
207 }
208}
209
211NTAPI
213 _In_ WDFDEVICE RootHubPdo,
214 _In_ PIRP Irp,
215 _In_ PURB Urb,
217{
218 Urb->UrbHeader.Status = USBD_STATUS_PENDING;
219
220 return UcxForwardIrpToQueue(RootHubPdo, Irp, UcxXrbStreamsCompletion, Urb, Controller->m_DeviceMgmtQueue);
221}
222
223/* Completions */
224
226static
227VOID
228NTAPI
233{
234 if (Device->m_Disconnected)
235 {
236 Urb->UrbHeader.Status = USBD_STATUS_DEVICE_GONE;
237 Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
238 }
239 else
240 {
241 Urb->UrbHeader.Status = USBD_STATUS_CANCELED;
242 }
243}
244
245static
247NTAPI
250 _In_ PIRP Irp,
251 _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
252{
253 PURB Urb = (PURB)Context;
254 UcxUsbDevice* Device = UcxUsbDevice::FromHandle((UCXUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle);
255 ULONG Index;
256
258
259 if (Urb->UrbHeader.Status == USBD_STATUS_PENDING)
260 {
261 DPRINT("XRB URB %p function 0x%x canceled before reaching the HCD\n", Urb, Urb->UrbHeader.Function);
262 Device->m_TransferFailureCount++;
263 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = 0;
265
266 /* Only the plain isoch function; the chained MDL one keeps its packets */
267 if (!Device->m_Disconnected && Urb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER)
268 {
269 for (Index = 0; Index < Urb->UrbIsochronousTransfer.NumberOfPackets; Index++)
270 Urb->UrbIsochronousTransfer.IsoPacket[Index].Status = 0xFFFFFFFF;
271 Urb->UrbIsochronousTransfer.ErrorCount = 0;
272 }
273 }
274 else
275 {
276 if (!USBD_SUCCESS(Urb->UrbHeader.Status))
277 {
278 DPRINT("XRB URB %p function 0x%x on device %p failed, USBD status 0x%lx\n",
279 Urb, Urb->UrbHeader.Function, Device, Urb->UrbHeader.Status);
280 Device->m_TransferFailureCount++;
281 Device->ReportNoPingResponseIfPending();
282 }
283
284 /* The URB status always wins on this path */
285 Irp->IoStatus.Status = UcxUsbdStatusToNtStatus(Urb->UrbHeader.Status);
286 }
287
288 if (Irp->PendingReturned)
290
294}
295
296static
298NTAPI
301 _In_ PIRP Irp,
302 _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
303{
304 PURB Urb = (PURB)Context;
305 UcxUsbDevice* Device = UcxUsbDevice::FromHandle((UCXUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle);
307
309
310 if (Urb->UrbHeader.Status == USBD_STATUS_PENDING)
311 {
312 DPRINT1("Streams URB %p function 0x%x never reached the HCD\n", Urb, Urb->UrbHeader.Function);
314 }
315 else
316 {
317 if (!USBD_SUCCESS(Urb->UrbHeader.Status))
318 {
319 DPRINT1("Streams URB %p function 0x%x failed, USBD status 0x%lx\n",
320 Urb, Urb->UrbHeader.Function, Urb->UrbHeader.Status);
321 }
322
323 Irp->IoStatus.Status = UcxUsbdStatusToNtStatus(Urb->UrbHeader.Status);
324 }
325
326 if (Irp->PendingReturned)
328
329 Endpoint = UcxEndpoint::FromPipe(Urb->UrbOpenStaticStreams.PipeHandle);
330
331 switch (Urb->UrbHeader.Function)
332 {
334 return Endpoint->OpenStaticStreamsComplete(Irp, Urb);
335
337 return Endpoint->CloseStaticStreamsComplete(Irp);
338
339 default:
342 }
343}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
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
NTSTATUS GetIsochPathDelays(_In_ PIRP Irp, _In_ PURB Urb)
Definition: pipeio.cpp:59
NTSTATUS CloseStaticStreams(_In_ PIRP Irp, _In_ PURB Urb)
Definition: pipeio.cpp:267
NTSTATUS OpenStaticStreams(_In_ PIRP Irp, _In_ PURB Urb)
Definition: pipeio.cpp:171
PDEVICE_OBJECT m_ClientDeviceObject
Definition: clientif.h:50
NTSTATUS NTAPI UcxForwardStreamsUrb(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PURB Urb, _In_ UcxController *Controller)
Definition: clientxrb.cpp:212
VOID NTAPI UcxCompleteHeldUrbIrp(_In_ PIRP Irp)
Definition: clientxrb.cpp:61
NTSTATUS NTAPI UcxProcessSubmitUrb(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp)
Definition: clientxrb.cpp:169
static NTSTATUS NTAPI UcxXrbSubmitTransfer(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PURB Urb)
Definition: clientxrb.cpp:111
static NTSTATUS NTAPI UcxXrbSubmitChainedMdlTransfer(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PURB Urb)
Definition: clientxrb.cpp:141
static VOID NTAPI UcxXrbCheckOnSubmit(_In_ PIRP Irp, _In_ PURB Urb)
Definition: clientxrb.cpp:78
static VOID NTAPI UcxXrbFixUnprocessed(_Inout_ PIRP Irp, _Inout_ PURB Urb, _In_ UcxUsbDevice *Device)
Definition: clientxrb.cpp:229
#define UCX_REQUEST_REUSE_MUST_COMPLETE
Definition: clientxrb.cpp:14
NTSTATUS NTAPI UcxCompleteUrb(_In_ PIRP Irp, _In_ PURB Urb, _In_ NTSTATUS Status, _In_ USBD_STATUS UsbdStatus)
Definition: clientxrb.cpp:23
static IO_COMPLETION_ROUTINE UcxXrbStreamsCompletion
Definition: clientxrb.cpp:17
static IO_COMPLETION_ROUTINE UcxXrbTransferCompletion
Definition: clientxrb.cpp:16
VOID NTAPI UcxCompleteUrbAtDispatch(_In_ PIRP Irp, _In_ PURB Urb, _In_ NTSTATUS Status, _In_ USBD_STATUS UsbdStatus)
Definition: clientxrb.cpp:42
#define UCX_XRB_SIGNATURE
Definition: clientxrb.h:11
FORCEINLINE VOID NTAPI UcxXrbMarkInactive(_In_ PURB Urb)
Definition: clientxrb.h:90
FORCEINLINE UcxXrbPreamble *NTAPI UcxXrbFromUrb(_In_ PURB Urb)
Definition: clientxrb.h:60
#define UCX_USB3_ACTIVE_URB_REUSED
Definition: clientxrb.h:23
#define UCX_USB3_CHAINED_MDL
Definition: clientxrb.h:30
FORCEINLINE BOOLEAN NTAPI UcxIsXrbIrp(_In_ PIRP Irp, _In_ PURB Urb)
Definition: clientxrb.h:79
#define UCX_BUGCHECK_USB3
Definition: clientxrb.h:22
#define UCX_USB3_XRB_CORRUPTED
Definition: clientxrb.h:24
#define UCX_XRB_IN_FLIGHT
Definition: clientxrb.h:19
#define UCX_XRB_IDLE
Definition: clientxrb.h:18
#define NULL
Definition: types.h:112
return pRequest Reuse(ReuseParams)
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
_In_ UCXHUB_DEVICE_CONTEXT _In_ UCXENDPOINT Endpoint
Definition: hubucx.h:238
IoMarkIrpPending(Irp)
_In_ PIRP Irp
Definition: kse.h:79
_In_ PIRP _In_ PIO_COMPLETION_ROUTINE _In_ PVOID Context
Definition: kse.h:81
#define _Inout_
Definition: no_sal2.h:162
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
#define _In_
Definition: no_sal2.h:158
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
#define IoCompleteRequest
Definition: irp.c:1272
#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
ULONG Signature
Definition: clientxrb.h:47
WDFREQUEST Request
Definition: clientxrb.h:41
UcxUsbdHandle * Handle
Definition: clientxrb.h:39
struct _IO_STACK_LOCATION::@5100::@5139 Others
union _IO_STACK_LOCATION::@1823 Parameters
Definition: usb.h:565
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE _In_ PUCX_CONTROLLER_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ UCXCONTROLLER * Controller
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
NTSTATUS NTAPI UcxUsbdStatusToNtStatus(_In_ USBD_STATUS UsbdStatus)
Definition: urbroute.cpp:18
NTSTATUS NTAPI UcxProcessLegacyUrb(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PURB Urb)
Definition: urbroute.cpp:760
NTSTATUS NTAPI UcxForwardIrpToQueue(_In_ WDFDEVICE RootHubPdo, _In_ PIRP Irp, _In_ PIO_COMPLETION_ROUTINE Completion, _In_ PVOID Context, _In_ WDFQUEUE Queue)
Definition: urbroute.cpp:308
VOID NTAPI UcxUnlockTransferBuffer(_Inout_ PURB Urb)
Definition: urbroute.cpp:130
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
VOID NTAPI UcxLockTransferBuffer(_Inout_ PURB Urb)
Definition: urbroute.cpp:82
FORCEINLINE VOID NTAPI UcxSetTransferDirection(_Inout_ PURB Urb, _In_ const UcxPipe *Pipe)
Definition: urbroute.h:48
FORCEINLINE VOID NTAPI UcxStampProcessorNumber(_Inout_ PURB Urb)
Definition: urbroute.h:32
#define URB_FUNCTION_ISOCH_TRANSFER_USING_CHAINED_MDL
Definition: usb.h:155
#define USBD_STATUS_DEVICE_GONE
Definition: usb.h:222
struct _URB * PURB
#define URB_FUNCTION_GET_ISOCH_PIPE_TRANSFER_PATH_DELAYS
Definition: usb.h:156
#define USBD_STATUS_CANCELED
Definition: usb.h:225
#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER_USING_CHAINED_MDL
Definition: usb.h:154
#define USBD_STATUS_INVALID_PARAMETER
Definition: usb.h:203
#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 URB_FUNCTION_OPEN_STATIC_STREAMS
Definition: usb.h:152
#define URB_FUNCTION_CLOSE_STATIC_STREAMS
Definition: usb.h:153
#define URB_FUNCTION_ISOCH_TRANSFER
Definition: usb.h:96
#define USBD_CLIENT_CONTRACT_VERSION_602
Definition: usbdlib.h:100
_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
FORCEINLINE VOID WDF_REQUEST_REUSE_PARAMS_SET_NEW_IRP(_Inout_ PWDF_REQUEST_REUSE_PARAMS Params, _In_ PIRP NewIrp)
Definition: wdfrequest.h:379
@ WDF_REQUEST_REUSE_SET_NEW_IRP
Definition: wdfrequest.h:93
FORCEINLINE VOID WDF_REQUEST_REUSE_PARAMS_INIT(_Out_ PWDF_REQUEST_REUSE_PARAMS Params, _In_ ULONG Flags, _In_ NTSTATUS Status)
Definition: wdfrequest.h:364
_In_ NTSTATUS _In_ USBD_STATUS UsbdStatus
Definition: wdfusb.h:403
_In_ WDFUSBPIPE Pipe
Definition: wdfusb.h:1741
#define STATUS_CONTINUE_COMPLETION
#define IO_NO_INCREMENT
Definition: iotypes.h:598