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