1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxDevice.cpp
8 
9 Abstract:
10 
11     This is the class implementation for the base Device class.
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 
27 extern "C" {
28 // #include "FxDevice.tmh"
29 }
30 
31 //
32 // This table contains the mapping between device type and the
33 // default priority boost used by the the framework when
34 // an I/O request is completed. The DeviceObject->DeviceType
35 // is used as an index into this table.
36 //
37 const CHAR FxDevice::m_PriorityBoosts[] = {
38     IO_NO_INCREMENT,        // FILE_DEVICE_UNDEFINED           0x00000000
39     IO_NO_INCREMENT,        // FILE_DEVICE_BEEP                0x00000001
40     IO_CD_ROM_INCREMENT,    // FILE_DEVICE_CD_ROM              0x00000002
41     IO_CD_ROM_INCREMENT,    // FILE_DEVICE_CD_ROM_FILE_SYSTEM  0x00000003
42     IO_NO_INCREMENT,        // FILE_DEVICE_CONTROLLER          0x00000004
43     IO_NO_INCREMENT,        // FILE_DEVICE_DATALINK            0x00000005
44     IO_NO_INCREMENT,        // FILE_DEVICE_DFS                 0x00000006
45     IO_DISK_INCREMENT,      // FILE_DEVICE_DISK                0x00000007
46     IO_DISK_INCREMENT,      // FILE_DEVICE_DISK_FILE_SYSTEM    0x00000008
47     IO_NO_INCREMENT,        // FILE_DEVICE_FILE_SYSTEM         0x00000009
48     IO_NO_INCREMENT,        // FILE_DEVICE_INPORT_PORT         0x0000000a
49     IO_KEYBOARD_INCREMENT,  // FILE_DEVICE_KEYBOARD            0x0000000b
50     IO_MAILSLOT_INCREMENT,  // FILE_DEVICE_MAILSLOT            0x0000000c
51     IO_SOUND_INCREMENT,     // FILE_DEVICE_MIDI_IN             0x0000000d
52     IO_SOUND_INCREMENT,     // FILE_DEVICE_MIDI_OUT            0x0000000e
53     IO_MOUSE_INCREMENT,     // FILE_DEVICE_MOUSE               0x0000000f
54     IO_NO_INCREMENT,        // FILE_DEVICE_MULTI_UNC_PROVIDER  0x00000010
55     IO_NAMED_PIPE_INCREMENT,// FILE_DEVICE_NAMED_PIPE          0x00000011
56     IO_NETWORK_INCREMENT,   // FILE_DEVICE_NETWORK             0x00000012
57     IO_NETWORK_INCREMENT,   // FILE_DEVICE_NETWORK_BROWSER     0x00000013
58     IO_NETWORK_INCREMENT,   // FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
59     IO_NO_INCREMENT,        // FILE_DEVICE_NULL                0x00000015
60     IO_PARALLEL_INCREMENT,  // FILE_DEVICE_PARALLEL_PORT       0x00000016
61     IO_NETWORK_INCREMENT,   // FILE_DEVICE_PHYSICAL_NETCARD    0x00000017
62     IO_NO_INCREMENT,        // FILE_DEVICE_PRINTER             0x00000018
63     IO_NO_INCREMENT,        // FILE_DEVICE_SCANNER             0x00000019
64     IO_SERIAL_INCREMENT,    // FILE_DEVICE_SERIAL_MOUSE_PORT   0x0000001a
65     IO_SERIAL_INCREMENT,    // FILE_DEVICE_SERIAL_PORT         0x0000001b
66     IO_VIDEO_INCREMENT,     // FILE_DEVICE_SCREEN              0x0000001c
67     IO_SOUND_INCREMENT,     // FILE_DEVICE_SOUND               0x0000001d
68     IO_SOUND_INCREMENT,     // FILE_DEVICE_STREAMS             0x0000001e
69     IO_NO_INCREMENT,        // FILE_DEVICE_TAPE                0x0000001f
70     IO_NO_INCREMENT,        // FILE_DEVICE_TAPE_FILE_SYSTEM    0x00000020
71     IO_NO_INCREMENT,        // FILE_DEVICE_TRANSPORT           0x00000021
72     IO_NO_INCREMENT,        // FILE_DEVICE_UNKNOWN             0x00000022
73     IO_VIDEO_INCREMENT,     // FILE_DEVICE_VIDEO               0x00000023
74     IO_DISK_INCREMENT,      // FILE_DEVICE_VIRTUAL_DISK        0x00000024
75     IO_SOUND_INCREMENT,     // FILE_DEVICE_WAVE_IN             0x00000025
76     IO_SOUND_INCREMENT,     // FILE_DEVICE_WAVE_OUT            0x00000026
77     IO_KEYBOARD_INCREMENT,  // FILE_DEVICE_8042_PORT           0x00000027
78     IO_NETWORK_INCREMENT,   // FILE_DEVICE_NETWORK_REDIRECTOR  0x00000028
79     IO_NO_INCREMENT,        // FILE_DEVICE_BATTERY             0x00000029
80     IO_NO_INCREMENT,        // FILE_DEVICE_BUS_EXTENDER        0x0000002a
81     IO_SERIAL_INCREMENT,    // FILE_DEVICE_MODEM               0x0000002b
82     IO_NO_INCREMENT,        // FILE_DEVICE_VDM                 0x0000002c
83     IO_DISK_INCREMENT,      // FILE_DEVICE_MASS_STORAGE        0x0000002d
84     IO_NETWORK_INCREMENT,   // FILE_DEVICE_SMB                 0x0000002e
85     IO_SOUND_INCREMENT,     // FILE_DEVICE_KS                  0x0000002f
86     IO_NO_INCREMENT,        // FILE_DEVICE_CHANGER             0x00000030
87     IO_NO_INCREMENT,        // FILE_DEVICE_SMARTCARD           0x00000031
88     IO_NO_INCREMENT,        // FILE_DEVICE_ACPI                0x00000032
89     IO_NO_INCREMENT,        // FILE_DEVICE_DVD                 0x00000033
90     IO_VIDEO_INCREMENT,     // FILE_DEVICE_FULLSCREEN_VIDEO    0x00000034
91     IO_NO_INCREMENT,        // FILE_DEVICE_DFS_FILE_SYSTEM     0x00000035
92     IO_NO_INCREMENT,        // FILE_DEVICE_DFS_VOLUME          0x00000036
93     IO_SERIAL_INCREMENT,    // FILE_DEVICE_SERENUM             0x00000037
94     IO_NO_INCREMENT,        // FILE_DEVICE_TERMSRV             0x00000038
95     IO_NO_INCREMENT,        // FILE_DEVICE_KSEC                0x00000039
96     IO_NO_INCREMENT,        // FILE_DEVICE_FIPS                0x0000003A
97     IO_NO_INCREMENT,        // FILE_DEVICE_INFINIBAND          0x0000003B
98 };
99 
100 NTSTATUS
101 FxDevice::_CompletionRoutineForRemlockMaintenance(
102     __in MdDeviceObject   DeviceObject,
103     __in MdIrp             Irp,
104     __in PVOID            Context
105     )
106 /*++
107 
108 Routine Description:
109 
110     A completion routine for the IRPs for which we acquired opt-in remove lock.
111 
112 Arguments:
113     DeviceObject - Pointer to deviceobject
114     Irp          - Pointer to the Irp for which we acquired opt-in remove lock.
115     Context      - NULL
116 Return Value:
117 
118     NT Status is returned.
119 
120 --*/
121 
122 {
123     FxIrp irp(Irp);
124 
125     UNREFERENCED_PARAMETER(Context);
126 
127     //
128     // Let the irp continue on its way.
129     //
130     irp.PropagatePendingReturned();
131 
132 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
133     Mx::MxReleaseRemoveLock(&((FxDevice::_GetFxWdmExtension(
134                             DeviceObject))->IoRemoveLock), Irp);
135 #else
136     UNREFERENCED_PARAMETER(DeviceObject);
137 #endif
138 
139     return STATUS_CONTINUE_COMPLETION;
140 }
141 
142 
143 FxDevice::FxDevice(
144     __in FxDriver *ArgDriver
145     ) :
146     FxDeviceBase(ArgDriver->GetDriverGlobals(), ArgDriver, FX_TYPE_DEVICE, sizeof(FxDevice)),
147     m_ParentDevice(NULL)
148 {
149     SetInitialState();
150 }
151 
152 VOID
153 FxDevice::SetInitialState(
154     VOID
155     )
156 {
157     //
158     // Set the initial device state
159     //
160     m_CurrentPnpState           = WdfDevStatePnpObjectCreated;
161     m_CurrentPowerState         = WdfDevStatePowerObjectCreated;
162     m_CurrentPowerPolicyState   = WdfDevStatePwrPolObjectCreated;
163 
164     //
165     // Set the default IO type to "buffered"
166     //
167     m_ReadWriteIoType = WdfDeviceIoBuffered;
168 
169     RtlZeroMemory(&m_DeviceName, sizeof(m_DeviceName));
170     RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName));
171     RtlZeroMemory(&m_MofResourceName, sizeof(m_MofResourceName));
172 
173     m_Filter = FALSE;
174     m_Exclusive = FALSE;
175     m_PowerPageableCapable = FALSE;
176     m_ParentWaitingOnChild = FALSE;
177     m_Legacy = FALSE;
178     m_DeviceObjectDeleted = FALSE;
179     m_PdoKnown = FALSE;
180     m_Legacy = FALSE;
181     m_AutoForwardCleanupClose = FALSE;
182     m_SelfIoTargetNeeded = FALSE;
183     m_DeviceTelemetryInfoFlags = 0;
184 
185     //
186     // Clear all packages by default
187     //
188 
189     m_PkgIo      = NULL;
190     m_PkgPnp     = NULL;
191     m_PkgGeneral = NULL;
192     m_PkgWmi     = NULL;
193     m_PkgDefault  = NULL;
194 
195     InitializeListHead(&m_PreprocessInfoListHead);
196     InitializeListHead(&m_CxDeviceInfoListHead);
197 
198 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
199     m_FileObjectClass = WdfFileObjectNotRequired;
200 #else // UMDF
201     //
202     // In UMDF file object is always required. So indicate that now.
203     //
204     m_FileObjectClass = WdfFileObjectWdfCannotUseFsContexts;
205 #endif
206 
207     m_DefaultPriorityBoost = IO_NO_INCREMENT;
208 
209     InitializeListHead(&m_FileObjectListHead);
210 
211     m_RequestLookasideListElementSize = 0;
212     RtlZeroMemory(&m_RequestLookasideList, sizeof(m_RequestLookasideList));
213     RtlZeroMemory(&m_RequestAttributes, sizeof(m_RequestAttributes));
214 
215 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
216     //
217     // Init UMDF specific members
218     //
219     m_CleanupFromFailedCreate = FALSE;
220     m_Dispatcher = NULL;
221     m_DevStack = NULL;
222     m_PdoDevKey = NULL;
223     m_DeviceKeyPath = NULL;
224     m_KernelDeviceName = NULL;
225     m_DeviceInstanceId = NULL;
226 
227     m_RetrievalMode = UMINT::WdfDeviceIoBufferRetrievalDeferred;
228     m_IoctlIoType = WdfDeviceIoBuffered;
229     m_DirectTransferThreshold = 0;
230 
231     m_DirectHardwareAccess = FX_DIRECT_HARDWARE_ACCESS_DEFAULT;
232     m_RegisterAccessMode = FX_REGISTER_ACCESS_MODE_DEFAULT;
233     m_FileObjectPolicy = FX_FILE_OBJECT_POLICY_DEFAULT;
234     m_FsContextUsePolicy = FX_FS_CONTEXT_USE_POLICY_DEFAULT;
235     m_InteruptThreadpool = NULL;
236 #endif
237 }
238 
239 FxDevice::~FxDevice()
240 {
241     PLIST_ENTRY next;
242 
243     // Make it always present right now even on free builds
244     if (IsDisposed() == FALSE) {
245         DoTraceLevelMessage(
246             GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGDEVICE,
247             "FxDevice 0x%p not disposed: this maybe a driver reference count "
248             "problem with WDFDEVICE %p", this, GetObjectHandleUnchecked());
249 
250         FxVerifierBugCheck(GetDriverGlobals(),
251                            WDF_OBJECT_ERROR,
252                            (ULONG_PTR) GetObjectHandleUnchecked(),
253                            (ULONG_PTR) this);
254     }
255 
256     //
257     // Execute mode-specific destructor. Noop for KMDF, but does
258     // does detach and delete of UM device object for UMDF. Therefore
259     // can be done before other cleanup.
260     //
261     DestructorInternal();
262 
263     //
264     // If the device has been initialized but hasn't yet been
265     // destroyed, destroy it now.
266     //
267 
268 
269 
270 
271 
272 
273 
274     ASSERT(m_DeviceObject.GetObject() == NULL);
275 
276     ASSERT(m_DeviceName.Buffer == NULL);
277 
278 #if FX_CORE_MODE == FX_CORE_KERNEL_MODE
279     //
280     // Assert only applicable to KM because FxDevice can get destroyed in UMDF
281     // without going through normal pnp remove path, for example, when an
282     // AddDevice failure is done in reflector, after all um drivers have
283     // succeeded AddDevice. KMDF and host use fake remove irp to handle
284     // AddDevice failure in KMDF and host respectively, but reflector does not
285     // do that for AddDevice failure that happens in reflector.
286     // Note that symbolicName buffer will anyway be deleted in this destructor
287     // later on so the symbolic link buffer doesn't leak out.
288     //
289     ASSERT(m_SymbolicLinkName.Buffer == NULL);
290 #endif
291 
292     ASSERT(m_MofResourceName.Buffer == NULL);
293 
294     if (m_PkgIo != NULL) {
295         m_PkgIo->RELEASE(NULL);
296         m_PkgIo = NULL;
297     }
298 
299     if (m_PkgPnp != NULL) {
300         m_PkgPnp->RELEASE(NULL);
301         m_PkgPnp = NULL;
302     }
303 
304     if (m_PkgGeneral != NULL) {
305         m_PkgGeneral->RELEASE(NULL);
306         m_PkgGeneral = NULL;
307     }
308 
309     if (m_PkgWmi != NULL) {
310         m_PkgWmi->RELEASE(NULL);
311         m_PkgWmi = NULL;
312     }
313 
314     if (m_PkgDefault != NULL) {
315         m_PkgDefault->RELEASE(NULL);
316         m_PkgDefault = NULL;
317     }
318 
319     while (!IsListEmpty(&m_PreprocessInfoListHead)) {
320         next = RemoveHeadList(&m_PreprocessInfoListHead);
321         FxIrpPreprocessInfo* info;
322         info = CONTAINING_RECORD(next, FxIrpPreprocessInfo, ListEntry);
323         InitializeListHead(next);
324         delete info;
325     }
326 
327     while (!IsListEmpty(&m_CxDeviceInfoListHead)) {
328         next = RemoveHeadList(&m_CxDeviceInfoListHead);
329         FxCxDeviceInfo* info;
330         info = CONTAINING_RECORD(next, FxCxDeviceInfo, ListEntry);
331         InitializeListHead(next);
332         delete info;
333     }
334 
335     //
336     // Clean up any referenced objects
337     //
338     if (m_DeviceName.Buffer != NULL) {
339         FxPoolFree(m_DeviceName.Buffer);
340         RtlZeroMemory(&m_DeviceName, sizeof(m_DeviceName));
341     }
342 
343     DeleteSymbolicLink();
344 
345     if (m_MofResourceName.Buffer != NULL) {
346         FxPoolFree(m_MofResourceName.Buffer);
347         RtlZeroMemory(&m_MofResourceName, sizeof(m_DeviceName));
348     }
349 
350     //
351     // m_RequestLookasideListElementSize will be set to non zero if we have
352     // initialized the request lookaside list.
353     //
354     if (m_RequestLookasideListElementSize != 0) {
355         Mx::MxDeleteNPagedLookasideList(&m_RequestLookasideList);
356         m_RequestLookasideListElementSize = 0;
357     }
358 
359     if (m_ParentDevice != NULL) {
360         m_ParentDevice->RELEASE(this);
361     }
362 }
363 
364 _Must_inspect_result_
365 NTSTATUS
366 FxDevice::_Create(
367     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
368     __in PWDFDEVICE_INIT* DeviceInit,
369     __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes,
370     __out FxDevice** Device
371     )
372 {
373     PWDFDEVICE_INIT     pInit;
374     FxDevice*           pDevice;
375     NTSTATUS            status;
376     WDFOBJECT           object;
377     PLIST_ENTRY         pNext;
378     PWDFCXDEVICE_INIT   pCxInit;
379     FxWdmDeviceExtension* wdmDeviceExtension;
380 
381     *Device = NULL;
382     pInit = *DeviceInit;
383 
384     pDevice = new (FxDriverGlobals, DeviceAttributes)
385         FxDevice(pInit->Driver);
386 
387     if (pDevice == NULL) {
388         status = STATUS_INSUFFICIENT_RESOURCES;
389         goto Done;
390     }
391 
392     status = pDevice->Initialize(pInit, DeviceAttributes);
393     if (!NT_SUCCESS(status)) {
394         goto Done;
395     }
396 
397     switch (pInit->InitType) {
398     case FxDeviceInitTypeFdo:
399         status = pDevice->FdoInitialize(pInit);
400         break;
401 
402     case FxDeviceInitTypePdo:
403         status = pDevice->PdoInitialize(pInit);
404         break;
405 
406     case FxDeviceInitTypeControlDevice:
407         status = pDevice->ControlDeviceInitialize(pInit);
408         break;
409 
410     default:
411         //
412         // Should not drop here
413         //
414         ASSERT(FALSE);
415         break;
416     }
417     if (!NT_SUCCESS(status)) {
418         goto Done;
419     }
420 
421     //
422     // Ok, we have created the device.  Now lets create a handle for it.
423     //
424     status = pDevice->PostInitialize();
425     if (!NT_SUCCESS(status)) {
426         goto Done;
427     }
428 
429     //
430     // Can't use the PDO's FxDevice m_Parent as the object hierarchy parent
431     // because the Fx object hierarchy lifetime rules do not match the
432     // rules for a pnp PDO lifetime vs its FDO.
433     //
434     status = pDevice->Commit(DeviceAttributes,
435                              &object,
436                              pDevice->GetDriver());
437     if (!NT_SUCCESS(status)) {
438         goto Done;
439     }
440 
441     //
442     // NOTE: ---> DO NOT FAIL FROM HERE FORWARD <---
443     //
444 
445     //
446     // Up until now we have not reassigned any of the allocations in pInit
447     // and assigned them to the underlying objects.  We are now at the point
448     // of "no return", ie we cannot fail.  If we reassigned the allocations
449     // before this point and the driver retried to create the device (let's
450     // say with a different name), we would have freed those allocations
451     // and the driver writer would have thought that particular settings
452     // we valid, but were not b/c we freed them on error.  So, to avoid a
453     // huge tracking mess, we only grab the allocations once we know for
454     // *sure* we are going to return success.
455     //
456     if (pInit->DeviceName != NULL) {
457         pInit->DeviceName->ReleaseString(&pDevice->m_DeviceName);
458     }
459 
460     //
461     // Check for driver preprocess requirements.
462     //
463     if (pInit->PreprocessInfo != NULL) {
464         ASSERT( pInit->PreprocessInfo->ClassExtension == FALSE);
465         ASSERT(IsListEmpty(&pDevice->m_PreprocessInfoListHead));
466         InsertTailList(&pDevice->m_PreprocessInfoListHead,
467                         &pInit->PreprocessInfo->ListEntry);
468         pInit->PreprocessInfo = NULL;
469 
470         //
471         // If the driver is preprocessing requests on this device, they need
472         // their own stack location so that they can set their own completion
473         // routine.
474         //
475         pDevice->SetStackSize(pDevice->GetStackSize()+1);
476     }
477 
478 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
479     wdmDeviceExtension = _GetFxWdmExtension(pDevice->GetDeviceObject());
480     if (wdmDeviceExtension->RemoveLockOptionFlags &
481             WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) {
482         //
483         // We will use a completion routine for remlock maintenance
484         //
485         pDevice->SetStackSize(pDevice->GetStackSize()+1);
486     }
487 
488     //
489     // Note: In case of UMDF StackSize is incremented prior to attaching
490     // the device to stack. See the comment in FxDeviceUm.cpp
491     //
492     if (pDevice->m_SelfIoTargetNeeded) {
493         pDevice->SetStackSize(pDevice->GetStackSize()+1);
494     }
495 
496 #else
497     UNREFERENCED_PARAMETER(wdmDeviceExtension);
498 #endif
499 
500     //
501     // Check for any class-extensions' preprocess requirements.
502     //
503     for (pNext = pInit->CxDeviceInitListHead.Flink;
504          pNext != &pInit->CxDeviceInitListHead;
505          pNext = pNext->Flink) {
506 
507         pCxInit = CONTAINING_RECORD(pNext, WDFCXDEVICE_INIT, ListEntry);
508 
509         if (pCxInit->PreprocessInfo != NULL) {
510             ASSERT(pCxInit->PreprocessInfo->ClassExtension);
511             InsertTailList(&pDevice->m_PreprocessInfoListHead,
512                            &pCxInit->PreprocessInfo->ListEntry);
513             pCxInit->PreprocessInfo = NULL;
514 
515             //
516             // If the class extension is preprocessing requests on this
517             // device, it needs its own stack location so that it can
518             // set its own completion routine.
519             //
520             pDevice->SetStackSize(pDevice->GetStackSize()+1);
521         }
522     }
523 
524     if (pDevice->IsPnp()) {
525         //
526         // Take all of the allocations out of pInit related to pnp.  This
527         // will also transition the pnp state machine into the added state.
528         //
529         pDevice->m_PkgPnp->FinishInitialize(pInit);
530     }
531 
532     pInit->CreatedDevice = pDevice;
533 
534     //
535     // Clear out the pointer, we freed it on behalf of the caller
536     //
537     *DeviceInit = NULL;
538 
539     if (pInit->CreatedOnStack == FALSE) {
540         delete pInit;
541     }
542 
543 Done:
544     if (!NT_SUCCESS(status) && pDevice != NULL) {
545         //
546         // We want to propagate the original error code
547         //
548         (void) pDevice->DeleteDeviceFromFailedCreate(status, FALSE);
549         pDevice = NULL;
550     }
551 
552     *Device = pDevice;
553 
554     return status;
555 }
556 
557 _Must_inspect_result_
558 NTSTATUS
559 FxDevice::DeleteDeviceFromFailedCreateNoDelete(
560     __in NTSTATUS FailedStatus,
561     __in BOOLEAN UseStateMachine
562     )
563 {
564     //
565     // Cleanup the device, the driver may have allocated resources
566     // associated with the WDFDEVICE
567     //
568     DoTraceLevelMessage(
569         GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
570         "WDFDEVICE %p !devobj %p created, but EvtDriverDeviceAdd returned "
571         "status %!STATUS! or failure in creation",
572         GetObjectHandleUnchecked(), GetDeviceObject(), FailedStatus);
573 
574     //
575     // We do not let filters affect the building of the rest of the stack.
576     // If they return error, we convert it to STATUS_SUCCESS, remove the
577     // attached device from the stack, and cleanup.
578     //
579     if (IsFilter()) {
580         DoTraceLevelMessage(
581             GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
582             "WDFDEVICE %p, !devobj %p is a filter, converting %!STATUS! to"
583             " STATUS_SUCCESS", GetObjectHandleUnchecked(), GetDeviceObject(),
584             FailedStatus);
585         FailedStatus = STATUS_SUCCESS;
586     }
587 
588     if (UseStateMachine) {
589         MxEvent waitEvent;
590 
591         //
592         // See comments for m_CleanupFromFailedCreate in class definition file
593         // for use of this statement.
594         //
595         SetCleanupFromFailedCreate(TRUE);
596 
597 
598 
599 
600 
601         waitEvent.Initialize(SynchronizationEvent, FALSE);
602         m_PkgPnp->CleanupDeviceFromFailedCreate(waitEvent.GetSelfPointer());
603     }
604     else {
605         //
606         // Upon certain types of failure, like STATUS_OBJECT_NAME_COLLISION, we
607         // could keep the pDevice around and the caller retry after changing
608         // a property, but the simpler route for now is to just recreate
609         // everything from scratch on the retry.
610         //
611         // Usually the pnp state machine will do this and the FxDevice destructor
612         // relies on it running b/c it does some cleanup.
613         //
614         EarlyDispose();
615         DestroyChildren();
616 
617         //
618         // Wait for all children to drain out and cleanup.
619         //
620         if (m_DisposeList != NULL) {
621             m_DisposeList->WaitForEmpty();
622         }
623 
624         //
625         // We keep a reference on m_PkgPnp which is released in the destructor
626         // so  we can safely touch m_PkgPnp after destroying all of the child
627         // objects.
628         //
629         if (m_PkgPnp != NULL) {
630             m_PkgPnp->CleanupStateMachines(TRUE);
631         }
632     }
633 
634     //
635     // This will detach and delete the device object
636     //
637     Destroy();
638 
639     return FailedStatus;
640 }
641 
642 _Must_inspect_result_
643 NTSTATUS
644 FxDevice::DeleteDeviceFromFailedCreate(
645     __in NTSTATUS FailedStatus,
646     __in BOOLEAN UseStateMachine
647     )
648 {
649     NTSTATUS status;
650 
651     status = DeleteDeviceFromFailedCreateNoDelete(FailedStatus, UseStateMachine);
652 
653     //
654     // Delete the Fx object now
655     //
656     DeleteObject();
657 
658     return status;
659 }
660 
661 _Must_inspect_result_
662 NTSTATUS
663 FxDevice::Initialize(
664     __in PWDFDEVICE_INIT DeviceInit,
665     __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes
666     )
667 /*++
668 
669 Routine Description:
670     Generic initialization for an FxDevice regardless of role (pdo, fdo, control).
671 
672 Arguments:
673 
674 
675 Return Value:
676 
677 
678   --*/
679 
680 {
681     PFX_DRIVER_GLOBALS  pGlobals;
682     PLIST_ENTRY         next;
683     NTSTATUS            status;
684     size_t              reqCtxSize;
685     PWDFCXDEVICE_INIT   cxInit;
686     CCHAR               cxIndex;
687     FxCxDeviceInfo*     cxDeviceInfo;
688 
689     pGlobals    = GetDriverGlobals();
690     m_Exclusive = DeviceInit->Exclusive;
691     cxIndex     = 0;
692 
693     MarkDisposeOverride(ObjectDoNotLock);
694 
695     //
696     // Configure device constraints.
697     //
698     status = ConfigureConstraints(DeviceAttributes);
699     if (!NT_SUCCESS(status)) {
700         return status;
701     }
702 
703     //
704     // Generic catch all
705     //
706     m_PkgDefault = new (pGlobals) FxDefaultIrpHandler(pGlobals, (CfxDevice*)this);
707     if (m_PkgDefault == NULL) {
708         return STATUS_INSUFFICIENT_RESOURCES;
709     }
710 
711     InstallPackage(m_PkgDefault);
712 
713     if (DeviceInit->InitType == FxDeviceInitTypeControlDevice) {
714         m_Legacy = TRUE;
715     }
716 
717     //
718     // Size will be set to a non zero if the driver wants request attributes
719     // associated with each created request.
720     //
721     if (DeviceInit->RequestAttributes.Size  != 0) {
722         ASSERT(DeviceInit->RequestAttributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES));
723         RtlCopyMemory(&m_RequestAttributes,
724                       &DeviceInit->RequestAttributes,
725                       sizeof(DeviceInit->RequestAttributes));
726     }
727 
728     reqCtxSize = FxGetContextSize(&m_RequestAttributes);
729 
730     //
731     // If present, setup a I/O class extensions info chain.
732     //
733     for (next = DeviceInit->CxDeviceInitListHead.Flink;
734          next != &DeviceInit->CxDeviceInitListHead;
735          next = next->Flink) {
736 
737         cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry);
738 
739         cxDeviceInfo = new(pGlobals) FxCxDeviceInfo(pGlobals);
740         if (NULL == cxDeviceInfo) {
741             return STATUS_INSUFFICIENT_RESOURCES;
742         }
743 
744         cxDeviceInfo->Index = ++cxIndex; // 1-based.
745         cxDeviceInfo->Driver = cxInit->CxDriverGlobals->Driver;
746         cxDeviceInfo->IoInCallerContextCallback.m_Method =
747                         cxInit->IoInCallerContextCallback;
748         cxDeviceInfo->RequestAttributes = cxInit->RequestAttributes;
749 
750         InsertTailList(&m_CxDeviceInfoListHead, &cxDeviceInfo->ListEntry);
751 
752         //
753         // Set weak ref to this run-time cx struct to help file-object logic later on.
754         //
755         cxInit->CxDeviceInfo = cxDeviceInfo;
756 
757         //
758         // Find the max size for the request context. Used below.
759         //
760         ASSERT(cxInit->RequestAttributes.Size == 0 ||
761                cxInit->RequestAttributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES));
762 
763         reqCtxSize = MAX(FxGetContextSize(&cxInit->RequestAttributes),
764                          reqCtxSize);
765     }
766 
767     //
768     // Memory layout for memory backing FxRequest which is allocated from the
769     // lookaside list:
770     //
771     // If we are tracking memory, the allocation layout is
772     // 0x0                                                 - FX_POOL_TRACKER
773     // 0x0 + sizeof(FX_POOL_TRACKER)                       - FX_POOL_HEADER
774     // 0x0 + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE - start of FxRequest
775     //
776     // if no tracking is occuring, the allocation layout is
777     // 0x0                                                 - FX_POOL_HEADER
778     // 0x0 + FX_POOL_HEADER_SIZE                           - start of FxRequest
779     //
780     // NOTE:  If the computation of m_RequestLookasideListElementSize changes,
781     //        FxDevice::AllocateRequestMemory and FxDevice::FreeRequestMemory will also
782     //        need to be updated to reflect the changes made.
783     //
784     status = FxCalculateObjectTotalSize2(pGlobals,
785                                          sizeof(FxRequest),
786                                          0,
787                                          reqCtxSize,
788                                          &m_RequestLookasideListElementSize);
789     if (!NT_SUCCESS(status)) {
790         return status;
791     }
792 
793     status = FxPoolAddHeaderSize(pGlobals,
794                                  m_RequestLookasideListElementSize,
795                                  &m_RequestLookasideListElementSize);
796 
797     if (!NT_SUCCESS(status)) {
798         //
799         // FxPoolAddHeaderSize will log to the IFR on error
800         //
801         return status;
802     }
803 
804     Mx::MxInitializeNPagedLookasideList(&m_RequestLookasideList,
805                                     NULL,
806                                     NULL,
807                                     0,
808                                     m_RequestLookasideListElementSize,
809                                     pGlobals->Tag,
810                                     0);
811     //
812     // Init device's auto_forward_cleanup_close.
813     //
814     ConfigureAutoForwardCleanupClose(DeviceInit);
815 
816     //
817     // Create, close, cleanup, shutdown
818     //
819     m_PkgGeneral = new(pGlobals) FxPkgGeneral(pGlobals, this);
820     if (m_PkgGeneral == NULL) {
821         return STATUS_INSUFFICIENT_RESOURCES;
822     }
823 
824     InstallPackage(m_PkgGeneral);
825 
826 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
827 
828 
829 
830 
831 
832 
833     // m_PkgWmi = new(pGlobals) FxWmiIrpHandler(pGlobals, this); __REACTOS__
834     // if (m_PkgWmi == NULL) {
835     //     return STATUS_INSUFFICIENT_RESOURCES;
836     // }
837     // InstallPackage(m_PkgWmi);
838 #endif
839 
840     //
841     // IO package handles reads, writes, internal and external IOCTLs
842     //
843     m_PkgIo = new(pGlobals) FxPkgIo(pGlobals, (CfxDevice*) this);
844 
845     if (m_PkgIo == NULL) {
846         return STATUS_INSUFFICIENT_RESOURCES;
847     }
848 
849     InstallPackage(m_PkgIo);
850 
851     //
852     // Configure I/O package.
853     //
854     m_PkgIo->SetIoInCallerContextCallback(DeviceInit->IoInCallerContextCallback);
855 
856     if (DeviceInit->RequiresSelfIoTarget) {
857         m_SelfIoTargetNeeded = TRUE;
858     }
859 
860     return STATUS_SUCCESS;
861 }
862 
863 VOID
864 FxDevice::ConfigureAutoForwardCleanupClose(
865     __in PWDFDEVICE_INIT DeviceInit
866     )
867 {
868     WDF_TRI_STATE   autoForwardCleanupClose;
869     PLIST_ENTRY     next;
870     BOOLEAN         checkClientDriver;
871 
872     autoForwardCleanupClose = WdfUseDefault;
873     checkClientDriver = TRUE;
874 
875     //
876     // Device-wide configuration for auto forwarding cleanup and close requests:
877     //  . Use WdfFalse if one of the devices in the chain use this setting with a create
878     //    callback (this means it will complete all create IRPs).
879     //  . Else use lowest driver's setting in the chain (order of cx chain: lower to higher).
880     //  . If no settings are present, use default.
881     //
882     for (next = DeviceInit->CxDeviceInitListHead.Blink;
883          next != &DeviceInit->CxDeviceInitListHead;
884          next = next->Blink) {
885 
886         PWDFCXDEVICE_INIT cxInit;
887 
888         cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry);
889 
890         if (cxInit->FileObject.Set) {
891             autoForwardCleanupClose = cxInit->FileObject.AutoForwardCleanupClose;
892 
893             if (autoForwardCleanupClose == WdfFalse &&
894                 cxInit->FileObject.Callbacks.EvtCxDeviceFileCreate != NULL) {
895 
896                 checkClientDriver = FALSE;
897                 break;
898             }
899         }
900     }
901 
902     if (checkClientDriver && DeviceInit->FileObject.Set) {
903         autoForwardCleanupClose = DeviceInit->FileObject.AutoForwardCleanupClose;
904     }
905 
906     switch (autoForwardCleanupClose) {
907     case WdfTrue:
908 
909         m_AutoForwardCleanupClose = TRUE;
910         //
911         // If the device is legacy then set it to false because you can't forward
912         // requests.
913         //
914         if(m_Legacy) {
915             m_AutoForwardCleanupClose = FALSE;
916         }
917         break;
918 
919     case WdfFalse:
920         m_AutoForwardCleanupClose = FALSE;
921         break;
922 
923     case WdfUseDefault:
924         //
925         // For filters (which must be FDOs), we default to TRUE.  All other
926         // device roles (FDO, PDO, control) default to FALSE.  We cannot check
927         // m_Filter yet because it is set in FdoInitialize which occurs later.
928         //
929         if (DeviceInit->IsFdoInit() && DeviceInit->Fdo.Filter) {
930             m_AutoForwardCleanupClose = TRUE;
931         }
932         else {
933             m_AutoForwardCleanupClose = FALSE;
934         }
935     }
936 }
937 
938 _Must_inspect_result_
939 NTSTATUS
940 FxDevice::PostInitialize(
941     VOID
942     )
943 {
944     NTSTATUS status;
945 
946     status = FxDisposeList::_Create(GetDriverGlobals(),
947                                    m_DeviceObject.GetObject(),
948                                    &m_DisposeList);
949 
950     return status;
951 }
952 
953 
954 
955 
956 
957 
958 
959 
960 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
961 
962 _Must_inspect_result_
963 NTSTATUS
964 FxDevice::CreateDevice(
965     __in PWDFDEVICE_INIT DeviceInit
966     )
967 {
968     MdDeviceObject  pNewDeviceObject;
969     ULONG           characteristics;
970     NTSTATUS        status;
971     DEVICE_TYPE     devType;
972 
973     status = m_PkgGeneral->Initialize(DeviceInit);
974     if (!NT_SUCCESS(status)) {
975         return status;
976     }
977 
978     devType = DeviceInit->DeviceType;
979     if (devType < ARRAY_SIZE(m_PriorityBoosts)) {
980         m_DefaultPriorityBoost= m_PriorityBoosts[devType];
981     }
982 
983     characteristics = DeviceInit->Characteristics;
984 
985     //
986     // You can only create secure device objects which have a name.  All other
987     // device objects rely on the PDO's security
988     //
989     if (DeviceInit->ShouldCreateSecure()) {
990         PUNICODE_STRING pName, pSddl;
991         LPGUID pGuid;
992 
993         if (DeviceInit->DeviceName != NULL) {
994             pName = DeviceInit->DeviceName->GetUnicodeString();
995         }
996         else {
997             pName = NULL;
998         }
999 
1000         if (DeviceInit->Security.DeviceClassSet) {
1001             pGuid = &DeviceInit->Security.DeviceClass;
1002         }
1003         else {
1004             pGuid = NULL;
1005         }
1006 
1007         if (DeviceInit->Security.Sddl != NULL) {
1008             pSddl = DeviceInit->Security.Sddl->GetUnicodeString();
1009         }
1010         else {
1011             //
1012             // Always provide an SDDL if one is not supplied.
1013             //
1014             // SDDL_DEVOBJ_SYS_ALL_ADM_ALL = "D:P(A;;GA;;;SY)(A;;GA;;;BA)"
1015             //
1016             // SDDL_DEVOBJ_SYS_ALL_ADM_ALL allows the kernel, system, and
1017             // administrator complete control over the device. No other users
1018             // may access the device.
1019             //
1020             // pSddl = (PUNICODE_STRING) &SDDL_DEVOBJ_SYS_ALL_ADM_ALL;
1021             pSddl = NULL; // __REACTOS__ : wdmsec.lib is not supported
1022         }
1023 
1024         status = Mx::MxCreateDeviceSecure(
1025             m_Driver->m_DriverObject.GetObject(),
1026             sizeof(FxWdmDeviceExtension),
1027             pName,
1028             devType,
1029             characteristics,
1030             m_Exclusive,
1031             pSddl,
1032             pGuid,
1033             &pNewDeviceObject);
1034     }
1035     else {
1036         status = Mx::MxCreateDevice(
1037             m_Driver->m_DriverObject.GetObject(),
1038             sizeof(FxWdmDeviceExtension),
1039             NULL,
1040             devType,
1041             characteristics,
1042             m_Exclusive,
1043             &pNewDeviceObject);
1044     }
1045 
1046     if (NT_SUCCESS(status)) {
1047         FxWdmDeviceExtension* pWdmExt;
1048 
1049         pWdmExt = _GetFxWdmExtension(pNewDeviceObject);
1050 
1051         //
1052         // We reassign DeviceExtension below and then use the knowledge that
1053         // we can always retrieve DeviceExtension by adding sizeof(DEVICE_OBJECT)
1054         // to pNewDeviceObject.  ASSERT that this assumption is correct.
1055         //
1056         MxDeviceObject newDeviceObject(pNewDeviceObject);
1057         ASSERT(pWdmExt == newDeviceObject.GetDeviceExtension());
1058 
1059         Mx::MxInitializeRemoveLock(&pWdmExt->IoRemoveLock,
1060                                GetDriverGlobals()->Tag,
1061                                0,          // max min
1062                                0           // highwater mark
1063                                );
1064 
1065         //
1066         // Option for remove lock is stored in device extension
1067         // since this option may be examined after FxDevice is destroyed
1068         // (if an Irp is sent after removal of device).
1069         // We combine the flags from DeviceInit with what's set through registry
1070         //
1071         pWdmExt->RemoveLockOptionFlags = DeviceInit->RemoveLockOptionFlags |
1072                                             GetDriverGlobals()->RemoveLockOptionFlags;
1073 
1074         //
1075         // We assign the first context assigned to this object as the
1076         // DeviceExtension for compatibility reasons.  This allows existing
1077         // WDM extensions to work as well as any stack which exports a known
1078         // structure for the extension (ie the FDO knows the extension of its
1079         // PDO and casts it and accesses it directly).
1080         //
1081         newDeviceObject.SetDeviceExtension(&GetContextHeader()->Context[0]);
1082         m_DeviceObject.SetObject(pNewDeviceObject);
1083 
1084         //
1085         // Set some device object flags based on properties of DeviceInit.
1086         //
1087         // If we are a filter, we will set these flags later
1088         // (in FxDevice::FdoInitialize) based on the device we are attached to.
1089         //
1090         if (m_Filter == FALSE) {
1091             if (DeviceInit->ReadWriteIoType == WdfDeviceIoBuffered) {
1092                 m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_BUFFERED_IO);
1093             }
1094             else if (DeviceInit->ReadWriteIoType == WdfDeviceIoDirect) {
1095                 m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_DIRECT_IO);
1096             }
1097 
1098             m_ReadWriteIoType = DeviceInit->ReadWriteIoType;
1099             m_PowerPageableCapable = DeviceInit->PowerPageable;
1100         }
1101     }
1102 
1103     return status;
1104 }
1105 
1106 #endif  // (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
1107 
1108 VOID
1109 FxDevice::FinishInitializing(
1110     VOID
1111     )
1112 
1113 /*++
1114 
1115 Routine Description:
1116 
1117     This routine is called when the device is completely initialized.
1118 
1119 Arguments:
1120 
1121     none.
1122 
1123 Returns:
1124 
1125     none.
1126 
1127 --*/
1128 
1129 {
1130 
1131     m_DeviceObject.SetFlags( m_DeviceObject.GetFlags() & ~DO_DEVICE_INITIALIZING);
1132 }
1133 
1134 VOID
1135 FxDevice::DeleteObject(
1136     VOID
1137     )
1138 /*++
1139 
1140 Routine Description:
1141     Virtual override of an FxObject::DeleteObject.  For PDOs which are created
1142     statically and then deleted before being reported to WDF, we must simulate
1143     a pnp remove event to trigger cleanup.
1144 
1145 Arguments:
1146     None
1147 
1148 Return Value:
1149     None
1150 
1151   --*/
1152 {
1153     if (IsPnp() && IsPdo()) {
1154         FxPkgPdo* pPkgPdo;
1155         KIRQL irql;
1156         BOOLEAN remove;
1157 
1158         remove = FALSE;
1159 
1160         pPkgPdo = GetPdoPkg();
1161 
1162         pPkgPdo->Lock(&irql);
1163 
1164         if (pPkgPdo->m_Static && pPkgPdo->m_AddedToStaticList == FALSE) {
1165             //
1166             // Since no pnp action has been taken since the child was created, we
1167             // should be in the initial state.
1168             //
1169             if (m_CurrentPnpState == WdfDevStatePnpInit) {
1170                 //
1171                 // A PDO in this state should be deletable
1172                 //
1173                 ASSERT(IsNoDeleteDDI() == FALSE);
1174 
1175                 remove = TRUE;
1176             }
1177             else {
1178                 //
1179                 // If we are not in the init state, we should be in the created
1180                 // state. This means we are failing from FxDevice::CreateDevice.
1181                 //
1182                 ASSERT(m_CurrentPnpState == WdfDevStatePnpObjectCreated);
1183             }
1184         }
1185 
1186         pPkgPdo->Unlock(irql);
1187 
1188         if (remove) {
1189             //
1190             // Cleanup the device and then let the super class delete the object.
1191             //
1192             (void) DeleteDeviceFromFailedCreateNoDelete(
1193                 STATUS_UNSUCCESSFUL, TRUE);
1194         }
1195     }
1196     else if (IsLegacy() && m_PkgGeneral != NULL && m_DeviceObject.GetObject() != NULL) {
1197         //
1198         // We allow tracing devices to go through a normal DeleteObject() path
1199         // where we do not prematurely delete the device object.
1200         //
1201         (void) FxVerifierCheckIrqlLevel(GetDriverGlobals(), PASSIVE_LEVEL);
1202 
1203         m_DeviceObjectDeleted = TRUE;
1204 
1205         //
1206         // This reference will be released in Destroy().
1207         //
1208         Mx::MxReferenceObject(m_DeviceObject.GetObject());
1209 
1210         if (m_PkgWmi != NULL) {
1211             //
1212             // Since a legacy NT4 driver does not have an explicit WMI
1213             // deregistration DDI, we do it for them on deletion.
1214             //
1215             // This is done in DeleteObject because we need to deregister before
1216             // we delete the device object, otherwise we can bugcheck when
1217             // running under driver verifier.
1218             //
1219             // m_PkgWmi->Deregister(); __REACTOS__
1220         }
1221 
1222         //
1223         // By deleting the device object now, we prevent any new creates from
1224         // being sent to the device (the io manager enforces this).
1225         //
1226         Mx::MxDeleteDevice(m_DeviceObject.GetObject());
1227 
1228         if (m_PkgGeneral->CanDestroyControlDevice() == FALSE) {
1229             //
1230             // Delay the actual destruction of the device until the last open
1231             // handle has been closed.  ControlDeviceDelete() will perform the
1232             // destruction later.
1233             //
1234             return;
1235         }
1236     }
1237 
1238     FxDeviceBase::DeleteObject(); // __super call
1239 }
1240 
1241 BOOLEAN
1242 FxDevice::Dispose(
1243     VOID
1244     )
1245 {
1246     ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
1247 
1248     if (m_Legacy) {
1249         if (m_PkgWmi != NULL) {
1250             //
1251             // We deregister in Dispose() (as well as DeleteObject()) for
1252             // control devices which are implicitly destroyed when the driver
1253             // unloads and FxDriver is being deleted.
1254             //
1255             // Since a legacy NT4 driver does not have an explicit WMI
1256             // deregistration DDI, we do it for them on destruction.
1257             //
1258             // This is done in Dispose because we are guaranteed to be at
1259             // passive level here.  Even though m_PkgWmi was already
1260             // Dispose()'ed (because it is a child of this object), it is still
1261             // valid to reference the pointer because there is an explicit
1262             // reference on the object that was taken when we created this object.
1263             //
1264             // m_PkgWmi->Deregister(); __REACTOS__
1265         }
1266 
1267         //
1268         // Important that the cleanup routine be called while the PDEVICE_OBJECT
1269         // is valid!
1270         //
1271         CallCleanup();
1272 
1273         //
1274         // Manually destroy the children now so that by the time we wait on the
1275         // dispose empty out, all of the children will have been added to it.
1276         //
1277         DestroyChildren();
1278 
1279         if (m_DisposeList != NULL) {
1280             m_DisposeList->WaitForEmpty();
1281         }
1282 
1283         //
1284         // Now delete the device object
1285         //
1286         Destroy();
1287 
1288         return FALSE;
1289     }
1290 
1291     return FxDeviceBase::Dispose(); // __super call
1292 }
1293 
1294 _Must_inspect_result_
1295 NTSTATUS
1296 FxDevice::_AcquireOptinRemoveLock(
1297     __in MdDeviceObject DeviceObject,
1298     __in MdIrp Irp
1299     )
1300 {
1301     NTSTATUS status;
1302     FxIrp irp(Irp);
1303 
1304     FxWdmDeviceExtension * wdmDeviceExtension =
1305         FxDevice::_GetFxWdmExtension(DeviceObject);
1306 
1307     if (wdmDeviceExtension->RemoveLockOptionFlags &
1308             WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) {
1309 
1310         status = Mx::MxAcquireRemoveLock(&(wdmDeviceExtension->IoRemoveLock), Irp);
1311 
1312         if (!NT_SUCCESS(status)) {
1313             return status;
1314         }
1315 
1316         irp.CopyCurrentIrpStackLocationToNext();
1317 
1318         irp.SetCompletionRoutineEx(
1319                 DeviceObject,
1320                 _CompletionRoutineForRemlockMaintenance,
1321                 DeviceObject,
1322                 TRUE,
1323                 TRUE,
1324                 TRUE
1325                 );
1326 
1327         irp.SetNextIrpStackLocation();
1328     }
1329 
1330     return STATUS_SUCCESS;
1331 }
1332 
1333 _Must_inspect_result_
1334 NTSTATUS
1335 FxDevice::DispatchWithLock(
1336     __in MdDeviceObject DeviceObject,
1337     __in MdIrp Irp
1338     )
1339 {
1340     NTSTATUS status;
1341     FxIrp irp(Irp);
1342 
1343     switch (_RequiresRemLock(irp.GetMajorFunction(),
1344                              irp.GetMinorFunction())) {
1345 
1346     case FxDeviceRemLockRequired:
1347         status = Mx::MxAcquireRemoveLock(
1348             &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1349             Irp
1350             );
1351 
1352         if (!NT_SUCCESS(status)) {
1353             irp.SetStatus(status);
1354             irp.CompleteRequest(IO_NO_INCREMENT);
1355 
1356             return status;
1357         }
1358 
1359         break;
1360 
1361     case FxDeviceRemLockOptIn:
1362         status = _AcquireOptinRemoveLock(
1363             DeviceObject,
1364             Irp
1365             );
1366 
1367         if (!NT_SUCCESS(status)) {
1368             irp.SetStatus(status);
1369             irp.CompleteRequest(IO_NO_INCREMENT);
1370 
1371             return status;
1372         }
1373 
1374         break;
1375 
1376     case FxDeviceRemLockTestValid:
1377         //
1378         // Try to Acquire and Release the RemLock.  If acquiring the lock
1379         // fails then it is not safe to process the IRP and the IRP should
1380         // be completed immediately.
1381         //
1382         status = Mx::MxAcquireRemoveLock(
1383             &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1384             Irp
1385             );
1386 
1387         if (!NT_SUCCESS(status)) {
1388             irp.SetStatus(status);
1389             irp.CompleteRequest(IO_NO_INCREMENT);
1390 
1391             return status;
1392         }
1393 
1394         Mx::MxReleaseRemoveLock(
1395             &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1396             Irp
1397             );
1398         break;
1399     }
1400 
1401     return Dispatch(DeviceObject, Irp);
1402 }
1403 
1404 _Must_inspect_result_
1405 __inline
1406 BOOLEAN
1407 IsPreprocessIrp(
1408     __in MdIrp       Irp,
1409     __in FxIrpPreprocessInfo*  Info
1410     )
1411 {
1412     UCHAR       major, minor;
1413     BOOLEAN     preprocess;
1414     FxIrp irp(Irp);
1415 
1416     major = irp.GetMajorFunction();
1417     minor = irp.GetMinorFunction();
1418 
1419     preprocess = FALSE;
1420 
1421     if (Info->Dispatch[major].EvtDevicePreprocess != NULL) {
1422         if (Info->Dispatch[major].NumMinorFunctions == 0) {
1423             //
1424             // If the driver is not interested in particular minor codes,
1425             // just give the irp to it.
1426             //
1427             preprocess = TRUE;
1428         }
1429         else {
1430             ULONG i;
1431 
1432             //
1433             // Try to match up to a minor code.
1434             //
1435             for (i = 0; i < Info->Dispatch[major].NumMinorFunctions; i++) {
1436                 if (Info->Dispatch[major].MinorFunctions[i] == minor) {
1437                     preprocess = TRUE;
1438                     break;
1439                 }
1440             }
1441         }
1442     }
1443 
1444     return preprocess;
1445 }
1446 
1447 _Must_inspect_result_
1448 __inline
1449 NTSTATUS
1450 PreprocessIrp(
1451     __in FxDevice*  Device,
1452     __in MdIrp       Irp,
1453     __in FxIrpPreprocessInfo*  Info,
1454     __in PVOID      DispatchContext
1455     )
1456 {
1457     NTSTATUS        status;
1458     UCHAR           major, minor;
1459     FxIrp irp(Irp);
1460 
1461     major = irp.GetMajorFunction();
1462     minor = irp.GetMinorFunction();
1463 
1464     //
1465     // If this is a pnp remove irp, this object could be deleted by the time
1466     // EvtDevicePreprocess returns.  To not touch freed pool, capture all
1467     // values we will need before preprocessing.
1468     //
1469 
1470     if (Info->ClassExtension == FALSE) {
1471         status = Info->Dispatch[major].EvtDevicePreprocess( Device->GetHandle(),
1472                                                             Irp);
1473     }
1474     else {
1475         status = Info->Dispatch[major].EvtCxDevicePreprocess(
1476                                                             Device->GetHandle(),
1477                                                             Irp,
1478                                                             DispatchContext);
1479     }
1480 
1481     //
1482     // If we got this far, we handed the irp off to EvtDevicePreprocess, so we
1483     // must now do our remlock maintainance if necessary.
1484     //
1485     if (FxDevice::_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) {
1486         //
1487         // Keep the remove lock active until after we call into the driver.
1488         // If the driver redispatches the irp to the framework, we will
1489         // reacquire the remove lock at that point in time.
1490         //
1491         // Touching pDevObj after sending the pnp remove irp to the framework
1492         // is OK b/c we have acquired the remlock previously and that will
1493         // prevent this irp's processing racing with the pnp remove irp
1494         // processing.
1495         //
1496         Mx::MxReleaseRemoveLock(Device->GetRemoveLock(),
1497                                 Irp);
1498     }
1499 
1500     return status;
1501 }
1502 
1503 _Must_inspect_result_
1504 __inline
1505 NTSTATUS
1506 DispatchWorker(
1507     __in FxDevice*  Device,
1508     __in MdIrp       Irp,
1509     __in WDFCONTEXT DispatchContext
1510     )
1511 {
1512     PLIST_ENTRY next;
1513     FxIrp irp(Irp);
1514 
1515     next = (PLIST_ENTRY)DispatchContext;
1516 
1517     ASSERT(NULL != DispatchContext &&
1518            ((UCHAR)(ULONG_PTR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0);
1519 
1520     //
1521     // Check for any driver/class-extensions' preprocess requirements.
1522     //
1523     while (next != &Device->m_PreprocessInfoListHead) {
1524         FxIrpPreprocessInfo* info;
1525 
1526         info = CONTAINING_RECORD(next, FxIrpPreprocessInfo, ListEntry);
1527 
1528         //
1529         // Advance to next node.
1530         //
1531         next = next->Flink;
1532 
1533         if (IsPreprocessIrp(Irp, info)) {
1534             return PreprocessIrp(Device, Irp, info, next);
1535         }
1536     }
1537 
1538     //
1539     // No preprocess requirements, directly dispatch the IRP.
1540     //
1541     return Device->GetDispatchPackage(
1542         irp.GetMajorFunction()
1543         )->Dispatch(Irp);
1544 }
1545 
1546 
1547 _Must_inspect_result_
1548 NTSTATUS
1549 FxDevice::Dispatch(
1550     __in MdDeviceObject DeviceObject,
1551     __in MdIrp       Irp
1552     )
1553 {
1554     FxDevice* device = FxDevice::GetFxDevice(DeviceObject);
1555     return DispatchWorker(device,
1556                           Irp,
1557                           device->m_PreprocessInfoListHead.Flink);
1558 }
1559 
1560 _Must_inspect_result_
1561 NTSTATUS
1562 FxDevice::DispatchPreprocessedIrp(
1563     __in MdIrp       Irp,
1564     __in WDFCONTEXT DispatchContext
1565     )
1566 {
1567     NTSTATUS    status;
1568     UCHAR       major, minor;
1569     FxIrp irp(Irp);
1570 
1571     //
1572     // The contract for this DDI is just like IoCallDriver.  The caller sets up
1573     // their stack location and then the DDI advances to the next stack location.
1574     // This means that the caller either has to call IoSkipCurrentIrpStackLocation
1575     // or IoCopyCurrentIrpStackLocationToNext before calling this DDI.
1576     //
1577     irp.SetNextIrpStackLocation();
1578 
1579     major = irp.GetMajorFunction();
1580     minor = irp.GetMinorFunction();
1581 
1582     //
1583     // FxPkgPnp and FxWmiIrpHandler expect that there will be a remove lock
1584     // acquired for all power irps.  We release the remlock when we called
1585     // Evt(Ext)DevicePreprocessIrp.
1586     //
1587     if (_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) {
1588         status = Mx::MxAcquireRemoveLock(
1589             GetRemoveLock(),
1590             Irp
1591             );
1592 
1593         if (!NT_SUCCESS(status)) {
1594             goto Done;
1595         }
1596     }
1597 
1598     return DispatchWorker(this, Irp, DispatchContext);
1599 
1600 Done:
1601     irp.SetStatus(status);
1602     irp.SetInformation(0);
1603     irp.CompleteRequest(IO_NO_INCREMENT);
1604 
1605     return status;
1606 }
1607 
1608 VOID
1609 FxDevice::InstallPackage(
1610     __inout FxPackage *Package
1611     )
1612 
1613 {
1614     //
1615     // Add this package as an association on FxDevice
1616     // so its children get Dispose notifications.
1617     //
1618     // Note: This assumes a transfer of the controlling reference
1619     //       count which it will dereference on FxDevice teardown.
1620     //       We need to add an extra one here since packages have
1621     //       an existing reference count model.
1622     //
1623     Package->AddRef();
1624     Package->AssignParentObject(this);
1625 }
1626 
1627 PVOID
1628 FxDevice::AllocateRequestMemory(
1629     __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes
1630     )
1631 /*++
1632 
1633 Routine Description:
1634     Allocates enough memory for an FxRequest* plus any additonal memory required
1635     for the device's specific context memory.
1636 
1637     If we are tracking memory, the allocation layout is
1638     0x0                                                 - FX_POOL_TRACKER
1639     0x0 + sizeof(FX_POOL_TRACKER)                       - FX_POOL_HEADER
1640     0x0 + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE - start of FxRequest
1641 
1642     if no tracking is occuring, the allocation layout is
1643     0x0                                                 - FX_POOL_HEADER
1644     0x0 + FX_POOL_HEADER_SIZE                           - start of FxRequest
1645 
1646     the total size is precomputed in m_RequestLookasideListElementSize during
1647     FxDevice::Initialize
1648 
1649 Arguments:
1650     RequestAttributes - Attributes setting for the request.
1651 
1652 Return Value:
1653     valid ptr or NULL
1654 
1655   --*/
1656 
1657 {
1658     PFX_DRIVER_GLOBALS pGlobals;
1659     PFX_POOL_TRACKER pTracker;
1660     PFX_POOL_HEADER  pHeader;
1661     PVOID ptr, pTrueBase;
1662 
1663     pGlobals = GetDriverGlobals();
1664     ptr = NULL;
1665 
1666     if (IsPdo() && GetPdoPkg()->IsForwardRequestToParentEnabled()) {
1667         pTrueBase = FxAllocateFromNPagedLookasideListNoTracking(&m_RequestLookasideList);
1668     }
1669     else {
1670         pTrueBase = FxAllocateFromNPagedLookasideList(&m_RequestLookasideList,
1671                                                       m_RequestLookasideListElementSize);
1672     }
1673 
1674     if (pTrueBase != NULL) {
1675         if (pGlobals->IsPoolTrackingOn()) {
1676             pTracker = (PFX_POOL_TRACKER) pTrueBase;
1677             pHeader  = WDF_PTR_ADD_OFFSET_TYPE(pTrueBase,
1678                                                sizeof(FX_POOL_TRACKER),
1679                                                PFX_POOL_HEADER);
1680 
1681             //
1682             // Format and insert the Tracker in the NonPagedHeader list.
1683             //
1684             FxPoolInsertNonPagedAllocateTracker(&pGlobals->FxPoolFrameworks,
1685                                                 pTracker,
1686                                                 m_RequestLookasideListElementSize,
1687                                                 pGlobals->Tag,
1688                                                 _ReturnAddress());
1689         }
1690         else {
1691             pHeader = (PFX_POOL_HEADER) pTrueBase;
1692         }
1693 
1694         //
1695         // Common init
1696         //
1697         pHeader->Base = pTrueBase;
1698         pHeader->FxDriverGlobals = pGlobals;
1699 
1700         ptr = &pHeader->AllocationStart[0];
1701 
1702         if (RequestAttributes == NULL) {
1703             RequestAttributes = &m_RequestAttributes;
1704         }
1705 
1706         ptr = FxObjectAndHandleHeaderInit(
1707             pGlobals,
1708             ptr,
1709             COMPUTE_OBJECT_SIZE(sizeof(FxRequest), 0),
1710             RequestAttributes,
1711             FxObjectTypeExternal
1712             );
1713 
1714 #if FX_VERBOSE_TRACE
1715         DoTraceLevelMessage(pGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
1716                             "Allocating FxRequest* %p, WDFREQUEST %p",
1717                             ptr, _ToHandle((FxObject*) ptr));
1718 #endif
1719         return ptr;
1720     }
1721 
1722     return NULL;
1723 }
1724 
1725 VOID
1726 FxDevice::FreeRequestMemory(
1727     __in FxRequest* Request
1728     )
1729 {
1730     PFX_POOL_HEADER pHeader;
1731 
1732 #if FX_VERBOSE_TRACE
1733     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
1734                         "Free FxRequest* %p memory", Request);
1735 #endif
1736 
1737     //
1738     // Remove the request from the list of outstanding requests against this
1739     // driver.
1740     //
1741     pHeader = FxObject::_CleanupPointer(GetDriverGlobals(), Request);
1742     if (IsPdo() && GetPdoPkg()->IsForwardRequestToParentEnabled()) {
1743         FxFreeToNPagedLookasideListNoTracking(&m_RequestLookasideList, pHeader->Base);
1744     }
1745     else {
1746         FxFreeToNPagedLookasideList(&m_RequestLookasideList, pHeader->Base);
1747     }
1748 }
1749 
1750 _Must_inspect_result_
1751 NTSTATUS
1752 FxDevice::QueryInterface(
1753     __inout FxQueryInterfaceParams* Params
1754     )
1755 {
1756     switch (Params->Type) {
1757     case FX_TYPE_DEVICE:
1758         *Params->Object = (FxDevice*) this;
1759         break;
1760 
1761     default:
1762         return FxDeviceBase::QueryInterface(Params); // __super call
1763     }
1764 
1765     return STATUS_SUCCESS;
1766 }
1767 
1768 _Must_inspect_result_
1769 NTSTATUS
1770 FxDevice::AddIoTarget(
1771     __inout FxIoTarget* IoTarget
1772     )
1773 {
1774     NTSTATUS status;
1775 
1776     status = m_IoTargetsList.Add(GetDriverGlobals(),
1777                                  &IoTarget->m_TransactionedEntry);
1778 
1779     if (NT_SUCCESS(status)) {
1780         IoTarget->m_AddedToDeviceList = TRUE;
1781         IoTarget->ADDREF(this);
1782     }
1783 
1784     return status;
1785 }
1786 
1787 VOID
1788 FxDevice::RemoveIoTarget(
1789     __inout FxIoTarget* IoTarget
1790     )
1791 {
1792     m_IoTargetsList.Remove(GetDriverGlobals(),
1793                            &IoTarget->m_TransactionedEntry);
1794 
1795     //
1796     // Assumes that the caller has its own reference on the IoTarget
1797     //
1798     IoTarget->RELEASE(this);
1799 }
1800 
1801 _Must_inspect_result_
1802 NTSTATUS
1803 FxDevice::AllocateEnumInfo(
1804     VOID
1805     )
1806 {
1807     if (IsPnp()) {
1808         return m_PkgPnp->AllocateEnumInfo();
1809     }
1810     else {
1811         return STATUS_SUCCESS;
1812     }
1813 }
1814 
1815 FxIoTarget*
1816 FxDevice::GetDefaultIoTarget(
1817     VOID
1818     )
1819 {
1820     if (IsPnp() && IsFdo()) {
1821         return GetFdoPkg()->m_DefaultTarget;
1822     }
1823     else {
1824         return NULL;
1825     }
1826 }
1827 
1828 FxIoTargetSelf*
1829 FxDevice::GetSelfIoTarget(
1830     VOID
1831     )
1832 /*++
1833 Routine Description:
1834     Returns the Self IO target for this FxDevice.
1835     Currently Self IO Target is supported only for a Pnp FDO.
1836     If the Self IO Target has not been established, it returns NULL.
1837 --*/
1838 {
1839     if (IsPnp() && IsFdo()) {
1840         return GetFdoPkg()->m_SelfTarget;
1841     }
1842     else {
1843         return NULL;
1844     }
1845 }
1846 
1847 _Must_inspect_result_
1848 NTSTATUS
1849 FxDevice::SetFilter(
1850     __in BOOLEAN Value
1851     )
1852 {
1853     NTSTATUS status;
1854 
1855     ASSERT(IsFdo());
1856 
1857     status = m_PkgIo->SetFilter(Value);
1858 
1859     if (NT_SUCCESS(status) && m_PkgPnp != NULL) {
1860         status = GetFdoPkg()->SetFilter(Value);
1861     }
1862 
1863     if (NT_SUCCESS(status)) {
1864         m_Filter = Value;
1865     }
1866 
1867     return status;
1868 }
1869 
1870 VOID
1871 FxDevice::SetFilterIoType(
1872     VOID
1873     )
1874 {
1875     FxIoTarget * ioTarget;
1876     FxTransactionedEntry * targetsList = NULL;
1877 
1878     ASSERT(IsFilter());
1879 
1880     m_DeviceObject.SetFlags( m_DeviceObject.GetFlags() & ~(DO_BUFFERED_IO | DO_DIRECT_IO));
1881 
1882     //
1883     // m_AttachedDevice can be NULL for UMDF, so check for NULL
1884     //
1885     if (m_AttachedDevice.GetObject() != NULL) {
1886         m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() |
1887             (m_AttachedDevice.GetFlags() & (DO_BUFFERED_IO | DO_DIRECT_IO)));
1888     }
1889 
1890     if (m_DeviceObject.GetFlags() & DO_BUFFERED_IO) {
1891         m_ReadWriteIoType = WdfDeviceIoBuffered;
1892     }
1893     else if (m_DeviceObject.GetFlags() & DO_DIRECT_IO) {
1894         m_ReadWriteIoType = WdfDeviceIoDirect;
1895     }
1896     else {
1897         m_ReadWriteIoType = WdfDeviceIoNeither;
1898     }
1899 
1900     //
1901     // We also need to propagate these settings to any io targets that
1902     // have already been created
1903     //
1904 
1905     m_IoTargetsList.LockForEnum(GetDriverGlobals());
1906 
1907     targetsList = m_IoTargetsList.GetNextEntry(targetsList);
1908 
1909     while (targetsList != NULL) {
1910 
1911         ioTarget = (FxIoTarget *) targetsList->GetTransactionedObject();
1912 
1913         if (ioTarget->GetTargetPDO() == GetPhysicalDevice()) {
1914             ioTarget->UpdateTargetIoType();
1915         }
1916 
1917         targetsList = m_IoTargetsList.GetNextEntry(targetsList);
1918     }
1919 
1920     m_IoTargetsList.UnlockFromEnum(GetDriverGlobals());
1921 }
1922 
1923 BOOLEAN
1924 FxDevice::IsInterfaceRegistered(
1925     _In_ const GUID* InterfaceClassGUID,
1926     _In_opt_ PCUNICODE_STRING RefString
1927     )
1928 {
1929     PSINGLE_LIST_ENTRY ple;
1930     BOOLEAN found = FALSE;
1931 
1932     m_PkgPnp->m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals());
1933 
1934     //
1935     // Iterate over the interfaces and see if we have a match
1936     //
1937     for (ple = m_PkgPnp->m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
1938         FxDeviceInterface *pDI;
1939 
1940         pDI = FxDeviceInterface::_FromEntry(ple);
1941 
1942         if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) {
1943             if (RefString != NULL) {
1944                 if ((RefString->Length == pDI->m_ReferenceString.Length)
1945                     &&
1946                     (RtlCompareMemory(RefString->Buffer,
1947                                       pDI->m_ReferenceString.Buffer,
1948                                       RefString->Length) == RefString->Length)) {
1949                     //
1950                     // They match, carry on
1951                     //
1952                     DO_NOTHING();
1953                 }
1954                 else {
1955                     //
1956                     // The ref strings do not match, continue on in the search
1957                     // of the collection.
1958                     //
1959                     continue;
1960                 }
1961             }
1962             else if (pDI->m_ReferenceString.Length > 0) {
1963                 //
1964                 // Caller didn't specify a ref string but this interface has
1965                 // one, continue on in the search through the collection.
1966                 //
1967                 continue;
1968             }
1969 
1970             //
1971             // Set the state and break out of the loop because we found our
1972             // interface.
1973             //
1974             found = TRUE;
1975             break;
1976         }
1977     }
1978 
1979     m_PkgPnp->m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals());
1980 
1981     return found;
1982 }
1983 
1984 _Must_inspect_result_
1985 NTSTATUS
1986 FxDevice::_AllocAndQueryProperty(
1987     _In_ PFX_DRIVER_GLOBALS Globals,
1988     _In_opt_ PWDFDEVICE_INIT DeviceInit,
1989     _In_opt_ FxDevice* Device,
1990     _In_opt_ MdDeviceObject RemotePdo,
1991     _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,
1992     _In_ POOL_TYPE PoolType,
1993     _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
1994     _Out_ WDFMEMORY* PropertyMemory
1995     )
1996 {
1997     FxMemoryObject* pMemory;
1998     NTSTATUS status;
1999     ULONG length = 0;
2000 
2001     status = FxDevice::_QueryProperty(Globals,
2002                                       DeviceInit,
2003                                       Device,
2004                                       RemotePdo,
2005                                       DeviceProperty,
2006                                       0,
2007                                       NULL,
2008                                       &length);
2009     if (status != STATUS_BUFFER_TOO_SMALL) {
2010         DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2011                             "Could not retrieve property %d length, %!STATUS!",
2012                             DeviceProperty, status);
2013         _Analysis_assume_(!NT_SUCCESS(status));
2014         return status;
2015     }
2016 
2017     status = FxMemoryObject::_Create(Globals,
2018                                      PropertyMemoryAttributes,
2019                                      PoolType,
2020                                      Globals->Tag,
2021                                      length,
2022                                      &pMemory);
2023     if (!NT_SUCCESS(status)) {
2024         DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2025                             "Could not allocate WDFMEMORY, %!STATUS!", status);
2026         return status;
2027     }
2028 
2029     status = FxDevice::_QueryProperty(Globals,
2030                                       DeviceInit,
2031                                       Device,
2032                                       RemotePdo,
2033                                       DeviceProperty,
2034                                       length,
2035                                       pMemory->GetBuffer(),
2036                                       &length);
2037     if (!NT_SUCCESS(status)) {
2038         DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2039                             "Could not query for full buffer, size %d, for "
2040                             "property %d, %!STATUS!",
2041                             length, DeviceProperty, status);
2042         pMemory->DeleteObject();
2043         return status;
2044     }
2045 
2046     status = pMemory->Commit(PropertyMemoryAttributes,
2047                              (WDFOBJECT*)PropertyMemory);
2048 
2049     if (!NT_SUCCESS(status)) {
2050         DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2051                             "Could not commit memory object, %!STATUS!",
2052                             status);
2053         pMemory->DeleteObject();
2054     }
2055 
2056     return status;
2057 }
2058 
2059 _Must_inspect_result_
2060 NTSTATUS
2061 FxDevice::_AllocAndQueryPropertyEx(
2062     _In_ PFX_DRIVER_GLOBALS DriverGlobals,
2063     _In_opt_ PWDFDEVICE_INIT DeviceInit,
2064     _In_opt_ FxDevice* Device,
2065     _In_ PVOID PropertyData,
2066     _In_ FxPropertyType FxPropertyType,
2067     _In_ POOL_TYPE PoolType,
2068     _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
2069     _Out_ WDFMEMORY*  PropertyMemory,
2070     _Out_ PDEVPROPTYPE PropertyType
2071     )
2072 {
2073     FxMemoryObject* pMemory;
2074     NTSTATUS status;
2075     ULONG length = 0;
2076     DEVPROPTYPE propType;
2077     ULONG requiredLength;
2078 
2079     status = FxDevice::_QueryPropertyEx(DriverGlobals,
2080                                         DeviceInit,
2081                                         Device,
2082                                         PropertyData,
2083                                         FxPropertyType,
2084                                         0,
2085                                         NULL,
2086                                         &requiredLength,
2087                                         &propType);
2088     if (status != STATUS_BUFFER_TOO_SMALL) {
2089         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2090                             "Could not retrieve property, %!STATUS!",
2091                             status);
2092         _Analysis_assume_(!NT_SUCCESS(status));
2093         return status;
2094     }
2095 
2096     *PropertyMemory = NULL;
2097     *PropertyType = 0;
2098 
2099     length = requiredLength;
2100     status = FxMemoryObject::_Create(DriverGlobals,
2101                                      PropertyMemoryAttributes,
2102                                      PoolType,
2103                                      DriverGlobals->Tag,
2104                                      length,
2105                                      &pMemory);
2106     if (!NT_SUCCESS(status)) {
2107         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2108                             "Could not allocate WDFMEMORY, %!STATUS!", status);
2109         return status;
2110     }
2111 
2112     status = FxDevice::_QueryPropertyEx(DriverGlobals,
2113                                         DeviceInit,
2114                                         Device,
2115                                         PropertyData,
2116                                         FxPropertyType,
2117                                         length,
2118                                         pMemory->GetBuffer(),
2119                                         &requiredLength,
2120                                         &propType);
2121     if (!NT_SUCCESS(status)) {
2122         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2123                             "Could not query for full buffer, size %d, for "
2124                             "property, %!STATUS!",
2125                             length, status);
2126         pMemory->DeleteObject();
2127         return status;
2128     }
2129 
2130     status = pMemory->Commit(PropertyMemoryAttributes,
2131                              (WDFOBJECT*)PropertyMemory);
2132 
2133     if (!NT_SUCCESS(status)) {
2134         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2135                             "Could not commit memory object, %!STATUS!",
2136                             status);
2137         pMemory->DeleteObject();
2138     }
2139     else {
2140         *PropertyMemory = pMemory->GetHandle();
2141         *PropertyType = propType;
2142     }
2143 
2144     return status;
2145 }
2146 
2147 _Must_inspect_result_
2148 NTSTATUS
2149 FxDevice::_ValidateOpenKeyParams(
2150     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
2151     _In_opt_ PWDFDEVICE_INIT DeviceInit,
2152     _In_opt_ FxDevice* Device
2153     )
2154 {
2155     NTSTATUS status = STATUS_SUCCESS;
2156 
2157     //
2158     // This function should be called with exactly one valid WDFDEVICE_INIT
2159     // or one valid FxDevice object. Supplying neither or both is an error.
2160     //
2161     if ((DeviceInit == NULL && Device == NULL) ||
2162         (DeviceInit != NULL && Device != NULL)) {
2163 
2164         status = STATUS_INVALID_PARAMETER;
2165         DoTraceLevelMessage(
2166             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2167             "Device OpenKey/QueryProperty was called with invalid "
2168             "DeviceInit and Device parameters, %!STATUS!", status);
2169         FxVerifierDbgBreakPoint(FxDriverGlobals);
2170     }
2171 
2172     return status;
2173 }
2174 
2175