1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxIoTargetAPI.cpp
8 
9 Abstract:
10 
11     This module implements the IO Target APIs
12 
13 Author:
14 
15 Environment:
16 
17     kernel mode only
18 
19 Revision History:
20 
21 --*/
22 
23 #include "../fxtargetsshared.hpp"
24 
25 extern "C" {
26 // #include "FxIoTargetAPI.tmh"
27 }
28 
29 //
30 // Extern the entire file
31 //
32 extern "C" {
33 
34 _Must_inspect_result_
35 __drv_maxIRQL(DISPATCH_LEVEL)
36 NTSTATUS
37 STDCALL
38 WDFEXPORT(WdfIoTargetStart)(
39     __in
40     PWDF_DRIVER_GLOBALS DriverGlobals,
41     __in
42     WDFIOTARGET IoTarget
43     )
44 /*++
45 
46 Routine Description:
47     Changes the target's state to started.  In the started state, the target
48     can send I/O.
49 
50 Arguments:
51     IoTarget - the target whose state will change
52 
53 Return Value:
54     NTSTATUS
55 
56   --*/
57 {
58     DDI_ENTRY();
59 
60     FxIoTarget* pTarget;
61 
62     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
63                          IoTarget,
64                          FX_TYPE_IO_TARGET,
65                          (PVOID*) &pTarget);
66 
67     return pTarget->Start();
68 }
69 
70 __drv_when(Action == 3, __drv_maxIRQL(DISPATCH_LEVEL))
71 __drv_when(Action == 0 || Action == 1 || Action == 2, __drv_maxIRQL(PASSIVE_LEVEL))
72 VOID
73 STDCALL
74 WDFEXPORT(WdfIoTargetStop)(
75     __in
76     PWDF_DRIVER_GLOBALS DriverGlobals,
77     __in
78     WDFIOTARGET IoTarget,
79     __in
80     __drv_strictTypeMatch(__drv_typeConst)
81     WDF_IO_TARGET_SENT_IO_ACTION Action
82     )
83 /*++
84 
85 Routine Description:
86     This function puts the target into the stopped state.  Depending on the value
87     of Action, this function may not return until sent I/O has been canceled and/or
88     completed.
89 
90 Arguments:
91     IoTarget - the target whose state is being changed
92 
93     Action - what to do with the I/O that is pending in the target already
94 
95 Return Value:
96     None
97 
98   --*/
99 {
100     DDI_ENTRY();
101 
102     PFX_DRIVER_GLOBALS pFxDriverGlobals;
103     FxIoTarget* pTarget;
104     NTSTATUS status;
105 
106     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
107                                    IoTarget,
108                                    FX_TYPE_IO_TARGET,
109                                    (PVOID*) &pTarget,
110                                    &pFxDriverGlobals);
111 
112     if (Action == WdfIoTargetSentIoUndefined ||
113         Action > WdfIoTargetLeaveSentIoPending) {
114         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
115                             "Action %d undefined or out of range", Action);
116         return;
117     }
118 
119     if (Action == WdfIoTargetCancelSentIo ||
120         Action == WdfIoTargetWaitForSentIoToComplete) {
121         status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
122         if (!NT_SUCCESS(status)) {
123             return;
124         }
125     }
126 
127     pTarget->Stop(Action);
128 }
129 
130 __drv_when(Action == 2, __drv_maxIRQL(DISPATCH_LEVEL))
131 __drv_when(Action == 0 || Action == 1, __drv_maxIRQL(PASSIVE_LEVEL))
132 VOID
133 STDCALL
134 WDFEXPORT(WdfIoTargetPurge)(
135     __in
136     PWDF_DRIVER_GLOBALS DriverGlobals,
137     __in
138     WDFIOTARGET IoTarget,
139     __in
140     __drv_strictTypeMatch(__drv_typeConst)
141     WDF_IO_TARGET_PURGE_IO_ACTION Action
142     )
143 /*++
144 
145 Routine Description:
146     This function puts the target into the purged state.  Depending on the value
147     of Action, this function may not return until pending and sent I/O has been
148     canceled and completed.
149 
150 Arguments:
151     IoTarget - the target whose state is being changed
152 
153     Action - purge action: wait or not for I/O to complete after doing the purge.
154 
155 Return Value:
156     None
157 
158   --*/
159 {
160     DDI_ENTRY();
161 
162     PFX_DRIVER_GLOBALS pFxDriverGlobals;
163     FxIoTarget* pTarget;
164     NTSTATUS status;
165 
166     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
167                                    IoTarget,
168                                    FX_TYPE_IO_TARGET,
169                                    (PVOID*) &pTarget,
170                                    &pFxDriverGlobals);
171 
172     if (Action == WdfIoTargetPurgeIoUndefined ||
173         Action > WdfIoTargetPurgeIo) {
174         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
175                             "Action %d undefined or out of range", Action);
176         return;
177     }
178 
179     if (Action == WdfIoTargetPurgeIoAndWait) {
180         status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
181         if (!NT_SUCCESS(status)) {
182             return;
183         }
184     }
185 
186     pTarget->Purge(Action);
187 }
188 
189 __drv_maxIRQL(DISPATCH_LEVEL)
190 WDF_IO_TARGET_STATE
191 STDCALL
192 WDFEXPORT(WdfIoTargetGetState)(
193     __in
194     PWDF_DRIVER_GLOBALS DriverGlobals,
195     __in
196     WDFIOTARGET IoTarget
197     )
198 /*++
199 
200 Routine Description:
201     Returns the current state of the target
202 
203 Arguments:
204     IoTarget - target whose state is being returned
205 
206 Return Value:
207     current target state
208 
209   --*/
210 {
211     DDI_ENTRY();
212 
213     FxIoTarget* pTarget;
214 
215     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
216                          IoTarget,
217                          FX_TYPE_IO_TARGET,
218                          (PVOID*) &pTarget);
219 
220     return pTarget->GetState();
221 }
222 
223 _Must_inspect_result_
224 NTSTATUS
225 FxIoTargetValidateOpenParams(
226     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
227     __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams
228     )
229 /*++
230 
231 Routine Description:
232     Validates the target open parameters structure.
233 
234 Arguments:
235     FxDriverGlobals - driver globals
236 
237     OpenParams - the structure to validate
238 
239 Return Value:
240     NTSTATUS
241 
242   --*/
243 
244 {
245     NTSTATUS status;
246 
247     //
248     // Check specific fields based on Type
249     //
250     switch (OpenParams->Type) {
251     case WdfIoTargetOpenUseExistingDevice:
252         if (OpenParams->TargetDeviceObject == NULL) {
253             status = STATUS_INVALID_PARAMETER;
254             DoTraceLevelMessage(
255                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
256                 "Expected non NULL TargetDeviceObject in OpenParams, %!STATUS!",
257                 status);
258             return status;
259         }
260 
261         //
262         // This type is supported only in KMDF.
263         //
264         if (FxDriverGlobals->IsUserModeDriver) {
265             status = STATUS_INVALID_PARAMETER;
266             DoTraceLevelMessage(
267                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
268                 "The open type WdfIoTargetOpenUseExistingDevice is not "
269                 "supported in UMDF drivers. It is supported in KMDF "
270                 "drivers only, %!STATUS!",
271                 status);
272             return status;
273         }
274 
275         if (OpenParams->TargetFileObject == NULL &&
276             (OpenParams->EvtIoTargetQueryRemove != NULL ||
277              OpenParams->EvtIoTargetRemoveCanceled != NULL ||
278              OpenParams->EvtIoTargetRemoveComplete != NULL)) {
279             status = STATUS_INVALID_PARAMETER;
280 
281             DoTraceLevelMessage(
282                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
283                 "OpenParams %p TargetFileObject is NULL but a state callback "
284                 "(query remove %p, remove canceled %p, remove complete %p)"
285                 " was specified, %!STATUS!",
286                 OpenParams, OpenParams->EvtIoTargetQueryRemove,
287                 OpenParams->EvtIoTargetRemoveCanceled,
288                 OpenParams->EvtIoTargetRemoveComplete, status);
289 
290             return status;
291         }
292         break;
293 
294     case WdfIoTargetOpenByName:
295         if (OpenParams->TargetDeviceName.Buffer == NULL ||
296             OpenParams->TargetDeviceName.Length == 0 ||
297             OpenParams->TargetDeviceName.MaximumLength == 0) {
298             status = STATUS_INVALID_PARAMETER;
299             DoTraceLevelMessage(
300                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
301                 "Expected valid OpenParams TargetDeviceName string, %!STATUS!",
302                 status);
303             return status;
304         }
305         break;
306 
307     case WdfIoTargetOpenLocalTargetByFile:
308         //
309         // This type is supported only in UMDF.
310         //
311         if (FxDriverGlobals->IsUserModeDriver == FALSE) {
312             status = STATUS_INVALID_PARAMETER;
313             DoTraceLevelMessage(
314                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
315                 "The open type WdfIoTargetOpenLocalTargetByFile is not "
316                 "supported in KMDF drivers. It is supported in UMDF "
317                 "drivers only, %!STATUS!",
318                 status);
319             return status;
320         }
321 
322         if ((OpenParams->EvtIoTargetQueryRemove != NULL ||
323              OpenParams->EvtIoTargetRemoveCanceled != NULL ||
324              OpenParams->EvtIoTargetRemoveComplete != NULL)) {
325             status = STATUS_INVALID_PARAMETER;
326 
327             DoTraceLevelMessage(
328                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
329                 "The open type is WdfIoTargetOpenLocalTargetByFile but a state"
330                 " callback (query remove %p, remove canceled %p, remove"
331                 " complete %p) was specified, %!STATUS!",
332                 OpenParams->EvtIoTargetQueryRemove,
333                 OpenParams->EvtIoTargetRemoveCanceled,
334                 OpenParams->EvtIoTargetRemoveComplete, status);
335 
336             return status;
337         }
338 
339         if (OpenParams->FileName.Buffer != NULL ||
340             OpenParams->FileName.Length != 0 ||
341             OpenParams->FileName.MaximumLength != 0) {
342             status = FxValidateUnicodeString(FxDriverGlobals,
343                                              &OpenParams->FileName);
344             if (!NT_SUCCESS(status)) {
345                 return status;
346             }
347         }
348 
349 
350         break;
351 
352     case WdfIoTargetOpenReopen:
353         break;
354 
355     default:
356         status = STATUS_INVALID_PARAMETER;
357         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
358                             "OpenParams Type (%d) incorrect, %!STATUS!",
359                             OpenParams->Type, status);
360 
361         return status;
362     }
363 
364     return STATUS_SUCCESS;
365 }
366 
367 
368 _Must_inspect_result_
369 __drv_maxIRQL(PASSIVE_LEVEL)
370 NTSTATUS
371 STDCALL
372 WDFEXPORT(WdfIoTargetCreate)(
373     __in
374     PWDF_DRIVER_GLOBALS DriverGlobals,
375     __in
376     WDFDEVICE Device,
377     __in_opt
378     PWDF_OBJECT_ATTRIBUTES IoTargetAttributes,
379     __out
380     WDFIOTARGET* IoTarget
381     )
382 /*++
383 
384 Routine Description:
385     Creates a WDFIOTARGET which can be opened upon success.
386 
387 Arguments:
388     Device - the device which will own the target.  The target will be parented
389              by the owning device
390 
391     IoTargetAttributes - optional attributes to apply to the target
392 
393     IoTarget - pointer which will receive the created target handle
394 
395 Return Value:
396     NTSTATUS
397 
398   --*/
399 {
400     DDI_ENTRY();
401 
402     PFX_DRIVER_GLOBALS pFxDriverGlobals;
403     FxIoTargetRemote* pTarget;
404     FxDeviceBase* pDevice;
405     NTSTATUS status;
406 
407     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
408                                    Device,
409                                    FX_TYPE_DEVICE_BASE,
410                                    (PWDFOBJECT) &pDevice,
411                                    &pFxDriverGlobals);
412 
413     FxPointerNotNull(pFxDriverGlobals, IoTarget);
414 
415     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
416                         "WDFDEVICE 0x%p", Device);
417 
418     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
419     if (!NT_SUCCESS(status)) {
420         return status;
421     }
422 
423     //
424     // Since the target is auto parented to the Device, we don't allow the client
425     // to specify a parent.
426     //
427     status = FxValidateObjectAttributes(pFxDriverGlobals, IoTargetAttributes);
428     if (!NT_SUCCESS(status)) {
429         return status;
430     }
431 
432     status = FxIoTargetRemote::_Create(
433         pFxDriverGlobals, IoTargetAttributes, pDevice, &pTarget);
434 
435     if (NT_SUCCESS(status)) {
436         *IoTarget = pTarget->GetHandle();
437     }
438 
439     return status;
440 }
441 
442 _Must_inspect_result_
443 __drv_maxIRQL(PASSIVE_LEVEL)
444 NTSTATUS
445 STDCALL
446 WDFEXPORT(WdfIoTargetOpen)(
447     __in
448     PWDF_DRIVER_GLOBALS DriverGlobals,
449     __in
450     WDFIOTARGET IoTarget,
451     __in
452     PWDF_IO_TARGET_OPEN_PARAMS OpenParams
453     )
454 /*++
455 
456 Routine Description:
457     Opens a target.  The target must be in the closed state for an open to
458     succeed.  Open is either wrapping an existing PDEVICE_OBJECT + PFILE_OBJECT
459     that the client provides or opening a PDEVICE_OBJECT by name.
460 
461 Arguments:
462     IoTarget - Target to be opened
463 
464     OpenParams - structure which describes how to open the target
465 
466 Return Value:
467     NTSTATUS
468 
469   --*/
470 {
471     //
472     // UMDF only, noop for KMDF.
473     // It's ok to be impersonated here, because it can be required in order for
474     // the CreateFile() call to succeed.
475     //
476     DDI_ENTRY_IMPERSONATION_OK();
477 
478     PFX_DRIVER_GLOBALS pFxDriverGlobals;
479     FxIoTargetRemote* pTarget;
480     NTSTATUS status;
481     ULONG expectedConfigSize;
482     WDF_IO_TARGET_OPEN_PARAMS openParams;
483 
484     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
485                                    IoTarget,
486                                    FX_TYPE_IO_TARGET_REMOTE,
487                                    (PVOID*) &pTarget,
488                                    &pFxDriverGlobals);
489 
490     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
491                         "enter WDFIOTARGET 0x%p", IoTarget);
492 
493     FxPointerNotNull(pFxDriverGlobals, OpenParams);
494 
495     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
496     if (!NT_SUCCESS(status)) {
497         return status;
498     }
499 
500     expectedConfigSize = pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13) ?
501                             sizeof(WDF_IO_TARGET_OPEN_PARAMS) :
502                             sizeof(WDF_IO_TARGET_OPEN_PARAMS_V1_11);
503 
504     //
505     // Check Size
506     //
507     if (OpenParams->Size != sizeof(WDF_IO_TARGET_OPEN_PARAMS) &&
508         OpenParams->Size != sizeof(WDF_IO_TARGET_OPEN_PARAMS_V1_11)) {
509         status = STATUS_INFO_LENGTH_MISMATCH;
510         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
511                             "OpenParams size (%d) incorrect, expected %d, %!STATUS!",
512                             OpenParams->Size, expectedConfigSize, status);
513         return status;
514     }
515 
516     //
517     // Normalize WDF_IO_TARGET_OPEN_PARAMS structure.
518     //
519     if (OpenParams->Size < sizeof(WDF_IO_TARGET_OPEN_PARAMS)) {
520         RtlZeroMemory(&openParams, sizeof(WDF_IO_TARGET_OPEN_PARAMS));
521 
522         //
523         // Copy over existing fields and readjust the struct size.
524         //
525         RtlCopyMemory(&openParams, OpenParams, OpenParams->Size);
526         openParams.Size = sizeof(openParams);
527 
528         //
529         // Use new open params structure from now on.
530         //
531         OpenParams = &openParams;
532     }
533 
534     status = FxIoTargetValidateOpenParams(pFxDriverGlobals, OpenParams);
535     if (!NT_SUCCESS(status)) {
536         //
537         // FxIoTargetValidateCreateParams traces the error
538         //
539         return status;
540     }
541 
542     status = pTarget->Open(OpenParams);
543 
544     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
545                         "exit WDFIOTARGET 0x%p, %!STATUS!", IoTarget, status);
546 
547     return status;
548 }
549 
550 __drv_maxIRQL(PASSIVE_LEVEL)
551 VOID
552 STDCALL
553 WDFEXPORT(WdfIoTargetCloseForQueryRemove)(
554     __in
555     PWDF_DRIVER_GLOBALS DriverGlobals,
556     __in
557     WDFIOTARGET IoTarget
558     )
559 /*++
560 
561 Routine Description:
562     Closes a target in response to a query remove notification callback.  This
563     will pend all i/o sent after the call returns.
564 
565 Arguments:
566     IoTarget - Target to be closed
567 
568 Return Value:
569     None
570 
571   --*/
572 {
573     DDI_ENTRY();
574 
575     PFX_DRIVER_GLOBALS pFxDriverGlobals;
576     FxIoTargetRemote* pTarget;
577     NTSTATUS status;
578 
579     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
580                                    IoTarget,
581                                    FX_TYPE_IO_TARGET_REMOTE,
582                                    (PVOID*) &pTarget,
583                                    &pFxDriverGlobals);
584 
585     pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
586 
587     DoTraceLevelMessage(
588         pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
589         "enter WDFIOTARGET 0x%p", IoTarget);
590 
591     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
592     if (!NT_SUCCESS(status)) {
593         return;
594     }
595 
596     pTarget->Close(FxIoTargetRemoteCloseReasonQueryRemove);
597 }
598 
599 __drv_maxIRQL(PASSIVE_LEVEL)
600 VOID
601 STDCALL
602 WDFEXPORT(WdfIoTargetClose)(
603     __in
604     PWDF_DRIVER_GLOBALS DriverGlobals,
605     __in
606     WDFIOTARGET IoTarget
607     )
608 /*++
609 
610 Routine Description:
611     Closes the target for good.  The target can be in either a query removed or
612     opened state.
613 
614 Arguments:
615     IoTarget - target to close
616 
617 Return Value:
618     None
619 
620   --*/
621 {
622     DDI_ENTRY();
623 
624     PFX_DRIVER_GLOBALS pFxDriverGlobals;
625     FxIoTargetRemote* pTarget;
626     NTSTATUS status;
627 
628     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
629                                    IoTarget,
630                                    FX_TYPE_IO_TARGET_REMOTE,
631                                    (PVOID*) &pTarget,
632                                    &pFxDriverGlobals);
633 
634     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
635                         "enter WDFIOTARGET 0x%p", IoTarget);
636 
637     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
638     if (!NT_SUCCESS(status)) {
639         return;
640     }
641 
642     pTarget->Close(FxIoTargetRemoteCloseReasonPlainClose);
643 }
644 
645 __drv_maxIRQL(DISPATCH_LEVEL)
646 WDFDEVICE
647 STDCALL
648 WDFEXPORT(WdfIoTargetGetDevice)(
649     __in
650     PWDF_DRIVER_GLOBALS DriverGlobals,
651     __in
652     WDFIOTARGET IoTarget
653     )
654 /*++
655 
656 Routine Description:
657     Returns the owning WDFDEVICE for the WDFIOTARGET, this is not necessarily
658     the PDEVICE_OBJECT of the target itself.
659 
660 Arguments:
661     IoTarget - the target being retrieved
662 
663 Return Value:
664     a valid WDFDEVICE handle , NULL if there are any problems
665 
666   --*/
667 
668 {
669     DDI_ENTRY();
670 
671     PFX_DRIVER_GLOBALS pFxDriverGlobals;
672     FxIoTarget* pTarget;
673     WDFDEVICE device;
674 
675     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
676                                    IoTarget,
677                                    FX_TYPE_IO_TARGET,
678                                    (PVOID*) &pTarget,
679                                    &pFxDriverGlobals);
680 
681     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
682                         "enter WDFIOTARGET 0x%p", IoTarget);
683 
684     device = pTarget->GetDeviceHandle();
685 
686     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
687                         "exit WDFIOTARGET 0x%p, WDFDEVICE 0x%p", IoTarget, device);
688 
689     return device;
690 }
691 
692 static
693 _Must_inspect_result_
694 NTSTATUS
695 FxIoTargetSendIo(
696     __in
697     PFX_DRIVER_GLOBALS FxDriverGlobals,
698     __in
699     WDFIOTARGET IoTarget,
700     __inout_opt
701     WDFREQUEST Request,
702     __in
703     UCHAR MajorCode,
704     __inout_opt
705     PWDF_MEMORY_DESCRIPTOR IoBuffer,
706     __in_opt
707     PLONGLONG DeviceOffset,
708     __in_opt
709     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
710     __out_opt
711     PULONG_PTR BytesReturned
712     )
713 /*++
714 
715 Routine Description:
716     This routine sends a read or write synchronously to the target.  If Request
717     is not NULL, the PIRP it contains will be used to send the IO.
718 
719 Arguments:
720     IoTarget - target to where the IO is going to be sent
721 
722     Request - optional.  If specified, the PIRP it contains will be used
723               to send the I/O
724 
725     MajorCode - read or write major code
726 
727     IoBuffer - Buffer which will be used in the I/O.  The buffer can be a PMDL,
728                buffer, or WDFMEMORY
729 
730     DeviceOffset - offset into the target (and not the memory) in which the I/O
731                    will start
732 
733     RequestOptions - optional.  If specified, the timeout value is used to cancel
734                      the sent i/o if the timeout is exceeded
735 
736     BytesReturned - upon success, the number of bytes transferred in the I/O
737                     request
738 
739 Return Value:
740     NTSTATUS
741 
742   --*/
743 
744 {
745     FxIoTarget* pTarget;
746     FxRequestBuffer ioBuf;
747     NTSTATUS status;
748 
749     FxObjectHandleGetPtrAndGlobals(FxDriverGlobals,
750                                    IoTarget,
751                                    FX_TYPE_IO_TARGET,
752                                    (PVOID*) &pTarget,
753                                    &FxDriverGlobals);
754 
755     //
756     // Minimize the points of failure by using the stack instead of allocating
757     // out of pool. For UMDF, request initialization can fail so we still need
758     // to call initialize for FxSyncRequest. Initialization always succeeds for
759     // KM.
760     //
761     FxIoContext context;
762     FxSyncRequest request(FxDriverGlobals, &context, Request);
763 
764     status = request.Initialize();
765     if (!NT_SUCCESS(status)) {
766         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
767                             "Failed to initialize FxSyncRequest for WDFIOTARGET "
768                             "0x%p", IoTarget);
769         return status;
770     }
771 
772     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
773                         "enter:  WDFIOTARGET 0x%p, WDFREQUEST 0x%p, MJ code 0x%x",
774                         IoTarget, Request, MajorCode);
775 
776     //
777     // Since we are synchronously waiting, we must be at passive level
778     //
779     status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL);
780     if (!NT_SUCCESS(status)) {
781         return status;
782     }
783 
784     status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions);
785     if (!NT_SUCCESS(status)) {
786         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
787                             "invalid options, %!STATUS!", status);
788         return status;
789     }
790 
791     if (IoBuffer != NULL) {
792         //
793         // This transcribes the client union into a local structure which we
794         // can change w/out altering the client's buffer.
795         //
796         status = ioBuf.ValidateMemoryDescriptor(FxDriverGlobals, IoBuffer);
797         if (!NT_SUCCESS(status)) {
798             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
799                                 "invalid input buffer descriptor 0x%p, %!STATUS!",
800                                 IoBuffer, status);
801             return status;
802         }
803     }
804 
805     //
806     // Format the next stack location in the PIRP
807     //
808     status = pTarget->FormatIoRequest(
809         request.m_TrueRequest, MajorCode, &ioBuf, DeviceOffset, NULL);
810 
811     if (NT_SUCCESS(status)) {
812         //
813         // And send it
814         //
815         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
816                             "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted",
817                             IoTarget, request.m_TrueRequest->GetTraceObjectHandle());
818 
819         status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions);
820 
821         if (BytesReturned != NULL) {
822             *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation();
823 
824         }
825     }
826     else {
827         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
828                             "could not format MJ 0x%x request, %!STATUS!",
829                             MajorCode, status);
830     }
831 
832     return status;
833 }
834 
835 static
836 _Must_inspect_result_
837 NTSTATUS
838 FxIoTargetFormatIo(
839     __in
840     PFX_DRIVER_GLOBALS FxDriverGlobals,
841     __in
842     WDFIOTARGET IoTarget,
843     __inout
844     WDFREQUEST Request,
845     __in
846     UCHAR MajorCode,
847     __inout_opt
848     WDFMEMORY IoBuffer,
849     __in_opt
850     PWDFMEMORY_OFFSET IoBufferOffsets,
851     __in_opt
852     PLONGLONG DeviceOffset
853     )
854 /*++
855 
856 Routine Description:
857     Formats a Request for a read or write.  The request can later be sent to the
858     target using WdfRequestSend. Upon success, this will take a reference on the
859     Iobuffer handle if it is not NULL.  This reference will be released when
860     one of the following occurs:
861     1)  the request is completed through WdfRequestComplete
862     2)  the request is reused through WdfRequestReuse
863     3)  the request is reformatted through any target format DDI
864 
865 Arguments:
866     IoTarget - the request that the read or write will later be sent to
867 
868     Request - the request that will be formatted
869 
870     MajorCode - read or write major code
871 
872     IoBuffer - optional reference counted memory handle
873 
874     IoBufferOffset - optional offset into the IoBuffer.  This can specify the
875                      starting offset and/or length of the transfer
876 
877     DeviceOffset - offset into the target in which the i/o will start
878 
879 Return Value:
880     NTSTATUS
881 
882   --*/
883 {
884     FxIoTarget *pTarget;
885     FxRequest *pRequest;
886     IFxMemory* pIoMemory;
887     FxRequestBuffer ioBuf;
888     NTSTATUS status;
889 
890     FxObjectHandleGetPtrAndGlobals(FxDriverGlobals,
891                                    IoTarget,
892                                    FX_TYPE_IO_TARGET,
893                                    (PVOID*) &pTarget,
894                                    &FxDriverGlobals);
895 
896     DoTraceLevelMessage(FxDriverGlobals,
897         TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
898         "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, MJ code 0x%x, WDFMEMORY 0x%p",
899         IoTarget, Request, MajorCode, IoBuffer);
900 
901     FxObjectHandleGetPtr(FxDriverGlobals,
902                          Request,
903                          FX_TYPE_REQUEST,
904                          (PVOID*) &pRequest);
905 
906     if (IoBuffer != NULL) {
907         FxObjectHandleGetPtr(FxDriverGlobals,
908                              IoBuffer,
909                              IFX_TYPE_MEMORY,
910                              (PVOID*) &pIoMemory);
911 
912         status = pIoMemory->ValidateMemoryOffsets(IoBufferOffsets);
913         if (!NT_SUCCESS(status)) {
914             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
915                                 "invalid memory offsets, %!STATUS!",
916                                 status);
917             return status;
918         }
919 
920         //
921         // This transcribes the client union into a local structure which we
922         // can change w/out altering the client's buffer.
923         //
924         ioBuf.SetMemory(pIoMemory, IoBufferOffsets);
925     }
926     else {
927         pIoMemory = NULL;
928     }
929 
930     //
931     // Format the next stack locaiton in the PIRP
932     //
933     status = pTarget->FormatIoRequest(
934         pRequest, MajorCode, &ioBuf, DeviceOffset, NULL);
935 
936     if (NT_SUCCESS(status)) {
937         if (MajorCode == IRP_MJ_WRITE) {
938             pRequest->GetContext()->FormatWriteParams(pIoMemory, IoBufferOffsets);
939         }
940         else if (MajorCode == IRP_MJ_READ) {
941             pRequest->GetContext()->FormatReadParams(pIoMemory, IoBufferOffsets);
942         }
943     }
944 
945     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
946                         "exit WDFIOTARGET 0x%p, WDFREQUEST 0x%p, %!STATUS!",
947                         IoTarget, Request, status);
948 
949     return status;
950 }
951 
952 _Must_inspect_result_
953 __drv_maxIRQL(PASSIVE_LEVEL)
954 NTSTATUS
955 STDCALL
956 WDFEXPORT(WdfIoTargetSendReadSynchronously)(
957     __in
958     PWDF_DRIVER_GLOBALS DriverGlobals,
959     __in
960     WDFIOTARGET IoTarget,
961     __in_opt
962     WDFREQUEST Request,
963     __in_opt
964     PWDF_MEMORY_DESCRIPTOR OutputBuffer,
965     __in_opt
966     PLONGLONG DeviceOffset,
967     __in_opt
968     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
969     __out_opt
970     PULONG_PTR BytesRead
971     )
972 {
973     DDI_ENTRY();
974 
975     return FxIoTargetSendIo(GetFxDriverGlobals(DriverGlobals),
976                             IoTarget,
977                             Request,
978                             IRP_MJ_READ,
979                             OutputBuffer,
980                             DeviceOffset,
981                             RequestOptions,
982                             BytesRead);
983 }
984 
985 _Must_inspect_result_
986 __drv_maxIRQL(DISPATCH_LEVEL)
987 NTSTATUS
988 STDCALL
989 WDFEXPORT(WdfIoTargetFormatRequestForRead)(
990     __in
991     PWDF_DRIVER_GLOBALS DriverGlobals,
992     __in
993     WDFIOTARGET IoTarget,
994     __in
995     WDFREQUEST Request,
996     __in_opt
997     WDFMEMORY OutputBuffer,
998     __in_opt
999     PWDFMEMORY_OFFSET OutputBufferOffsets,
1000     __in_opt
1001     PLONGLONG DeviceOffset
1002     )
1003 {
1004     DDI_ENTRY();
1005 
1006     return FxIoTargetFormatIo(GetFxDriverGlobals(DriverGlobals),
1007                               IoTarget,
1008                               Request,
1009                               IRP_MJ_READ,
1010                               OutputBuffer,
1011                               OutputBufferOffsets,
1012                               DeviceOffset);
1013 }
1014 
1015 
1016 _Must_inspect_result_
1017 __drv_maxIRQL(PASSIVE_LEVEL)
1018 NTSTATUS
1019 STDCALL
1020 WDFEXPORT(WdfIoTargetSendWriteSynchronously)(
1021     __in
1022     PWDF_DRIVER_GLOBALS DriverGlobals,
1023     __in
1024     WDFIOTARGET IoTarget,
1025     __in_opt
1026     WDFREQUEST Request,
1027     __in_opt
1028     PWDF_MEMORY_DESCRIPTOR InputBuffer,
1029     __in_opt
1030     PLONGLONG DeviceOffset,
1031     __in_opt
1032     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
1033     __out_opt
1034     PULONG_PTR BytesWritten
1035     )
1036 {
1037     DDI_ENTRY();
1038 
1039     return FxIoTargetSendIo(GetFxDriverGlobals(DriverGlobals),
1040                             IoTarget,
1041                             Request,
1042                             IRP_MJ_WRITE,
1043                             InputBuffer,
1044                             DeviceOffset,
1045                             RequestOptions,
1046                             BytesWritten);
1047 }
1048 
1049 _Must_inspect_result_
1050 __drv_maxIRQL(DISPATCH_LEVEL)
1051 NTSTATUS
1052 STDCALL
1053 WDFEXPORT(WdfIoTargetFormatRequestForWrite)(
1054     __in
1055     PWDF_DRIVER_GLOBALS DriverGlobals,
1056     __in
1057     WDFIOTARGET IoTarget,
1058     __in
1059     WDFREQUEST Request,
1060     __in_opt
1061     WDFMEMORY InputBuffer,
1062     __in_opt
1063     PWDFMEMORY_OFFSET InputBufferOffsets,
1064     __in_opt
1065     PLONGLONG DeviceOffset
1066     )
1067 {
1068     DDI_ENTRY();
1069 
1070     return FxIoTargetFormatIo(GetFxDriverGlobals(DriverGlobals),
1071                               IoTarget,
1072                               Request,
1073                               IRP_MJ_WRITE,
1074                               InputBuffer,
1075                               InputBufferOffsets,
1076                               DeviceOffset);
1077 }
1078 
1079 _Must_inspect_result_
1080 NTSTATUS
1081 FxIoTargetSendIoctl(
1082     __in
1083      PFX_DRIVER_GLOBALS FxDriverGlobals,
1084     __in
1085     WDFIOTARGET IoTarget,
1086     __in_opt
1087     WDFREQUEST Request,
1088     __in
1089     ULONG Ioctl,
1090     __in
1091     BOOLEAN Internal,
1092     __in_opt
1093     PWDF_MEMORY_DESCRIPTOR InputBuffer,
1094     __in_opt
1095     PWDF_MEMORY_DESCRIPTOR OutputBuffer,
1096     __in_opt
1097     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
1098     __out_opt
1099     PULONG_PTR BytesReturned
1100     )
1101 /*++
1102 
1103 Routine Description:
1104     Sends an external or internal IOCTL to the target.  If the optional request
1105     is specified, this function will use it's PIRP to send the request to the
1106     target.  Both buffers are optional.
1107 
1108 Arguments:
1109     IoTarget - the target to which the IOCTL is being sent
1110 
1111     IOCTL - the device io control value
1112 
1113     Internal - if TRUE, an internal IOCTL, if FALSE, a normal IOCTL
1114 
1115     InputBuffer - optional.  Can be one of the following:  PMDL, PVOID, or WDFMEMORY
1116 
1117     OutputBuffer - optional.  Can be one of the following:  PMDL, PVOID, or WDFMEMORY
1118 
1119     RequestOptions - optional.  Specifies a timeout to be used if the sent IO
1120                      does not return within the time specified.
1121 
1122     BytesReturned - number of bytes transfered
1123 
1124 Return Value:
1125     NTSTATUS
1126 
1127   --*/
1128 {
1129     FxIoTarget* pTarget;
1130     FxRequestBuffer inputBuf, outputBuf;
1131     NTSTATUS status;
1132 
1133     FxObjectHandleGetPtrAndGlobals(FxDriverGlobals,
1134                                    IoTarget,
1135                                    FX_TYPE_IO_TARGET,
1136                                    (PVOID*) &pTarget,
1137                                    &FxDriverGlobals);
1138 
1139     //
1140     // Minimize the points of failure by using the stack instead of allocating
1141     // out of pool. For UMDF, request initialization can fail so we still need
1142     // to call initialize for FxSyncRequest. Initialization always succeeds for
1143     // KM.
1144     //
1145     FxIoContext context;
1146     FxSyncRequest request(FxDriverGlobals, &context, Request);
1147 
1148     status = request.Initialize();
1149     if (!NT_SUCCESS(status)) {
1150         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1151                             "Failed to initialize FxSyncRequest for WDFIOTARGET "
1152                             "0x%p", IoTarget);
1153         return status;
1154     }
1155 
1156     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1157                         "enter:  WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, "
1158                         "internal %d", IoTarget, Request, Ioctl, Internal);
1159 
1160     //
1161     // Since we are synchronously waiting, we must be at passive
1162     //
1163     status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL);
1164     if (!NT_SUCCESS(status)) {
1165         return status;
1166     }
1167 
1168     status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions);
1169     if (!NT_SUCCESS(status)) {
1170         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1171                             "invalid options, %!STATUS!", status);
1172         return status;
1173     }
1174 
1175     if (InputBuffer != NULL) {
1176         //
1177         // This transcribes the client union into a local structure which we
1178         // can change w/out altering the client's buffer.
1179         //
1180         status = inputBuf.ValidateMemoryDescriptor(FxDriverGlobals, InputBuffer);
1181         if (!NT_SUCCESS(status)) {
1182             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1183                                 "invalid input buffer descriptor 0x%p, %!STATUS!",
1184                                 InputBuffer, status);
1185             return status;
1186         }
1187     }
1188 
1189     if (OutputBuffer != NULL) {
1190         //
1191         // This transcribes the client union into a local structure which we
1192         // can change w/out altering the client's buffer.
1193         //
1194         status = outputBuf.ValidateMemoryDescriptor(FxDriverGlobals, OutputBuffer);
1195         if (!NT_SUCCESS(status)) {
1196             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1197                                 "invalid output buffer descriptor 0x%p, %!STATUS!",
1198                                 OutputBuffer, status);
1199             return status;
1200         }
1201     }
1202 
1203     //
1204     // Format the next stack location
1205     //
1206     status = pTarget->FormatIoctlRequest(
1207         request.m_TrueRequest, Ioctl, Internal, &inputBuf, &outputBuf, NULL);
1208 
1209     if (NT_SUCCESS(status)) {
1210         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1211                             "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted",
1212                             IoTarget,
1213                             request.m_TrueRequest->GetTraceObjectHandle());
1214 
1215         status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions);
1216 
1217         if (BytesReturned != NULL) {
1218             *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation();
1219         }
1220     }
1221     else {
1222         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1223                             "could not format IOCTL 0x%x request, %!STATUS!",
1224                             Ioctl, status);
1225     }
1226 
1227     return status;
1228 }
1229 
1230 static
1231 _Must_inspect_result_
1232 NTSTATUS
1233 FxIoTargetFormatIoctl(
1234     __in
1235     PFX_DRIVER_GLOBALS FxDriverGlobals,
1236     __in
1237     WDFIOTARGET IoTarget,
1238     __in
1239     WDFREQUEST Request,
1240     __in
1241     ULONG Ioctl,
1242     __in
1243     BOOLEAN Internal,
1244     __in_opt
1245     WDFMEMORY InputBuffer,
1246     __in_opt
1247     PWDFMEMORY_OFFSET InputBufferOffsets,
1248     __in_opt
1249     WDFMEMORY OutputBuffer,
1250     __in_opt
1251     PWDFMEMORY_OFFSET OutputBufferOffsets
1252     )
1253 /*++
1254 
1255 Routine Description:
1256     Formats a request as an IOCTL to be sent to the specified target.  Upon
1257     success, this will take a reference on each of the WDFMEMORY handles that
1258     are passed in.  This reference will be released when one of the following
1259     occurs:
1260     1)  the request is completed through WdfRequestComplete
1261     2)  the request is reused through WdfRequestReuse
1262     3)  the request is reformatted through any target format DDI
1263 
1264 Arguments:
1265     IoTarget - the target to which the IOCTL will be formatted for
1266 
1267     Request - the request which will be formatted
1268 
1269     IOCTL - the device IO control itself to be used
1270 
1271     Internal - if TRUE, an internal IOCTL, if FALSE, a normal IOCTL
1272 
1273     InputBuffer - optional.  If specified, a reference counted memory handle to
1274                   be placed in the next stack location.
1275 
1276     InputBufferOffsets - optional.  If specified, it can override the starting
1277                          offset of the buffer and the length of the buffer used
1278 
1279     OutputBuffer - optional.  If specified, a reference counted memory handle to
1280                    be placed in the next stack location.
1281 
1282     OutputBufferOffsets - optional.  If specified, it can override the starting
1283                           offset of the buffer and the length of the buffer used
1284 
1285 Return Value:
1286     NTSTATUS
1287 
1288   --*/
1289 {
1290     FxIoTarget *pTarget;
1291     FxRequest *pRequest;
1292     IFxMemory *pInputMemory, *pOutputMemory;
1293     FxRequestBuffer inputBuf, outputBuf;
1294     NTSTATUS status;
1295 
1296     FxObjectHandleGetPtrAndGlobals(FxDriverGlobals,
1297                                    IoTarget,
1298                                    FX_TYPE_IO_TARGET,
1299                                    (PVOID*) &pTarget,
1300                                    &FxDriverGlobals);
1301 
1302     DoTraceLevelMessage(
1303         FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1304         "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, internal %d, input "
1305         "WDFMEMORY 0x%p, output WDFMEMORY 0x%p",
1306         IoTarget, Request, Ioctl, Internal, InputBuffer, OutputBuffer);
1307 
1308     FxObjectHandleGetPtr(FxDriverGlobals,
1309                          Request,
1310                          FX_TYPE_REQUEST,
1311                          (PVOID*) &pRequest);
1312 
1313     if (InputBuffer != NULL) {
1314         FxObjectHandleGetPtr(FxDriverGlobals,
1315                              InputBuffer,
1316                              IFX_TYPE_MEMORY,
1317                              (PVOID*) &pInputMemory);
1318 
1319         status = pInputMemory->ValidateMemoryOffsets(InputBufferOffsets);
1320         if (!NT_SUCCESS(status)) {
1321             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1322                                 "Invalid input memory offsets, %!STATUS!",
1323                                 status);
1324             return status;
1325         }
1326 
1327         //
1328         // This transcribes the client union into a local structure which we
1329         // can change w/out altering the client's buffer.
1330         //
1331         inputBuf.SetMemory(pInputMemory, InputBufferOffsets);
1332     }
1333 
1334     if (OutputBuffer != NULL) {
1335         FxObjectHandleGetPtr(FxDriverGlobals,
1336                              OutputBuffer,
1337                              IFX_TYPE_MEMORY,
1338                              (PVOID*) &pOutputMemory);
1339 
1340         status = pOutputMemory->ValidateMemoryOffsets(OutputBufferOffsets);
1341         if (!NT_SUCCESS(status)) {
1342             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1343                                 "Invalid output memory offsets, %!STATUS!",
1344                                 status);
1345             return status;
1346         }
1347 
1348         //
1349         // This transcribes the client union into a local structure which we
1350         // can change w/out altering the client's buffer.
1351         //
1352         outputBuf.SetMemory(pOutputMemory, OutputBufferOffsets);
1353     }
1354 
1355     //
1356     // format the next stack location
1357     //
1358     status = pTarget->FormatIoctlRequest(
1359         pRequest, Ioctl, Internal, &inputBuf, &outputBuf, NULL);
1360 
1361     if (NT_SUCCESS(status)) {
1362         FxRequestContext* pContext;
1363 
1364         //
1365         // Upon a successful format,  a FxRequestContext will have been
1366         // associated with the FxRequest
1367         //
1368         pContext = pRequest->GetContext();
1369 
1370         pContext->m_CompletionParams.Parameters.Ioctl.IoControlCode = Ioctl;
1371 
1372         if (Internal) {
1373             pContext->m_CompletionParams.Type = WdfRequestTypeDeviceControlInternal;
1374         }
1375         else {
1376             pContext->m_CompletionParams.Type = WdfRequestTypeDeviceControl;
1377         }
1378 
1379         pContext->m_CompletionParams.Parameters.Ioctl.Input.Buffer = InputBuffer;
1380         if (InputBufferOffsets != NULL) {
1381             pContext->m_CompletionParams.Parameters.Ioctl.Input.Offset =
1382                 InputBufferOffsets->BufferOffset;
1383         }
1384 
1385         pContext->m_CompletionParams.Parameters.Ioctl.Output.Buffer = OutputBuffer;
1386         if (OutputBufferOffsets != NULL) {
1387             pContext->m_CompletionParams.Parameters.Ioctl.Output.Offset =
1388                 OutputBufferOffsets->BufferOffset;
1389         }
1390     }
1391 
1392     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1393                         "Exit WDFIOTARGET 0x%p, WDFREQUEST 0x%p, %!STATUS!",
1394                         IoTarget, Request, status);
1395 
1396     return status;
1397 }
1398 
1399 _Must_inspect_result_
1400 __drv_maxIRQL(PASSIVE_LEVEL)
1401 NTSTATUS
1402 STDCALL
1403 WDFEXPORT(WdfIoTargetSendIoctlSynchronously)(
1404     __in
1405     PWDF_DRIVER_GLOBALS DriverGlobals,
1406     __in
1407     WDFIOTARGET IoTarget,
1408     __in_opt
1409     WDFREQUEST Request,
1410     __in
1411     ULONG Ioctl,
1412     __in_opt
1413     PWDF_MEMORY_DESCRIPTOR InputBuffer,
1414     __in_opt
1415     PWDF_MEMORY_DESCRIPTOR OutputBuffer,
1416     __in_opt
1417     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
1418     __out_opt
1419     PULONG_PTR BytesReturned
1420     )
1421 {
1422     DDI_ENTRY();
1423 
1424     return FxIoTargetSendIoctl(
1425         GetFxDriverGlobals(DriverGlobals),
1426         IoTarget,
1427         Request,
1428         Ioctl,
1429         FALSE,
1430         InputBuffer,
1431         OutputBuffer,
1432         RequestOptions,
1433         BytesReturned
1434         );
1435 }
1436 
1437 _Must_inspect_result_
1438 __drv_maxIRQL(DISPATCH_LEVEL)
1439 NTSTATUS
1440 STDCALL
1441 WDFEXPORT(WdfIoTargetFormatRequestForIoctl)(
1442     __in
1443     PWDF_DRIVER_GLOBALS DriverGlobals,
1444     __in
1445     WDFIOTARGET IoTarget,
1446     __in
1447     WDFREQUEST Request,
1448     __in
1449     ULONG Ioctl,
1450     __in_opt
1451     WDFMEMORY InputBuffer,
1452     __in_opt
1453     PWDFMEMORY_OFFSET InputBufferOffsets,
1454     __in_opt
1455     WDFMEMORY OutputBuffer,
1456     __in_opt
1457     PWDFMEMORY_OFFSET OutputBufferOffsets
1458     )
1459 {
1460     DDI_ENTRY();
1461 
1462     return FxIoTargetFormatIoctl(GetFxDriverGlobals(DriverGlobals),
1463                                  IoTarget,
1464                                  Request,
1465                                  Ioctl,
1466                                  FALSE,
1467                                  InputBuffer,
1468                                  InputBufferOffsets,
1469                                  OutputBuffer,
1470                                  OutputBufferOffsets);
1471 }
1472 
1473 _Must_inspect_result_
1474 __drv_maxIRQL(PASSIVE_LEVEL)
1475 NTSTATUS
1476 STDCALL
1477 WDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously)(
1478     __in
1479     PWDF_DRIVER_GLOBALS DriverGlobals,
1480     __in
1481     WDFIOTARGET IoTarget,
1482     __in_opt
1483     WDFREQUEST Request,
1484     __in
1485     ULONG Ioctl,
1486     __in_opt
1487     PWDF_MEMORY_DESCRIPTOR InputBuffer,
1488     __in_opt
1489     PWDF_MEMORY_DESCRIPTOR OutputBuffer,
1490     __in_opt
1491     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
1492     __out_opt
1493     PULONG_PTR BytesReturned
1494     )
1495 {
1496     DDI_ENTRY();
1497 
1498     return FxIoTargetSendIoctl(
1499         GetFxDriverGlobals(DriverGlobals),
1500         IoTarget,
1501         Request,
1502         Ioctl,
1503         TRUE,
1504         InputBuffer,
1505         OutputBuffer,
1506         RequestOptions,
1507         BytesReturned
1508         );
1509 }
1510 
1511 _Must_inspect_result_
1512 __drv_maxIRQL(DISPATCH_LEVEL)
1513 NTSTATUS
1514 STDCALL
1515 WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl)(
1516     __in
1517     PWDF_DRIVER_GLOBALS DriverGlobals,
1518     __in
1519     WDFIOTARGET IoTarget,
1520     __in
1521     WDFREQUEST Request,
1522     __in
1523     ULONG Ioctl,
1524     __in_opt
1525     WDFMEMORY InputBuffer,
1526     __in_opt
1527     PWDFMEMORY_OFFSET InputBufferOffsets,
1528     __in_opt
1529     WDFMEMORY OutputBuffer,
1530     __in_opt
1531     PWDFMEMORY_OFFSET OutputBufferOffsets
1532     )
1533 {
1534     DDI_ENTRY();
1535 
1536     return FxIoTargetFormatIoctl(GetFxDriverGlobals(DriverGlobals),
1537                                  IoTarget,
1538                                  Request,
1539                                  Ioctl,
1540                                  TRUE,
1541                                  InputBuffer,
1542                                  InputBufferOffsets,
1543                                  OutputBuffer,
1544                                  OutputBufferOffsets);
1545 }
1546 
1547 _Must_inspect_result_
1548 __drv_maxIRQL(PASSIVE_LEVEL)
1549 NTSTATUS
1550 STDCALL
1551 WDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously)(
1552     __in
1553     PWDF_DRIVER_GLOBALS DriverGlobals,
1554     __in
1555     WDFIOTARGET IoTarget,
1556     __in_opt
1557     WDFREQUEST Request,
1558     __in
1559     ULONG Ioctl,
1560     __in_opt
1561     PWDF_MEMORY_DESCRIPTOR OtherArg1,
1562     __in_opt
1563     PWDF_MEMORY_DESCRIPTOR OtherArg2,
1564     __in_opt
1565     PWDF_MEMORY_DESCRIPTOR OtherArg4,
1566     __in_opt
1567     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
1568     __out_opt
1569     PULONG_PTR BytesReturned
1570     )
1571 /*++
1572 
1573 Routine Description:
1574     Sends an internal IOCTL to the target synchronously.  Since all 3 buffers can
1575     be used, we cannot overload WdfIoTargetSendInternalIoctlSynchronously since
1576     it can only take 2 buffers.
1577 
1578 Arguments:
1579     IoTarget - the target to which the request will be sent
1580 
1581     Request - optional.  If specified, the request's PIRP will be used to send
1582               the i/o to the target.
1583 
1584     Ioctl - internal ioctl value to send
1585 
1586     OtherArg1
1587     OtherArg2
1588     OtherArg4 - arguments to use in the stack locations's Others field.  There
1589                 is no OtherArg3 because 3 is where the IOCTL value is written.
1590                 All buffers are optional.
1591 
1592     RequestOptions - optional.  If specified, the timeout indicated will be used
1593                      if the request exceeds the timeout.
1594 
1595     BytesReturned - the number of bytes returned by the target
1596 
1597 Return Value:
1598     NTSTATUS
1599 
1600   --*/
1601 {
1602     DDI_ENTRY();
1603 
1604     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1605     FxIoTarget* pTarget;
1606     FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS];
1607     NTSTATUS status;
1608 
1609     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1610                                    IoTarget,
1611                                    FX_TYPE_IO_TARGET,
1612                                    (PVOID*) &pTarget,
1613                                    &pFxDriverGlobals);
1614 
1615     //
1616     // Minimize the points of failure by using the stack instead of allocating
1617     // out of pool. For UMDF, request initialization can fail so we still need
1618     // to call initialize for FxSyncRequest. Initialization always succeeds for
1619     // KM.
1620     //
1621     FxInternalIoctlOthersContext context;
1622     FxSyncRequest request(pFxDriverGlobals, &context, Request);
1623 
1624     status = request.Initialize();
1625     if (!NT_SUCCESS(status)) {
1626         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1627                             "Failed to initialize FxSyncRequest for WDFIOTARGET "
1628                             "0x%p", IoTarget);
1629         return status;
1630     }
1631 
1632     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1633         "enter:  WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, Args %p %p %p",
1634         IoTarget, Request, Ioctl, OtherArg1, OtherArg2, OtherArg4);
1635 
1636     //
1637     // Since we are waiting synchronously, we must be at pasisve
1638     //
1639     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1640     if (!NT_SUCCESS(status)) {
1641         return status;
1642     }
1643 
1644     status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions);
1645     if (!NT_SUCCESS(status)) {
1646         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1647                             "Invalid options, %!STATUS!", status);
1648         return status;
1649     }
1650 
1651     ULONG i;
1652 
1653     i = 0;
1654     if (OtherArg1 != NULL) {
1655         //
1656         // This transcribes the client union into a local structure which we
1657         // can change w/out altering the client's buffer.
1658         //
1659         status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg1);
1660         if (!NT_SUCCESS(status)) {
1661             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1662                                 "invalid OtherArg1 buffer descriptor 0x%p, %!STATUS!",
1663                                 OtherArg1, status);
1664             return status;
1665         }
1666     }
1667 
1668     i++;
1669     if (OtherArg2 != NULL) {
1670         //
1671         // This transcribes the client union into a local structure which we
1672         // can change w/out altering the client's buffer.
1673         //
1674         status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg2);
1675         if (!NT_SUCCESS(status)) {
1676             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1677                                 "invalid OtherArg2 buffer descriptor 0x%p, %!STATUS!",
1678                                 OtherArg2, status);
1679             return status;
1680         }
1681     }
1682 
1683     i++;
1684     if (OtherArg4 != NULL) {
1685         //
1686         // This transcribes the client union into a local structure which we
1687         // can change w/out altering the client's buffer.
1688         //
1689         status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg4);
1690         if (!NT_SUCCESS(status)) {
1691             DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1692                                 "invalid OtherArg4 buffer descriptor 0x%p, %!STATUS!",
1693                                 OtherArg4, status);
1694             return status;
1695         }
1696     }
1697 
1698     //
1699     // Format the next stack location
1700     //
1701     status = pTarget->FormatInternalIoctlOthersRequest(request.m_TrueRequest,
1702                                                        Ioctl,
1703                                                        args);
1704 
1705     if (NT_SUCCESS(status)) {
1706         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1707                             "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted",
1708                             IoTarget,
1709                             request.m_TrueRequest->GetTraceObjectHandle());
1710 
1711         status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions);
1712 
1713         if (BytesReturned != NULL) {
1714             *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation();
1715         }
1716     }
1717     else {
1718         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1719                             "Could not format IOCTL 0x%x request, %!STATUS!",
1720                             Ioctl, status);
1721     }
1722 
1723     return status;
1724 }
1725 
1726 _Must_inspect_result_
1727 __drv_maxIRQL(DISPATCH_LEVEL)
1728 NTSTATUS
1729 STDCALL
1730 WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers)(
1731     __in
1732     PWDF_DRIVER_GLOBALS DriverGlobals,
1733     __in
1734     WDFIOTARGET IoTarget,
1735     __in
1736     WDFREQUEST Request,
1737     __in
1738     ULONG Ioctl,
1739     __in_opt
1740     WDFMEMORY OtherArg1,
1741     __in_opt
1742     PWDFMEMORY_OFFSET OtherArg1Offsets,
1743     __in_opt
1744     WDFMEMORY OtherArg2,
1745     __in_opt
1746     PWDFMEMORY_OFFSET OtherArg2Offsets,
1747     __in_opt
1748     WDFMEMORY OtherArg4,
1749     __in_opt
1750     PWDFMEMORY_OFFSET OtherArg4Offsets
1751     )
1752 /*++
1753 
1754 Routine Description:
1755     Formats an internal IOCTL so that it can sent to the target.  Since all 3
1756     buffers can be used, we cannot overload
1757     WdfIoTargetFormatRequestForInternalIoctlOthers since it can only take 2 buffers.
1758 
1759     Upon success, this will take a reference on each of the WDFMEMORY handles that
1760     are passed in.  This reference will be released when one of the following
1761     occurs:
1762     1)  the request is completed through WdfRequestComplete
1763     2)  the request is reused through WdfRequestReuse
1764     3)  the request is reformatted through any target format DDI
1765 
1766 Arguments:
1767     IoTarget - the target to which the request will be sent
1768 
1769     Request - the request to be formatted
1770 
1771     Ioctl - internal ioctl value to send
1772 
1773     OtherArg1
1774     OtherArg2
1775     OtherArg4 - arguments to use in the stack locations's Others field.  There
1776                 is no OtherArg3 because 3 is where the IOCTL value is written.
1777                 All buffers are optional
1778 
1779     OterhArgXOffsets - offset into each buffer which can override the starting
1780                        offset of the buffer.  Length does not matter since
1781                        there is no way of generically describing the length of
1782                        each of the 3 buffers in the PIRP
1783 
1784 Return Value:
1785     NTSTATUS
1786 
1787   --*/
1788 {
1789     DDI_ENTRY();
1790 
1791     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1792     FxIoTarget *pTarget;
1793     FxRequest *pRequest;
1794     IFxMemory *pMemory[FX_REQUEST_NUM_OTHER_PARAMS];
1795     FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS];
1796     WDFMEMORY memoryHandles[FX_REQUEST_NUM_OTHER_PARAMS];
1797     PWDFMEMORY_OFFSET offsets[FX_REQUEST_NUM_OTHER_PARAMS];
1798     NTSTATUS status;
1799     ULONG i;
1800     FxInternalIoctlParams InternalIoctlParams;
1801 
1802     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1803                                    IoTarget,
1804                                    FX_TYPE_IO_TARGET,
1805                                    (PVOID*) &pTarget,
1806                                    &pFxDriverGlobals);
1807 
1808     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1809                         "Enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, "
1810                         "WDFMEMORY 1 0x%p, 2 0x%p, 3 0x%p",
1811                         IoTarget, Request, Ioctl, OtherArg1, OtherArg2,
1812                         OtherArg4);
1813 
1814     FxObjectHandleGetPtr(pFxDriverGlobals,
1815                          Request,
1816                          FX_TYPE_REQUEST,
1817                          (PVOID*) &pRequest);
1818 
1819     i = 0;
1820     InternalIoctlParams.Argument1 = memoryHandles[i] = OtherArg1;
1821     offsets[i] = OtherArg1Offsets;
1822 
1823     InternalIoctlParams.Argument2 = memoryHandles[++i] = OtherArg2;
1824     offsets[i] = OtherArg2Offsets;
1825 
1826     InternalIoctlParams.Argument4 = memoryHandles[++i] = OtherArg4;
1827     offsets[i] = OtherArg4Offsets;
1828 
1829     for (i = 0; i < FX_REQUEST_NUM_OTHER_PARAMS; i++) {
1830         if (memoryHandles[i] != NULL) {
1831 
1832             FxObjectHandleGetPtr(pFxDriverGlobals,
1833                                  memoryHandles[i],
1834                                  IFX_TYPE_MEMORY,
1835                                  (PVOID*) &pMemory[i]);
1836 
1837             status = pMemory[i]->ValidateMemoryOffsets(offsets[i]);
1838             if (!NT_SUCCESS(status)) {
1839                 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1840                                     "Invalid OtherArg%d memory offsets, %!STATUS!",
1841                                     i+1, status);
1842                 return status;
1843             }
1844 
1845             //
1846             // This transcribes the client union into a local structure which we
1847             // can change w/out altering the client's buffer.
1848             //
1849             args[i].SetMemory(pMemory[i], offsets[i]);
1850         }
1851     }
1852 
1853     status = pTarget->FormatInternalIoctlOthersRequest(pRequest, Ioctl, args);
1854     if (NT_SUCCESS(status)) {
1855         pRequest->GetContext()->FormatOtherParams(&InternalIoctlParams);
1856     }
1857     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1858                         "Exit: WDFIOTARGET %p, WDFREQUEST %p, IOCTL 0x%x, "
1859                         "Arg Handles %p %p %p, status %!STATUS!",
1860                         IoTarget, Request, Ioctl, OtherArg1, OtherArg2,
1861                         OtherArg4, status);
1862 
1863     return status;
1864 }
1865 
1866 _Must_inspect_result_
1867 _IRQL_requires_max_(DISPATCH_LEVEL)
1868 NTSTATUS
1869 STDCALL
1870 WDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)(
1871     _In_
1872     PWDF_DRIVER_GLOBALS DriverGlobals,
1873     _In_
1874     WDFIOTARGET IoTarget,
1875     _In_
1876     WDFQUEUE Queue
1877     )
1878 
1879 /*++
1880 
1881 Routine Description:
1882 
1883     Assigns a default queue for the Self IO Target.
1884 
1885     By default the IO sent to the Self IO Target is dispatched ot the
1886     client's default / top level queue.
1887 
1888     This routine assigns a default queue for the Intenral I/O target.
1889     If a client calls this API, all the I/O directed to the Self IO target
1890     is dispatched to the queue specified.
1891 
1892 Arguments:
1893 
1894     IoTarget - Handle to the Self Io Target.
1895 
1896     Queue - Handle to a queue that is being assigned as the default queue for
1897        the Self io target.
1898 
1899 Returns:
1900 
1901     NTSTATUS
1902 
1903 --*/
1904 
1905 {
1906     DDI_ENTRY();
1907 
1908     PFX_DRIVER_GLOBALS pGlobals;
1909     NTSTATUS status;
1910     FxIoTargetSelf* pTargetSelf;
1911     FxDevice*  pDevice;
1912     FxIoQueue* pFxIoQueue;
1913 
1914     pDevice = NULL;
1915     pFxIoQueue = NULL;
1916 
1917     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1918                                    IoTarget,
1919                                    FX_TYPE_IO_TARGET_SELF,
1920                                    (PVOID *) &pTargetSelf,
1921                                    &pGlobals);
1922 
1923     pDevice = pTargetSelf->GetDevice();
1924 
1925     //
1926     // Validate the Queue handle
1927     //
1928     FxObjectHandleGetPtr(pGlobals,
1929                          Queue,
1930                          FX_TYPE_QUEUE,
1931                          (PVOID*)&pFxIoQueue);
1932 
1933     if (pDevice != pFxIoQueue->GetDevice()) {
1934         status = STATUS_INVALID_DEVICE_REQUEST;
1935 
1936         DoTraceLevelMessage(
1937             pGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1938             "Input WDFQUEUE 0x%p belongs to WDFDEVICE 0x%p, but "
1939             "Self Io Target 0x%p corresponds to the WDFDEVICE 0x%p, %!STATUS!",
1940             Queue, pFxIoQueue->GetDevice()->GetHandle(), IoTarget,
1941             pDevice->GetHandle(), status);
1942 
1943         return status;
1944     }
1945 
1946     if (pDevice->IsLegacy()) {
1947         //
1948         // This is a controldevice. Make sure the create is called after the device
1949         // is initialized and ready to accept I/O.
1950         //
1951         MxDeviceObject deviceObject(pDevice->GetDeviceObject());
1952         if ((deviceObject.GetFlags() & DO_DEVICE_INITIALIZING) == 0x0) {
1953 
1954             status = STATUS_INVALID_DEVICE_STATE;
1955             DoTraceLevelMessage(
1956                 pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1957                 "Queue cannot be configured for automatic dispatching"
1958                 " after WdfControlDeviceFinishInitializing"
1959                 "is called on the WDFDEVICE %p is called %!STATUS!",
1960                 pDevice->GetHandle(),
1961                 status);
1962             return status;
1963         }
1964     }
1965     else {
1966         //
1967         // This is either FDO or PDO. Make sure it's not started yet.
1968         //
1969         if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) {
1970             status = STATUS_INVALID_DEVICE_STATE;
1971             DoTraceLevelMessage(
1972                 pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1973                 "Queue cannot be configured for automatic dispatching"
1974                 "after the WDFDEVICE %p is started, %!STATUS!",
1975                 pDevice->GetHandle(), status);
1976             return status;
1977         }
1978     }
1979 
1980     pTargetSelf->SetDispatchQueue(pFxIoQueue);
1981 
1982     return STATUS_SUCCESS;
1983 }
1984 
1985 __drv_maxIRQL(DISPATCH_LEVEL)
1986 HANDLE
1987 STDCALL
1988 WDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)(
1989     __in
1990     PWDF_DRIVER_GLOBALS DriverGlobals,
1991     __in
1992     WDFIOTARGET IoTarget
1993     )
1994 /*++
1995 
1996 Routine Description:
1997     Returns the file handle that the target represents. For KMDF, the handle is a kernel
1998     handle, so it is not tied to any process context. For UMDF it is a Win32 handle opened
1999     in the host process context. Not all targets have a file handle associated with them,
2000     so NULL is a valid return value that does not indicate error.
2001 
2002 Arguments:
2003     IoTarget - target whose file handle is being returned
2004 
2005 Return Value:
2006     A valid kernel/win32 handle or NULL
2007 
2008   --*/
2009 {
2010     PFX_DRIVER_GLOBALS pFxDriverGlobals;
2011     FxIoTargetRemote* pTarget;
2012     PVOID handle;
2013 
2014     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
2015                                    IoTarget,
2016                                    FX_TYPE_IO_TARGET_REMOTE,
2017                                    (PVOID*) &pTarget,
2018                                    &pFxDriverGlobals);
2019 
2020     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
2021                         "enter WDFIOTARGET 0x%p", IoTarget);
2022 
2023     handle = pTarget->GetTargetHandle();
2024 
2025     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
2026                         "exit WDFIOTARGET 0x%p, WDM file handle 0x%p",
2027                         IoTarget, handle);
2028 
2029     return handle;
2030 }
2031 
2032 
2033 } // extern "C"
2034