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
_CompletionRoutineForRemlockMaintenance(__in MdDeviceObject DeviceObject,__in MdIrp Irp,__in PVOID Context)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
FxDevice(__in FxDriver * ArgDriver)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
SetInitialState(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
~FxDevice()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
_Create(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PWDFDEVICE_INIT * DeviceInit,__in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes,__out FxDevice ** Device)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
DeleteDeviceFromFailedCreateNoDelete(__in NTSTATUS FailedStatus,__in BOOLEAN UseStateMachine)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
DeleteDeviceFromFailedCreate(__in NTSTATUS FailedStatus,__in BOOLEAN UseStateMachine)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
Initialize(__in PWDFDEVICE_INIT DeviceInit,__in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes)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
ConfigureAutoForwardCleanupClose(__in PWDFDEVICE_INIT DeviceInit)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
PostInitialize(VOID)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
CreateDevice(__in PWDFDEVICE_INIT DeviceInit)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
FinishInitializing(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
DeleteObject(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
Dispose(VOID)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
_AcquireOptinRemoveLock(__in MdDeviceObject DeviceObject,__in MdIrp Irp)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 STDCALL
DispatchWithLock(__in MdDeviceObject DeviceObject,__in MdIrp Irp)1336 FxDevice::DispatchWithLock(
1337 __in MdDeviceObject DeviceObject,
1338 __in MdIrp Irp
1339 )
1340 {
1341 NTSTATUS status;
1342 FxIrp irp(Irp);
1343
1344 switch (_RequiresRemLock(irp.GetMajorFunction(),
1345 irp.GetMinorFunction())) {
1346
1347 case FxDeviceRemLockRequired:
1348 status = Mx::MxAcquireRemoveLock(
1349 &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1350 Irp
1351 );
1352
1353 if (!NT_SUCCESS(status)) {
1354 irp.SetStatus(status);
1355 irp.CompleteRequest(IO_NO_INCREMENT);
1356
1357 return status;
1358 }
1359
1360 break;
1361
1362 case FxDeviceRemLockOptIn:
1363 status = _AcquireOptinRemoveLock(
1364 DeviceObject,
1365 Irp
1366 );
1367
1368 if (!NT_SUCCESS(status)) {
1369 irp.SetStatus(status);
1370 irp.CompleteRequest(IO_NO_INCREMENT);
1371
1372 return status;
1373 }
1374
1375 break;
1376
1377 case FxDeviceRemLockTestValid:
1378 //
1379 // Try to Acquire and Release the RemLock. If acquiring the lock
1380 // fails then it is not safe to process the IRP and the IRP should
1381 // be completed immediately.
1382 //
1383 status = Mx::MxAcquireRemoveLock(
1384 &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1385 Irp
1386 );
1387
1388 if (!NT_SUCCESS(status)) {
1389 irp.SetStatus(status);
1390 irp.CompleteRequest(IO_NO_INCREMENT);
1391
1392 return status;
1393 }
1394
1395 Mx::MxReleaseRemoveLock(
1396 &_GetFxWdmExtension(DeviceObject)->IoRemoveLock,
1397 Irp
1398 );
1399 break;
1400 }
1401
1402 return Dispatch(DeviceObject, Irp);
1403 }
1404
1405 _Must_inspect_result_
1406 __inline
1407 BOOLEAN
IsPreprocessIrp(__in MdIrp Irp,__in FxIrpPreprocessInfo * Info)1408 IsPreprocessIrp(
1409 __in MdIrp Irp,
1410 __in FxIrpPreprocessInfo* Info
1411 )
1412 {
1413 UCHAR major, minor;
1414 BOOLEAN preprocess;
1415 FxIrp irp(Irp);
1416
1417 major = irp.GetMajorFunction();
1418 minor = irp.GetMinorFunction();
1419
1420 preprocess = FALSE;
1421
1422 if (Info->Dispatch[major].EvtDevicePreprocess != NULL) {
1423 if (Info->Dispatch[major].NumMinorFunctions == 0) {
1424 //
1425 // If the driver is not interested in particular minor codes,
1426 // just give the irp to it.
1427 //
1428 preprocess = TRUE;
1429 }
1430 else {
1431 ULONG i;
1432
1433 //
1434 // Try to match up to a minor code.
1435 //
1436 for (i = 0; i < Info->Dispatch[major].NumMinorFunctions; i++) {
1437 if (Info->Dispatch[major].MinorFunctions[i] == minor) {
1438 preprocess = TRUE;
1439 break;
1440 }
1441 }
1442 }
1443 }
1444
1445 return preprocess;
1446 }
1447
1448 _Must_inspect_result_
1449 __inline
1450 NTSTATUS
PreprocessIrp(__in FxDevice * Device,__in MdIrp Irp,__in FxIrpPreprocessInfo * Info,__in PVOID DispatchContext)1451 PreprocessIrp(
1452 __in FxDevice* Device,
1453 __in MdIrp Irp,
1454 __in FxIrpPreprocessInfo* Info,
1455 __in PVOID DispatchContext
1456 )
1457 {
1458 NTSTATUS status;
1459 UCHAR major, minor;
1460 FxIrp irp(Irp);
1461
1462 major = irp.GetMajorFunction();
1463 minor = irp.GetMinorFunction();
1464
1465 //
1466 // If this is a pnp remove irp, this object could be deleted by the time
1467 // EvtDevicePreprocess returns. To not touch freed pool, capture all
1468 // values we will need before preprocessing.
1469 //
1470
1471 if (Info->ClassExtension == FALSE) {
1472 status = Info->Dispatch[major].EvtDevicePreprocess( Device->GetHandle(),
1473 Irp);
1474 }
1475 else {
1476 status = Info->Dispatch[major].EvtCxDevicePreprocess(
1477 Device->GetHandle(),
1478 Irp,
1479 DispatchContext);
1480 }
1481
1482 //
1483 // If we got this far, we handed the irp off to EvtDevicePreprocess, so we
1484 // must now do our remlock maintainance if necessary.
1485 //
1486 if (FxDevice::_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) {
1487 //
1488 // Keep the remove lock active until after we call into the driver.
1489 // If the driver redispatches the irp to the framework, we will
1490 // reacquire the remove lock at that point in time.
1491 //
1492 // Touching pDevObj after sending the pnp remove irp to the framework
1493 // is OK b/c we have acquired the remlock previously and that will
1494 // prevent this irp's processing racing with the pnp remove irp
1495 // processing.
1496 //
1497 Mx::MxReleaseRemoveLock(Device->GetRemoveLock(),
1498 Irp);
1499 }
1500
1501 return status;
1502 }
1503
1504 _Must_inspect_result_
1505 __inline
1506 NTSTATUS
DispatchWorker(__in FxDevice * Device,__in MdIrp Irp,__in WDFCONTEXT DispatchContext)1507 DispatchWorker(
1508 __in FxDevice* Device,
1509 __in MdIrp Irp,
1510 __in WDFCONTEXT DispatchContext
1511 )
1512 {
1513 PLIST_ENTRY next;
1514 FxIrp irp(Irp);
1515
1516 next = (PLIST_ENTRY)DispatchContext;
1517
1518 ASSERT(NULL != DispatchContext &&
1519 ((UCHAR)(ULONG_PTR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0);
1520
1521 //
1522 // Check for any driver/class-extensions' preprocess requirements.
1523 //
1524 while (next != &Device->m_PreprocessInfoListHead) {
1525 FxIrpPreprocessInfo* info;
1526
1527 info = CONTAINING_RECORD(next, FxIrpPreprocessInfo, ListEntry);
1528
1529 //
1530 // Advance to next node.
1531 //
1532 next = next->Flink;
1533
1534 if (IsPreprocessIrp(Irp, info)) {
1535 return PreprocessIrp(Device, Irp, info, next);
1536 }
1537 }
1538
1539 //
1540 // No preprocess requirements, directly dispatch the IRP.
1541 //
1542 return Device->GetDispatchPackage(
1543 irp.GetMajorFunction()
1544 )->Dispatch(Irp);
1545 }
1546
1547
1548 _Must_inspect_result_
1549 NTSTATUS
1550 STDCALL
Dispatch(__in MdDeviceObject DeviceObject,__in MdIrp Irp)1551 FxDevice::Dispatch(
1552 __in MdDeviceObject DeviceObject,
1553 __in MdIrp Irp
1554 )
1555 {
1556 FxDevice* device = FxDevice::GetFxDevice(DeviceObject);
1557 return DispatchWorker(device,
1558 Irp,
1559 device->m_PreprocessInfoListHead.Flink);
1560 }
1561
1562 _Must_inspect_result_
1563 NTSTATUS
DispatchPreprocessedIrp(__in MdIrp Irp,__in WDFCONTEXT DispatchContext)1564 FxDevice::DispatchPreprocessedIrp(
1565 __in MdIrp Irp,
1566 __in WDFCONTEXT DispatchContext
1567 )
1568 {
1569 NTSTATUS status;
1570 UCHAR major, minor;
1571 FxIrp irp(Irp);
1572
1573 //
1574 // The contract for this DDI is just like IoCallDriver. The caller sets up
1575 // their stack location and then the DDI advances to the next stack location.
1576 // This means that the caller either has to call IoSkipCurrentIrpStackLocation
1577 // or IoCopyCurrentIrpStackLocationToNext before calling this DDI.
1578 //
1579 irp.SetNextIrpStackLocation();
1580
1581 major = irp.GetMajorFunction();
1582 minor = irp.GetMinorFunction();
1583
1584 //
1585 // FxPkgPnp and FxWmiIrpHandler expect that there will be a remove lock
1586 // acquired for all power irps. We release the remlock when we called
1587 // Evt(Ext)DevicePreprocessIrp.
1588 //
1589 if (_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) {
1590 status = Mx::MxAcquireRemoveLock(
1591 GetRemoveLock(),
1592 Irp
1593 );
1594
1595 if (!NT_SUCCESS(status)) {
1596 goto Done;
1597 }
1598 }
1599
1600 return DispatchWorker(this, Irp, DispatchContext);
1601
1602 Done:
1603 irp.SetStatus(status);
1604 irp.SetInformation(0);
1605 irp.CompleteRequest(IO_NO_INCREMENT);
1606
1607 return status;
1608 }
1609
1610 VOID
InstallPackage(__inout FxPackage * Package)1611 FxDevice::InstallPackage(
1612 __inout FxPackage *Package
1613 )
1614
1615 {
1616 //
1617 // Add this package as an association on FxDevice
1618 // so its children get Dispose notifications.
1619 //
1620 // Note: This assumes a transfer of the controlling reference
1621 // count which it will dereference on FxDevice teardown.
1622 // We need to add an extra one here since packages have
1623 // an existing reference count model.
1624 //
1625 Package->AddRef();
1626 Package->AssignParentObject(this);
1627 }
1628
1629 PVOID
AllocateRequestMemory(__in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes)1630 FxDevice::AllocateRequestMemory(
1631 __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes
1632 )
1633 /*++
1634
1635 Routine Description:
1636 Allocates enough memory for an FxRequest* plus any additonal memory required
1637 for the device's specific context memory.
1638
1639 If we are tracking memory, the allocation layout is
1640 0x0 - FX_POOL_TRACKER
1641 0x0 + sizeof(FX_POOL_TRACKER) - FX_POOL_HEADER
1642 0x0 + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE - start of FxRequest
1643
1644 if no tracking is occuring, the allocation layout is
1645 0x0 - FX_POOL_HEADER
1646 0x0 + FX_POOL_HEADER_SIZE - start of FxRequest
1647
1648 the total size is precomputed in m_RequestLookasideListElementSize during
1649 FxDevice::Initialize
1650
1651 Arguments:
1652 RequestAttributes - Attributes setting for the request.
1653
1654 Return Value:
1655 valid ptr or NULL
1656
1657 --*/
1658
1659 {
1660 PFX_DRIVER_GLOBALS pGlobals;
1661 PFX_POOL_TRACKER pTracker;
1662 PFX_POOL_HEADER pHeader;
1663 PVOID ptr, pTrueBase;
1664
1665 pGlobals = GetDriverGlobals();
1666 ptr = NULL;
1667
1668 if (IsPdo() && GetPdoPkg()->IsForwardRequestToParentEnabled()) {
1669 pTrueBase = FxAllocateFromNPagedLookasideListNoTracking(&m_RequestLookasideList);
1670 }
1671 else {
1672 pTrueBase = FxAllocateFromNPagedLookasideList(&m_RequestLookasideList,
1673 m_RequestLookasideListElementSize);
1674 }
1675
1676 if (pTrueBase != NULL) {
1677 if (pGlobals->IsPoolTrackingOn()) {
1678 pTracker = (PFX_POOL_TRACKER) pTrueBase;
1679 pHeader = WDF_PTR_ADD_OFFSET_TYPE(pTrueBase,
1680 sizeof(FX_POOL_TRACKER),
1681 PFX_POOL_HEADER);
1682
1683 //
1684 // Format and insert the Tracker in the NonPagedHeader list.
1685 //
1686 FxPoolInsertNonPagedAllocateTracker(&pGlobals->FxPoolFrameworks,
1687 pTracker,
1688 m_RequestLookasideListElementSize,
1689 pGlobals->Tag,
1690 _ReturnAddress());
1691 }
1692 else {
1693 pHeader = (PFX_POOL_HEADER) pTrueBase;
1694 }
1695
1696 //
1697 // Common init
1698 //
1699 pHeader->Base = pTrueBase;
1700 pHeader->FxDriverGlobals = pGlobals;
1701
1702 ptr = &pHeader->AllocationStart[0];
1703
1704 if (RequestAttributes == NULL) {
1705 RequestAttributes = &m_RequestAttributes;
1706 }
1707
1708 ptr = FxObjectAndHandleHeaderInit(
1709 pGlobals,
1710 ptr,
1711 COMPUTE_OBJECT_SIZE(sizeof(FxRequest), 0),
1712 RequestAttributes,
1713 FxObjectTypeExternal
1714 );
1715
1716 #if FX_VERBOSE_TRACE
1717 DoTraceLevelMessage(pGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
1718 "Allocating FxRequest* %p, WDFREQUEST %p",
1719 ptr, _ToHandle((FxObject*) ptr));
1720 #endif
1721 return ptr;
1722 }
1723
1724 return NULL;
1725 }
1726
1727 VOID
FreeRequestMemory(__in FxRequest * Request)1728 FxDevice::FreeRequestMemory(
1729 __in FxRequest* Request
1730 )
1731 {
1732 PFX_POOL_HEADER pHeader;
1733
1734 #if FX_VERBOSE_TRACE
1735 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
1736 "Free FxRequest* %p memory", Request);
1737 #endif
1738
1739 //
1740 // Remove the request from the list of outstanding requests against this
1741 // driver.
1742 //
1743 pHeader = FxObject::_CleanupPointer(GetDriverGlobals(), Request);
1744 if (IsPdo() && GetPdoPkg()->IsForwardRequestToParentEnabled()) {
1745 FxFreeToNPagedLookasideListNoTracking(&m_RequestLookasideList, pHeader->Base);
1746 }
1747 else {
1748 FxFreeToNPagedLookasideList(&m_RequestLookasideList, pHeader->Base);
1749 }
1750 }
1751
1752 _Must_inspect_result_
1753 NTSTATUS
QueryInterface(__inout FxQueryInterfaceParams * Params)1754 FxDevice::QueryInterface(
1755 __inout FxQueryInterfaceParams* Params
1756 )
1757 {
1758 switch (Params->Type) {
1759 case FX_TYPE_DEVICE:
1760 *Params->Object = (FxDevice*) this;
1761 break;
1762
1763 default:
1764 return FxDeviceBase::QueryInterface(Params); // __super call
1765 }
1766
1767 return STATUS_SUCCESS;
1768 }
1769
1770 _Must_inspect_result_
1771 NTSTATUS
AddIoTarget(__inout FxIoTarget * IoTarget)1772 FxDevice::AddIoTarget(
1773 __inout FxIoTarget* IoTarget
1774 )
1775 {
1776 NTSTATUS status;
1777
1778 status = m_IoTargetsList.Add(GetDriverGlobals(),
1779 &IoTarget->m_TransactionedEntry);
1780
1781 if (NT_SUCCESS(status)) {
1782 IoTarget->m_AddedToDeviceList = TRUE;
1783 IoTarget->ADDREF(this);
1784 }
1785
1786 return status;
1787 }
1788
1789 VOID
RemoveIoTarget(__inout FxIoTarget * IoTarget)1790 FxDevice::RemoveIoTarget(
1791 __inout FxIoTarget* IoTarget
1792 )
1793 {
1794 m_IoTargetsList.Remove(GetDriverGlobals(),
1795 &IoTarget->m_TransactionedEntry);
1796
1797 //
1798 // Assumes that the caller has its own reference on the IoTarget
1799 //
1800 IoTarget->RELEASE(this);
1801 }
1802
1803 _Must_inspect_result_
1804 NTSTATUS
AllocateEnumInfo(VOID)1805 FxDevice::AllocateEnumInfo(
1806 VOID
1807 )
1808 {
1809 if (IsPnp()) {
1810 return m_PkgPnp->AllocateEnumInfo();
1811 }
1812 else {
1813 return STATUS_SUCCESS;
1814 }
1815 }
1816
1817 FxIoTarget*
GetDefaultIoTarget(VOID)1818 FxDevice::GetDefaultIoTarget(
1819 VOID
1820 )
1821 {
1822 if (IsPnp() && IsFdo()) {
1823 return GetFdoPkg()->m_DefaultTarget;
1824 }
1825 else {
1826 return NULL;
1827 }
1828 }
1829
1830 FxIoTargetSelf*
GetSelfIoTarget(VOID)1831 FxDevice::GetSelfIoTarget(
1832 VOID
1833 )
1834 /*++
1835 Routine Description:
1836 Returns the Self IO target for this FxDevice.
1837 Currently Self IO Target is supported only for a Pnp FDO.
1838 If the Self IO Target has not been established, it returns NULL.
1839 --*/
1840 {
1841 if (IsPnp() && IsFdo()) {
1842 return GetFdoPkg()->m_SelfTarget;
1843 }
1844 else {
1845 return NULL;
1846 }
1847 }
1848
1849 _Must_inspect_result_
1850 NTSTATUS
SetFilter(__in BOOLEAN Value)1851 FxDevice::SetFilter(
1852 __in BOOLEAN Value
1853 )
1854 {
1855 NTSTATUS status;
1856
1857 ASSERT(IsFdo());
1858
1859 status = m_PkgIo->SetFilter(Value);
1860
1861 if (NT_SUCCESS(status) && m_PkgPnp != NULL) {
1862 status = GetFdoPkg()->SetFilter(Value);
1863 }
1864
1865 if (NT_SUCCESS(status)) {
1866 m_Filter = Value;
1867 }
1868
1869 return status;
1870 }
1871
1872 VOID
SetFilterIoType(VOID)1873 FxDevice::SetFilterIoType(
1874 VOID
1875 )
1876 {
1877 FxIoTarget * ioTarget;
1878 FxTransactionedEntry * targetsList = NULL;
1879
1880 ASSERT(IsFilter());
1881
1882 m_DeviceObject.SetFlags( m_DeviceObject.GetFlags() & ~(DO_BUFFERED_IO | DO_DIRECT_IO));
1883
1884 //
1885 // m_AttachedDevice can be NULL for UMDF, so check for NULL
1886 //
1887 if (m_AttachedDevice.GetObject() != NULL) {
1888 m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() |
1889 (m_AttachedDevice.GetFlags() & (DO_BUFFERED_IO | DO_DIRECT_IO)));
1890 }
1891
1892 if (m_DeviceObject.GetFlags() & DO_BUFFERED_IO) {
1893 m_ReadWriteIoType = WdfDeviceIoBuffered;
1894 }
1895 else if (m_DeviceObject.GetFlags() & DO_DIRECT_IO) {
1896 m_ReadWriteIoType = WdfDeviceIoDirect;
1897 }
1898 else {
1899 m_ReadWriteIoType = WdfDeviceIoNeither;
1900 }
1901
1902 //
1903 // We also need to propagate these settings to any io targets that
1904 // have already been created
1905 //
1906
1907 m_IoTargetsList.LockForEnum(GetDriverGlobals());
1908
1909 targetsList = m_IoTargetsList.GetNextEntry(targetsList);
1910
1911 while (targetsList != NULL) {
1912
1913 ioTarget = (FxIoTarget *) targetsList->GetTransactionedObject();
1914
1915 if (ioTarget->GetTargetPDO() == GetPhysicalDevice()) {
1916 ioTarget->UpdateTargetIoType();
1917 }
1918
1919 targetsList = m_IoTargetsList.GetNextEntry(targetsList);
1920 }
1921
1922 m_IoTargetsList.UnlockFromEnum(GetDriverGlobals());
1923 }
1924
1925 BOOLEAN
IsInterfaceRegistered(_In_ const GUID * InterfaceClassGUID,_In_opt_ PCUNICODE_STRING RefString)1926 FxDevice::IsInterfaceRegistered(
1927 _In_ const GUID* InterfaceClassGUID,
1928 _In_opt_ PCUNICODE_STRING RefString
1929 )
1930 {
1931 PSINGLE_LIST_ENTRY ple;
1932 BOOLEAN found = FALSE;
1933
1934 m_PkgPnp->m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals());
1935
1936 //
1937 // Iterate over the interfaces and see if we have a match
1938 //
1939 for (ple = m_PkgPnp->m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
1940 FxDeviceInterface *pDI;
1941
1942 pDI = FxDeviceInterface::_FromEntry(ple);
1943
1944 if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) {
1945 if (RefString != NULL) {
1946 if ((RefString->Length == pDI->m_ReferenceString.Length)
1947 &&
1948 (RtlCompareMemory(RefString->Buffer,
1949 pDI->m_ReferenceString.Buffer,
1950 RefString->Length) == RefString->Length)) {
1951 //
1952 // They match, carry on
1953 //
1954 DO_NOTHING();
1955 }
1956 else {
1957 //
1958 // The ref strings do not match, continue on in the search
1959 // of the collection.
1960 //
1961 continue;
1962 }
1963 }
1964 else if (pDI->m_ReferenceString.Length > 0) {
1965 //
1966 // Caller didn't specify a ref string but this interface has
1967 // one, continue on in the search through the collection.
1968 //
1969 continue;
1970 }
1971
1972 //
1973 // Set the state and break out of the loop because we found our
1974 // interface.
1975 //
1976 found = TRUE;
1977 break;
1978 }
1979 }
1980
1981 m_PkgPnp->m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals());
1982
1983 return found;
1984 }
1985
1986 _Must_inspect_result_
1987 NTSTATUS
_AllocAndQueryProperty(_In_ PFX_DRIVER_GLOBALS Globals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device,_In_opt_ MdDeviceObject RemotePdo,_In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,_In_ POOL_TYPE PoolType,_In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,_Out_ WDFMEMORY * PropertyMemory)1988 FxDevice::_AllocAndQueryProperty(
1989 _In_ PFX_DRIVER_GLOBALS Globals,
1990 _In_opt_ PWDFDEVICE_INIT DeviceInit,
1991 _In_opt_ FxDevice* Device,
1992 _In_opt_ MdDeviceObject RemotePdo,
1993 _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,
1994 _In_ POOL_TYPE PoolType,
1995 _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
1996 _Out_ WDFMEMORY* PropertyMemory
1997 )
1998 {
1999 FxMemoryObject* pMemory;
2000 NTSTATUS status;
2001 ULONG length = 0;
2002
2003 status = FxDevice::_QueryProperty(Globals,
2004 DeviceInit,
2005 Device,
2006 RemotePdo,
2007 DeviceProperty,
2008 0,
2009 NULL,
2010 &length);
2011 if (status != STATUS_BUFFER_TOO_SMALL) {
2012 DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2013 "Could not retrieve property %d length, %!STATUS!",
2014 DeviceProperty, status);
2015 _Analysis_assume_(!NT_SUCCESS(status));
2016 return status;
2017 }
2018
2019 status = FxMemoryObject::_Create(Globals,
2020 PropertyMemoryAttributes,
2021 PoolType,
2022 Globals->Tag,
2023 length,
2024 &pMemory);
2025 if (!NT_SUCCESS(status)) {
2026 DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2027 "Could not allocate WDFMEMORY, %!STATUS!", status);
2028 return status;
2029 }
2030
2031 status = FxDevice::_QueryProperty(Globals,
2032 DeviceInit,
2033 Device,
2034 RemotePdo,
2035 DeviceProperty,
2036 length,
2037 pMemory->GetBuffer(),
2038 &length);
2039 if (!NT_SUCCESS(status)) {
2040 DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2041 "Could not query for full buffer, size %d, for "
2042 "property %d, %!STATUS!",
2043 length, DeviceProperty, status);
2044 pMemory->DeleteObject();
2045 return status;
2046 }
2047
2048 status = pMemory->Commit(PropertyMemoryAttributes,
2049 (WDFOBJECT*)PropertyMemory);
2050
2051 if (!NT_SUCCESS(status)) {
2052 DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2053 "Could not commit memory object, %!STATUS!",
2054 status);
2055 pMemory->DeleteObject();
2056 }
2057
2058 return status;
2059 }
2060
2061 _Must_inspect_result_
2062 NTSTATUS
_AllocAndQueryPropertyEx(_In_ PFX_DRIVER_GLOBALS DriverGlobals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device,_In_ PVOID PropertyData,_In_ FxPropertyType FxPropertyType,_In_ POOL_TYPE PoolType,_In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,_Out_ WDFMEMORY * PropertyMemory,_Out_ PDEVPROPTYPE PropertyType)2063 FxDevice::_AllocAndQueryPropertyEx(
2064 _In_ PFX_DRIVER_GLOBALS DriverGlobals,
2065 _In_opt_ PWDFDEVICE_INIT DeviceInit,
2066 _In_opt_ FxDevice* Device,
2067 _In_ PVOID PropertyData,
2068 _In_ FxPropertyType FxPropertyType,
2069 _In_ POOL_TYPE PoolType,
2070 _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes,
2071 _Out_ WDFMEMORY* PropertyMemory,
2072 _Out_ PDEVPROPTYPE PropertyType
2073 )
2074 {
2075 FxMemoryObject* pMemory;
2076 NTSTATUS status;
2077 ULONG length = 0;
2078 DEVPROPTYPE propType;
2079 ULONG requiredLength;
2080
2081 status = FxDevice::_QueryPropertyEx(DriverGlobals,
2082 DeviceInit,
2083 Device,
2084 PropertyData,
2085 FxPropertyType,
2086 0,
2087 NULL,
2088 &requiredLength,
2089 &propType);
2090 if (status != STATUS_BUFFER_TOO_SMALL) {
2091 DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2092 "Could not retrieve property, %!STATUS!",
2093 status);
2094 _Analysis_assume_(!NT_SUCCESS(status));
2095 return status;
2096 }
2097
2098 *PropertyMemory = NULL;
2099 *PropertyType = 0;
2100
2101 length = requiredLength;
2102 status = FxMemoryObject::_Create(DriverGlobals,
2103 PropertyMemoryAttributes,
2104 PoolType,
2105 DriverGlobals->Tag,
2106 length,
2107 &pMemory);
2108 if (!NT_SUCCESS(status)) {
2109 DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2110 "Could not allocate WDFMEMORY, %!STATUS!", status);
2111 return status;
2112 }
2113
2114 status = FxDevice::_QueryPropertyEx(DriverGlobals,
2115 DeviceInit,
2116 Device,
2117 PropertyData,
2118 FxPropertyType,
2119 length,
2120 pMemory->GetBuffer(),
2121 &requiredLength,
2122 &propType);
2123 if (!NT_SUCCESS(status)) {
2124 DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2125 "Could not query for full buffer, size %d, for "
2126 "property, %!STATUS!",
2127 length, status);
2128 pMemory->DeleteObject();
2129 return status;
2130 }
2131
2132 status = pMemory->Commit(PropertyMemoryAttributes,
2133 (WDFOBJECT*)PropertyMemory);
2134
2135 if (!NT_SUCCESS(status)) {
2136 DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
2137 "Could not commit memory object, %!STATUS!",
2138 status);
2139 pMemory->DeleteObject();
2140 }
2141 else {
2142 *PropertyMemory = pMemory->GetHandle();
2143 *PropertyType = propType;
2144 }
2145
2146 return status;
2147 }
2148
2149 _Must_inspect_result_
2150 NTSTATUS
_ValidateOpenKeyParams(_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device)2151 FxDevice::_ValidateOpenKeyParams(
2152 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
2153 _In_opt_ PWDFDEVICE_INIT DeviceInit,
2154 _In_opt_ FxDevice* Device
2155 )
2156 {
2157 NTSTATUS status = STATUS_SUCCESS;
2158
2159 //
2160 // This function should be called with exactly one valid WDFDEVICE_INIT
2161 // or one valid FxDevice object. Supplying neither or both is an error.
2162 //
2163 if ((DeviceInit == NULL && Device == NULL) ||
2164 (DeviceInit != NULL && Device != NULL)) {
2165
2166 status = STATUS_INVALID_PARAMETER;
2167 DoTraceLevelMessage(
2168 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
2169 "Device OpenKey/QueryProperty was called with invalid "
2170 "DeviceInit and Device parameters, %!STATUS!", status);
2171 FxVerifierDbgBreakPoint(FxDriverGlobals);
2172 }
2173
2174 return status;
2175 }
2176
2177