1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxDeviceApi.cpp
8 
9 Abstract:
10 
11     This module exposes the "C" interface to the FxDevice object.
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19     Both kernel and user mode
20 
21 Revision History:
22 
23 --*/
24 
25 #include "coreprivshared.hpp"
26 #include "fxiotarget.hpp"
27 
28 extern "C" {
29 // #include "FxDeviceApi.tmh"
30 }
31 
32 struct FxOffsetAndName {
33     __nullterminated PCHAR Name;
34     UCHAR Offset;
35 };
36 
37 #define OFFSET_AND_NAME(type, offset) { #offset, FIELD_OFFSET(type, offset) }
38 
39 //
40 // extern "C" the entire file
41 //
42 extern "C" {
43 
__drv_maxIRQL(DISPATCH_LEVEL)44 __drv_maxIRQL(DISPATCH_LEVEL)
45 WDFDRIVER
46 STDCALL
47 WDFEXPORT(WdfDeviceGetDriver)(
48     __in
49     PWDF_DRIVER_GLOBALS DriverGlobals,
50     __in
51     WDFDEVICE Device
52     )
53 /*++
54 
55 Routine Description:
56 
57     Given a Device Handle, return a Handle to the Driver object
58     containing this device.
59 
60 Arguments:
61     Device - WDF Device handle.
62 
63 Returns:
64     WDF Driver handle.
65 
66 --*/
67 
68 {
69     DDI_ENTRY();
70 
71     FxDevice* pDevice;
72 
73     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
74                          Device,
75                          FX_TYPE_DEVICE,
76                          (PVOID*) &pDevice);
77 
78     //
79     // No need to ref count the driver handle b/c it will be around as long
80     // as the device handle is.
81     //
82     return pDevice->GetDriver()->GetHandle();
83 }
84 
__drv_maxIRQL(DISPATCH_LEVEL)85 __drv_maxIRQL(DISPATCH_LEVEL)
86 WDFIOTARGET
87 STDCALL
88 WDFEXPORT(WdfDeviceGetIoTarget)(
89     __in
90     PWDF_DRIVER_GLOBALS DriverGlobals,
91     __in
92     WDFDEVICE Device
93     )
94 {
95     DDI_ENTRY();
96 
97     FxIoTarget* pTarget;
98     FxDeviceBase *pDeviceBase;
99 
100     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
101                          Device,
102                          FX_TYPE_DEVICE_BASE,
103                          (PVOID*) &pDeviceBase);
104 
105     pTarget = pDeviceBase->GetDefaultIoTarget();
106 
107     if (pTarget != NULL) {
108         return pTarget->GetHandle();
109     }
110 
111     return NULL;
112 }
113 
_IRQL_requires_max_(DISPATCH_LEVEL)114 _IRQL_requires_max_(DISPATCH_LEVEL)
115 WDFIOTARGET
116 STDCALL
117 WDFEXPORT(WdfDeviceGetSelfIoTarget)(
118     _In_
119     PWDF_DRIVER_GLOBALS DriverGlobals,
120     _In_
121     WDFDEVICE Device
122     )
123 
124 /*++
125 
126 Routine Description:
127 
128     Return the handle to the Self IO target for the device. A Self
129     IO target is only created if the client opted for it by calling
130     WdfDeviceInitAllowSelfTarget
131 
132 Arguments:
133 
134     Device - Handle to the Device Object for which Self IO target is needed
135 
136 Returns:
137 
138     WDFIOTARGET handle to the Self IO Target. NULL is returned in case the
139     device does not have an Self IO target.
140 
141 --*/
142 
143 {
144     DDI_ENTRY();
145 
146     FxIoTargetSelf* pTarget;
147     FxDevice *pDevice;
148 
149     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
150                          Device,
151                          FX_TYPE_DEVICE,
152                          (PVOID*) &pDevice);
153 
154     pTarget = pDevice->GetSelfIoTarget();
155 
156     if (pTarget != NULL) {
157         return pTarget->GetHandle();
158     }
159 
160     return NULL;
161 }
162 
163 _Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)164 __drv_maxIRQL(PASSIVE_LEVEL)
165 NTSTATUS
166 STDCALL
167 WDFEXPORT(WdfDeviceRetrieveDeviceName)(
168     __in
169     PWDF_DRIVER_GLOBALS DriverGlobals,
170     __in
171     WDFDEVICE Device,
172     __in
173     WDFSTRING String
174     )
175 {
176     DDI_ENTRY();
177 
178     PFX_DRIVER_GLOBALS pFxDriverGlobals;
179     FxDevice *pDevice;
180     FxString* pString;
181     NTSTATUS status;
182 
183     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
184                                    Device,
185                                    FX_TYPE_DEVICE,
186                                    (PVOID *) &pDevice,
187                                    &pFxDriverGlobals);
188 
189     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
190     if (!NT_SUCCESS(status)) {
191         return status;
192     }
193 
194     FxObjectHandleGetPtr(pFxDriverGlobals,
195                          String,
196                          FX_TYPE_STRING,
197                          (PVOID*) &pString);
198 
199     if (pDevice->m_DeviceName.Buffer != NULL) {
200         status = pString->Assign(&pDevice->m_DeviceName);
201     }
202     else {
203         status = STATUS_INVALID_PARAMETER;
204         DoTraceLevelMessage(
205             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
206             "Device name for WDFDEVICE 0x%p is NULL. Possibly incorrect "
207             "device handle was passed, %!STATUS!", Device, status);
208     }
209 
210     return status;
211 }
212 
__drv_maxIRQL(DISPATCH_LEVEL)213 __drv_maxIRQL(DISPATCH_LEVEL)
214 VOID
215 STDCALL
216 WDFEXPORT(WdfDeviceSetCharacteristics)(
217     __in
218     PWDF_DRIVER_GLOBALS DriverGlobals,
219     __in
220     WDFDEVICE Device,
221     __in
222     ULONG DeviceCharacteristics
223     )
224 {
225     DDI_ENTRY();
226 
227     FxDevice *pDevice;
228     MxDeviceObject deviceObject;
229 
230     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
231                          Device,
232                          FX_TYPE_DEVICE,
233                          (PVOID*) &pDevice);
234 
235     deviceObject.SetObject(pDevice->GetDeviceObject());
236     deviceObject.SetCharacteristics(DeviceCharacteristics |
237                                                   FILE_DEVICE_SECURE_OPEN);
238 }
239 
__drv_maxIRQL(DISPATCH_LEVEL)240 __drv_maxIRQL(DISPATCH_LEVEL)
241 ULONG
242 STDCALL
243 WDFEXPORT(WdfDeviceGetCharacteristics)(
244     __in
245     PWDF_DRIVER_GLOBALS DriverGlobals,
246     __in
247     WDFDEVICE Device
248     )
249 {
250     DDI_ENTRY();
251 
252     FxDevice *pDevice;
253     MxDeviceObject deviceObject;
254 
255     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
256                          Device,
257                          FX_TYPE_DEVICE,
258                          (PVOID*) &pDevice);
259 
260     deviceObject.SetObject(pDevice->GetDeviceObject());
261 
262     return deviceObject.GetCharacteristics();
263 }
264 
__drv_maxIRQL(DISPATCH_LEVEL)265 __drv_maxIRQL(DISPATCH_LEVEL)
266 ULONG
267 STDCALL
268 WDFEXPORT(WdfDeviceGetAlignmentRequirement)(
269     __in
270     PWDF_DRIVER_GLOBALS DriverGlobals,
271     __in
272     WDFDEVICE Device
273     )
274 {
275     DDI_ENTRY();
276 
277     FxDeviceBase* pDeviceBase;
278     MxDeviceObject deviceObject;
279 
280     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
281                          Device,
282                          FX_TYPE_DEVICE_BASE,
283                          (PVOID*) &pDeviceBase);
284 
285     deviceObject.SetObject(pDeviceBase->GetDeviceObject());
286 
287     return deviceObject.GetAlignmentRequirement();
288 }
289 
__drv_maxIRQL(DISPATCH_LEVEL)290 __drv_maxIRQL(DISPATCH_LEVEL)
291 VOID
292 STDCALL
293 WDFEXPORT(WdfDeviceSetAlignmentRequirement)(
294     __in
295     PWDF_DRIVER_GLOBALS DriverGlobals,
296     __in
297     WDFDEVICE Device,
298     __in
299     ULONG AlignmentRequirement
300     )
301 {
302     DDI_ENTRY();
303 
304     FxDeviceBase* pDeviceBase;
305     MxDeviceObject deviceObject;
306 
307     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
308                          Device,
309                          FX_TYPE_DEVICE_BASE,
310                          (PVOID*) &pDeviceBase);
311 
312     deviceObject.SetObject(pDeviceBase->GetDeviceObject());
313 
314     deviceObject.SetAlignmentRequirement(AlignmentRequirement);
315 }
316 
__drv_maxIRQL(DISPATCH_LEVEL)317 __drv_maxIRQL(DISPATCH_LEVEL)
318 WDF_DEVICE_PNP_STATE
319 STDCALL
320 WDFEXPORT(WdfDeviceGetDevicePnpState)(
321     __in
322     PWDF_DRIVER_GLOBALS DriverGlobals,
323     __in
324     WDFDEVICE Device
325     )
326 {
327     DDI_ENTRY();
328 
329     FxDevice *pDevice;
330 
331     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
332                          Device,
333                          FX_TYPE_DEVICE,
334                          (PVOID*) &pDevice);
335 
336     return pDevice->GetDevicePnpState();
337 }
338 
__drv_maxIRQL(DISPATCH_LEVEL)339 __drv_maxIRQL(DISPATCH_LEVEL)
340 WDF_DEVICE_POWER_STATE
341 STDCALL
342 WDFEXPORT(WdfDeviceGetDevicePowerState)(
343     __in
344     PWDF_DRIVER_GLOBALS DriverGlobals,
345     __in
346     WDFDEVICE Device
347     )
348 {
349     DDI_ENTRY();
350 
351     FxDevice *pDevice;
352 
353     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
354                          Device,
355                          FX_TYPE_DEVICE,
356                          (PVOID*) &pDevice);
357 
358     return pDevice->GetDevicePowerState();
359 }
360 
__drv_maxIRQL(DISPATCH_LEVEL)361 __drv_maxIRQL(DISPATCH_LEVEL)
362 WDF_DEVICE_POWER_POLICY_STATE
363 STDCALL
364 WDFEXPORT(WdfDeviceGetDevicePowerPolicyState)(
365     __in
366     PWDF_DRIVER_GLOBALS DriverGlobals,
367     __in
368     WDFDEVICE Device
369     )
370 {
371     DDI_ENTRY();
372 
373     FxDevice *pDevice;
374 
375     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
376                          Device,
377                          FX_TYPE_DEVICE,
378                          (PVOID*) &pDevice);
379 
380     return pDevice->GetDevicePowerPolicyState();
381 }
382 
383 _Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)384 __drv_maxIRQL(DISPATCH_LEVEL)
385 NTSTATUS
386 STDCALL
387 WDFEXPORT(WdfDeviceAssignS0IdleSettings)(
388     __in
389     PWDF_DRIVER_GLOBALS DriverGlobals,
390     __in
391     WDFDEVICE Device,
392     __in
393     PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings
394     )
395 {
396     DDI_ENTRY();
397 
398     PFX_DRIVER_GLOBALS pFxDriverGlobals;
399     NTSTATUS status;
400     FxDevice* pDevice;
401 
402     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
403                                    Device,
404                                    FX_TYPE_DEVICE,
405                                    (PVOID *) &pDevice,
406                                    &pFxDriverGlobals);
407 
408     FxPointerNotNull(pFxDriverGlobals, Settings);
409 
410     if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) {
411         status = STATUS_INVALID_DEVICE_REQUEST;
412 
413         DoTraceLevelMessage(
414             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
415             "Device 0x%p is not the power policy owner, caller cannot set S0"
416             " idle settings %!STATUS!", Device, status);
417 
418         return status;
419     }
420 
421     //
422     // Validate the Settings parameter
423     //
424     if (Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS) &&
425         Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9) &&
426         Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7)) {
427         status = STATUS_INFO_LENGTH_MISMATCH;
428         DoTraceLevelMessage(
429             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
430             "Expected Settings Size %d, got %d, %!STATUS!",
431             sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS), Settings->Size,
432             status);
433         return status;
434     }
435     else if (Settings->DxState < PowerDeviceD1 ||
436              Settings->DxState > PowerDeviceMaximum ||
437              Settings->IdleCaps < IdleCannotWakeFromS0 ||
438              Settings->IdleCaps > IdleUsbSelectiveSuspend ||
439              Settings->UserControlOfIdleSettings < IdleDoNotAllowUserControl ||
440              Settings->UserControlOfIdleSettings > IdleAllowUserControl ||
441              Settings->Enabled < WdfFalse ||
442              Settings->Enabled > WdfUseDefault) {
443 
444         status = STATUS_INVALID_PARAMETER;
445         DoTraceLevelMessage(
446             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
447             "a field (DxState, IdleCaps, Enabled, or UserControlOfIdleSettings)"
448             " is out range, %!STATUS!", status);
449         return status;
450     }
451 
452     //
453     // PowerUpIdleDeviceOnSystemWake is available only on > 1.7 and can be set to true
454     // only when IdleCaps is IdleCannotWakeFromS0
455     //
456     if (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7)) {
457         if (Settings->PowerUpIdleDeviceOnSystemWake < WdfFalse ||
458             Settings->PowerUpIdleDeviceOnSystemWake > WdfUseDefault) {
459 
460             status = STATUS_INVALID_PARAMETER;
461             DoTraceLevelMessage(
462                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
463                 "value of field PowerUpIdleDeviceOnSystemWake is out of range,"
464                 " %!STATUS!", status);
465             return status;
466         }
467         else if (Settings->IdleCaps != IdleCannotWakeFromS0 &&
468             Settings->PowerUpIdleDeviceOnSystemWake != WdfUseDefault) {
469 
470             status = STATUS_INVALID_PARAMETER;
471             DoTraceLevelMessage(
472                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
473                 "value of field PowerUpIdleDeviceOnSystemWake should be set only when"
474                 " IdleCaps is IdleCannotWakeFromS0, %!STATUS!", status);
475             return status;
476         }
477     }
478 
479     //
480     // IdleTimeoutType is available only on > 1.9
481     //
482     if (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) {
483         if (Settings->IdleTimeoutType > SystemManagedIdleTimeoutWithHint) {
484             status = STATUS_INVALID_PARAMETER;
485             DoTraceLevelMessage(
486                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
487                 "WDFDEVICE %p, value of field IdleTimeoutType is out of range,"
488                 " %!STATUS!", Device, status);
489             return status;
490         }
491     }
492 
493     return pDevice->m_PkgPnp->PowerPolicySetS0IdleSettings(Settings);
494 }
495 
496 _Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)497 __drv_maxIRQL(DISPATCH_LEVEL)
498 NTSTATUS
499 STDCALL
500 WDFEXPORT(WdfDeviceAssignSxWakeSettings)(
501     __in
502     PWDF_DRIVER_GLOBALS DriverGlobals,
503     __in
504     WDFDEVICE Device,
505     __in
506     PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings
507     )
508 {
509     DDI_ENTRY();
510 
511     NTSTATUS status;
512     FxDevice* pDevice;
513     PFX_DRIVER_GLOBALS pFxDriverGlobals;
514     BOOLEAN armForWakeIfChildrenAreArmedForWake;
515     BOOLEAN indicateChildWakeOnParentWake;
516 
517     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
518                                    Device,
519                                    FX_TYPE_DEVICE,
520                                    (PVOID *) &pDevice,
521                                    &pFxDriverGlobals);
522 
523     FxPointerNotNull(pFxDriverGlobals, Settings);
524 
525     if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) {
526         status = STATUS_INVALID_DEVICE_REQUEST;
527 
528         DoTraceLevelMessage(
529             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
530             "Device 0x%p is not the power policy owner, caller cannot set Sx"
531             " wake settings %!STATUS!", Device, status);
532 
533         return status;
534     }
535 
536     //
537     // Validate the Settings parameter
538     //
539     if (Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS) &&
540         Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5)) {
541         status = STATUS_INFO_LENGTH_MISMATCH;
542         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
543                             "Expected Settings Size %x, got %x, %!STATUS!",
544                             sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS),
545                             Settings->Size,
546                             status);
547         return status;
548     }
549     else if (Settings->DxState < PowerDeviceD1 ||
550              Settings->DxState > PowerDeviceMaximum ||
551              Settings->UserControlOfWakeSettings < WakeDoNotAllowUserControl ||
552              Settings->UserControlOfWakeSettings > WakeAllowUserControl ||
553              Settings->Enabled < WdfFalse ||
554              Settings->Enabled > WdfUseDefault) {
555 
556         status = STATUS_INVALID_PARAMETER;
557         DoTraceLevelMessage(
558             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
559             "a field (DxState, Enabled, or UserControlOfIdleSettings) is out "
560             "range, %!STATUS!", status);
561         return status;
562     }
563 
564     //
565     // Extract the values from the structure for all the parameters that were
566     // added after v1.5.  Since the size of the structure can only grow, get
567     // the values only if we are using a version of the struct after v1.5
568     //
569 
570     //
571     // ArmForWakeIfChildrenAreArmedForWake added after v1.5
572     //
573     armForWakeIfChildrenAreArmedForWake =
574         (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5)) ?
575             Settings->ArmForWakeIfChildrenAreArmedForWake :
576             FALSE;
577 
578     //
579     // IndicateChildWakeOnParentWake added after v1.5
580     //
581     indicateChildWakeOnParentWake =
582         (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5)) ?
583             Settings->IndicateChildWakeOnParentWake :
584             FALSE;
585 
586     return pDevice->m_PkgPnp->PowerPolicySetSxWakeSettings(
587         Settings,
588         armForWakeIfChildrenAreArmedForWake,
589         indicateChildWakeOnParentWake);
590 }
591 
592 _Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)593 __drv_maxIRQL(PASSIVE_LEVEL)
594 NTSTATUS
595 STDCALL
596 WDFEXPORT(WdfDeviceOpenRegistryKey)(
597     __in
598     PWDF_DRIVER_GLOBALS DriverGlobals,
599     __in
600     WDFDEVICE Device,
601     __in
602     ULONG DeviceInstanceKeyType,
603     __in
604     ACCESS_MASK DesiredAccess,
605     __in_opt
606     PWDF_OBJECT_ATTRIBUTES KeyAttributes,
607     __out
608     WDFKEY* Key
609     )
610 {
611     DDI_ENTRY();
612 
613     NTSTATUS status;
614     FxDevice* pDevice;
615     PFX_DRIVER_GLOBALS pFxDriverGlobals;
616 
617     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
618                                    Device,
619                                    FX_TYPE_DEVICE,
620                                    (PVOID *) &pDevice,
621                                    &pFxDriverGlobals);
622 
623     FxPointerNotNull(pFxDriverGlobals, Key);
624 
625     *Key = NULL;
626 
627     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
628     if (!NT_SUCCESS(status)) {
629         FxVerifierDbgBreakPoint(pFxDriverGlobals);
630         return status;
631     }
632 
633     status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes,
634                                         FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
635     if (!NT_SUCCESS(status)) {
636 
637         return status;
638     }
639 
640     return FxDevice::_OpenKey(pDevice->GetDriverGlobals(),
641                               NULL,
642                               pDevice,
643                               DeviceInstanceKeyType,
644                               DesiredAccess,
645                               KeyAttributes,
646                               Key);
647 }
648 
649 _Must_inspect_result_
_IRQL_requires_max_(PASSIVE_LEVEL)650 _IRQL_requires_max_(PASSIVE_LEVEL)
651 NTSTATUS
652 STDCALL
653 WDFEXPORT(WdfDeviceOpenDevicemapKey) (
654     _In_
655     PWDF_DRIVER_GLOBALS DriverGlobals,
656     _In_
657     WDFDEVICE Device,
658     _In_
659     PCUNICODE_STRING KeyName,
660     _In_
661     ACCESS_MASK DesiredAccess,
662     _In_opt_
663     PWDF_OBJECT_ATTRIBUTES KeyAttributes,
664     _Out_
665     WDFKEY* Key
666     )
667 {
668     DDI_ENTRY();
669 
670     NTSTATUS status;
671     FxDevice* pDevice;
672     PFX_DRIVER_GLOBALS pFxDriverGlobals;
673     FxRegKey* pKey = NULL;
674     WDFKEY keyHandle;
675 
676     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
677                                    Device,
678                                    FX_TYPE_DEVICE,
679                                    (PVOID *) &pDevice,
680                                    &pFxDriverGlobals);
681 
682     FxPointerNotNull(pFxDriverGlobals, Key);
683 
684     *Key = NULL;
685 
686     status = FxValidateUnicodeString(pFxDriverGlobals, KeyName);
687     if (!NT_SUCCESS(status)) {
688         return status;
689     }
690 
691     if (KeyName->Length == 0) {
692         status = STATUS_INVALID_PARAMETER;
693         DoTraceLevelMessage(
694             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
695             "The subkey cannot be of length zero, %!STATUS!", status);
696         return status;
697     }
698 
699     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
700     if (!NT_SUCCESS(status)) {
701         FxVerifierDbgBreakPoint(pFxDriverGlobals);
702         return status;
703     }
704 
705     status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes,
706                                         FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
707     if (!NT_SUCCESS(status)) {
708         return status;
709     }
710 
711     pKey = new(pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals);
712 
713     if (pKey == NULL) {
714         status = STATUS_INSUFFICIENT_RESOURCES;
715         DoTraceLevelMessage(
716             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
717             "Unable to allocate memory for WDFKEY object, %!STATUS!", status);
718             return status;
719     }
720 
721     pKey->SetDeviceBase(pDevice);
722 
723     status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle);
724     if (NT_SUCCESS(status)) {
725 
726         status = pDevice->OpenDevicemapKeyWorker(pFxDriverGlobals,
727                                                  KeyName,
728                                                  DesiredAccess,
729                                                  pKey);
730         if (NT_SUCCESS(status)) {
731             *Key = keyHandle;
732         }
733     }
734 
735     if (!NT_SUCCESS(status)) {
736         pKey->DeleteFromFailedCreate();
737         pKey = NULL;
738     }
739 
740     return status;
741 }
742 
__drv_maxIRQL(DISPATCH_LEVEL)743 __drv_maxIRQL(DISPATCH_LEVEL)
744 VOID
745 STDCALL
746 WDFEXPORT(WdfDeviceGetDeviceState)(
747     __in
748     PWDF_DRIVER_GLOBALS DriverGlobals,
749     __in
750     WDFDEVICE Device,
751     __out
752     PWDF_DEVICE_STATE DeviceState
753     )
754 {
755     DDI_ENTRY();
756 
757     FxDevice *pDevice;
758     PFX_DRIVER_GLOBALS pFxDriverGlobals;
759 
760     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
761                                    Device,
762                                    FX_TYPE_DEVICE,
763                                    (PVOID *) &pDevice,
764                                    &pFxDriverGlobals);
765 
766     FxPointerNotNull(pFxDriverGlobals, DeviceState);
767 
768     if (DeviceState->Size != sizeof(WDF_DEVICE_STATE)) {
769         DoTraceLevelMessage(
770             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
771             "WDFDEVICE 0x%p DeviceState Size %d, expected %d",
772             Device, DeviceState->Size, sizeof(WDF_DEVICE_STATE));
773 
774         FxVerifierDbgBreakPoint(pFxDriverGlobals);
775 
776         return; // STATUS_INFO_LENGTH_MISMATCH;
777     }
778 
779     pDevice->m_PkgPnp->GetPnpState(DeviceState);
780 }
781 
__drv_maxIRQL(DISPATCH_LEVEL)782 __drv_maxIRQL(DISPATCH_LEVEL)
783 VOID
784 STDCALL
785 WDFEXPORT(WdfDeviceSetDeviceState)(
786     __in
787     PWDF_DRIVER_GLOBALS DriverGlobals,
788     __in
789     WDFDEVICE Device,
790     __in
791     PWDF_DEVICE_STATE DeviceState
792     )
793 {
794     DDI_ENTRY();
795 
796     FxDevice *pDevice;
797     PFX_DRIVER_GLOBALS pFxDriverGlobals;
798     ULONG i;
799 
800     const static FxOffsetAndName offsets[] = {
801         OFFSET_AND_NAME(WDF_DEVICE_STATE, Disabled),
802         OFFSET_AND_NAME(WDF_DEVICE_STATE, DontDisplayInUI),
803         OFFSET_AND_NAME(WDF_DEVICE_STATE, Failed),
804         OFFSET_AND_NAME(WDF_DEVICE_STATE, NotDisableable),
805         OFFSET_AND_NAME(WDF_DEVICE_STATE, Removed),
806         OFFSET_AND_NAME(WDF_DEVICE_STATE, ResourcesChanged),
807     };
808 
809     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
810                                    Device,
811                                    FX_TYPE_DEVICE,
812                                    (PVOID *) &pDevice,
813                                    &pFxDriverGlobals);
814 
815     FxPointerNotNull(pFxDriverGlobals, DeviceState);
816 
817     if (DeviceState->Size != sizeof(WDF_DEVICE_STATE)) {
818         DoTraceLevelMessage(
819             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
820             "WDFDEVICE 0x%p, DeviceState Size %d, expected %d",
821             Device, DeviceState->Size, sizeof(WDF_DEVICE_STATE));
822 
823         FxVerifierDbgBreakPoint(pFxDriverGlobals);
824         return; // STATUS_INFO_LENGTH_MISMATCH;
825     }
826 
827     for (i = 0; i < ARRAY_SIZE(offsets); i++) {
828         WDF_TRI_STATE value;
829 
830         //
831         // This check makes prefast happy
832         //
833         if (offsets[i].Offset + sizeof(WDF_TRI_STATE) > sizeof(*DeviceState)) {
834             return;
835         }
836 
837         value = *(WDF_TRI_STATE*) WDF_PTR_ADD_OFFSET(DeviceState,
838                                                      offsets[i].Offset);
839 
840         switch (value) {
841         case WdfFalse:
842         case WdfTrue:
843         case WdfUseDefault:
844             break;
845 
846         default:
847             DoTraceLevelMessage(
848                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
849                 "WDFDEVICE 0x%p DeviceState WDF_TRI_STATE %s value out of range, "
850                 "value is %d", Device, offsets[i].Name, value);
851             FxVerifierDbgBreakPoint(pFxDriverGlobals);
852 
853             return; // STATUS_INVALID_PARAMETER
854         }
855     }
856 
857     pDevice->m_PkgPnp->SetPnpState(DeviceState);
858 
859     pDevice->InvalidateDeviceState();
860 }
861 
862 
863 _Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)864 __drv_maxIRQL(PASSIVE_LEVEL)
865 NTSTATUS
866 STDCALL
867 WDFEXPORT(WdfDeviceCreate)(
868     __in
869     PWDF_DRIVER_GLOBALS DriverGlobals,
870 
871 
872     __inout
873 
874     PWDFDEVICE_INIT* DeviceInit,
875     __in_opt
876     PWDF_OBJECT_ATTRIBUTES DeviceAttributes,
877     __out
878     WDFDEVICE* Device
879     )
880 {
881     DDI_ENTRY();
882 
883     FxDevice* pDevice;
884     NTSTATUS status;
885     PFX_DRIVER_GLOBALS pFxDriverGlobals;
886 
887     pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);
888 
889     FxPointerNotNull(pFxDriverGlobals, DeviceInit);
890     FxPointerNotNull(pFxDriverGlobals, *DeviceInit);
891     FxPointerNotNull(pFxDriverGlobals, Device);
892 
893     //
894     // Use the object's globals, not the caller's globals
895     //
896     pFxDriverGlobals = (*DeviceInit)->DriverGlobals;
897 
898     *Device = NULL;
899 
900     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
901     if (!NT_SUCCESS(status)) {
902         return status;
903     }
904 
905     //
906     // Make sure the device attributes is initialized properly if passed in
907     //
908     status = FxValidateObjectAttributes(pFxDriverGlobals,
909                                         DeviceAttributes,
910                                         (FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED |
911                                         FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED |
912                                         FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED));
913 
914     if (!NT_SUCCESS(status)) {
915         return status;
916     }
917 
918     if ((*DeviceInit)->CreatedDevice != NULL) {
919         //
920         // Already created the device!
921         //
922         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
923                             "WDFDEVICE 0x%p   already created"
924                             "STATUS_INVALID_DEVICE_STATE",
925                             Device);
926 
927         return STATUS_INVALID_DEVICE_STATE;
928     }
929 
930     //
931     // If security is specified, then the device being created *must* have a
932     // name to apply that security too.
933     //
934     if ((*DeviceInit)->Security.Sddl != NULL || (*DeviceInit)->Security.DeviceClassSet) {
935         if ((*DeviceInit)->HasName()) {
936             //
937             // Driver writer specified a name, all is good
938             //
939             DO_NOTHING();
940         }
941         else {
942             status = STATUS_INVALID_SECURITY_DESCR;
943 
944             DoTraceLevelMessage(
945                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
946                 "Device init: has device class or SDDL set, but does not have "
947                 "a name, %!STATUS!", status);
948 
949             return status;
950         }
951     }
952 
953     if ((*DeviceInit)->RequiresSelfIoTarget) {
954         if ((*DeviceInit)->InitType != FxDeviceInitTypeFdo) {
955             status = STATUS_INVALID_DEVICE_REQUEST;
956             DoTraceLevelMessage(
957                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
958                 "Client called WdfDeviceInitAllowSelfTarget. Self "
959                 "IO Targets are supported only for FDOs, %!STATUS!", status);
960             return status;
961         }
962     }
963 
964     status = FxDevice::_Create(pFxDriverGlobals,
965                                DeviceInit,
966                                DeviceAttributes,
967                                &pDevice);
968     if (NT_SUCCESS(status)) {
969         *Device = pDevice->GetHandle();
970     }
971 
972     return status;
973 }
974 
975 _Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)976 __drv_maxIRQL(PASSIVE_LEVEL)
977 NTSTATUS
978 STDCALL
979 WDFEXPORT(WdfDeviceCreateSymbolicLink)(
980     __in
981     PWDF_DRIVER_GLOBALS DriverGlobals,
982     __in
983     WDFDEVICE Device,
984     __in
985     PCUNICODE_STRING SymbolicLinkName
986     )
987 {
988     DDI_ENTRY();
989 
990     PFX_DRIVER_GLOBALS pFxDriverGlobals;
991     FxAutoString pdoName;
992     FxDevice* pDevice;
993     NTSTATUS status;
994 
995     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
996                                    Device,
997                                    FX_TYPE_DEVICE,
998                                    (PVOID *) &pDevice,
999                                    &pFxDriverGlobals);
1000 
1001     FxPointerNotNull(pFxDriverGlobals, SymbolicLinkName);
1002 
1003     if (SymbolicLinkName->Length == 0) {
1004         status = STATUS_INVALID_DEVICE_REQUEST;
1005 
1006         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1007                             "WDFDEVICE %p, SymbolicLinkName has no length, %!STATUS!",
1008                             Device, status);
1009 
1010         return status;
1011     }
1012 
1013     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1014     if (!NT_SUCCESS(status)) {
1015         return status;
1016     }
1017 
1018     status = FxValidateUnicodeString(pFxDriverGlobals, SymbolicLinkName);
1019     if (!NT_SUCCESS(status)) {
1020         return status;
1021     }
1022 
1023     if (pDevice->m_SymbolicLinkName.Buffer != NULL) {
1024         status = STATUS_INVALID_DEVICE_REQUEST;
1025 
1026         DoTraceLevelMessage(
1027             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1028             "WDFDEVICE %p already has a symbolic link associated with it, %!STATUS!",
1029             Device, status);
1030 
1031         return status;
1032     }
1033 
1034     status = pDevice->CreateSymbolicLink(pFxDriverGlobals, SymbolicLinkName);
1035 
1036     return status;
1037 }
1038 
1039 _Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)1040 __drv_maxIRQL(PASSIVE_LEVEL)
1041 NTSTATUS
1042 STDCALL
1043 WDFEXPORT(WdfDeviceQueryProperty)(
1044     __in
1045     PWDF_DRIVER_GLOBALS DriverGlobals,
1046     __in
1047     WDFDEVICE Device,
1048     __in
1049     DEVICE_REGISTRY_PROPERTY  DeviceProperty,
1050     __in
1051     ULONG BufferLength,
1052      __out_bcount_full(BufferLength)
1053     PVOID PropertyBuffer,
1054     __out
1055     PULONG ResultLength
1056     )
1057 /*++
1058 
1059 Routine Description:
1060     Retrieves the requested device property for the given device
1061 
1062 Arguments:
1063     Device - the device whose PDO whose will be queried
1064 
1065     DeviceProperty - the property being queried
1066 
1067     BufferLength - length of PropertyBuffer in bytes
1068 
1069     PropertyBuffer - Buffer which will receive the property being queried
1070 
1071     ResultLength - if STATUS_BUFFER_TOO_SMALL is returned, then this will contain
1072                    the required length
1073 
1074 Return Value:
1075     NTSTATUS
1076 
1077   --*/
1078 {
1079     DDI_ENTRY();
1080 
1081     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1082     FxDevice* pDevice;
1083     NTSTATUS status;
1084 
1085     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1086                                    Device,
1087                                    FX_TYPE_DEVICE,
1088                                    (PVOID *) &pDevice,
1089                                    &pFxDriverGlobals);
1090 
1091     FxPointerNotNull(pFxDriverGlobals, ResultLength);
1092     if (BufferLength > 0) {
1093         FxPointerNotNull(pFxDriverGlobals, PropertyBuffer);
1094     }
1095 
1096     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1097     if (!NT_SUCCESS(status)) {
1098         return status;
1099     }
1100 
1101     if (pDevice->IsLegacy()) {
1102         status = STATUS_INVALID_DEVICE_REQUEST;
1103 
1104         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1105                             "WDFDEVICE 0x%p is not a PnP device %!STATUS!",
1106                             Device, status);
1107 
1108         return status;
1109     }
1110 
1111     status = FxDevice::_QueryProperty(pFxDriverGlobals,
1112                                       NULL,
1113                                       pDevice,
1114                                       NULL,
1115                                       DeviceProperty,
1116                                       BufferLength,
1117                                       PropertyBuffer,
1118                                       ResultLength);
1119 
1120     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE,
1121                         "exit WDFDEVICE %p, Property %d, %!STATUS!",
1122                         Device, DeviceProperty, status);
1123 
1124     return status;
1125 }
1126 
1127 _Must_inspect_result_
__drv_maxIRQL(PASSIVE_LEVEL)1128 __drv_maxIRQL(PASSIVE_LEVEL)
1129 NTSTATUS
1130 STDCALL
1131 WDFEXPORT(WdfDeviceAllocAndQueryProperty)(
1132     __in
1133     PWDF_DRIVER_GLOBALS DriverGlobals,
1134     __in
1135     WDFDEVICE Device,
1136     __in
1137     DEVICE_REGISTRY_PROPERTY  DeviceProperty,
1138     __in
1139     __drv_strictTypeMatch(__drv_typeExpr)
1140     POOL_TYPE PoolType,
1141     __in_opt
1142     PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
1143     __out
1144     WDFMEMORY* PropertyMemory
1145     )
1146 /*++
1147 
1148 Routine Description:
1149     Allocates and retrieves the requested device property for the given device
1150 
1151 Arguments:
1152     Device - the pnp device whose PDO whose will be queried
1153 
1154     DeviceProperty - the property being queried
1155 
1156     PoolType - what type of pool to allocate
1157 
1158     PropertyMemoryAttributes - attributes to associate with PropertyMemory
1159 
1160     PropertyMemory - handle which will receive the property buffer
1161 
1162 Return Value:
1163     NTSTATUS
1164 
1165   --*/
1166 {
1167     DDI_ENTRY();
1168 
1169     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1170     FxDevice* pDevice;
1171     NTSTATUS status;
1172 
1173     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1174                                    Device,
1175                                    FX_TYPE_DEVICE,
1176                                    (PVOID *) &pDevice,
1177                                    &pFxDriverGlobals);
1178 
1179     FxPointerNotNull(pFxDriverGlobals, PropertyMemory);
1180 
1181     *PropertyMemory = NULL;
1182 
1183     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1184     if (!NT_SUCCESS(status)) {
1185         return status;
1186     }
1187 
1188     FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag);
1189 
1190     status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes);
1191     if (!NT_SUCCESS(status)) {
1192         return status;
1193     }
1194 
1195     if (pDevice->IsLegacy()) {
1196         status = STATUS_INVALID_DEVICE_REQUEST;
1197 
1198         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1199                             "WDFDEVICE %p is not a PnP device, %!STATUS!",
1200                             Device, status);
1201 
1202         return status;
1203     }
1204 
1205     status = FxDevice::_AllocAndQueryProperty(pFxDriverGlobals,
1206                                               NULL,
1207                                               pDevice,
1208                                               NULL,
1209                                               DeviceProperty,
1210                                               PoolType,
1211                                               PropertyMemoryAttributes,
1212                                               PropertyMemory);
1213 
1214     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE,
1215                         "exit WDFDEVICE %p, Property %d, %!STATUS!",
1216                         Device, DeviceProperty, status);
1217 
1218     return status;
1219 }
1220 
__drv_maxIRQL(DISPATCH_LEVEL)1221 __drv_maxIRQL(DISPATCH_LEVEL)
1222 VOID
1223 STDCALL
1224 WDFEXPORT(WdfDeviceSetStaticStopRemove)(
1225     __in
1226     PWDF_DRIVER_GLOBALS DriverGlobals,
1227     __in
1228     WDFDEVICE Device,
1229     __in
1230     BOOLEAN Stoppable
1231     )
1232 {
1233     DDI_ENTRY();
1234 
1235     FxDevice *pDevice;
1236 
1237     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
1238                          Device,
1239                          FX_TYPE_DEVICE,
1240                          (PVOID*) &pDevice);
1241 
1242     if (Stoppable) {
1243         //
1244         // Stoppable means that query stop / query remove can succeed.
1245         // This means m_DeviceStopCount == 0 (eventually if there are nested
1246         // calls to this function).
1247         //
1248         ASSERT(pDevice->m_PkgPnp->m_DeviceStopCount > 0);
1249         InterlockedDecrement((PLONG) &pDevice->m_PkgPnp->m_DeviceStopCount);
1250     }
1251     else {
1252         InterlockedIncrement((PLONG) &pDevice->m_PkgPnp->m_DeviceStopCount);
1253     }
1254 
1255     return;
1256 }
1257 
__drv_maxIRQL(DISPATCH_LEVEL)1258 __drv_maxIRQL(DISPATCH_LEVEL)
1259 VOID
1260 STDCALL
1261 WDFEXPORT(WdfDeviceSetFailed)(
1262     __in
1263     PWDF_DRIVER_GLOBALS DriverGlobals,
1264     __in
1265     WDFDEVICE Device,
1266     __in
1267     WDF_DEVICE_FAILED_ACTION FailedAction
1268     )
1269 {
1270     DDI_ENTRY();
1271 
1272     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1273     FxDevice *pDevice;
1274 
1275     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1276                                    Device,
1277                                    FX_TYPE_DEVICE,
1278                                    (PVOID *) &pDevice,
1279                                    &pFxDriverGlobals);
1280 
1281     if (FailedAction < WdfDeviceFailedAttemptRestart ||
1282         FailedAction > WdfDeviceFailedNoRestart) {
1283         DoTraceLevelMessage(
1284             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1285             "Invalid FailedAction %d", FailedAction);
1286         FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
1287         return;
1288     }
1289 
1290     DoTraceLevelMessage(
1291         pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDEVICE,
1292         "WDFDEVICE %p, !devobj %p SetFailed %!WDF_DEVICE_FAILED_ACTION!",
1293         Device, pDevice->GetDeviceObject(), FailedAction);
1294 
1295     pDevice->m_PkgPnp->SetDeviceFailed(FailedAction);
1296 }
1297 
1298 __inline
1299 NTSTATUS
StopIdleWorker(__in PWDF_DRIVER_GLOBALS DriverGlobals,__in WDFDEVICE Device,__in BOOLEAN WaitForD0,__in PVOID Tag,__in LONG Line,__in PSTR File)1300 StopIdleWorker(
1301     __in
1302     PWDF_DRIVER_GLOBALS DriverGlobals,
1303     __in
1304     WDFDEVICE Device,
1305     __in
1306     BOOLEAN WaitForD0,
1307     __in
1308     PVOID Tag,
1309     __in
1310     LONG Line,
1311     __in
1312     PSTR File
1313     )
1314 {
1315     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1316     NTSTATUS status;
1317     FxDevice *pDevice;
1318 
1319     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1320                                    Device,
1321                                    FX_TYPE_DEVICE,
1322                                    (PVOID *) &pDevice,
1323                                    &pFxDriverGlobals);
1324 
1325     if (WaitForD0) {
1326         status = FxVerifierCheckIrqlLevel(pFxDriverGlobals,
1327                                           PASSIVE_LEVEL);
1328         if (!NT_SUCCESS(status)) {
1329             return status;
1330         }
1331     }
1332 
1333 
1334     if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) {
1335         status = STATUS_INVALID_DEVICE_STATE;
1336         DoTraceLevelMessage(
1337             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1338             "WDFDEVICE %p WdfDeviceStopIdle does nothing if you are not the power "
1339             "policy owner for the stack, %!STATUS!", Device, status);
1340         return status;
1341     }
1342 
1343     status = pDevice->m_PkgPnp->PowerReference(WaitForD0, Tag, Line, File);
1344 
1345     DoTraceLevelMessage(
1346         pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE,
1347         "WDFDEVICE %p WdfDeviceStopIdle, WaitForD0 %d %!STATUS!",
1348         Device, WaitForD0, status);
1349 
1350     return status;
1351 }
1352 
1353 __inline
1354 VOID
ResumeIdleWorker(__in PWDF_DRIVER_GLOBALS DriverGlobals,__in WDFDEVICE Device,__in PVOID Tag,__in LONG Line,__in PSTR File)1355 ResumeIdleWorker(
1356     __in
1357     PWDF_DRIVER_GLOBALS DriverGlobals,
1358     __in
1359     WDFDEVICE Device,
1360     __in
1361     PVOID Tag,
1362     __in
1363     LONG Line,
1364     __in
1365     PSTR File
1366     )
1367 {
1368     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1369     FxDevice *pDevice;
1370 
1371     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1372                                    Device,
1373                                    FX_TYPE_DEVICE,
1374                                    (PVOID *) &pDevice,
1375                                    &pFxDriverGlobals);
1376 
1377     if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) {
1378         DoTraceLevelMessage(
1379             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1380             "WdfDeviceResumeIdle does nothing if you are not the power "
1381             "policy owner for the stack");
1382         return;
1383     }
1384 
1385     pDevice->m_PkgPnp->PowerDereference(Tag, Line, File);
1386 }
1387 
1388 _Must_inspect_result_
1389 __drv_when(WaitForD0 == 0, __drv_maxIRQL(DISPATCH_LEVEL))
1390 __drv_when(WaitForD0 != 0, __drv_maxIRQL(PASSIVE_LEVEL))
1391 NTSTATUS
1392 STDCALL
WDFEXPORT(WdfDeviceStopIdleNoTrack)1393 WDFEXPORT(WdfDeviceStopIdleNoTrack)(
1394     __in
1395     PWDF_DRIVER_GLOBALS DriverGlobals,
1396     __in
1397     WDFDEVICE Device,
1398     __in
1399     BOOLEAN WaitForD0
1400     )
1401 {
1402     DDI_ENTRY();
1403 
1404     NTSTATUS status;
1405 
1406     status = StopIdleWorker(DriverGlobals,
1407                             Device,
1408                             WaitForD0,
1409                             NULL,
1410                             0,
1411                             NULL);
1412 
1413     return status;
1414 }
1415 
1416 _Must_inspect_result_
1417 __drv_when(WaitForD0 == 0, __drv_maxIRQL(DISPATCH_LEVEL))
1418 __drv_when(WaitForD0 != 0, __drv_maxIRQL(PASSIVE_LEVEL))
1419 NTSTATUS
1420 STDCALL
WDFEXPORT(WdfDeviceStopIdleActual)1421 WDFEXPORT(WdfDeviceStopIdleActual)(
1422     __in
1423     PWDF_DRIVER_GLOBALS DriverGlobals,
1424     __in
1425     WDFDEVICE Device,
1426     __in
1427     BOOLEAN WaitForD0,
1428     __in_opt
1429     PVOID Tag,
1430     __in
1431     LONG Line,
1432     __in
1433     PSTR File
1434     )
1435 {
1436     DDI_ENTRY();
1437 
1438     NTSTATUS status;
1439 
1440     status = StopIdleWorker(DriverGlobals,
1441                             Device,
1442                             WaitForD0,
1443                             Tag,
1444                             Line,
1445                             File);
1446 
1447     return status;
1448 }
1449 
__drv_maxIRQL(DISPATCH_LEVEL)1450 __drv_maxIRQL(DISPATCH_LEVEL)
1451 VOID
1452 STDCALL
1453 WDFEXPORT(WdfDeviceResumeIdleNoTrack)(
1454     __in
1455     PWDF_DRIVER_GLOBALS DriverGlobals,
1456     __in
1457     WDFDEVICE Device
1458     )
1459 {
1460     DDI_ENTRY();
1461 
1462     ResumeIdleWorker(DriverGlobals,
1463                      Device,
1464                      NULL,
1465                      0,
1466                      NULL);
1467 }
1468 
__drv_maxIRQL(DISPATCH_LEVEL)1469 __drv_maxIRQL(DISPATCH_LEVEL)
1470 VOID
1471 STDCALL
1472 WDFEXPORT(WdfDeviceResumeIdleActual)(
1473     __in
1474     PWDF_DRIVER_GLOBALS DriverGlobals,
1475     __in
1476     WDFDEVICE Device,
1477     __in_opt
1478     PVOID Tag,
1479     __in
1480     LONG Line,
1481     __in
1482     PSTR File
1483     )
1484 {
1485     DDI_ENTRY();
1486 
1487     ResumeIdleWorker(DriverGlobals,
1488                      Device,
1489                      Tag,
1490                      Line,
1491                      File);
1492 }
1493 
__drv_maxIRQL(DISPATCH_LEVEL)1494 __drv_maxIRQL(DISPATCH_LEVEL)
1495 VOID
1496 STDCALL
1497 WDFEXPORT(WdfDeviceSetPnpCapabilities)(
1498     __in
1499     PWDF_DRIVER_GLOBALS DriverGlobals,
1500     __in
1501     WDFDEVICE Device,
1502     __in
1503     PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities
1504     )
1505 /*++
1506 
1507 Routine Description:
1508     Sets the pnp capabilities of the device.  This function is usually called
1509     during AddDevice or EvtDevicePrepareHardware since these values are queried
1510     by the stack and pnp during start device processing or immediately afterwards.
1511 
1512 Arguments:
1513     Device - Device being set
1514 
1515     PnpCapabilities - Caps being set
1516 
1517 Return Value:
1518     None
1519 
1520   --*/
1521 {
1522     DDI_ENTRY();
1523 
1524     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1525     FxDevice* pDevice;
1526     ULONG i;
1527 
1528     const static FxOffsetAndName offsets[] = {
1529         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, LockSupported),
1530         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, EjectSupported),
1531         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, Removable),
1532         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, DockDevice),
1533         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, UniqueID),
1534         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, SilentInstall),
1535         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, SurpriseRemovalOK),
1536         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, HardwareDisabled),
1537         OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, NoDisplayInUI),
1538     };
1539 
1540     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1541                                    Device,
1542                                    FX_TYPE_DEVICE,
1543                                    (PVOID *) &pDevice,
1544                                    &pFxDriverGlobals);
1545 
1546     FxPointerNotNull(pFxDriverGlobals, PnpCapabilities);
1547 
1548     if (PnpCapabilities->Size != sizeof(WDF_DEVICE_PNP_CAPABILITIES)) {
1549         DoTraceLevelMessage(
1550             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1551             "WDFDEVICE 0x%p PnpCapabilities Size %d, expected %d",
1552             Device, PnpCapabilities->Size, sizeof(WDF_DEVICE_PNP_CAPABILITIES));
1553         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1554 
1555         return; // STATUS_INFO_LENGTH_MISMATCH;
1556     }
1557     else {
1558         for (i = 0; i < ARRAY_SIZE(offsets); i++) {
1559             WDF_TRI_STATE value;
1560 
1561             //
1562             // This check makes prefast happy
1563             //
1564             if (offsets[i].Offset + sizeof(WDF_TRI_STATE) >
1565                                                     sizeof(*PnpCapabilities)) {
1566                 return;
1567             }
1568 
1569             value = *(WDF_TRI_STATE*) WDF_PTR_ADD_OFFSET(PnpCapabilities,
1570                                                          offsets[i].Offset);
1571             switch (value) {
1572             case WdfFalse:
1573             case WdfTrue:
1574             case WdfUseDefault:
1575                 break;
1576 
1577             default:
1578                 DoTraceLevelMessage(
1579                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1580                     "WDFDEVICE 0x%p PnpCapabilities WDF_TRI_STATE %s value out "
1581                     "of range, value is %d", Device, offsets[i].Name, value);
1582                 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1583 
1584                 return; // STATUS_INVALID_PARAMETER
1585             }
1586         }
1587     }
1588 
1589     pDevice->m_PkgPnp->SetPnpCaps(PnpCapabilities);
1590 }
1591 
__drv_maxIRQL(DISPATCH_LEVEL)1592 __drv_maxIRQL(DISPATCH_LEVEL)
1593 VOID
1594 STDCALL
1595 WDFEXPORT(WdfDeviceSetPowerCapabilities)(
1596     __in
1597     PWDF_DRIVER_GLOBALS DriverGlobals,
1598     __in
1599     WDFDEVICE Device,
1600     __in
1601     PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities
1602     )
1603 /*++
1604 
1605 Routine Description:
1606     Sets the power capabilities of the device.  This function is usually called
1607     during AddDevice or EvtDevicePrepareHardware since these values are queried
1608     by the stack and power during start device processing or immediately afterwards.
1609 
1610 Arguments:
1611     Device - Device being set
1612 
1613     PowerCapabilities - Caps being set
1614 
1615 Return Value:
1616     None
1617 
1618   --*/
1619 {
1620     DDI_ENTRY();
1621 
1622     FxDevice* pDevice;
1623     ULONG i;
1624     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1625 
1626     const static FxOffsetAndName offsets[] = {
1627         OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, DeviceD1),
1628         OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, DeviceD2),
1629         OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, WakeFromD0),
1630         OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, WakeFromD1),
1631         OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, WakeFromD2),
1632         OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, WakeFromD3),
1633     };
1634 
1635     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1636                                    Device,
1637                                    FX_TYPE_DEVICE,
1638                                    (PVOID *) &pDevice,
1639                                    &pFxDriverGlobals);
1640 
1641     FxPointerNotNull(pFxDriverGlobals, PowerCapabilities);
1642 
1643     if (PowerCapabilities->Size != sizeof(WDF_DEVICE_POWER_CAPABILITIES)) {
1644 
1645         DoTraceLevelMessage(
1646             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1647             "WDFDEVICE 0x%p PowerCapabilities Size %d, expected %d",
1648             Device, PowerCapabilities->Size,
1649             sizeof(WDF_DEVICE_POWER_CAPABILITIES));
1650 
1651         FxVerifierDbgBreakPoint(pFxDriverGlobals);
1652 
1653         return; // STATUS_INFO_LENGTH_MISMATCH;
1654     }
1655     else {
1656         for (i = 0; i < ARRAY_SIZE(offsets); i++) {
1657             WDF_TRI_STATE value;
1658 
1659             //
1660             // This check makes prefast happy
1661             //
1662             if (offsets[i].Offset + sizeof(WDF_TRI_STATE) >
1663                                                 sizeof(*PowerCapabilities)) {
1664                 return;
1665             }
1666 
1667             value = *(WDF_TRI_STATE*) WDF_PTR_ADD_OFFSET(PowerCapabilities,
1668                                                          offsets[i].Offset);
1669             switch (value) {
1670             case WdfFalse:
1671             case WdfTrue:
1672             case WdfUseDefault:
1673                 break;
1674 
1675             default:
1676                 DoTraceLevelMessage(
1677                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1678                     "WDFDEVICE 0x%p PowerCapabilities WDF_TRI_STATE %s value out "
1679                     "of range, value is %d",
1680                     Device, offsets[i].Name, value);
1681                 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1682 
1683                 return; // STATUS_INVALID_PARAMETER
1684             }
1685         }
1686 
1687         for (i = 0; i < ARRAY_SIZE(PowerCapabilities->DeviceState); i++) {
1688             if (PowerCapabilities->DeviceState[i] < PowerDeviceUnspecified ||
1689                 PowerCapabilities->DeviceState[i] > PowerDeviceMaximum) {
1690 
1691                 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1692                                     "WDFDEVICE 0x%p PowerCapabilities DeviceState is invalid",
1693                                     Device);
1694 
1695                 FxVerifierDbgBreakPoint(pFxDriverGlobals);
1696 
1697                 return; // STATUS_INVALID_PARAMETER;
1698             }
1699         }
1700 
1701         if (PowerCapabilities->DeviceWake < PowerDeviceUnspecified ||
1702             PowerCapabilities->DeviceWake > PowerDeviceMaximum) {
1703 
1704             DoTraceLevelMessage(
1705                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1706                 "WDFDEVICE 0x%p PowerCapabilities DeviceWake %d is out of range",
1707                 Device, PowerCapabilities->DeviceWake);
1708 
1709             FxVerifierDbgBreakPoint(pFxDriverGlobals);
1710 
1711             return; // STATUS_INVALID_PARAMETER;
1712         }
1713 
1714         if (PowerCapabilities->SystemWake < PowerSystemUnspecified ||
1715             PowerCapabilities->SystemWake > PowerSystemMaximum) {
1716 
1717             DoTraceLevelMessage(
1718                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1719                 "WDFDEVICE 0x%p PowerCapabilities SystemWake %d is out of range",
1720                 Device, PowerCapabilities->SystemWake);
1721 
1722             FxVerifierDbgBreakPoint(pFxDriverGlobals);
1723 
1724             return; // STATUS_INVALID_PARAMETER;
1725         }
1726 
1727         if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE &&
1728             PowerCapabilities->IdealDxStateForSx != PowerDeviceMaximum) {
1729             DoTraceLevelMessage(
1730                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1731                 "WDFDEVICE 0x%p PowerCapabilities IdealDxStateForSx %d can only"
1732                 " be set by the power policy owner",
1733                 Device, PowerCapabilities->IdealDxStateForSx);
1734 
1735             FxVerifierDbgBreakPoint(pFxDriverGlobals);
1736 
1737             return; // STATUS_INVALID_PARAMETER;
1738         }
1739 
1740         //
1741         // D0 is not allowed as an ideal Dx state
1742         //
1743         if (PowerCapabilities->IdealDxStateForSx < PowerDeviceD1 ||
1744             PowerCapabilities->IdealDxStateForSx > PowerDeviceMaximum) {
1745 
1746             DoTraceLevelMessage(
1747                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1748                 "WDFDEVICE 0x%p PowerCapabilities IdealDxStateForSx %d is out "
1749                 "of range", Device, PowerCapabilities->IdealDxStateForSx);
1750 
1751             FxVerifierDbgBreakPoint(pFxDriverGlobals);
1752 
1753             return; // STATUS_INVALID_PARAMETER;
1754         }
1755     }
1756 
1757 
1758     pDevice->m_PkgPnp->SetPowerCaps(PowerCapabilities);
1759 }
1760 
1761 _Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)1762 __drv_maxIRQL(DISPATCH_LEVEL)
1763 NTSTATUS
1764 STDCALL
1765 WDFEXPORT(WdfDeviceConfigureRequestDispatching)(
1766     __in
1767     PWDF_DRIVER_GLOBALS DriverGlobals,
1768     __in
1769     WDFDEVICE Device,
1770     __in
1771     WDFQUEUE Queue,
1772     __in
1773     __drv_strictTypeMatch(__drv_typeCond)
1774     WDF_REQUEST_TYPE RequestType
1775     )
1776 
1777 /*++
1778 
1779 Routine Description:
1780 
1781     Configure which IRP_MJ_* requests are automatically
1782     forwarded by the I/O package to the specified Queue.
1783 
1784     By default the I/O package sends all requests to the
1785     devices default queue. This API allows certain requests
1786     to be specified to their own queues under driver control.
1787 
1788 Arguments:
1789 
1790     Device    - The device which is handling the IO.
1791 
1792     Queue     - I/O Queue object to forward specified request to.
1793 
1794     RequestType - WDF Request type to be forwarded to the queue
1795 
1796 Returns:
1797 
1798     NTSTATUS
1799 
1800 --*/
1801 
1802 {
1803     DDI_ENTRY();
1804 
1805     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1806     NTSTATUS  status;
1807     FxDevice*  pDevice;
1808     FxIoQueue* pFxIoQueue;
1809 
1810     pDevice = NULL;
1811     pFxIoQueue = NULL;
1812 
1813     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1814                                    Device,
1815                                    FX_TYPE_DEVICE,
1816                                    (PVOID *) &pDevice,
1817                                    &pFxDriverGlobals);
1818 
1819     if (RequestType != WdfRequestTypeCreate &&
1820         RequestType != WdfRequestTypeRead &&
1821         RequestType != WdfRequestTypeWrite &&
1822         RequestType != WdfRequestTypeDeviceControl &&
1823         RequestType != WdfRequestTypeDeviceControlInternal) {
1824         status = STATUS_INVALID_PARAMETER;
1825         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1826                             "Invalid RequestType %!WDF_REQUEST_TYPE!, %!STATUS!",
1827                             RequestType, status);
1828         return status;
1829     }
1830 
1831     //
1832     // Validate the Queue handle
1833     //
1834     FxObjectHandleGetPtr(pFxDriverGlobals,
1835                          Queue,
1836                          FX_TYPE_QUEUE,
1837                          (PVOID*)&pFxIoQueue);
1838 
1839     if (pDevice != pFxIoQueue->GetDevice()) {
1840         status = STATUS_INVALID_DEVICE_REQUEST;
1841 
1842         DoTraceLevelMessage(
1843             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
1844             "Input WDFQUEUE 0x%p doesn't belong to the WDFDEVICE 0x%p, %!STATUS!",
1845             Queue, Device, status);
1846 
1847         return status;
1848     }
1849 
1850     if (pDevice->IsLegacy()) {
1851         //
1852         // This is a controldevice. Make sure the create is called after the device
1853         // is initialized and ready to accept I/O.
1854         //
1855         MxDeviceObject deviceObject(pDevice->GetDeviceObject());
1856         if ((deviceObject.GetFlags() & DO_DEVICE_INITIALIZING) == 0x0) {
1857 
1858             status = STATUS_INVALID_DEVICE_STATE;
1859             DoTraceLevelMessage(
1860                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1861                 "Queue cannot be configured for automatic dispatching"
1862                 " after WdfControlDeviceFinishInitializing"
1863                 "is called on the WDFDEVICE %p is called %!STATUS!",
1864                 Device,
1865                 status);
1866             return status;
1867         }
1868     }
1869     else {
1870         //
1871         // This is either FDO or PDO. Make sure it's not started yet.
1872         //
1873         if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) {
1874             status = STATUS_INVALID_DEVICE_STATE;
1875             DoTraceLevelMessage(
1876                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1877                 "Queue cannot be configured for automatic dispatching"
1878                 "after the WDFDEVICE %p is started, %!STATUS!",
1879                 Device, status);
1880             return status;
1881         }
1882     }
1883 
1884     if (RequestType == WdfRequestTypeCreate) {
1885         status = pDevice->m_PkgGeneral->ConfigureForwarding(pFxIoQueue);
1886     }
1887     else {
1888         status = pDevice->m_PkgIo->ConfigureForwarding(pFxIoQueue, RequestType);
1889     }
1890 
1891     return status;
1892 }
1893 
__drv_maxIRQL(DISPATCH_LEVEL)1894 __drv_maxIRQL(DISPATCH_LEVEL)
1895 WDFQUEUE
1896 STDCALL
1897 WDFEXPORT(WdfDeviceGetDefaultQueue)(
1898     __in
1899     PWDF_DRIVER_GLOBALS DriverGlobals,
1900     __in
1901     WDFDEVICE Device
1902     )
1903 
1904 /*++
1905 
1906 Routine Description:
1907 
1908     Return the handle to the default queue for the device.
1909 
1910 Arguments:
1911 
1912     Device - Handle to the Device Object
1913 
1914 Returns:
1915 
1916     WDFQUEUE
1917 
1918 --*/
1919 
1920 {
1921     DDI_ENTRY();
1922 
1923     FxPkgIo*   pPkgIo;;
1924     FxIoQueue* pFxIoQueue;;
1925     FxDevice * pFxDevice;
1926     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1927 
1928     pPkgIo = NULL;
1929     pFxIoQueue = NULL;
1930 
1931     //
1932     // Validate the I/O Package handle, and get the FxPkgIo*
1933     //
1934     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1935                                    Device,
1936                                    FX_TYPE_DEVICE,
1937                                    (PVOID *) &pFxDevice,
1938                                    &pFxDriverGlobals);
1939 
1940     pPkgIo = (FxPkgIo *) pFxDevice->m_PkgIo;
1941     pFxIoQueue = pPkgIo->GetDefaultQueue();
1942 
1943     //
1944     // A default queue is optional
1945     //
1946     if (pFxIoQueue == NULL) {
1947         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIO,
1948                             "No default Queue configured "
1949                             "for Device 0x%p", Device);
1950         return NULL;
1951     }
1952 
1953     return (WDFQUEUE)pFxIoQueue->GetObjectHandle();;
1954 }
1955 
1956 _Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)1957 __drv_maxIRQL(DISPATCH_LEVEL)
1958 NTSTATUS
1959 STDCALL
1960 WDFEXPORT(WdfDeviceEnqueueRequest)(
1961     __in
1962     PWDF_DRIVER_GLOBALS DriverGlobals,
1963     __in
1964     WDFDEVICE  Device,
1965     __in
1966     WDFREQUEST Request
1967     )
1968 
1969 /*++
1970 
1971 Routine Description:
1972 
1973     Inserts a request into the I/O Package processing pipeline.
1974 
1975     The given request is processed by the I/O package, forwarding
1976     it to its configured destination or the default queue.
1977 
1978     If an EvtIoInCallerContext is callback is registered, it is not called.
1979 
1980 Arguments:
1981 
1982     Device  - Handle to the Device Object
1983 
1984     Request - Request to insert in the processing pipeline
1985 
1986 Return Value:
1987 
1988     STATUS_SUCCESS - Request has been inserted into the I/O processing pipeline
1989 
1990     !NT_SUCCESS(status)
1991     STATUS_WDF_BUSY - Device is not accepting requests, the driver still owns the
1992                      the request and must complete it, or correct the conditions.
1993 
1994 --*/
1995 
1996 {
1997     DDI_ENTRY();
1998 
1999     PFX_DRIVER_GLOBALS pFxDriverGlobals;
2000     FxDevice *pDevice;
2001     FxRequest* pRequest;
2002 
2003     //
2004     // Validate the device object handle
2005     //
2006     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
2007                                    Device,
2008                                    FX_TYPE_DEVICE,
2009                                    (PVOID *) &pDevice,
2010                                    &pFxDriverGlobals);
2011     //
2012     // Validate Device object handle
2013     //
2014     FxObjectHandleGetPtr(pFxDriverGlobals,
2015                          Device,
2016                          FX_TYPE_DEVICE,
2017                          (PVOID *) &pDevice);
2018 
2019     //
2020     // Validate the request object handle
2021     //
2022     FxObjectHandleGetPtr(pFxDriverGlobals,
2023                          Request,
2024                          FX_TYPE_REQUEST,
2025                          (PVOID *) &pRequest);
2026 
2027     //
2028     // Dispatch it to the Io Package object
2029     //
2030     return pDevice->m_PkgIo->EnqueueRequest(pDevice, pRequest);
2031 }
2032 
__drv_maxIRQL(DISPATCH_LEVEL)2033 __drv_maxIRQL(DISPATCH_LEVEL)
2034 POWER_ACTION
2035 STDCALL
2036 WDFEXPORT(WdfDeviceGetSystemPowerAction)(
2037     __in
2038     PWDF_DRIVER_GLOBALS DriverGlobals,
2039     __in
2040     WDFDEVICE Device
2041     )
2042 
2043 /*++
2044 
2045 Routine Description:
2046 
2047     This DDI returns the System power action.
2048 
2049     If the DDI is called in the power down path of a device, it will return the
2050     current system power transition type because of which the device is powering
2051     down.  If the DDI is called in the power up path of a device, it will return
2052     the system power transition type which initially put the device into a lower
2053     power state.  If the DDI is called during the normal functioning of a device
2054     that is not undergoing a power state transition, or if the device is powering
2055     up as part of the system start up, the DDI will return the PowerActionNone
2056     value.
2057 
2058 Arguments:
2059 
2060     Device  - Handle to the Device Object
2061 
2062 Return Value:
2063 
2064     Returns a POWER_ACTION enum value that represents the current system power
2065     action with regards to any system power transition underway.
2066 
2067 --*/
2068 
2069 {
2070     DDI_ENTRY();
2071 
2072     FxDevice *pDevice;
2073 
2074     //
2075     // Validate Device object handle
2076     //
2077     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
2078                          Device,
2079                          FX_TYPE_DEVICE,
2080                          (PVOID*) &pDevice);
2081 
2082     return pDevice->m_PkgPnp->GetSystemPowerAction();
2083 }
2084 
2085 _Must_inspect_result_
_IRQL_requires_max_(APC_LEVEL)2086 _IRQL_requires_max_(APC_LEVEL)
2087 WDFAPI
2088 NTSTATUS
2089 STDCALL
2090 WDFEXPORT(WdfDeviceQueryPropertyEx)(
2091     _In_
2092     PWDF_DRIVER_GLOBALS DriverGlobals,
2093     _In_
2094     WDFDEVICE Device,
2095     _In_
2096     PWDF_DEVICE_PROPERTY_DATA DeviceProperty,
2097     _In_
2098     ULONG BufferLength,
2099     _Out_
2100     PVOID PropertyBuffer,
2101     _Out_
2102     PULONG RequiredSize,
2103     _Out_
2104     PDEVPROPTYPE Type
2105     )
2106 /*++
2107 
2108 Routine Description:
2109 
2110     This routine queries interface property.
2111 
2112 Arguments:
2113 
2114     DriverGlobals - DriverGlobals pointer
2115 
2116     Device - WDF Device handle.
2117 
2118     DeviceProperty - A pointer to WDF_DEVICE_PROPERTY_ DATA structure.
2119 
2120     BufferLength - The size, in bytes, of the buffer that is pointed to by
2121                    PropertyBuffer.
2122 
2123     PropertyBuffer - A caller-supplied pointer to a caller-allocated buffer that
2124                   receives the requested information. The pointer can be NULL
2125                   if the BufferLength parameter is zero.
2126 
2127     ResultLength - A caller-supplied location that, on return, contains the
2128                   size, in bytes, of the information that the method stored in
2129                   PropertyBuffer. If the function's return value is
2130                   STATUS_BUFFER_TOO_SMALL, this location receives the required
2131                   buffer size.
2132 
2133     Type - A pointer to a DEVPROPTYPE variable. If method successfully retrieves
2134                   the property data, the routine writes the property type value
2135                   to this variable. This value indicates the type of property
2136                   data that is in the Data buffer.
2137 
2138 Return Value:
2139 
2140     Method returns an NTSTATUS value. This routine might return one of the
2141     following values.
2142 
2143     STATUS_BUFFER_TOO_SMALL - The supplied buffer is too small to receive the
2144                             information. The ResultLength member receives the
2145                             size of buffer required.
2146     STATUS_SUCCESS  - The operation succeeded.
2147     STATUS_INVALID_PARAMETER - One of the parameters is incorrect.
2148 
2149     The method might return other NTSTATUS values.
2150 
2151 --*/
2152 
2153 {
2154     DDI_ENTRY();
2155 
2156     PFX_DRIVER_GLOBALS pFxDriverGlobals;
2157     FxDevice* pDevice;
2158     NTSTATUS status;
2159 
2160     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
2161                                    Device,
2162                                    FX_TYPE_DEVICE,
2163                                    (PVOID *) &pDevice,
2164                                    &pFxDriverGlobals);
2165 
2166     FxPointerNotNull(pFxDriverGlobals, DeviceProperty);
2167 
2168     //
2169     // Validate PropertyData
2170     //
2171     if (DeviceProperty->Size != sizeof(WDF_DEVICE_PROPERTY_DATA)) {
2172         status = STATUS_INFO_LENGTH_MISMATCH;
2173         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2174                      "PropertyData size (%d) incorrect, expected %d, %!STATUS!",
2175                      DeviceProperty->Size,
2176                      sizeof(WDF_DEVICE_PROPERTY_DATA), status);
2177         return status;
2178     }
2179 
2180     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, APC_LEVEL);
2181     if (!NT_SUCCESS(status)) {
2182         FxVerifierDbgBreakPoint(pFxDriverGlobals);
2183         return status;
2184     }
2185 
2186     FxPointerNotNull(pFxDriverGlobals, RequiredSize);
2187     FxPointerNotNull(pFxDriverGlobals, Type);
2188 
2189     if (BufferLength != 0 && PropertyBuffer == NULL) {
2190         status = STATUS_INVALID_PARAMETER;
2191         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2192                     "Property buffer size is non-zero, while the buffer is NULL"
2193                     ", %!STATUS!", status);
2194         return status;
2195     }
2196 
2197     if (BufferLength == 0 && PropertyBuffer != NULL) {
2198         status = STATUS_INVALID_PARAMETER;
2199         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2200                     "Property buffer size is zero, while the buffer is non-NULL"
2201                     ", %!STATUS!", status);
2202         return status;
2203     }
2204 
2205     status = FxDevice::_QueryPropertyEx(pFxDriverGlobals,
2206                                         NULL,
2207                                         pDevice,
2208                                         DeviceProperty,
2209                                         FxDeviceProperty,
2210                                         BufferLength,
2211                                         PropertyBuffer,
2212                                         RequiredSize,
2213                                         Type);
2214     return status;
2215 }
2216 
2217 _Must_inspect_result_
_IRQL_requires_max_(APC_LEVEL)2218 _IRQL_requires_max_(APC_LEVEL)
2219 WDFAPI
2220 NTSTATUS
2221 STDCALL
2222 WDFEXPORT(WdfDeviceAllocAndQueryPropertyEx)(
2223     _In_
2224     PWDF_DRIVER_GLOBALS DriverGlobals,
2225     _In_
2226     WDFDEVICE Device,
2227     _In_
2228     PWDF_DEVICE_PROPERTY_DATA DeviceProperty,
2229     _In_
2230     _Strict_type_match_
2231     POOL_TYPE PoolType,
2232     _In_opt_
2233     PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
2234     _Out_
2235     WDFMEMORY* PropertyMemory,
2236     _Out_
2237     PDEVPROPTYPE Type
2238     )
2239 /*++
2240 
2241 Routine Description:
2242 
2243     This routine queries device property.
2244 
2245 Arguments:
2246 
2247     DriverGlobals - DriverGlobals pointer
2248 
2249     Device - WDF Device handle.
2250 
2251     PropertyData - A pointer to WDF_DEVICE_PROPERTY_ DATA structure.
2252 
2253     PoolType - A POOL_TYPE-typed enumerator that specifies the type of memory
2254                to be allocated.
2255 
2256     PropertyMemoryAttributes - optional, A pointer to a caller-allocated
2257                WDF_OBJECT_ATTRIBUTES structure that describes object attributes
2258                for the memory object that the function will allocate. This
2259                parameter is optional and can be WDF_NO_OBJECT_ATTRIBUTES.
2260 
2261     PropertyMemory - A pointer to a WDFMEMORY-typed location that receives a
2262                handle to a framework memory object.
2263 
2264     Type - A pointer to a DEVPROPTYPE variable. If method successfully retrieves
2265                the property data, the routine writes the property type value to
2266                this variable. This value indicates the type of property data
2267                that is in the Data buffer.
2268 
2269 Return Value:
2270 
2271     Method returns an NTSTATUS value. This routine might return one of the
2272     following values. It might return other NTSTATUS-codes as well.
2273 
2274     STATUS_SUCCESS  The operation succeeded.
2275     STATUS_INVALID_PARAMETER    One of the parameters is incorrect.
2276 
2277 --*/
2278 {
2279     DDI_ENTRY();
2280 
2281     PFX_DRIVER_GLOBALS pFxDriverGlobals;
2282     FxDevice* pDevice;
2283     NTSTATUS status;
2284 
2285     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
2286                                    Device,
2287                                    FX_TYPE_DEVICE,
2288                                    (PVOID *) &pDevice,
2289                                    &pFxDriverGlobals);
2290 
2291     FxPointerNotNull(pFxDriverGlobals, DeviceProperty);
2292 
2293     //
2294     // Validate PropertyData
2295     //
2296     if (DeviceProperty->Size != sizeof(WDF_DEVICE_PROPERTY_DATA)) {
2297         status = STATUS_INFO_LENGTH_MISMATCH;
2298         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2299                      "PropertyData size (%d) incorrect, expected %d, %!STATUS!",
2300                      DeviceProperty->Size,
2301                      sizeof(WDF_DEVICE_PROPERTY_DATA), status);
2302         return status;
2303     }
2304 
2305     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, APC_LEVEL);
2306     if (!NT_SUCCESS(status)) {
2307         FxVerifierDbgBreakPoint(pFxDriverGlobals);
2308         return status;
2309     }
2310 
2311     FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag);
2312 
2313     FxPointerNotNull(pFxDriverGlobals, PropertyMemory);
2314     FxPointerNotNull(pFxDriverGlobals, Type);
2315 
2316     *PropertyMemory = NULL;
2317 
2318     status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes);
2319     if (!NT_SUCCESS(status)) {
2320         return status;
2321     }
2322 
2323     status = FxDevice::_AllocAndQueryPropertyEx(pFxDriverGlobals,
2324                                                 NULL,
2325                                                 pDevice,
2326                                                 DeviceProperty,
2327                                                 FxDeviceProperty,
2328                                                 PoolType,
2329                                                 PropertyMemoryAttributes,
2330                                                 PropertyMemory,
2331                                                 Type);
2332     return status;
2333 }
2334 
2335 _Must_inspect_result_
_IRQL_requires_max_(APC_LEVEL)2336 _IRQL_requires_max_(APC_LEVEL)
2337 WDFAPI
2338 NTSTATUS
2339 STDCALL
2340 WDFEXPORT(WdfDeviceAssignProperty)(
2341     _In_
2342     PWDF_DRIVER_GLOBALS DriverGlobals,
2343     _In_
2344     WDFDEVICE Device,
2345     _In_
2346     PWDF_DEVICE_PROPERTY_DATA DeviceProperty,
2347     _In_
2348     DEVPROPTYPE Type,
2349     _In_
2350     ULONG BufferLength,
2351     _In_opt_
2352     PVOID PropertyBuffer
2353     )
2354 /*++
2355 
2356 Routine Description:
2357 
2358     This routine assigns interface property.
2359 
2360 Arguments:
2361 
2362     DriverGlobals - DriverGlobals pointer
2363 
2364     Device - WDF Device handle.
2365 
2366     PropertyData - A pointer to WDF_DEVICE_PROPERTY_ DATA structure.
2367 
2368     Type - Set this parameter to the DEVPROPTYPE value that specifies the type
2369            of the data that is supplied in the Data buffer.
2370 
2371     BufferLength - Specifies the length, in bytes, of the buffer that
2372            PropertyBuffer points to.
2373 
2374     PropertyBuffer - optional, A pointer to the device interface property data.
2375            Set this parameter to NULL to delete the specified property.
2376 
2377 Return Value:
2378 
2379     Mthod returns an NTSTATUS value. This routine might return one of the
2380     following values. It might return other NTSTATUS-codes as well.
2381 
2382     STATUS_SUCCESS - The operation succeeded.
2383     STATUS_INVALID_PARAMETER - One of the parameters is incorrect.
2384 
2385 --*/
2386 
2387 {
2388     DDI_ENTRY();
2389 
2390     PFX_DRIVER_GLOBALS pFxDriverGlobals;
2391     FxDevice *pDevice;
2392     NTSTATUS status;
2393 
2394     //
2395     // Validate the Device object handle and get its FxDevice. Also get the
2396     // driver globals pointer.
2397     //
2398     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
2399                                    Device,
2400                                    FX_TYPE_DEVICE,
2401                                    (PVOID *) &pDevice,
2402                                    &pFxDriverGlobals);
2403 
2404     FxPointerNotNull(pFxDriverGlobals, DeviceProperty);
2405 
2406     //
2407     // Validate PropertyData
2408     //
2409     if (DeviceProperty->Size != sizeof(WDF_DEVICE_PROPERTY_DATA)) {
2410         status = STATUS_INFO_LENGTH_MISMATCH;
2411         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2412                      "PropertyData size (%d) incorrect, expected %d, %!STATUS!",
2413                      DeviceProperty->Size,
2414                      sizeof(WDF_DEVICE_PROPERTY_DATA), status);
2415         return status;
2416     }
2417 
2418     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, APC_LEVEL);
2419     if (!NT_SUCCESS(status)) {
2420         FxVerifierDbgBreakPoint(pFxDriverGlobals);
2421         return status;
2422     }
2423 
2424     if (BufferLength == 0 && PropertyBuffer != NULL) {
2425         status = STATUS_INVALID_PARAMETER;
2426         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2427                     "Property buffer size is zero, while the buffer is non-NULL"
2428                     ", %!STATUS!", status);
2429         return status;
2430     }
2431 
2432     status = pDevice->AssignProperty(DeviceProperty,
2433                                      FxDeviceProperty,
2434                                      Type,
2435                                      BufferLength,
2436                                      PropertyBuffer
2437                                      );
2438     return status;
2439 }
2440 
2441 _Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)2442 __drv_maxIRQL(DISPATCH_LEVEL)
2443 WDFAPI
2444 NTSTATUS
2445 STDCALL
2446 WDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback)(
2447     _In_
2448     PWDF_DRIVER_GLOBALS DriverGlobals,
2449     _In_
2450     WDFDEVICE Device,
2451     _In_opt_
2452     WDFDRIVER Driver,
2453     _In_
2454     UCHAR MajorFunction,
2455     _In_
2456     PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDispatch,
2457     _In_opt_
2458     WDFCONTEXT DriverContext
2459     )
2460 
2461 /*++
2462 
2463     Routine Description:
2464 
2465         Configure callbacks for IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_DEVICE_CONTROL, and
2466         IRP_MJ_INTERNAL_DEVICE_CONTROL (KMDF only). By default the I/O package sends all requests to
2467         a device's default queue, or to the queues configured with
2468         WdfDeviceConfigureRequestDisaptching. This DDI allows a driver specified
2469         callback to select a different queue dynamically during runtime.
2470 
2471     Arguments:
2472 
2473         Device - The device which is handling the I/O.
2474 
2475         Driver - An optional driver handle. Used to associate the
2476                  callback with a specific class extension.
2477 
2478         MajorFunction - IRP major function type to be forwarded to the callback
2479 
2480         EvtDeviceWdmIrpDispatch - Callback invoked when encountering the given major function.
2481 
2482         DriverContext - An optional untyped driver specified context.
2483 
2484     Returns:
2485 
2486         STATUS_SUCCESS on success
2487         STATUS_INVALID_PARAMETER if an incorrect MajorFunction was provided
2488         STATUS_INSUFFICIENT_RESOURCES if insufficient memory was available
2489         STATUS_INVALID_DEVICE_STATE if this DDI was called at an improper time
2490 
2491  --*/
2492 {
2493     PFX_DRIVER_GLOBALS  pFxDriverGlobals;
2494     NTSTATUS            status;
2495     FxDevice*           pDevice;
2496     FxCxDeviceInfo*     pCxDeviceInfo;
2497     ULONG               deviceFlags;
2498 
2499     pDevice = NULL;
2500     pCxDeviceInfo = NULL;
2501 
2502     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
2503                                    Device,
2504                                    FX_TYPE_DEVICE,
2505                                    (PVOID *) &pDevice,
2506                                    &pFxDriverGlobals);
2507 
2508     //
2509     // Validate the MajorFunction provided. Note that
2510     // IRP_MJ_INTERNAL_DEVICE_CONTROL is KMDF only.
2511     //
2512     switch (MajorFunction) {
2513         case IRP_MJ_WRITE:
2514         case IRP_MJ_READ:
2515         case IRP_MJ_DEVICE_CONTROL:
2516 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
2517         case IRP_MJ_INTERNAL_DEVICE_CONTROL:
2518 #endif
2519             break;
2520         default:
2521             status = STATUS_INVALID_PARAMETER;
2522             DoTraceLevelMessage(
2523                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2524                 "Invalid MajorFunction provided %!IRPMJ!, %!STATUS!",
2525                 MajorFunction, status);
2526             goto exit;
2527     }
2528 
2529     //
2530     // Validate the driver handle and get (if present) the associated cx info.
2531     //
2532     if (Driver != NULL) {
2533         FxDriver*   pDriver;
2534 
2535         FxObjectHandleGetPtr(pFxDriverGlobals,
2536                              Driver,
2537                              FX_TYPE_DRIVER,
2538                              (PVOID*)&pDriver);
2539 
2540         //
2541         // Find the driver's cx info if it's not the main driver for this device.
2542         // cx struct info can be NULL if cx acts as client driver.
2543         //
2544         pCxDeviceInfo = pDevice->GetCxDeviceInfo(pDriver);
2545     }
2546 
2547     //
2548     // Make sure callback is not null.
2549     //
2550     FxPointerNotNull(pFxDriverGlobals, EvtDeviceWdmIrpDispatch);
2551 
2552     //
2553     // This callback can only be called during initialization.
2554     //
2555     if (pDevice->IsLegacy()) {
2556 
2557         //
2558         // Extract the device flags from the device object
2559         //
2560 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
2561         deviceFlags = pDevice->GetDeviceObject()->Flags;
2562 #else
2563         deviceFlags = pDevice->GetDeviceObject()->GetDeviceObjectWdmFlags();
2564 #endif
2565 
2566         //
2567         // This is a controldevice. Make sure the create is called after the device
2568         // is initialized and ready to accept I/O.
2569         //
2570         if ((deviceFlags & DO_DEVICE_INITIALIZING) == 0x0) {
2571             status = STATUS_INVALID_DEVICE_STATE;
2572             DoTraceLevelMessage(
2573                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2574                 "Driver cannot set IRP dispatch callback "
2575                 "after WdfControlDeviceFinishInitializing "
2576                 "is called on the WDFDEVICE %p, %!STATUS!",
2577                 pDevice, status);
2578             goto exit;
2579         }
2580     } else {
2581         //
2582         // This is either FDO or PDO. Make sure it's not started yet.
2583         //
2584         if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) {
2585             status = STATUS_INVALID_DEVICE_STATE;
2586             DoTraceLevelMessage(
2587                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2588                 "Driver cannot set IRP dispatch callback "
2589                 "after the WDFDEVICE %p is started, %!STATUS!",
2590                 pDevice, status);
2591             goto exit;
2592         }
2593     }
2594 
2595     //
2596     // Let I/O package do the rest.
2597     //
2598     status = pDevice->m_PkgIo->ConfigureDynamicDispatching(MajorFunction,
2599                                                            pCxDeviceInfo,
2600                                                            EvtDeviceWdmIrpDispatch,
2601                                                            DriverContext);
2602 exit:
2603     return status;
2604 }
2605 
2606 _Must_inspect_result_
2607 NTSTATUS
FX_VF_FUNCTION(VerifyWdfDeviceWdmDispatchIrpToIoQueue)2608 FX_VF_FUNCTION(VerifyWdfDeviceWdmDispatchIrpToIoQueue) (
2609     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
2610     _In_ FxDevice* device,
2611     _In_ MdIrp Irp,
2612     _In_ FxIoQueue* queue,
2613     _In_ ULONG Flags
2614     )
2615 {
2616     NTSTATUS status = STATUS_SUCCESS;
2617     UCHAR majorFunction, minorFunction;
2618     FxIrp fxIrp(Irp);
2619 
2620     PAGED_CODE_LOCKED();
2621 
2622     majorFunction = fxIrp.GetMajorFunction();
2623     minorFunction = fxIrp.GetMinorFunction();
2624 
2625     DoTraceLevelMessage(
2626         FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
2627         "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ!, IRP_MN %x, IRP 0x%p",
2628         device->GetHandle(), device->GetDeviceObject(),
2629         majorFunction, minorFunction, Irp);
2630 
2631     //
2632     // Validate Flags. For UMDF, this field is reserved and must be zero.
2633     //
2634 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
2635     if (Flags & ~FX_DISPATCH_IRP_TO_IO_QUEUE_FLAGS_MASK) {
2636 #else
2637     if (Flags != WDF_DISPATCH_IRP_TO_IO_QUEUE_NO_FLAGS) {
2638 #endif
2639         status = STATUS_INVALID_PARAMETER;
2640         DoTraceLevelMessage(
2641                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2642                 "Flags 0x%x are invalid, %!STATUS!",
2643                 Flags, status);
2644         FxVerifierDbgBreakPoint(FxDriverGlobals);
2645         goto Done;
2646     }
2647 
2648     //
2649     // Only read/writes/ctrls/internal_ctrls IRPs are allowed, i.e., the I/O request set.
2650     //
2651     if (device->GetDispatchPackage(majorFunction) != device->m_PkgIo) {
2652         status = STATUS_INVALID_PARAMETER;
2653         DoTraceLevelMessage(
2654                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2655                 "Only Read/Write/Control/Internal-Control IRPs can be "
2656                 "forwarded to I/O Queue 0x%p, Irp 0x%p, %!IRPMJ!, "
2657                 "IRP_MN %x, Device 0x%p, %!STATUS!",
2658                  queue->GetHandle(), Irp, majorFunction, minorFunction,
2659                  device->GetObjectHandle(), status);
2660         FxVerifierDbgBreakPoint(FxDriverGlobals);
2661         goto Done;
2662     }
2663 
2664     //
2665     // Make sure queue can handle the request.
2666     //
2667     if (FALSE == queue->IsIoEventHandlerRegistered(
2668                             (WDF_REQUEST_TYPE)majorFunction)) {
2669 
2670         status = STATUS_INVALID_PARAMETER;
2671         DoTraceLevelMessage(
2672                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2673                 "I/O Queue 0x%p cannot handle Irp 0x%p, %!IRPMJ!, "
2674                 "IRP_MN %x, Device 0x%p, %!STATUS!",
2675                  queue->GetHandle(), Irp, majorFunction, minorFunction,
2676                  device->GetObjectHandle(), status);
2677         FxVerifierDbgBreakPoint(FxDriverGlobals);
2678         goto Done;
2679     }
2680 
2681     if (device->m_ParentDevice == queue->GetDevice()) {
2682         //
2683         // Send to parent device's queue validation.
2684         //
2685         if (device->m_ParentDevice == NULL) {
2686             status = STATUS_INVALID_PARAMETER;
2687             DoTraceLevelMessage(
2688                     FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2689                     "No parent device for Device 0x%p, %!STATUS!",
2690                      device->GetObjectHandle(), status);
2691             FxVerifierDbgBreakPoint(FxDriverGlobals);
2692             goto Done;
2693         }
2694 
2695         //
2696         // Make sure the child device is a PDO
2697         //
2698         ASSERT(device->IsPdo());
2699 
2700         //
2701         // Check if the WdfPdoInitSetForwardRequestToParent was called to
2702         // increase the StackSize of the child Device  to include the stack
2703         // size of the parent Device
2704         //
2705         if (device->IsPnp() &&
2706             device->GetPdoPkg()->m_AllowForwardRequestToParent == FALSE) {
2707             status = STATUS_INVALID_DEVICE_REQUEST;
2708             DoTraceLevelMessage(
2709                     FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2710                     "WdfPdoInitSetForwardRequestToParent not called on "
2711                     "Device 0x%p, %!STATUS!",
2712                     device->GetObjectHandle(), status);
2713             FxVerifierDbgBreakPoint(FxDriverGlobals);
2714             goto Done;
2715         }
2716     }
2717     else {
2718         //
2719         // Send to current device's queue validation.
2720         //
2721         if (device != queue->GetDevice()) {
2722             status = STATUS_INVALID_PARAMETER;
2723             DoTraceLevelMessage(
2724                     FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2725                     "Cannot forward a request to "
2726                     "a different Device 0x%p, %!STATUS!",
2727                     queue->GetDevice()->GetObjectHandle(), status);
2728             FxVerifierDbgBreakPoint(FxDriverGlobals);
2729             goto Done;
2730         }
2731     }
2732 
2733 Done:
2734     return status;
2735 }
2736 
2737 } // extern "C"
2738