1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxDeviceKm.cpp
8 
9 Abstract:
10 
11     This is the KM specific class implementation for the base Device class.
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19     Kernel mode only
20 
21 Revision History:
22 
23 --*/
24 
25 #include "coreprivshared.hpp"
26 
27 extern "C" {
28 // #include "FxDeviceKm.tmh"
29 }
30 
31 _Must_inspect_result_
32 NTSTATUS
FdoInitialize(__in PWDFDEVICE_INIT DeviceInit)33 FxDevice::FdoInitialize(
34     __in PWDFDEVICE_INIT DeviceInit
35     )
36 {
37     PFX_DRIVER_GLOBALS pGlobals;
38     NTSTATUS status;
39     FxPkgFdo * pkgFdo;
40 
41     pGlobals = GetDriverGlobals();
42 
43     if (DeviceInit->Fdo.EventCallbacks.EvtDeviceFilterAddResourceRequirements != NULL &&
44         DeviceInit->Fdo.EventCallbacks.EvtDeviceRemoveAddedResources == NULL) {
45         //
46         // Not allowed to add resources without filtering them out later
47         //
48         DoTraceLevelMessage(
49             pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
50             "Must set EvtDeviceRemoveAddedResources if "
51             "EvtDeviceFilterAddResourceRequirements (%p) is set",
52             DeviceInit->Fdo.EventCallbacks.EvtDeviceFilterAddResourceRequirements);
53 
54         FxVerifierDbgBreakPoint(pGlobals);
55 
56         return STATUS_INVALID_DEVICE_STATE;
57     }
58 
59     //
60     // All FDOs cannot be deleted through the driver calling WdfObjectDelete
61     //
62     MarkNoDeleteDDI();
63 
64     m_PhysicalDevice.SetObject((MdDeviceObject)DeviceInit->Fdo.PhysicalDevice);
65 
66     //
67     // The PDO is known because it was used to bring up this FDO.
68     //
69     m_PdoKnown = TRUE;
70 
71     //
72     // Try to create and install the default packages that an FDO contains.
73     //
74 
75     // PnP
76     status = FxPkgFdo::_Create(pGlobals, (CfxDevice*)this, &pkgFdo);
77 
78     if (!NT_SUCCESS(status)) {
79         return status;
80     }
81     else {
82         m_PkgPnp = pkgFdo;
83     }
84 
85     InstallPackage(m_PkgPnp);
86 
87     status = SetFilter(DeviceInit->Fdo.Filter);
88     if (!NT_SUCCESS(status)) {
89         return status;
90     }
91 
92     status = GetFdoPkg()->Initialize(DeviceInit);
93     if (!NT_SUCCESS(status)) {
94         return status;
95     }
96 
97 
98     //
99     // Should be done after invoking Initialize so that FxPkgFdo::m_EnumInfo is
100     // already allocated.
101     //
102     if (DeviceInit->Fdo.ListConfig.Size > 0) {
103         status = GetFdoPkg()->CreateDefaultDeviceList(
104             &DeviceInit->Fdo.ListConfig,
105             DeviceInit->Fdo.ListConfigAttributes.Size > 0
106                 ? &DeviceInit->Fdo.ListConfigAttributes
107                 : NULL);
108 
109         if (!NT_SUCCESS(status)) {
110             return status;
111         }
112 
113         SetDeviceTelemetryInfoFlags(DeviceInfoHasDynamicChildren);
114     }
115 
116     //
117     // If the Size is zero then the driver writer never set any callbacks so we
118     // can skip this call.
119     //
120     if (DeviceInit->Fdo.EventCallbacks.Size != 0) {
121         status = GetFdoPkg()->RegisterCallbacks(&DeviceInit->Fdo.EventCallbacks);
122         if (!NT_SUCCESS(status)) {
123             return status;
124         }
125     }
126 
127     status = CreateDevice(DeviceInit);
128     if (NT_SUCCESS(status)) {
129         //
130         // If this is an FDO then the PhysicalDevice field will be initialized,
131         // and we need to attach to the device stack.
132         //
133         m_AttachedDevice.SetObject(Mx::MxAttachDeviceToDeviceStack(
134             m_DeviceObject.GetObject(), m_PhysicalDevice.GetObject()));
135 
136         if (m_AttachedDevice.GetObject() == NULL) {
137             //
138             // We couldn't attach the device for some reason.
139             //
140             Mx::MxDeleteDevice(m_DeviceObject.GetObject());
141             m_DeviceObject = NULL;
142 
143             status = STATUS_NO_SUCH_DEVICE;
144         }
145         else {
146             //
147             // If we are a filter device, inherit some state from the
148             // attached device.
149             //
150             if (m_Filter) {
151                 //
152                 // Set the IO type and power pageable status on our device based
153                 // on the attached device's settings.
154                 //
155                 SetFilterIoType();
156 
157                 m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() |
158                     (m_AttachedDevice.GetFlags() & (DO_POWER_PAGABLE | DO_POWER_INRUSH)));
159 
160                 m_DeviceObject.SetDeviceType(m_AttachedDevice.GetDeviceType());
161                 m_DeviceObject.SetCharacteristics(m_AttachedDevice.GetCharacteristics());
162 
163                 //
164                 // For devices other then filters, m_PowerPageableCapable gets
165                 // set in CreateDevice, but since this is determined for filters
166                 // by the device they have attached to, we must set this value
167                 // later as a special case only for filters.
168                 //
169                 if (m_DeviceObject.GetFlags() & DO_POWER_PAGABLE) {
170                     m_PowerPageableCapable = TRUE;
171                 }
172             }
173             else {
174                 //
175                 // We are not a filter, we dictate our own DO flags
176                 //
177 
178                 //
179                 // Power pageable and inrush are mutually exclusive
180                 //
181                 if (DeviceInit->PowerPageable) {
182                     m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_PAGABLE);
183                 }
184                 else if (DeviceInit->Inrush) {
185                     m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_INRUSH);
186                 }
187             }
188         }
189     }
190 
191     if (!NT_SUCCESS(status)) {
192         return status;
193     }
194 
195     // status = m_PkgWmi->PostCreateDeviceInitialize(); __REACTOS__
196     // if (!NT_SUCCESS(status)) {
197     //     return status;
198     // }
199 
200     status = m_PkgGeneral->PostCreateDeviceInitialize(DeviceInit);
201     if (!NT_SUCCESS(status)) {
202         return status;
203     }
204 
205     status = GetFdoPkg()->PostCreateDeviceInitialize();
206 
207     if (NT_SUCCESS(status)) {
208         //
209         // Do not clear the DO_DEVICE_INITIALIZING bit here.  Instead, either
210         // let the caller do it in their AddDevice or do it after the AddDevice
211         // callback returns.
212         //
213         // FinishInitializing();
214     }
215 
216     return status;
217 }
218 
219 _Must_inspect_result_
220 NTSTATUS
PdoInitialize(__in PWDFDEVICE_INIT DeviceInit)221 FxDevice::PdoInitialize(
222     __in PWDFDEVICE_INIT DeviceInit
223     )
224 {
225     PFX_DRIVER_GLOBALS pGlobals;
226     FxPkgPdo* pPkgPdo;
227     NTSTATUS status;
228 
229     pGlobals = GetDriverGlobals();
230 
231     //
232     // If the child is static, the driver has the ability to delete the child
233     // device handle in between WdfDeviceCreate succeededing and then adding
234     // the child to the list of static children.
235     //
236     if (DeviceInit->Pdo.Static == FALSE) {
237         MarkNoDeleteDDI();
238     }
239 
240     //
241     // Double check to make sure that the PDO has a name
242     //
243     if (DeviceInit->HasName() == FALSE) {
244         return STATUS_OBJECT_NAME_INVALID;
245     }
246 
247     m_ParentDevice = DeviceInit->Pdo.Parent;
248 
249     //
250     // This reference will be removed when this object is destroyed
251     //
252     m_ParentDevice->ADDREF(this);
253 
254     pPkgPdo = new(pGlobals) FxPkgPdo(pGlobals, (CfxDevice*)this);
255 
256     m_PkgPnp = pPkgPdo;
257     if (m_PkgPnp == NULL) {
258         return STATUS_INSUFFICIENT_RESOURCES;
259     }
260     InstallPackage(m_PkgPnp);
261 
262     status = m_PkgPnp->Initialize(DeviceInit);
263     if (!NT_SUCCESS(status)) {
264         return status;
265     }
266 
267     //
268     // If the Size is zero then the driver writer never set any callbacks so we
269     // can skip this call.
270     //
271     if (DeviceInit->Pdo.EventCallbacks.Size != 0) {
272         pPkgPdo->RegisterCallbacks(&DeviceInit->Pdo.EventCallbacks);
273     }
274 
275     status = CreateDevice(DeviceInit);
276 
277     if (NT_SUCCESS(status)) {
278 
279         //
280         // We are initializing the PDO, stash away the PDO's device object
281         // under m_PhysicalDevice as well so that we don't have to check
282         // for device type later.
283         //
284         m_PhysicalDevice = m_DeviceObject;
285 
286         if (DeviceInit->Pdo.Raw) {
287             pPkgPdo->m_RawOK = TRUE;
288         }
289 
290         //
291         // Power pageable and inrush are mutually exclusive
292         //
293         if (DeviceInit->PowerPageable) {
294             m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_PAGABLE);
295         }
296         else if (DeviceInit->Inrush) {
297             m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_INRUSH);
298         }
299 
300         if (DeviceInit->Pdo.ForwardRequestToParent) {
301             m_DeviceObject.SetStackSize(m_DeviceObject.GetStackSize() + DeviceInit->Pdo.Parent->GetDeviceObject()->StackSize);
302             pPkgPdo->m_AllowForwardRequestToParent = TRUE;
303         }
304 
305         // status = m_PkgWmi->PostCreateDeviceInitialize(); __REACTOS__
306         // if (!NT_SUCCESS(status)) {
307         //     return status;
308         // }
309 
310         status = m_PkgGeneral->PostCreateDeviceInitialize(DeviceInit);
311         if (!NT_SUCCESS(status)) {
312             return status;
313         }
314 
315         status = pPkgPdo->PostCreateDeviceInitialize();
316 
317         if (NT_SUCCESS(status)) {
318             //
319             // Clear the DO_DEVICE_INITIALIZING bit.
320             //
321             FinishInitializing();
322         }
323     }
324 
325     return status;
326 }
327 
328 VOID
Destroy(VOID)329 FxDevice::Destroy(
330     VOID
331     )
332 {
333     //
334     // We must be at passive for IoDeleteDevice
335     //
336     ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
337 
338     if (m_DeviceObject.GetObject() != NULL) {
339         //
340         // The device object may not go away right away if there are pending
341         // references on it.  But we can't look up our FxDevice anymore, so
342         // lets clear the DeviceExtension pointer.
343         //
344         m_DeviceObject.SetDeviceExtension(NULL);
345     }
346 
347     //
348     // Since this can be called in the context of the destructor when the ref
349     // count is zero, use GetObjectHandleUnchecked() to get the handle value.
350     //
351     DoTraceLevelMessage(
352         GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGDEVICE,
353         "Deleting !devobj %p, WDFDEVICE %p, attached to !devobj %p",
354         m_DeviceObject.GetObject(), GetObjectHandleUnchecked(), m_AttachedDevice.GetObject());
355 
356     DetachDevice();
357 
358     if (m_DeviceObject.GetObject() != NULL) {
359         DeleteSymbolicLink();
360 
361         if (m_DeviceObjectDeleted) {
362             //
363             // The device already deleted previously, release the reference we
364             // took at the time of delete.
365             //
366             Mx::MxDereferenceObject(m_DeviceObject.GetObject());
367         }
368         else {
369             Mx::MxDeleteDevice(m_DeviceObject.GetObject());
370         }
371 
372         m_DeviceObject.SetObject(NULL);
373     }
374 
375     //
376     // Clean up any referenced objects
377     //
378     if (m_DeviceName.Buffer != NULL) {
379         FxPoolFree(m_DeviceName.Buffer);
380         RtlZeroMemory(&m_DeviceName, sizeof(m_DeviceName));
381     }
382 
383     if (m_MofResourceName.Buffer != NULL) {
384         FxPoolFree(m_MofResourceName.Buffer);
385         RtlZeroMemory(&m_MofResourceName, sizeof(m_DeviceName));
386     }
387 }
388 
389 VOID
DestructorInternal(VOID)390 FxDevice::DestructorInternal(
391     VOID
392     )
393 {
394     // NOTHING TO DO
395 }
396 
397 _Must_inspect_result_
398 NTSTATUS
ControlDeviceInitialize(__in PWDFDEVICE_INIT DeviceInit)399 FxDevice::ControlDeviceInitialize(
400     __in PWDFDEVICE_INIT DeviceInit
401     )
402 {
403     NTSTATUS status;
404 
405     m_Legacy = TRUE;
406 
407     status = CreateDevice(DeviceInit);
408 
409     if (!NT_SUCCESS(status)) {
410         return status;
411     }
412 
413     // status = m_PkgWmi->PostCreateDeviceInitialize(); __REACTOS__
414     // if (!NT_SUCCESS(status)) {
415     //     return status;
416     // }
417 
418     status = m_PkgGeneral->PostCreateDeviceInitialize(DeviceInit);
419     if (!NT_SUCCESS(status)) {
420         return status;
421     }
422 
423     //
424     // NOTE: The driver writer must clear the DO_DEVICE_INITIALIZING bit
425     //       via WdfControlFinishInitializing
426     //
427     return status;
428 }
429 
430 VOID
AddChildList(__inout FxChildList * List)431 FxDevice::AddChildList(
432     __inout FxChildList* List
433     )
434 {
435     if (IsPnp()) {
436         m_PkgPnp->AddChildList(List);
437     }
438 }
439 
440 VOID
RemoveChildList(__inout FxChildList * List)441 FxDevice::RemoveChildList(
442     __inout FxChildList* List
443     )
444 {
445     if (IsPnp()) {
446         m_PkgPnp->RemoveChildList(List);
447     }
448 }
449 
450 _Must_inspect_result_
451 NTSTATUS
AllocateDmaEnablerList(VOID)452 FxDevice::AllocateDmaEnablerList(
453     VOID
454     )
455 {
456     if (IsPnp()) {
457         return m_PkgPnp->AllocateDmaEnablerList();
458     }
459     else {
460         return STATUS_SUCCESS;
461     }
462 }
463 
464 VOID
AddDmaEnabler(__inout FxDmaEnabler * Enabler)465 FxDevice::AddDmaEnabler(
466     __inout FxDmaEnabler* Enabler
467     )
468 {
469     if (IsPnp()) {
470         m_PkgPnp->AddDmaEnabler(Enabler);
471     }
472 }
473 
474 VOID
RemoveDmaEnabler(__inout FxDmaEnabler * Enabler)475 FxDevice::RemoveDmaEnabler(
476     __inout FxDmaEnabler* Enabler
477     )
478 {
479     if (IsPnp()) {
480         m_PkgPnp->RemoveDmaEnabler(Enabler);
481     }
482 }
483 
484 
485 
486 
487 NTSTATUS
WmiPkgRegister(VOID)488 FxDevice::WmiPkgRegister(
489     VOID
490     )
491 {
492     // return m_PkgWmi->Register(); __REACTOS__
493     return STATUS_SUCCESS;
494 }
495 
496 VOID
WmiPkgDeregister(VOID)497 FxDevice::WmiPkgDeregister(
498     VOID
499     )
500 {
501     // m_PkgWmi->Deregister(); __REACTOS__
502 }
503 
504 VOID
WmiPkgCleanup(VOID)505 FxDevice::WmiPkgCleanup(
506     VOID
507     )
508 {
509     // m_PkgWmi->Cleanup(); __REACTOS__
510 }
511 
512 NTSTATUS
CreateSymbolicLink(_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,_In_ PCUNICODE_STRING SymbolicLinkName)513 FxDevice::CreateSymbolicLink(
514     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
515     _In_ PCUNICODE_STRING SymbolicLinkName
516     )
517 {
518     NTSTATUS status;
519     PUNICODE_STRING pName;
520     FxAutoString pdoName;
521 
522     //
523     // Ensure m_DeviceName has been set or we can get the PDO's name
524     //
525     if (m_DeviceName.Buffer == NULL) {
526         MdDeviceObject pPdo;
527         PWSTR pBuffer;
528         ULONG length;
529 
530         if (IsLegacy()) {
531             //
532             // No PDO on a legacy stack, can't call IoGetDeviceProperty
533             //
534             status = STATUS_INVALID_DEVICE_STATE;
535 
536             DoTraceLevelMessage(
537                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
538                 "WDFDEVICE %p has no device name (use WdfDeviceInitAssignName), "
539                 "%!STATUS!", GetHandle(), status);
540 
541             return status;
542         }
543 
544         pPdo = GetSafePhysicalDevice();
545         if (pPdo == NULL) {
546             //
547             // No PDO yet for this device, pnp doesn't know about it.
548             //
549             status = STATUS_INVALID_DEVICE_STATE;
550 
551             DoTraceLevelMessage(
552                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
553                 "WDFDEVICE %p has not yet been reported to pnp, cannot call "
554                 "IoGetDeviceProperty in this state, %!STATUS!", GetHandle(), status);
555 
556             return status;
557         }
558 
559         length = 0;
560 
561         status = _GetDeviceProperty(pPdo,
562                                     DevicePropertyPhysicalDeviceObjectName,
563                                     0,
564                                     NULL,
565                                     &length);
566 
567         if (status != STATUS_BUFFER_TOO_SMALL && !NT_SUCCESS(status)) {
568             DoTraceLevelMessage(
569                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
570                 "WDFDEVICE %p IoGetDeviceProperty failed %!STATUS!",
571                 GetHandle(), status);
572             return status;
573         }
574         else if (length > USHORT_MAX) {
575             status = STATUS_INTEGER_OVERFLOW;
576 
577             DoTraceLevelMessage(
578                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
579                 "WDFDEVICE %p PDO name too long (%d, max is %d), %!STATUS!",
580                 GetHandle(), length, USHORT_MAX, status);
581 
582             return status;
583         }
584         else if (length == 0) {
585             //
586             // We can get zero back if the PDO is being deleted.
587             //
588             status = STATUS_INVALID_DEVICE_STATE;
589 
590             DoTraceLevelMessage(
591                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
592                 "WDFDEVICE %p PDO name length is zero, %!STATUS!",
593                 GetHandle(), status);
594 
595             return status;
596         }
597 
598         pBuffer = (PWSTR) FxPoolAllocate(FxDriverGlobals, PagedPool, length);
599         if (pBuffer == NULL) {
600             status = STATUS_INSUFFICIENT_RESOURCES;
601 
602             DoTraceLevelMessage(
603                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
604                 "WDFDEVICE %p could not allocate buffer for PDO name, %!STATUS!",
605                 GetHandle(), status);
606 
607             return status;
608         }
609 
610         //
611         // pdoName will free pBuffer when it is destructed
612         //
613         pdoName.m_UnicodeString.Buffer = pBuffer;
614 
615         status = _GetDeviceProperty(pPdo,
616                                     DevicePropertyPhysicalDeviceObjectName,
617                                     length,
618                                     pBuffer,
619                                     &length);
620 
621         if (!NT_SUCCESS(status)) {
622             DoTraceLevelMessage(
623                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
624                 "WDFDEVICE %p IoGetDeviceProperty failed second time, %!STATUS!",
625                 GetHandle(), status);
626             return status;
627         }
628 
629         pdoName.m_UnicodeString.Length = (USHORT) length - sizeof(UNICODE_NULL);
630         pdoName.m_UnicodeString.MaximumLength = (USHORT) length;
631 
632         pName = &pdoName.m_UnicodeString;
633     }
634     else {
635         pName = &m_DeviceName;
636     }
637 
638     status = FxDuplicateUnicodeString(FxDriverGlobals,
639                                       SymbolicLinkName,
640                                       &m_SymbolicLinkName);
641 
642     if (!NT_SUCCESS(status)) {
643         DoTraceLevelMessage(
644             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
645             "WDFDEVICE %p allocate buffer for symbolic name failed, %!STATUS!",
646             GetHandle(), status);
647 
648         return status;
649     }
650 
651     status = Mx::MxCreateSymbolicLink(&m_SymbolicLinkName, pName);
652 
653     if (!NT_SUCCESS(status)) {
654         FxPoolFree(m_SymbolicLinkName.Buffer);
655 
656         RtlZeroMemory(&m_SymbolicLinkName,
657                       sizeof(m_SymbolicLinkName));
658 
659         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
660                             "WDFDEVICE %p  create sybolic link failed, %!STATUS!",
661                             GetHandle(), status);
662     }
663 
664     return status;
665 }
666 
667 NTSTATUS
AssignProperty(_In_ PVOID PropertyData,_In_ FxPropertyType FxPropertyType,_In_ DEVPROPTYPE Type,_In_ ULONG BufferLength,_In_opt_ PVOID PropertyBuffer)668 FxDevice::AssignProperty (
669     _In_ PVOID PropertyData,
670     _In_ FxPropertyType FxPropertyType,
671     _In_ DEVPROPTYPE Type,
672     _In_ ULONG BufferLength,
673     _In_opt_ PVOID PropertyBuffer
674     )
675 {
676     NTSTATUS status;
677     const DEVPROPKEY * propertyKey;
678     LCID lcid;
679     ULONG flags;
680     PWDF_DEVICE_PROPERTY_DATA deviceData;
681     PDEVICE_OBJECT pdo;
682 
683     UNREFERENCED_PARAMETER(FxPropertyType);
684 
685     ASSERT(FxPropertyType == FxDeviceProperty);
686 
687     deviceData = (PWDF_DEVICE_PROPERTY_DATA) PropertyData;
688 
689     propertyKey = deviceData->PropertyKey;
690     lcid = deviceData->Lcid;
691     flags = deviceData->Flags;
692 
693     pdo = GetSafePhysicalDevice();
694 
695     if (pdo == NULL) {
696         //
697         // Pnp doesn't know about the PDO yet.
698         //
699         status = STATUS_INVALID_DEVICE_STATE;
700         DoTraceLevelMessage(
701             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
702             "WDFDEVICE %p is not yet known to PnP manager, cannot call "
703             "WdfDeviceAssignPropertyEx in this state, %!STATUS!",
704             GetHandle(), status);
705 
706         return status;
707     }
708 
709     status = IoSetDevicePropertyData(
710                 pdo,
711                 propertyKey,
712                 lcid,
713                 flags,
714                 Type,
715                 BufferLength,
716                 PropertyBuffer
717                 );
718 
719     if (!NT_SUCCESS(status)) {
720         DoTraceLevelMessage(
721             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
722             "WDFDEVICE %p failed to assign device property, %!STATUS!",
723             GetHandle(), status);
724     }
725 
726     return status;
727 }
728 
729 _Must_inspect_result_
730 NTSTATUS
_OpenKey(_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device,_In_ ULONG DeviceInstanceKeyType,_In_ ACCESS_MASK DesiredAccess,_In_opt_ PWDF_OBJECT_ATTRIBUTES KeyAttributes,_Out_ WDFKEY * Key)731 FxDevice::_OpenKey(
732     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
733     _In_opt_ PWDFDEVICE_INIT DeviceInit,
734     _In_opt_ FxDevice* Device,
735     _In_ ULONG DeviceInstanceKeyType,
736     _In_ ACCESS_MASK DesiredAccess,
737     _In_opt_ PWDF_OBJECT_ATTRIBUTES KeyAttributes,
738     _Out_ WDFKEY* Key
739     )
740 {
741     FxRegKey* pKey;
742     WDFKEY keyHandle;
743     HANDLE hKey = NULL;
744     NTSTATUS status;
745     MdDeviceObject pdo;
746 
747     status = FxValidateObjectAttributes(FxDriverGlobals, KeyAttributes);
748     if (!NT_SUCCESS(status)) {
749         return status;
750     }
751 
752     status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL);
753     if (!NT_SUCCESS(status)) {
754         return status;
755     }
756 
757     status = _ValidateOpenKeyParams(FxDriverGlobals, DeviceInit, Device);
758     if (!NT_SUCCESS(status)) {
759         return status;
760     }
761 
762     _Analysis_assume_(DeviceInit != NULL || Device != NULL);
763 
764     if (DeviceInit != NULL) {
765         pdo = DeviceInit->Fdo.PhysicalDevice;
766     }
767     else {
768         pdo = Device->GetSafePhysicalDevice();
769         if (pdo == NULL) {
770             //
771             // Pnp doesn't know about the PDO yet.
772             //
773             status = STATUS_INVALID_DEVICE_STATE;
774             DoTraceLevelMessage(
775                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
776                 "WDFDEVICE %p is not yet known to PnP manager, cannot open "
777                 "PNP registry keys in this state, %!STATUS!", Device->GetHandle(), status);
778             return status;
779         }
780     }
781 
782     pKey = new(FxDriverGlobals, KeyAttributes) FxRegKey(FxDriverGlobals);
783 
784     if (pKey == NULL) {
785         return STATUS_INSUFFICIENT_RESOURCES;
786     }
787 
788     if (Device != NULL) {
789         pKey->SetDeviceBase(Device);
790     }
791 
792     status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle);
793 
794     if (NT_SUCCESS(status)) {
795         status = _OpenDeviceRegistryKey(pdo,
796                                         DeviceInstanceKeyType,
797                                         DesiredAccess,
798                                         &hKey);
799         if (NT_SUCCESS(status)) {
800             pKey->SetHandle(hKey);
801             *Key = keyHandle;
802         }
803     }
804 
805     if (!NT_SUCCESS(status)) {
806         //
807         // No object is being returned, make sure the destroy callback will not
808         // be called.
809         //
810         pKey->DeleteFromFailedCreate();
811     }
812 
813     return status;
814 }
815 
816 _Must_inspect_result_
817 NTSTATUS
OpenSettingsKey(__out HANDLE * Key,__in ACCESS_MASK DesiredAccess)818 FxDevice::OpenSettingsKey(
819     __out HANDLE* Key,
820     __in ACCESS_MASK DesiredAccess
821     )
822 {
823     NTSTATUS status;
824     FxAutoRegKey parent;
825     MdDeviceObject pdo;
826 
827     //
828     // We need a PDO to open this reg key.  in the case of failure to create
829     // a static PDO, we will go down this path in the pnp state machine, so we
830     // must check for validity always.
831     //
832     pdo = GetSafePhysicalDevice();
833 
834     if (pdo == NULL) {
835         return STATUS_INVALID_DEVICE_STATE;
836     }
837 
838     status = _OpenDeviceRegistryKey(pdo,
839                                     PLUGPLAY_REGKEY_DEVICE,
840                                     DesiredAccess,
841                                     &parent.m_Key);
842     if (NT_SUCCESS(status)) {
843         DECLARE_CONST_UNICODE_STRING(wdf, L"WDF");
844 
845         //
846         // Create the key if it does not already exist
847         //
848         status = FxRegKey::_Create(parent.m_Key,
849                                    &wdf,
850                                    Key,
851                                    DesiredAccess);
852     }
853 
854     return status;
855 }
856 
857 _Must_inspect_result_
858 NTSTATUS
_QueryPropertyEx(_In_ PFX_DRIVER_GLOBALS DriverGlobals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device,_In_ PVOID PropertyData,_In_ FxPropertyType FxPropertyType,_In_ ULONG BufferLength,_Out_ PVOID PropertyBuffer,_Out_ PULONG ResultLength,_Out_ PDEVPROPTYPE PropertyType)859 FxDevice::_QueryPropertyEx (
860     _In_ PFX_DRIVER_GLOBALS DriverGlobals,
861     _In_opt_ PWDFDEVICE_INIT DeviceInit,
862     _In_opt_ FxDevice* Device,
863     _In_ PVOID PropertyData,
864     _In_ FxPropertyType FxPropertyType,
865     _In_ ULONG BufferLength,
866     _Out_ PVOID PropertyBuffer,
867     _Out_ PULONG ResultLength,
868     _Out_ PDEVPROPTYPE PropertyType
869     )
870 {
871     NTSTATUS status;
872     DEVPROPTYPE propType;
873     ULONG requiredLength = 0;
874     const DEVPROPKEY * propertyKey;
875     LCID lcid;
876     PWDF_DEVICE_PROPERTY_DATA deviceData;
877     MdDeviceObject pdo;
878 
879     UNREFERENCED_PARAMETER(FxPropertyType);
880     ASSERT(FxPropertyType == FxDeviceProperty);
881 
882     *ResultLength = 0;
883     *PropertyType = 0;
884 
885     status = FxDevice::_ValidateOpenKeyParams(DriverGlobals,
886                                               DeviceInit,
887                                               Device);
888     if (!NT_SUCCESS(status)) {
889         return status;
890     }
891 
892     _Analysis_assume_(DeviceInit != NULL || Device != NULL);
893 
894     if (DeviceInit != NULL) {
895         pdo = DeviceInit->Fdo.PhysicalDevice;
896     }
897     else {
898         pdo = Device->GetSafePhysicalDevice();
899         if (pdo == NULL) {
900             //
901             // Pnp doesn't know about the PDO yet.
902             //
903             status = STATUS_INVALID_DEVICE_STATE;
904             DoTraceLevelMessage(
905                 DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
906                 "WDFDEVICE %p is not yet known to PnP manager, cannot query "
907                 "device properties in this state, %!STATUS!", Device->GetHandle(), status);
908             return status;
909         }
910     }
911 
912     deviceData = (PWDF_DEVICE_PROPERTY_DATA) PropertyData;
913     propertyKey = deviceData->PropertyKey;
914     lcid = deviceData->Lcid;
915 
916     status = IoGetDevicePropertyData(pdo,
917                                      propertyKey,
918                                      lcid,
919                                      0,
920                                      BufferLength,
921                                      PropertyBuffer,
922                                      &requiredLength,
923                                      &propType);
924     if (status == STATUS_BUFFER_TOO_SMALL || NT_SUCCESS(status)) {
925         *ResultLength = requiredLength;
926         *PropertyType = propType;
927     }
928     else {
929         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
930                             "Query for property buffer failed, %!STATUS!",
931                             status);
932     }
933 
934     return status;
935 }
936 
937 _Must_inspect_result_
938 NTSTATUS
_QueryProperty(_In_ PFX_DRIVER_GLOBALS FxDriverGlobals,_In_opt_ PWDFDEVICE_INIT DeviceInit,_In_opt_ FxDevice * Device,_In_opt_ MdDeviceObject RemotePdo,_In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,_In_ ULONG BufferLength,_Out_opt_ PVOID PropertyBuffer,_Out_opt_ PULONG ResultLength)939 FxDevice::_QueryProperty(
940     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
941     _In_opt_ PWDFDEVICE_INIT DeviceInit,
942     _In_opt_ FxDevice* Device,
943     _In_opt_ MdDeviceObject RemotePdo,
944     _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty,
945     _In_ ULONG BufferLength,
946     _Out_opt_ PVOID PropertyBuffer,
947     _Out_opt_ PULONG ResultLength
948     )
949 {
950     NTSTATUS status;
951     MdDeviceObject pdo;
952 
953     ASSERT(DeviceInit != NULL || Device != NULL || RemotePdo != NULL);
954 
955     if (RemotePdo != NULL) {
956         pdo = RemotePdo;
957     }
958     else {
959         status = FxDevice::_ValidateOpenKeyParams(FxDriverGlobals,
960                                                   DeviceInit,
961                                                   Device);
962         if (!NT_SUCCESS(status)) {
963             return status;
964         }
965 
966         if (DeviceInit != NULL) {
967             pdo = DeviceInit->Fdo.PhysicalDevice;
968         }
969         else {
970             pdo = Device->GetSafePhysicalDevice();
971             if (pdo == NULL) {
972                 //
973                 // Pnp doesn't know about the PDO yet.
974                 //
975                 status = STATUS_INVALID_DEVICE_STATE;
976                 DoTraceLevelMessage(
977                     FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
978                     "WDFDEVICE %p is not yet known to PnP manager, cannot query "
979                     "device properties in this state, %!STATUS!", Device->GetHandle(), status);
980                 return status;
981             }
982         }
983     }
984 
985     status = _GetDeviceProperty(pdo,
986                                 DeviceProperty,
987                                 BufferLength,
988                                 PropertyBuffer,
989                                 ResultLength);
990     return status;
991 }
992 
993 _Must_inspect_result_
994 NTSTATUS
OpenDevicemapKeyWorker(_In_ PFX_DRIVER_GLOBALS pFxDriverGlobals,_In_ PCUNICODE_STRING KeyName,_In_ ACCESS_MASK DesiredAccess,_In_ FxRegKey * pKey)995 FxDevice::OpenDevicemapKeyWorker(
996     _In_ PFX_DRIVER_GLOBALS pFxDriverGlobals,
997     _In_ PCUNICODE_STRING KeyName,
998     _In_ ACCESS_MASK DesiredAccess,
999     _In_ FxRegKey* pKey
1000     )
1001 {
1002 
1003     NTSTATUS status;
1004     UNICODE_STRING registryKeyPath;
1005     wchar_t baseStringBuffer[256] = FX_DEVICEMAP_PATH;
1006 
1007     //
1008     // Unlike UMDF, KMDF can open any DEVICEMAP key directly. Create a fully qualified
1009     // DEVICEMAP path from the provided subkey and pass it to FxRegKey::_OpenKey
1010     //
1011     registryKeyPath.Buffer = baseStringBuffer;
1012     registryKeyPath.MaximumLength = sizeof(baseStringBuffer);
1013     registryKeyPath.Length = sizeof(FX_DEVICEMAP_PATH) - sizeof(UNICODE_NULL);
1014 
1015     status = RtlAppendUnicodeStringToString(&registryKeyPath, KeyName);
1016 
1017     if (!NT_SUCCESS(status)) {
1018         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
1019             "Unable to create a DEVICEMAP registry path for subkey %S, %!STATUS!",
1020             KeyName->Buffer, status);
1021     } else {
1022 
1023         status = pKey->Create(NULL,
1024                               &registryKeyPath,
1025                               DesiredAccess,
1026                               REG_OPTION_VOLATILE,
1027                               NULL);
1028 
1029         if (!NT_SUCCESS(status)) {
1030             DoTraceLevelMessage(
1031                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
1032                 "WDFKEY open failed, %!STATUS!", status);
1033         }
1034     }
1035 
1036     return status;
1037 }
1038 
1039