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(®istryKeyPath, 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 ®istryKeyPath,
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