2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 PDEVICE_NODE IopRootDeviceNode
;
19 KSPIN_LOCK IopDeviceTreeLock
;
20 ERESOURCE PpRegistryDeviceResource
;
21 KGUARDED_MUTEX PpDeviceReferenceTableLock
;
22 RTL_AVL_TABLE PpDeviceReferenceTable
;
24 extern ERESOURCE IopDriverLoadResource
;
25 extern ULONG ExpInitializationPhase
;
26 extern BOOLEAN PnpSystemInit
;
28 #define MAX_DEVICE_ID_LEN 200
29 #define MAX_SEPARATORS_INSTANCEID 0
30 #define MAX_SEPARATORS_DEVICEID 1
32 /* DATA **********************************************************************/
34 PDRIVER_OBJECT IopRootDriverObject
;
35 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList
= NULL
;
36 LIST_ENTRY IopDeviceActionRequestList
;
37 WORK_QUEUE_ITEM IopDeviceActionWorkItem
;
38 BOOLEAN IopDeviceActionInProgress
;
39 KSPIN_LOCK IopDeviceActionLock
;
41 typedef struct _DEVICE_ACTION_DATA
43 LIST_ENTRY RequestListEntry
;
44 PDEVICE_OBJECT DeviceObject
;
45 DEVICE_RELATION_TYPE Type
;
46 } DEVICE_ACTION_DATA
, *PDEVICE_ACTION_DATA
;
48 /* FUNCTIONS *****************************************************************/
51 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
52 IN ULONG CreateOptions
,
56 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
);
59 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
);
62 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
);
66 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject
)
68 return ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
72 IopFixupDeviceId(PWCHAR String
)
74 SIZE_T Length
= wcslen(String
), i
;
76 for (i
= 0; i
< Length
; i
++)
78 if (String
[i
] == L
'\\')
85 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode
)
88 HANDLE CriticalDeviceKey
, InstanceKey
;
89 OBJECT_ATTRIBUTES ObjectAttributes
;
90 UNICODE_STRING CriticalDeviceKeyU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
91 UNICODE_STRING CompatibleIdU
= RTL_CONSTANT_STRING(L
"CompatibleIDs");
92 UNICODE_STRING HardwareIdU
= RTL_CONSTANT_STRING(L
"HardwareID");
93 UNICODE_STRING ServiceU
= RTL_CONSTANT_STRING(L
"Service");
94 UNICODE_STRING ClassGuidU
= RTL_CONSTANT_STRING(L
"ClassGUID");
95 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
96 ULONG HidLength
= 0, CidLength
= 0, BufferLength
;
97 PWCHAR IdBuffer
, OriginalIdBuffer
;
99 /* Open the device instance key */
100 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceKey
);
101 if (Status
!= STATUS_SUCCESS
)
104 Status
= ZwQueryValueKey(InstanceKey
,
106 KeyValuePartialInformation
,
110 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
112 ZwClose(InstanceKey
);
116 Status
= ZwQueryValueKey(InstanceKey
,
118 KeyValuePartialInformation
,
122 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
127 BufferLength
= HidLength
+ CidLength
;
128 BufferLength
-= (((CidLength
!= 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
));
130 /* Allocate a buffer to hold data from both */
131 OriginalIdBuffer
= IdBuffer
= ExAllocatePool(PagedPool
, BufferLength
);
134 ZwClose(InstanceKey
);
138 /* Compute the buffer size */
139 if (HidLength
> CidLength
)
140 BufferLength
= HidLength
;
142 BufferLength
= CidLength
;
144 PartialInfo
= ExAllocatePool(PagedPool
, BufferLength
);
147 ZwClose(InstanceKey
);
148 ExFreePool(OriginalIdBuffer
);
152 Status
= ZwQueryValueKey(InstanceKey
,
154 KeyValuePartialInformation
,
158 if (Status
!= STATUS_SUCCESS
)
160 ExFreePool(PartialInfo
);
161 ExFreePool(OriginalIdBuffer
);
162 ZwClose(InstanceKey
);
166 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
167 HidLength
= PartialInfo
->DataLength
- ((CidLength
!= 0) ? sizeof(WCHAR
) : 0);
168 RtlCopyMemory(IdBuffer
, PartialInfo
->Data
, HidLength
);
172 Status
= ZwQueryValueKey(InstanceKey
,
174 KeyValuePartialInformation
,
178 if (Status
!= STATUS_SUCCESS
)
180 ExFreePool(PartialInfo
);
181 ExFreePool(OriginalIdBuffer
);
182 ZwClose(InstanceKey
);
187 CidLength
= PartialInfo
->DataLength
;
188 RtlCopyMemory(((PUCHAR
)IdBuffer
) + HidLength
, PartialInfo
->Data
, CidLength
);
191 /* Free our temp buffer */
192 ExFreePool(PartialInfo
);
194 InitializeObjectAttributes(&ObjectAttributes
,
196 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
199 Status
= ZwOpenKey(&CriticalDeviceKey
,
200 KEY_ENUMERATE_SUB_KEYS
,
202 if (!NT_SUCCESS(Status
))
204 /* The critical device database doesn't exist because
205 * we're probably in 1st stage setup, but it's ok */
206 ExFreePool(OriginalIdBuffer
);
207 ZwClose(InstanceKey
);
213 USHORT StringLength
= (USHORT
)wcslen(IdBuffer
) + 1, Index
;
215 IopFixupDeviceId(IdBuffer
);
217 /* Look through all subkeys for a match */
218 for (Index
= 0; TRUE
; Index
++)
221 PKEY_BASIC_INFORMATION BasicInfo
;
223 Status
= ZwEnumerateKey(CriticalDeviceKey
,
229 if (Status
== STATUS_NO_MORE_ENTRIES
)
231 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
233 UNICODE_STRING ChildIdNameU
, RegKeyNameU
;
235 BasicInfo
= ExAllocatePool(PagedPool
, NeededLength
);
239 ExFreePool(OriginalIdBuffer
);
240 ZwClose(CriticalDeviceKey
);
241 ZwClose(InstanceKey
);
245 Status
= ZwEnumerateKey(CriticalDeviceKey
,
251 if (Status
!= STATUS_SUCCESS
)
253 /* This shouldn't happen */
254 ExFreePool(BasicInfo
);
258 ChildIdNameU
.Buffer
= IdBuffer
;
259 ChildIdNameU
.MaximumLength
= ChildIdNameU
.Length
= (StringLength
- 1) * sizeof(WCHAR
);
260 RegKeyNameU
.Buffer
= BasicInfo
->Name
;
261 RegKeyNameU
.MaximumLength
= RegKeyNameU
.Length
= (USHORT
)BasicInfo
->NameLength
;
263 if (RtlEqualUnicodeString(&ChildIdNameU
, &RegKeyNameU
, TRUE
))
265 HANDLE ChildKeyHandle
;
267 InitializeObjectAttributes(&ObjectAttributes
,
269 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
273 Status
= ZwOpenKey(&ChildKeyHandle
,
276 if (Status
!= STATUS_SUCCESS
)
278 ExFreePool(BasicInfo
);
282 /* Check if there's already a driver installed */
283 Status
= ZwQueryValueKey(InstanceKey
,
285 KeyValuePartialInformation
,
289 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
291 ExFreePool(BasicInfo
);
295 Status
= ZwQueryValueKey(ChildKeyHandle
,
297 KeyValuePartialInformation
,
301 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
303 ExFreePool(BasicInfo
);
307 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
310 ExFreePool(OriginalIdBuffer
);
311 ExFreePool(BasicInfo
);
312 ZwClose(InstanceKey
);
313 ZwClose(ChildKeyHandle
);
314 ZwClose(CriticalDeviceKey
);
318 /* Read ClassGUID entry in the CDDB */
319 Status
= ZwQueryValueKey(ChildKeyHandle
,
321 KeyValuePartialInformation
,
325 if (Status
!= STATUS_SUCCESS
)
327 ExFreePool(BasicInfo
);
331 /* Write it to the ENUM key */
332 Status
= ZwSetValueKey(InstanceKey
,
337 PartialInfo
->DataLength
);
338 if (Status
!= STATUS_SUCCESS
)
340 ExFreePool(BasicInfo
);
341 ExFreePool(PartialInfo
);
342 ZwClose(ChildKeyHandle
);
346 Status
= ZwQueryValueKey(ChildKeyHandle
,
348 KeyValuePartialInformation
,
352 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
354 ExFreePool(PartialInfo
);
355 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
358 ExFreePool(OriginalIdBuffer
);
359 ExFreePool(BasicInfo
);
360 ZwClose(InstanceKey
);
361 ZwClose(ChildKeyHandle
);
362 ZwClose(CriticalDeviceKey
);
366 /* Read the service entry from the CDDB */
367 Status
= ZwQueryValueKey(ChildKeyHandle
,
369 KeyValuePartialInformation
,
373 if (Status
!= STATUS_SUCCESS
)
375 ExFreePool(BasicInfo
);
376 ExFreePool(PartialInfo
);
377 ZwClose(ChildKeyHandle
);
381 /* Write it to the ENUM key */
382 Status
= ZwSetValueKey(InstanceKey
,
387 PartialInfo
->DataLength
);
388 if (Status
!= STATUS_SUCCESS
)
390 ExFreePool(BasicInfo
);
391 ExFreePool(PartialInfo
);
392 ZwClose(ChildKeyHandle
);
396 DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo
->Data
, &ChildIdNameU
);
400 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU
);
403 ExFreePool(OriginalIdBuffer
);
404 ExFreePool(PartialInfo
);
405 ExFreePool(BasicInfo
);
406 ZwClose(InstanceKey
);
407 ZwClose(ChildKeyHandle
);
408 ZwClose(CriticalDeviceKey
);
414 ExFreePool(BasicInfo
);
418 /* Umm, not sure what happened here */
423 /* Advance to the next ID */
424 IdBuffer
+= StringLength
;
427 ExFreePool(OriginalIdBuffer
);
428 ZwClose(InstanceKey
);
429 ZwClose(CriticalDeviceKey
);
434 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
435 PDRIVER_OBJECT DriverObject
)
442 /* Special case for bus driven devices */
443 DeviceNode
->Flags
|= DNF_ADDED
;
444 return STATUS_SUCCESS
;
447 if (!DriverObject
->DriverExtension
->AddDevice
)
449 DeviceNode
->Flags
|= DNF_LEGACY_DRIVER
;
452 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
454 DeviceNode
->Flags
|= (DNF_ADDED
| DNF_STARTED
);
455 return STATUS_SUCCESS
;
458 /* This is a Plug and Play driver */
459 DPRINT("Plug and Play driver found\n");
460 ASSERT(DeviceNode
->PhysicalDeviceObject
);
462 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
463 &DriverObject
->DriverName
,
464 &DeviceNode
->InstancePath
);
465 Status
= DriverObject
->DriverExtension
->AddDevice(DriverObject
,
466 DeviceNode
->PhysicalDeviceObject
);
467 if (!NT_SUCCESS(Status
))
469 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
470 &DriverObject
->DriverName
,
471 &DeviceNode
->InstancePath
,
473 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
474 DeviceNode
->Problem
= CM_PROB_FAILED_ADD
;
478 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
480 /* Check if we have a ACPI device (needed for power management) */
481 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
483 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
485 /* There can be only one system power device */
486 if (!SystemPowerDeviceNodeCreated
)
488 PopSystemPowerDeviceNode
= DeviceNode
;
489 ObReferenceObject(PopSystemPowerDeviceNode
->PhysicalDeviceObject
);
490 SystemPowerDeviceNodeCreated
= TRUE
;
494 ObDereferenceObject(Fdo
);
496 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
498 return STATUS_SUCCESS
;
504 IopSendEject(IN PDEVICE_OBJECT DeviceObject
)
506 IO_STACK_LOCATION Stack
;
509 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
510 Stack
.MajorFunction
= IRP_MJ_PNP
;
511 Stack
.MinorFunction
= IRP_MN_EJECT
;
513 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
519 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject
)
521 IO_STACK_LOCATION Stack
;
524 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
525 Stack
.MajorFunction
= IRP_MJ_PNP
;
526 Stack
.MinorFunction
= IRP_MN_SURPRISE_REMOVAL
;
528 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
529 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
535 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
537 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
538 IO_STACK_LOCATION Stack
;
544 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING
,
545 &DeviceNode
->InstancePath
);
547 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
548 Stack
.MajorFunction
= IRP_MJ_PNP
;
549 Stack
.MinorFunction
= IRP_MN_QUERY_REMOVE_DEVICE
;
551 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
553 IopNotifyPlugPlayNotification(DeviceObject
,
554 EventCategoryTargetDeviceChange
,
555 &GUID_TARGET_DEVICE_QUERY_REMOVE
,
559 if (!NT_SUCCESS(Status
))
561 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode
->InstancePath
);
562 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED
,
563 &DeviceNode
->InstancePath
);
572 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject
)
574 IO_STACK_LOCATION Stack
;
577 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
578 Stack
.MajorFunction
= IRP_MJ_PNP
;
579 Stack
.MinorFunction
= IRP_MN_QUERY_STOP_DEVICE
;
581 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
587 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
589 IO_STACK_LOCATION Stack
;
591 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
593 /* Drop all our state for this device in case it isn't really going away */
594 DeviceNode
->Flags
&= DNF_ENUMERATED
| DNF_PROCESSED
;
596 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
597 Stack
.MajorFunction
= IRP_MJ_PNP
;
598 Stack
.MinorFunction
= IRP_MN_REMOVE_DEVICE
;
600 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
601 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
603 IopNotifyPlugPlayNotification(DeviceObject
,
604 EventCategoryTargetDeviceChange
,
605 &GUID_TARGET_DEVICE_REMOVE_COMPLETE
,
608 ObDereferenceObject(DeviceObject
);
614 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
616 IO_STACK_LOCATION Stack
;
619 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
620 Stack
.MajorFunction
= IRP_MJ_PNP
;
621 Stack
.MinorFunction
= IRP_MN_CANCEL_REMOVE_DEVICE
;
623 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
624 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
626 IopNotifyPlugPlayNotification(DeviceObject
,
627 EventCategoryTargetDeviceChange
,
628 &GUID_TARGET_DEVICE_REMOVE_CANCELLED
,
636 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject
)
638 IO_STACK_LOCATION Stack
;
641 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
642 Stack
.MajorFunction
= IRP_MJ_PNP
;
643 Stack
.MinorFunction
= IRP_MN_STOP_DEVICE
;
645 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
646 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
651 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject
)
653 IO_STACK_LOCATION Stack
;
654 PDEVICE_NODE DeviceNode
;
657 DEVICE_CAPABILITIES DeviceCapabilities
;
659 /* Get the device node */
660 DeviceNode
= IopGetDeviceNode(DeviceObject
);
662 ASSERT(!(DeviceNode
->Flags
& DNF_DISABLED
));
664 /* Build the I/O stack location */
665 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
666 Stack
.MajorFunction
= IRP_MJ_PNP
;
667 Stack
.MinorFunction
= IRP_MN_START_DEVICE
;
669 Stack
.Parameters
.StartDevice
.AllocatedResources
=
670 DeviceNode
->ResourceList
;
671 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
=
672 DeviceNode
->ResourceListTranslated
;
675 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
676 if (!NT_SUCCESS(Status
))
678 /* Send an IRP_MN_REMOVE_DEVICE request */
679 IopRemoveDevice(DeviceNode
);
681 /* Set the appropriate flag */
682 DeviceNode
->Flags
|= DNF_START_FAILED
;
683 DeviceNode
->Problem
= CM_PROB_FAILED_START
;
685 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode
->InstancePath
, Status
);
689 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
691 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
692 if (!NT_SUCCESS(Status
))
694 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
697 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
698 IoInvalidateDeviceState(DeviceObject
);
700 /* Otherwise, mark us as started */
701 DeviceNode
->Flags
|= DNF_STARTED
;
702 DeviceNode
->Flags
&= ~DNF_STOPPED
;
704 /* We now need enumeration */
705 DeviceNode
->Flags
|= DNF_NEED_ENUMERATION_ONLY
;
710 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode
)
712 PDEVICE_OBJECT DeviceObject
;
717 ASSERT((DeviceNode
->Flags
& DNF_ADDED
));
718 ASSERT((DeviceNode
->Flags
& (DNF_RESOURCE_ASSIGNED
|
719 DNF_RESOURCE_REPORTED
|
720 DNF_NO_RESOURCE_REQUIRED
)));
722 /* Get the device object */
723 DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
725 /* Check if we're not started yet */
726 if (!(DeviceNode
->Flags
& DNF_STARTED
))
729 IopStartDevice2(DeviceObject
);
732 /* Do we need to query IDs? This happens in the case of manual reporting */
734 if (DeviceNode
->Flags
& DNF_NEED_QUERY_IDS
)
736 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
737 /* And that case shouldn't happen yet */
742 /* Make sure we're started, and check if we need enumeration */
743 if ((DeviceNode
->Flags
& DNF_STARTED
) &&
744 (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
))
747 IoSynchronousInvalidateDeviceRelations(DeviceObject
, BusRelations
);
748 Status
= STATUS_SUCCESS
;
753 Status
= STATUS_SUCCESS
;
762 PDEVICE_NODE DeviceNode
)
766 DPRINT("Stopping device: %wZ\n", &DeviceNode
->InstancePath
);
768 Status
= IopQueryStopDevice(DeviceNode
->PhysicalDeviceObject
);
769 if (NT_SUCCESS(Status
))
771 IopSendStopDevice(DeviceNode
->PhysicalDeviceObject
);
773 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
774 DeviceNode
->Flags
|= DNF_STOPPED
;
776 return STATUS_SUCCESS
;
784 PDEVICE_NODE DeviceNode
)
787 HANDLE InstanceHandle
= NULL
, ControlHandle
= NULL
;
788 UNICODE_STRING KeyName
, ValueString
;
789 OBJECT_ATTRIBUTES ObjectAttributes
;
791 if (DeviceNode
->Flags
& DNF_DISABLED
)
792 return STATUS_SUCCESS
;
794 Status
= IopAssignDeviceResources(DeviceNode
);
795 if (!NT_SUCCESS(Status
))
799 IopStartAndEnumerateDevice(DeviceNode
);
801 /* FIX: Should be done in new device instance code */
802 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceHandle
);
803 if (!NT_SUCCESS(Status
))
806 /* FIX: Should be done in IoXxxPrepareDriverLoading */
808 RtlInitUnicodeString(&KeyName
, L
"Control");
809 InitializeObjectAttributes(&ObjectAttributes
,
811 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
814 Status
= ZwCreateKey(&ControlHandle
,
821 if (!NT_SUCCESS(Status
))
824 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
825 ValueString
= DeviceNode
->ServiceName
;
826 if (!ValueString
.Buffer
)
827 RtlInitUnicodeString(&ValueString
, L
"");
828 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, ValueString
.Buffer
, ValueString
.Length
+ sizeof(UNICODE_NULL
));
832 if (ControlHandle
!= NULL
)
833 ZwClose(ControlHandle
);
835 if (InstanceHandle
!= NULL
)
836 ZwClose(InstanceHandle
);
843 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
844 PDEVICE_CAPABILITIES DeviceCaps
)
846 IO_STATUS_BLOCK StatusBlock
;
847 IO_STACK_LOCATION Stack
;
850 UNICODE_STRING ValueName
;
852 /* Set up the Header */
853 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
854 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
855 DeviceCaps
->Version
= 1;
856 DeviceCaps
->Address
= -1;
857 DeviceCaps
->UINumber
= -1;
859 /* Set up the Stack */
860 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
861 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
864 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
866 IRP_MN_QUERY_CAPABILITIES
,
868 if (!NT_SUCCESS(Status
))
870 if (Status
!= STATUS_NOT_SUPPORTED
)
872 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status
);
877 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCaps
->Version
+ sizeof(DeviceCaps
->Version
));
879 if (DeviceCaps
->NoDisplayInUI
)
880 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
882 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
884 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceKey
);
885 if (NT_SUCCESS(Status
))
887 /* Set 'Capabilities' value */
888 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
889 Status
= ZwSetValueKey(InstanceKey
,
893 &DeviceNode
->CapabilityFlags
,
896 /* Set 'UINumber' value */
897 if (DeviceCaps
->UINumber
!= MAXULONG
)
899 RtlInitUnicodeString(&ValueName
, L
"UINumber");
900 Status
= ZwSetValueKey(InstanceKey
,
904 &DeviceCaps
->UINumber
,
908 ZwClose(InstanceKey
);
917 IopDeviceActionWorker(
920 PLIST_ENTRY ListEntry
;
921 PDEVICE_ACTION_DATA Data
;
924 KeAcquireSpinLock(&IopDeviceActionLock
, &OldIrql
);
925 while (!IsListEmpty(&IopDeviceActionRequestList
))
927 ListEntry
= RemoveHeadList(&IopDeviceActionRequestList
);
928 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
929 Data
= CONTAINING_RECORD(ListEntry
,
933 IoSynchronousInvalidateDeviceRelations(Data
->DeviceObject
,
936 ObDereferenceObject(Data
->DeviceObject
);
937 ExFreePoolWithTag(Data
, TAG_IO
);
938 KeAcquireSpinLock(&IopDeviceActionLock
, &OldIrql
);
940 IopDeviceActionInProgress
= FALSE
;
941 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
945 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
949 if (PopSystemPowerDeviceNode
)
951 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
952 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
953 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
955 return STATUS_SUCCESS
;
958 return STATUS_UNSUCCESSFUL
;
963 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
965 USHORT i
= 0, FoundIndex
= 0xFFFF;
969 /* Acquire the lock */
970 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
972 /* Loop all entries */
973 while (i
< PnpBusTypeGuidList
->GuidCount
)
975 /* Try to find a match */
976 if (RtlCompareMemory(BusTypeGuid
,
977 &PnpBusTypeGuidList
->Guids
[i
],
978 sizeof(GUID
)) == sizeof(GUID
))
987 /* Check if we have to grow the list */
988 if (PnpBusTypeGuidList
->GuidCount
)
990 /* Calculate the new size */
991 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
992 (sizeof(GUID
) * PnpBusTypeGuidList
->GuidCount
);
994 /* Allocate the new copy */
995 NewList
= ExAllocatePool(PagedPool
, NewSize
);
1000 ExFreePool(PnpBusTypeGuidList
);
1004 /* Now copy them, decrease the size too */
1005 NewSize
-= sizeof(GUID
);
1006 RtlCopyMemory(NewList
, PnpBusTypeGuidList
, NewSize
);
1008 /* Free the old list */
1009 ExFreePool(PnpBusTypeGuidList
);
1011 /* Use the new buffer */
1012 PnpBusTypeGuidList
= NewList
;
1015 /* Copy the new GUID */
1016 RtlCopyMemory(&PnpBusTypeGuidList
->Guids
[PnpBusTypeGuidList
->GuidCount
],
1020 /* The new entry is the index */
1021 FoundIndex
= (USHORT
)PnpBusTypeGuidList
->GuidCount
;
1022 PnpBusTypeGuidList
->GuidCount
++;
1025 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
1031 * Creates a device node
1034 * ParentNode = Pointer to parent device node
1035 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
1036 * to have the root device node create one
1037 * (eg. for legacy drivers)
1038 * DeviceNode = Pointer to storage for created device node
1044 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
1045 PDEVICE_OBJECT PhysicalDeviceObject
,
1046 PUNICODE_STRING ServiceName
,
1047 PDEVICE_NODE
*DeviceNode
)
1052 UNICODE_STRING FullServiceName
;
1053 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
1054 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
1055 UNICODE_STRING KeyName
, ClassName
;
1056 PUNICODE_STRING ServiceName1
;
1058 UNICODE_STRING ClassGUID
;
1059 HANDLE InstanceHandle
;
1061 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1062 ParentNode
, PhysicalDeviceObject
, ServiceName
);
1064 Node
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), TAG_IO_DEVNODE
);
1067 return STATUS_INSUFFICIENT_RESOURCES
;
1070 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
1073 ServiceName1
= &UnknownDeviceName
;
1075 ServiceName1
= ServiceName
;
1077 if (!PhysicalDeviceObject
)
1079 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName1
->Length
+ sizeof(UNICODE_NULL
);
1080 FullServiceName
.Length
= 0;
1081 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
1082 if (!FullServiceName
.Buffer
)
1084 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1085 return STATUS_INSUFFICIENT_RESOURCES
;
1088 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
1089 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName1
);
1090 RtlUpcaseUnicodeString(&FullServiceName
, &FullServiceName
, FALSE
);
1092 Status
= PnpRootCreateDevice(&FullServiceName
, NULL
, &PhysicalDeviceObject
, &Node
->InstancePath
);
1093 if (!NT_SUCCESS(Status
))
1095 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
1096 ExFreePool(FullServiceName
.Buffer
);
1097 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1101 /* Create the device key for legacy drivers */
1102 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, REG_OPTION_VOLATILE
, &InstanceHandle
);
1103 if (!NT_SUCCESS(Status
))
1105 ExFreePool(FullServiceName
.Buffer
);
1106 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1110 Node
->ServiceName
.MaximumLength
= ServiceName1
->Length
+ sizeof(UNICODE_NULL
);
1111 Node
->ServiceName
.Length
= 0;
1112 Node
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, Node
->ServiceName
.MaximumLength
);
1113 if (!Node
->ServiceName
.Buffer
)
1115 ZwClose(InstanceHandle
);
1116 ExFreePool(FullServiceName
.Buffer
);
1117 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1121 RtlCopyUnicodeString(&Node
->ServiceName
, ServiceName1
);
1125 RtlInitUnicodeString(&KeyName
, L
"Service");
1126 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName
->Buffer
, ServiceName
->Length
+ sizeof(UNICODE_NULL
));
1129 if (NT_SUCCESS(Status
))
1131 RtlInitUnicodeString(&KeyName
, L
"Legacy");
1133 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
1135 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1137 ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
1139 if (NT_SUCCESS(Status
))
1141 RtlInitUnicodeString(&KeyName
, L
"Class");
1142 RtlInitUnicodeString(&ClassName
, L
"LegacyDriver");
1143 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassName
.Buffer
, ClassName
.Length
+ sizeof(UNICODE_NULL
));
1144 if (NT_SUCCESS(Status
))
1146 RtlInitUnicodeString(&KeyName
, L
"ClassGUID");
1147 RtlInitUnicodeString(&ClassGUID
, L
"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
1148 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassGUID
.Buffer
, ClassGUID
.Length
+ sizeof(UNICODE_NULL
));
1149 if (NT_SUCCESS(Status
))
1151 // FIXME: Retrieve the real "description" by looking at the "DisplayName" string
1152 // of the corresponding CurrentControlSet\Services\xxx entry for this driver.
1153 RtlInitUnicodeString(&KeyName
, L
"DeviceDesc");
1154 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName1
->Buffer
, ServiceName1
->Length
+ sizeof(UNICODE_NULL
));
1160 ZwClose(InstanceHandle
);
1161 ExFreePool(FullServiceName
.Buffer
);
1163 if (!NT_SUCCESS(Status
))
1165 ExFreePool(Node
->ServiceName
.Buffer
);
1166 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1170 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
1171 IopDeviceNodeSetFlag(Node
, DNF_PROCESSED
);
1172 IopDeviceNodeSetFlag(Node
, DNF_ADDED
);
1173 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
1176 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
1178 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
1182 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1183 Node
->Parent
= ParentNode
;
1184 Node
->Sibling
= NULL
;
1185 if (ParentNode
->LastChild
== NULL
)
1187 ParentNode
->Child
= Node
;
1188 ParentNode
->LastChild
= Node
;
1192 ParentNode
->LastChild
->Sibling
= Node
;
1193 ParentNode
->LastChild
= Node
;
1195 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1196 Node
->Level
= ParentNode
->Level
+ 1;
1199 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1203 return STATUS_SUCCESS
;
1207 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
1210 PDEVICE_NODE PrevSibling
= NULL
;
1212 /* All children must be deleted before a parent is deleted */
1213 ASSERT(!DeviceNode
->Child
);
1214 ASSERT(DeviceNode
->PhysicalDeviceObject
);
1216 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1218 /* Get previous sibling */
1219 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
1221 PrevSibling
= DeviceNode
->Parent
->Child
;
1222 while (PrevSibling
->Sibling
!= DeviceNode
)
1223 PrevSibling
= PrevSibling
->Sibling
;
1226 /* Unlink from parent if it exists */
1227 if (DeviceNode
->Parent
)
1229 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
1231 DeviceNode
->Parent
->LastChild
= PrevSibling
;
1233 PrevSibling
->Sibling
= NULL
;
1235 if (DeviceNode
->Parent
->Child
== DeviceNode
)
1236 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
1239 /* Unlink from sibling list */
1241 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
1243 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1245 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
1247 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
1249 if (DeviceNode
->ResourceList
)
1251 ExFreePool(DeviceNode
->ResourceList
);
1254 if (DeviceNode
->ResourceListTranslated
)
1256 ExFreePool(DeviceNode
->ResourceListTranslated
);
1259 if (DeviceNode
->ResourceRequirements
)
1261 ExFreePool(DeviceNode
->ResourceRequirements
);
1264 if (DeviceNode
->BootResources
)
1266 ExFreePool(DeviceNode
->BootResources
);
1269 ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceNode
->PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= NULL
;
1270 ExFreePoolWithTag(DeviceNode
, TAG_IO_DEVNODE
);
1272 return STATUS_SUCCESS
;
1277 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject
,
1278 IN PIO_STACK_LOCATION IoStackLocation
,
1279 OUT PVOID
*Information
)
1282 PIO_STACK_LOCATION IrpStack
;
1283 IO_STATUS_BLOCK IoStatusBlock
;
1286 PDEVICE_OBJECT TopDeviceObject
;
1289 /* Call the top of the device stack */
1290 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
1292 /* Allocate an IRP */
1293 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
, FALSE
);
1294 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
1296 /* Initialize to failure */
1297 Irp
->IoStatus
.Status
= IoStatusBlock
.Status
= STATUS_NOT_SUPPORTED
;
1298 Irp
->IoStatus
.Information
= IoStatusBlock
.Information
= 0;
1300 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1301 if (IoStackLocation
->MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
)
1303 /* Copy the resource requirements list into the IOSB */
1304 Irp
->IoStatus
.Information
=
1305 IoStatusBlock
.Information
= (ULONG_PTR
)IoStackLocation
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
1308 /* Initialize the event */
1309 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1312 Irp
->UserIosb
= &IoStatusBlock
;
1313 Irp
->UserEvent
= &Event
;
1316 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1317 IoQueueThreadIrp(Irp
);
1319 /* Copy-in the stack */
1320 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1321 *IrpStack
= *IoStackLocation
;
1323 /* Call the driver */
1324 Status
= IoCallDriver(TopDeviceObject
, Irp
);
1325 if (Status
== STATUS_PENDING
)
1328 KeWaitForSingleObject(&Event
,
1333 Status
= IoStatusBlock
.Status
;
1336 /* Remove the reference */
1337 ObDereferenceObject(TopDeviceObject
);
1339 /* Return the information */
1340 *Information
= (PVOID
)IoStatusBlock
.Information
;
1346 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject
,
1347 IN OUT PIO_STATUS_BLOCK IoStatusBlock
,
1348 IN UCHAR MinorFunction
,
1349 IN PIO_STACK_LOCATION Stack OPTIONAL
)
1351 IO_STACK_LOCATION IoStackLocation
;
1353 /* Fill out the stack information */
1354 RtlZeroMemory(&IoStackLocation
, sizeof(IO_STACK_LOCATION
));
1355 IoStackLocation
.MajorFunction
= IRP_MJ_PNP
;
1356 IoStackLocation
.MinorFunction
= MinorFunction
;
1360 RtlCopyMemory(&IoStackLocation
.Parameters
,
1362 sizeof(Stack
->Parameters
));
1365 /* Do the PnP call */
1366 IoStatusBlock
->Status
= IopSynchronousCall(DeviceObject
,
1368 (PVOID
)&IoStatusBlock
->Information
);
1369 return IoStatusBlock
->Status
;
1373 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1375 PDEVICE_NODE ParentDeviceNode
;
1376 PDEVICE_NODE ChildDeviceNode
;
1379 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1380 ParentDeviceNode
= Context
->DeviceNode
;
1382 /* Call the action routine */
1383 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
1384 if (!NT_SUCCESS(Status
))
1389 /* Traversal of all children nodes */
1390 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
1391 ChildDeviceNode
!= NULL
;
1392 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
1394 /* Pass the current device node to the action routine */
1395 Context
->DeviceNode
= ChildDeviceNode
;
1397 Status
= IopTraverseDeviceTreeNode(Context
);
1398 if (!NT_SUCCESS(Status
))
1409 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1413 DPRINT("Context 0x%p\n", Context
);
1415 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
1416 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
1418 /* Start from the specified device node */
1419 Context
->DeviceNode
= Context
->FirstDeviceNode
;
1421 /* Recursively traverse the device tree */
1422 Status
= IopTraverseDeviceTreeNode(Context
);
1423 if (Status
== STATUS_UNSUCCESSFUL
)
1425 /* The action routine just wanted to terminate the traversal with status
1426 code STATUS_SUCCESS */
1427 Status
= STATUS_SUCCESS
;
1435 * IopCreateDeviceKeyPath
1437 * Creates a registry key
1441 * Name of the key to be created.
1443 * Handle to the newly created key
1446 * This method can create nested trees, so parent of RegistryPath can
1447 * be not existant, and will be created if needed.
1451 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
1452 IN ULONG CreateOptions
,
1455 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
1456 HANDLE hParent
= NULL
, hKey
;
1457 OBJECT_ATTRIBUTES ObjectAttributes
;
1458 UNICODE_STRING KeyName
;
1459 PCWSTR Current
, Last
;
1463 /* Assume failure */
1466 /* Open root key for device instances */
1467 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
1468 if (!NT_SUCCESS(Status
))
1470 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
1474 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
1475 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
1477 /* Go up to the end of the string */
1478 while (Current
<= Last
)
1480 if (Current
!= Last
&& *Current
!= L
'\\')
1482 /* Not the end of the string and not a separator */
1487 /* Prepare relative key name */
1488 Length
= (USHORT
)((ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
);
1489 KeyName
.MaximumLength
= KeyName
.Length
= Length
;
1490 DPRINT("Create '%wZ'\n", &KeyName
);
1493 InitializeObjectAttributes(&ObjectAttributes
,
1495 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1498 Status
= ZwCreateKey(&hKey
,
1499 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
1506 /* Close parent key handle, we don't need it anymore */
1510 /* Key opening/creating failed? */
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
1517 /* Check if it is the end of the string */
1518 if (Current
== Last
)
1520 /* Yes, return success */
1522 return STATUS_SUCCESS
;
1525 /* Start with this new parent key */
1528 KeyName
.Buffer
= (PWSTR
)Current
;
1531 return STATUS_UNSUCCESSFUL
;
1535 IopSetDeviceInstanceData(HANDLE InstanceKey
,
1536 PDEVICE_NODE DeviceNode
)
1538 OBJECT_ATTRIBUTES ObjectAttributes
;
1539 UNICODE_STRING KeyName
;
1540 HANDLE LogConfKey
, ControlKey
, DeviceParamsKey
;
1545 DPRINT("IopSetDeviceInstanceData() called\n");
1547 /* Create the 'LogConf' key */
1548 RtlInitUnicodeString(&KeyName
, L
"LogConf");
1549 InitializeObjectAttributes(&ObjectAttributes
,
1551 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1554 Status
= ZwCreateKey(&LogConfKey
,
1559 // FIXME? In r53694 it was silently turned from non-volatile into this,
1560 // without any extra warning. Is this still needed??
1561 REG_OPTION_VOLATILE
,
1563 if (NT_SUCCESS(Status
))
1565 /* Set 'BootConfig' value */
1566 if (DeviceNode
->BootResources
!= NULL
)
1568 ResCount
= DeviceNode
->BootResources
->Count
;
1571 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
1572 Status
= ZwSetValueKey(LogConfKey
,
1576 DeviceNode
->BootResources
,
1577 PnpDetermineResourceListSize(DeviceNode
->BootResources
));
1581 /* Set 'BasicConfigVector' value */
1582 if (DeviceNode
->ResourceRequirements
!= NULL
&&
1583 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
1585 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
1586 Status
= ZwSetValueKey(LogConfKey
,
1589 REG_RESOURCE_REQUIREMENTS_LIST
,
1590 DeviceNode
->ResourceRequirements
,
1591 DeviceNode
->ResourceRequirements
->ListSize
);
1594 ZwClose(LogConfKey
);
1597 /* Set the 'ConfigFlags' value */
1598 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1599 Status
= ZwQueryValueKey(InstanceKey
,
1601 KeyValueBasicInformation
,
1605 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1607 /* Write the default value */
1608 ULONG DefaultConfigFlags
= 0;
1609 Status
= ZwSetValueKey(InstanceKey
,
1613 &DefaultConfigFlags
,
1614 sizeof(DefaultConfigFlags
));
1617 /* Create the 'Control' key */
1618 RtlInitUnicodeString(&KeyName
, L
"Control");
1619 InitializeObjectAttributes(&ObjectAttributes
,
1621 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1624 Status
= ZwCreateKey(&ControlKey
,
1629 REG_OPTION_VOLATILE
,
1631 if (NT_SUCCESS(Status
))
1632 ZwClose(ControlKey
);
1634 /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
1635 if (_wcsnicmp(DeviceNode
->InstancePath
.Buffer
, L
"ACPI\\", 5) == 0)
1637 RtlInitUnicodeString(&KeyName
, L
"Device Parameters");
1638 InitializeObjectAttributes(&ObjectAttributes
,
1640 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1643 Status
= ZwCreateKey(&DeviceParamsKey
,
1648 REG_OPTION_NON_VOLATILE
,
1650 if (NT_SUCCESS(Status
))
1652 ULONG FirmwareIdentified
= 1;
1653 RtlInitUnicodeString(&KeyName
, L
"FirmwareIdentified");
1654 Status
= ZwSetValueKey(DeviceParamsKey
,
1658 &FirmwareIdentified
,
1659 sizeof(FirmwareIdentified
));
1661 ZwClose(DeviceParamsKey
);
1665 DPRINT("IopSetDeviceInstanceData() done\n");
1671 * IopGetParentIdPrefix
1673 * Retrieve (or create) a string which identifies a device.
1677 * Pointer to device node.
1679 * Pointer to the string where is returned the parent node identifier
1682 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1683 * valid and its Buffer field is NULL-terminated. The caller needs to
1684 * to free the string with RtlFreeUnicodeString when it is no longer
1689 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1690 PUNICODE_STRING ParentIdPrefix
)
1692 const UNICODE_STRING EnumKeyPath
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1693 ULONG KeyNameBufferLength
;
1694 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1695 UNICODE_STRING KeyName
= {0, 0, NULL
};
1696 UNICODE_STRING KeyValue
;
1697 UNICODE_STRING ValueName
;
1702 /* HACK: As long as some devices have a NULL device
1703 * instance path, the following test is required :(
1705 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1707 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1708 &DeviceNode
->InstancePath
);
1709 return STATUS_UNSUCCESSFUL
;
1712 /* 1. Try to retrieve ParentIdPrefix from registry */
1713 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1714 ParentIdPrefixInformation
= ExAllocatePoolWithTag(PagedPool
,
1715 KeyNameBufferLength
+ sizeof(UNICODE_NULL
),
1717 if (!ParentIdPrefixInformation
)
1719 return STATUS_INSUFFICIENT_RESOURCES
;
1723 KeyName
.MaximumLength
= EnumKeyPath
.Length
+
1724 DeviceNode
->Parent
->InstancePath
.Length
+
1725 sizeof(UNICODE_NULL
);
1726 KeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1727 KeyName
.MaximumLength
,
1729 if (!KeyName
.Buffer
)
1731 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1735 RtlCopyUnicodeString(&KeyName
, &EnumKeyPath
);
1736 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1738 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1739 if (!NT_SUCCESS(Status
))
1743 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1744 Status
= ZwQueryValueKey(hKey
,
1746 KeyValuePartialInformation
,
1747 ParentIdPrefixInformation
,
1748 KeyNameBufferLength
,
1749 &KeyNameBufferLength
);
1750 if (NT_SUCCESS(Status
))
1752 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1754 Status
= STATUS_UNSUCCESSFUL
;
1758 KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1759 KeyValue
.Length
= KeyValue
.MaximumLength
- sizeof(UNICODE_NULL
);
1760 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1761 ASSERT(KeyValue
.Buffer
[KeyValue
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
);
1765 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1767 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
1768 KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1769 KeyValue
.Length
= KeyValue
.MaximumLength
- sizeof(UNICODE_NULL
);
1770 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1771 ASSERT(KeyValue
.Buffer
[KeyValue
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
);
1775 /* 2. Create the ParentIdPrefix value */
1776 crc32
= RtlComputeCrc32(0,
1777 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1778 DeviceNode
->Parent
->InstancePath
.Length
);
1780 RtlStringCbPrintfW((PWSTR
)ParentIdPrefixInformation
,
1781 KeyNameBufferLength
,
1783 DeviceNode
->Parent
->Level
,
1785 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
);
1787 /* 3. Try to write the ParentIdPrefix to registry */
1788 Status
= ZwSetValueKey(hKey
,
1793 ((ULONG
)wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
1796 if (NT_SUCCESS(Status
))
1798 /* Duplicate the string to return it */
1799 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1803 ExFreePoolWithTag(ParentIdPrefixInformation
, TAG_IO
);
1804 RtlFreeUnicodeString(&KeyName
);
1816 _In_ BUS_QUERY_ID_TYPE QueryType
)
1821 ULONG SeparatorsCount
= 0;
1822 PWCHAR PtrPrevChar
= NULL
;
1823 ULONG MaxSeparators
;
1830 case BusQueryDeviceID
:
1831 MaxSeparators
= MAX_SEPARATORS_DEVICEID
;
1834 case BusQueryInstanceID
:
1835 MaxSeparators
= MAX_SEPARATORS_INSTANCEID
;
1839 case BusQueryHardwareIDs
:
1840 case BusQueryCompatibleIDs
:
1841 MaxSeparators
= MAX_SEPARATORS_DEVICEID
;
1846 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType
);
1850 StringEnd
= Id
+ MAX_DEVICE_ID_LEN
;
1852 for (PtrChar
= Id
; PtrChar
< StringEnd
; PtrChar
++)
1856 if (Char
== UNICODE_NULL
)
1858 if (!IsMultiSz
|| (PtrPrevChar
&& PtrChar
== PtrPrevChar
+ 1))
1860 if (MaxSeparators
== SeparatorsCount
|| IsMultiSz
)
1865 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1866 SeparatorsCount
, MaxSeparators
);
1870 StringEnd
= PtrChar
+ MAX_DEVICE_ID_LEN
+ 1;
1871 PtrPrevChar
= PtrChar
;
1872 SeparatorsCount
= 0;
1874 else if (Char
< ' ' || Char
> 0x7F || Char
== ',')
1876 DPRINT1("IopValidateID: Invalid character - %04X\n", Char
);
1879 else if (Char
== ' ')
1883 else if (Char
== '\\')
1887 if (SeparatorsCount
> MaxSeparators
)
1889 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1890 SeparatorsCount
, MaxSeparators
);
1896 DPRINT1("IopValidateID: Not terminated ID\n");
1904 IopQueryHardwareIds(PDEVICE_NODE DeviceNode
,
1907 IO_STACK_LOCATION Stack
;
1908 IO_STATUS_BLOCK IoStatusBlock
;
1910 UNICODE_STRING ValueName
;
1912 ULONG Length
, TotalLength
;
1915 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1917 RtlZeroMemory(&Stack
, sizeof(Stack
));
1918 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
1919 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1923 if (NT_SUCCESS(Status
))
1925 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryHardwareIDs
);
1929 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode
);
1934 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1935 DPRINT("Hardware IDs:\n");
1938 DPRINT(" %S\n", Ptr
);
1939 Length
= (ULONG
)wcslen(Ptr
) + 1;
1942 TotalLength
+= Length
;
1944 DPRINT("TotalLength: %hu\n", TotalLength
);
1947 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
1948 Status
= ZwSetValueKey(InstanceKey
,
1952 (PVOID
)IoStatusBlock
.Information
,
1953 (TotalLength
+ 1) * sizeof(WCHAR
));
1954 if (!NT_SUCCESS(Status
))
1956 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1961 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1968 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode
,
1971 IO_STACK_LOCATION Stack
;
1972 IO_STATUS_BLOCK IoStatusBlock
;
1974 UNICODE_STRING ValueName
;
1976 ULONG Length
, TotalLength
;
1979 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1981 RtlZeroMemory(&Stack
, sizeof(Stack
));
1982 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1983 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1987 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1989 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryCompatibleIDs
);
1993 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode
);
1998 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1999 DPRINT("Compatible IDs:\n");
2002 DPRINT(" %S\n", Ptr
);
2003 Length
= (ULONG
)wcslen(Ptr
) + 1;
2006 TotalLength
+= Length
;
2008 DPRINT("TotalLength: %hu\n", TotalLength
);
2011 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
2012 Status
= ZwSetValueKey(InstanceKey
,
2016 (PVOID
)IoStatusBlock
.Information
,
2017 (TotalLength
+ 1) * sizeof(WCHAR
));
2018 if (!NT_SUCCESS(Status
))
2020 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
2025 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2032 IopCreateDeviceInstancePath(
2033 _In_ PDEVICE_NODE DeviceNode
,
2034 _Out_ PUNICODE_STRING InstancePath
)
2036 IO_STATUS_BLOCK IoStatusBlock
;
2037 UNICODE_STRING DeviceId
;
2038 UNICODE_STRING InstanceId
;
2039 IO_STACK_LOCATION Stack
;
2041 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
2042 DEVICE_CAPABILITIES DeviceCapabilities
;
2045 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2047 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
2048 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2052 if (!NT_SUCCESS(Status
))
2054 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status
);
2058 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryDeviceID
);
2062 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode
);
2065 /* Save the device id string */
2066 RtlInitUnicodeString(&DeviceId
, (PWSTR
)IoStatusBlock
.Information
);
2068 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
2070 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
2071 if (!NT_SUCCESS(Status
))
2073 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status
);
2074 RtlFreeUnicodeString(&DeviceId
);
2078 /* This bit is only check after enumeration */
2079 if (DeviceCapabilities
.HardwareDisabled
)
2081 /* FIXME: Cleanup device */
2082 DeviceNode
->Flags
|= DNF_DISABLED
;
2083 RtlFreeUnicodeString(&DeviceId
);
2084 return STATUS_PLUGPLAY_NO_DEVICE
;
2088 DeviceNode
->Flags
&= ~DNF_DISABLED
;
2091 if (!DeviceCapabilities
.UniqueID
)
2093 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2094 DPRINT("Instance ID is not unique\n");
2095 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
2096 if (!NT_SUCCESS(Status
))
2098 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
2099 RtlFreeUnicodeString(&DeviceId
);
2104 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2106 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
2107 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2111 if (!NT_SUCCESS(Status
))
2113 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status
);
2114 ASSERT(IoStatusBlock
.Information
== 0);
2117 if (IoStatusBlock
.Information
)
2119 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryInstanceID
);
2123 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode
);
2127 RtlInitUnicodeString(&InstanceId
,
2128 (PWSTR
)IoStatusBlock
.Information
);
2130 InstancePath
->Length
= 0;
2131 InstancePath
->MaximumLength
= DeviceId
.Length
+ sizeof(WCHAR
) +
2132 ParentIdPrefix
.Length
+
2134 sizeof(UNICODE_NULL
);
2135 if (ParentIdPrefix
.Length
&& InstanceId
.Length
)
2137 InstancePath
->MaximumLength
+= sizeof(WCHAR
);
2140 InstancePath
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
2141 InstancePath
->MaximumLength
,
2143 if (!InstancePath
->Buffer
)
2145 RtlFreeUnicodeString(&InstanceId
);
2146 RtlFreeUnicodeString(&ParentIdPrefix
);
2147 RtlFreeUnicodeString(&DeviceId
);
2148 return STATUS_INSUFFICIENT_RESOURCES
;
2151 /* Start with the device id */
2152 RtlCopyUnicodeString(InstancePath
, &DeviceId
);
2153 RtlAppendUnicodeToString(InstancePath
, L
"\\");
2155 /* Add information from parent bus device to InstancePath */
2156 RtlAppendUnicodeStringToString(InstancePath
, &ParentIdPrefix
);
2157 if (ParentIdPrefix
.Length
&& InstanceId
.Length
)
2159 RtlAppendUnicodeToString(InstancePath
, L
"&");
2162 /* Finally, add the id returned by the driver stack */
2163 RtlAppendUnicodeStringToString(InstancePath
, &InstanceId
);
2166 * FIXME: Check for valid characters, if there is invalid characters
2170 RtlFreeUnicodeString(&InstanceId
);
2171 RtlFreeUnicodeString(&DeviceId
);
2172 RtlFreeUnicodeString(&ParentIdPrefix
);
2174 return STATUS_SUCCESS
;
2178 * IopActionInterrogateDeviceStack
2180 * Retrieve information for all (direct) child nodes of a parent node.
2184 * Pointer to device node.
2186 * Pointer to parent node to retrieve child node information for.
2189 * Any errors that occur are logged instead so that all child services have a chance
2190 * of being interrogated.
2194 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
2197 IO_STATUS_BLOCK IoStatusBlock
;
2198 PWSTR DeviceDescription
;
2199 PWSTR LocationInformation
;
2200 PDEVICE_NODE ParentDeviceNode
;
2201 IO_STACK_LOCATION Stack
;
2203 ULONG RequiredLength
;
2205 HANDLE InstanceKey
= NULL
;
2206 UNICODE_STRING ValueName
;
2207 UNICODE_STRING InstancePathU
;
2208 PDEVICE_OBJECT OldDeviceObject
;
2210 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
2211 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
2213 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2216 * We are called for the parent too, but we don't need to do special
2217 * handling for this node
2219 if (DeviceNode
== ParentDeviceNode
)
2221 DPRINT("Success\n");
2222 return STATUS_SUCCESS
;
2226 * Make sure this device node is a direct child of the parent device node
2227 * that is given as an argument
2229 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2231 DPRINT("Skipping 2+ level child\n");
2232 return STATUS_SUCCESS
;
2235 /* Skip processing if it was already completed before */
2236 if (DeviceNode
->Flags
& DNF_PROCESSED
)
2239 return STATUS_SUCCESS
;
2243 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
2244 if (!NT_SUCCESS(Status
))
2246 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
2251 * FIXME: For critical errors, cleanup and disable device, but always
2252 * return STATUS_SUCCESS.
2255 Status
= IopCreateDeviceInstancePath(DeviceNode
, &InstancePathU
);
2256 if (!NT_SUCCESS(Status
))
2258 if (Status
!= STATUS_PLUGPLAY_NO_DEVICE
)
2260 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status
);
2263 /* We have to return success otherwise we abort the traverse operation */
2264 return STATUS_SUCCESS
;
2267 /* Verify that this is not a duplicate */
2268 OldDeviceObject
= IopGetDeviceObjectFromDeviceInstance(&InstancePathU
);
2269 if (OldDeviceObject
!= NULL
)
2271 PDEVICE_NODE OldDeviceNode
= IopGetDeviceNode(OldDeviceObject
);
2273 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU
);
2274 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode
->Parent
->InstancePath
);
2275 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode
->Parent
->InstancePath
);
2277 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR
,
2279 (ULONG_PTR
)DeviceNode
->PhysicalDeviceObject
,
2280 (ULONG_PTR
)OldDeviceObject
,
2284 DeviceNode
->InstancePath
= InstancePathU
;
2286 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
2289 * Create registry key for the instance id, if it doesn't exist yet
2291 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceKey
);
2292 if (!NT_SUCCESS(Status
))
2294 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2296 /* We have to return success otherwise we abort the traverse operation */
2297 return STATUS_SUCCESS
;
2300 IopQueryHardwareIds(DeviceNode
, InstanceKey
);
2302 IopQueryCompatibleIds(DeviceNode
, InstanceKey
);
2304 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2306 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2307 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2308 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2310 IRP_MN_QUERY_DEVICE_TEXT
,
2312 DeviceDescription
= NT_SUCCESS(Status
) ? (PWSTR
)IoStatusBlock
.Information
2314 /* This key is mandatory, so even if the Irp fails, we still write it */
2315 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2316 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2318 if (DeviceDescription
&&
2319 *DeviceDescription
!= UNICODE_NULL
)
2321 /* This key is overriden when a driver is installed. Don't write the
2322 * new description if another one already exists */
2323 Status
= ZwSetValueKey(InstanceKey
,
2328 ((ULONG
)wcslen(DeviceDescription
) + 1) * sizeof(WCHAR
));
2332 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2333 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2335 Status
= ZwSetValueKey(InstanceKey
,
2340 DeviceDesc
.MaximumLength
);
2341 if (!NT_SUCCESS(Status
))
2343 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2349 if (DeviceDescription
)
2351 ExFreePoolWithTag(DeviceDescription
, 0);
2354 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2356 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2357 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2358 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2360 IRP_MN_QUERY_DEVICE_TEXT
,
2362 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2364 LocationInformation
= (PWSTR
)IoStatusBlock
.Information
;
2365 DPRINT("LocationInformation: %S\n", LocationInformation
);
2366 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2367 Status
= ZwSetValueKey(InstanceKey
,
2371 LocationInformation
,
2372 ((ULONG
)wcslen(LocationInformation
) + 1) * sizeof(WCHAR
));
2373 if (!NT_SUCCESS(Status
))
2375 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2378 ExFreePoolWithTag(LocationInformation
, 0);
2382 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2385 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2387 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2389 IRP_MN_QUERY_BUS_INFORMATION
,
2391 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2393 PPNP_BUS_INFORMATION BusInformation
= (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2395 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2396 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2397 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2398 ExFreePoolWithTag(BusInformation
, 0);
2402 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2404 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2405 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2406 DeviceNode
->ChildBusTypeIndex
= -1;
2409 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2411 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2413 IRP_MN_QUERY_RESOURCES
,
2415 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2417 DeviceNode
->BootResources
= (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2418 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
2422 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2423 DeviceNode
->BootResources
= NULL
;
2426 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2428 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2430 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2432 if (NT_SUCCESS(Status
))
2434 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2438 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2439 DeviceNode
->ResourceRequirements
= NULL
;
2442 if (InstanceKey
!= NULL
)
2444 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2447 ZwClose(InstanceKey
);
2449 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2451 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2453 /* Report the device to the user-mode pnp manager */
2454 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2455 &DeviceNode
->InstancePath
);
2458 return STATUS_SUCCESS
;
2463 IopHandleDeviceRemoval(
2464 IN PDEVICE_NODE DeviceNode
,
2465 IN PDEVICE_RELATIONS DeviceRelations
)
2467 PDEVICE_NODE Child
= DeviceNode
->Child
, NextChild
;
2471 if (DeviceNode
== IopRootDeviceNode
)
2474 while (Child
!= NULL
)
2476 NextChild
= Child
->Sibling
;
2479 for (i
= 0; DeviceRelations
&& i
< DeviceRelations
->Count
; i
++)
2481 if (IopGetDeviceNode(DeviceRelations
->Objects
[i
]) == Child
)
2488 if (!Found
&& !(Child
->Flags
& DNF_WILL_BE_REMOVED
))
2490 /* Send removal IRPs to all of its children */
2491 IopPrepareDeviceForRemoval(Child
->PhysicalDeviceObject
, TRUE
);
2493 /* Send the surprise removal IRP */
2494 IopSendSurpriseRemoval(Child
->PhysicalDeviceObject
);
2496 /* Tell the user-mode PnP manager that a device was removed */
2497 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
2498 &Child
->InstancePath
);
2500 /* Send the remove device IRP */
2501 IopSendRemoveDevice(Child
->PhysicalDeviceObject
);
2510 IN PDEVICE_OBJECT DeviceObject
)
2512 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2513 DEVICETREE_TRAVERSE_CONTEXT Context
;
2514 PDEVICE_RELATIONS DeviceRelations
;
2515 PDEVICE_OBJECT ChildDeviceObject
;
2516 IO_STATUS_BLOCK IoStatusBlock
;
2517 PDEVICE_NODE ChildDeviceNode
;
2518 IO_STACK_LOCATION Stack
;
2522 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2524 if (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
)
2526 DeviceNode
->Flags
&= ~DNF_NEED_ENUMERATION_ONLY
;
2528 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2529 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2530 &DeviceNode
->InstancePath
);
2533 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2535 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2537 Status
= IopInitiatePnpIrp(
2540 IRP_MN_QUERY_DEVICE_RELATIONS
,
2542 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2544 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2548 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2551 * Send removal IRPs for devices that have disappeared
2552 * NOTE: This code handles the case where no relations are specified
2554 IopHandleDeviceRemoval(DeviceNode
, DeviceRelations
);
2556 /* Now we bail if nothing was returned */
2557 if (!DeviceRelations
)
2559 /* We're all done */
2560 DPRINT("No PDOs\n");
2561 return STATUS_SUCCESS
;
2564 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2567 * Create device nodes for all discovered devices
2569 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2571 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2572 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2574 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2575 if (!ChildDeviceNode
)
2577 /* One doesn't exist, create it */
2578 Status
= IopCreateDeviceNode(
2583 if (NT_SUCCESS(Status
))
2585 /* Mark the node as enumerated */
2586 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2588 /* Mark the DO as bus enumerated */
2589 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2593 /* Ignore this DO */
2594 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2595 ObDereferenceObject(ChildDeviceObject
);
2600 /* Mark it as enumerated */
2601 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2602 ObDereferenceObject(ChildDeviceObject
);
2605 ExFreePool(DeviceRelations
);
2608 * Retrieve information about all discovered children from the bus driver
2610 IopInitDeviceTreeTraverseContext(
2613 IopActionInterrogateDeviceStack
,
2616 Status
= IopTraverseDeviceTree(&Context
);
2617 if (!NT_SUCCESS(Status
))
2619 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2624 * Retrieve configuration from the registry for discovered children
2626 IopInitDeviceTreeTraverseContext(
2629 IopActionConfigureChildServices
,
2632 Status
= IopTraverseDeviceTree(&Context
);
2633 if (!NT_SUCCESS(Status
))
2635 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2640 * Initialize services for discovered children.
2642 Status
= IopInitializePnpServices(DeviceNode
);
2643 if (!NT_SUCCESS(Status
))
2645 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2649 DPRINT("IopEnumerateDevice() finished\n");
2650 return STATUS_SUCCESS
;
2655 * IopActionConfigureChildServices
2657 * Retrieve configuration for all (direct) child nodes of a parent node.
2661 * Pointer to device node.
2663 * Pointer to parent node to retrieve child node configuration for.
2666 * Any errors that occur are logged instead so that all child services have a chance of beeing
2671 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2674 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2675 PDEVICE_NODE ParentDeviceNode
;
2676 PUNICODE_STRING Service
;
2677 UNICODE_STRING ClassGUID
;
2679 DEVICE_CAPABILITIES DeviceCaps
;
2681 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2683 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2686 * We are called for the parent too, but we don't need to do special
2687 * handling for this node
2689 if (DeviceNode
== ParentDeviceNode
)
2691 DPRINT("Success\n");
2692 return STATUS_SUCCESS
;
2696 * Make sure this device node is a direct child of the parent device node
2697 * that is given as an argument
2700 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2702 DPRINT("Skipping 2+ level child\n");
2703 return STATUS_SUCCESS
;
2706 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2708 DPRINT1("Child not ready to be configured\n");
2709 return STATUS_SUCCESS
;
2712 if (!(DeviceNode
->Flags
& (DNF_DISABLED
| DNF_STARTED
| DNF_ADDED
)))
2714 WCHAR RegKeyBuffer
[MAX_PATH
];
2715 UNICODE_STRING RegKey
;
2717 /* Install the service for this if it's in the CDDB */
2718 IopInstallCriticalDevice(DeviceNode
);
2721 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2722 RegKey
.Buffer
= RegKeyBuffer
;
2725 * Retrieve configuration from Enum key
2728 Service
= &DeviceNode
->ServiceName
;
2730 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2731 RtlInitUnicodeString(Service
, NULL
);
2732 RtlInitUnicodeString(&ClassGUID
, NULL
);
2734 QueryTable
[0].Name
= L
"Service";
2735 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2736 QueryTable
[0].EntryContext
= Service
;
2738 QueryTable
[1].Name
= L
"ClassGUID";
2739 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2740 QueryTable
[1].EntryContext
= &ClassGUID
;
2741 QueryTable
[1].DefaultType
= REG_SZ
;
2742 QueryTable
[1].DefaultData
= L
"";
2743 QueryTable
[1].DefaultLength
= 0;
2745 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2746 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2748 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2749 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2751 if (!NT_SUCCESS(Status
))
2753 /* FIXME: Log the error */
2754 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2755 &DeviceNode
->InstancePath
, Status
);
2756 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2757 return STATUS_SUCCESS
;
2760 if (Service
->Buffer
== NULL
)
2762 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2763 DeviceCaps
.RawDeviceOK
)
2765 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2766 RtlInitEmptyUnicodeString(&DeviceNode
->ServiceName
, NULL
, 0);
2768 else if (ClassGUID
.Length
!= 0)
2770 /* Device has a ClassGUID value, but no Service value.
2771 * Suppose it is using the NULL driver, so state the
2772 * device is started */
2773 DPRINT("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2774 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2778 DeviceNode
->Problem
= CM_PROB_FAILED_INSTALL
;
2779 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2781 return STATUS_SUCCESS
;
2784 DPRINT("Got Service %S\n", Service
->Buffer
);
2787 return STATUS_SUCCESS
;
2791 * IopActionInitChildServices
2793 * Initialize the service for all (direct) child nodes of a parent node
2797 * Pointer to device node.
2799 * Pointer to parent node to initialize child node services for.
2802 * If the driver image for a service is not loaded and initialized
2803 * it is done here too. Any errors that occur are logged instead so
2804 * that all child services have a chance of being initialized.
2808 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2811 PDEVICE_NODE ParentDeviceNode
;
2813 BOOLEAN BootDrivers
= !PnpSystemInit
;
2815 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2817 ParentDeviceNode
= Context
;
2820 * We are called for the parent too, but we don't need to do special
2821 * handling for this node
2823 if (DeviceNode
== ParentDeviceNode
)
2825 DPRINT("Success\n");
2826 return STATUS_SUCCESS
;
2830 * We don't want to check for a direct child because
2831 * this function is called during boot to reinitialize
2832 * devices with drivers that couldn't load yet due to
2833 * stage 0 limitations (ie can't load from disk yet).
2836 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2838 DPRINT1("Child not ready to be added\n");
2839 return STATUS_SUCCESS
;
2842 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
) ||
2843 IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) ||
2844 IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2845 return STATUS_SUCCESS
;
2847 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
2849 /* We don't need to worry about loading the driver because we're
2850 * being driven in raw mode so our parent must be loaded to get here */
2851 Status
= IopInitializeDevice(DeviceNode
, NULL
);
2852 if (NT_SUCCESS(Status
))
2854 Status
= IopStartDevice(DeviceNode
);
2855 if (!NT_SUCCESS(Status
))
2857 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2858 &DeviceNode
->InstancePath
, Status
);
2864 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2865 PDRIVER_OBJECT DriverObject
;
2867 KeEnterCriticalRegion();
2868 ExAcquireResourceExclusiveLite(&IopDriverLoadResource
, TRUE
);
2869 /* Get existing DriverObject pointer (in case the driver has
2870 already been loaded and initialized) */
2871 Status
= IopGetDriverObject(
2873 &DeviceNode
->ServiceName
,
2876 if (!NT_SUCCESS(Status
))
2878 /* Driver is not initialized, try to load it */
2879 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2881 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2883 /* Initialize the driver */
2884 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2885 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2886 if (!NT_SUCCESS(Status
)) DeviceNode
->Problem
= CM_PROB_FAILED_DRIVER_ENTRY
;
2888 else if (Status
== STATUS_DRIVER_UNABLE_TO_LOAD
)
2890 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode
->ServiceName
);
2891 DeviceNode
->Problem
= CM_PROB_DISABLED_SERVICE
;
2895 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2896 &DeviceNode
->ServiceName
, Status
);
2897 if (!BootDrivers
) DeviceNode
->Problem
= CM_PROB_DRIVER_FAILED_LOAD
;
2900 ExReleaseResourceLite(&IopDriverLoadResource
);
2901 KeLeaveCriticalRegion();
2903 /* Driver is loaded and initialized at this point */
2904 if (NT_SUCCESS(Status
))
2906 /* Initialize the device, including all filters */
2907 Status
= PipCallDriverAddDevice(DeviceNode
, FALSE
, DriverObject
);
2909 /* Remove the extra reference */
2910 ObDereferenceObject(DriverObject
);
2915 * Don't disable when trying to load only boot drivers
2919 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2924 return STATUS_SUCCESS
;
2928 * IopInitializePnpServices
2930 * Initialize services for discovered children
2934 * Top device node to start initializing services.
2940 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2942 DEVICETREE_TRAVERSE_CONTEXT Context
;
2944 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2946 IopInitDeviceTreeTraverseContext(
2949 IopActionInitChildServices
,
2952 return IopTraverseDeviceTree(&Context
);
2955 static NTSTATUS INIT_FUNCTION
2956 IopEnumerateDetectedDevices(
2958 IN PUNICODE_STRING RelativePath OPTIONAL
,
2960 IN BOOLEAN EnumerateSubKeys
,
2961 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2962 IN ULONG ParentBootResourcesLength
)
2964 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2965 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2966 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2967 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2968 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2969 OBJECT_ATTRIBUTES ObjectAttributes
;
2970 HANDLE hDevicesKey
= NULL
;
2971 HANDLE hDeviceKey
= NULL
;
2972 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2973 UNICODE_STRING Level2NameU
;
2974 WCHAR Level2Name
[5];
2975 ULONG IndexDevice
= 0;
2977 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2978 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2979 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2980 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2981 UNICODE_STRING DeviceName
, ValueName
;
2983 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2984 ULONG BootResourcesLength
;
2987 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2988 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2989 static ULONG DeviceIndexSerial
= 0;
2990 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2991 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2992 static ULONG DeviceIndexKeyboard
= 0;
2993 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2994 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2995 static ULONG DeviceIndexMouse
= 0;
2996 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
2997 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
2998 static ULONG DeviceIndexParallel
= 0;
2999 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
3000 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
3001 static ULONG DeviceIndexFloppy
= 0;
3002 UNICODE_STRING HardwareIdKey
;
3003 PUNICODE_STRING pHardwareId
;
3004 ULONG DeviceIndex
= 0;
3005 PUCHAR CmResourceList
;
3010 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
3011 if (!NT_SUCCESS(Status
))
3013 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3018 hDevicesKey
= hBaseKey
;
3020 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3021 if (!pDeviceInformation
)
3023 DPRINT("ExAllocatePool() failed\n");
3024 Status
= STATUS_NO_MEMORY
;
3028 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3029 if (!pValueInformation
)
3031 DPRINT("ExAllocatePool() failed\n");
3032 Status
= STATUS_NO_MEMORY
;
3038 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3039 if (Status
== STATUS_NO_MORE_ENTRIES
)
3041 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3043 ExFreePool(pDeviceInformation
);
3044 DeviceInfoLength
= RequiredSize
;
3045 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3046 if (!pDeviceInformation
)
3048 DPRINT("ExAllocatePool() failed\n");
3049 Status
= STATUS_NO_MEMORY
;
3052 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3054 if (!NT_SUCCESS(Status
))
3056 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3061 /* Open device key */
3062 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3063 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3065 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
3066 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
3067 if (!NT_SUCCESS(Status
))
3069 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3073 /* Read boot resources, and add then to parent ones */
3074 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3075 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3077 ExFreePool(pValueInformation
);
3078 ValueInfoLength
= RequiredSize
;
3079 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3080 if (!pValueInformation
)
3082 DPRINT("ExAllocatePool() failed\n");
3083 ZwDeleteKey(hLevel2Key
);
3084 Status
= STATUS_NO_MEMORY
;
3087 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3089 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
3091 BootResources
= ParentBootResources
;
3092 BootResourcesLength
= ParentBootResourcesLength
;
3094 else if (!NT_SUCCESS(Status
))
3096 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3099 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
3101 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
3106 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
3108 /* Concatenate current resources and parent ones */
3109 if (ParentBootResourcesLength
== 0)
3110 BootResourcesLength
= pValueInformation
->DataLength
;
3112 BootResourcesLength
= ParentBootResourcesLength
3113 + pValueInformation
->DataLength
3115 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
3118 DPRINT("ExAllocatePool() failed\n");
3121 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3123 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3125 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
3127 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3129 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
3130 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3131 ParentBootResourcesLength
- Header
);
3132 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
3136 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
3138 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
3139 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3140 ParentBootResourcesLength
- Header
);
3142 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
3143 pValueInformation
->Data
+ Header
,
3144 pValueInformation
->DataLength
- Header
);
3145 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
3149 if (EnumerateSubKeys
)
3154 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3155 if (Status
== STATUS_NO_MORE_ENTRIES
)
3157 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3159 ExFreePool(pDeviceInformation
);
3160 DeviceInfoLength
= RequiredSize
;
3161 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3162 if (!pDeviceInformation
)
3164 DPRINT("ExAllocatePool() failed\n");
3165 Status
= STATUS_NO_MEMORY
;
3168 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3170 if (!NT_SUCCESS(Status
))
3172 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3176 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3177 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3179 Status
= IopEnumerateDetectedDevices(
3185 BootResourcesLength
);
3186 if (!NT_SUCCESS(Status
))
3191 /* Read identifier */
3192 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3193 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3195 ExFreePool(pValueInformation
);
3196 ValueInfoLength
= RequiredSize
;
3197 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3198 if (!pValueInformation
)
3200 DPRINT("ExAllocatePool() failed\n");
3201 Status
= STATUS_NO_MEMORY
;
3204 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3206 if (!NT_SUCCESS(Status
))
3208 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
3210 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3213 ValueName
.Length
= ValueName
.MaximumLength
= 0;
3215 else if (pValueInformation
->Type
!= REG_SZ
)
3217 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
3222 /* Assign hardware id to this device */
3223 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
3224 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
3225 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
3226 ValueName
.Length
-= sizeof(WCHAR
);
3229 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
3231 pHardwareId
= &HardwareIdSerial
;
3232 DeviceIndex
= DeviceIndexSerial
++;
3234 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
3236 pHardwareId
= &HardwareIdKeyboard
;
3237 DeviceIndex
= DeviceIndexKeyboard
++;
3239 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
3241 pHardwareId
= &HardwareIdMouse
;
3242 DeviceIndex
= DeviceIndexMouse
++;
3244 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
3246 pHardwareId
= &HardwareIdParallel
;
3247 DeviceIndex
= DeviceIndexParallel
++;
3249 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
3251 pHardwareId
= &HardwareIdFloppy
;
3252 DeviceIndex
= DeviceIndexFloppy
++;
3256 /* Unknown key path */
3257 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
3261 /* Prepare hardware id key (hardware id value without final \0) */
3262 HardwareIdKey
= *pHardwareId
;
3263 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
3265 /* Add the detected device to Root key */
3266 InitializeObjectAttributes(&ObjectAttributes
, &HardwareIdKey
, OBJ_KERNEL_HANDLE
, hRootKey
, NULL
);
3267 Status
= ZwCreateKey(
3273 REG_OPTION_NON_VOLATILE
,
3275 if (!NT_SUCCESS(Status
))
3277 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3280 swprintf(Level2Name
, L
"%04lu", DeviceIndex
);
3281 RtlInitUnicodeString(&Level2NameU
, Level2Name
);
3282 InitializeObjectAttributes(&ObjectAttributes
, &Level2NameU
, OBJ_KERNEL_HANDLE
, hLevel1Key
, NULL
);
3283 Status
= ZwCreateKey(
3285 KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
,
3289 REG_OPTION_NON_VOLATILE
,
3291 ZwClose(hLevel1Key
);
3292 if (!NT_SUCCESS(Status
))
3294 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3297 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName
, DeviceIndex
, &HardwareIdKey
);
3298 Status
= ZwSetValueKey(hLevel2Key
, &HardwareIDU
, 0, REG_MULTI_SZ
, pHardwareId
->Buffer
, pHardwareId
->MaximumLength
);
3299 if (!NT_SUCCESS(Status
))
3301 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3302 ZwDeleteKey(hLevel2Key
);
3305 /* Create 'LogConf' subkey */
3306 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
, hLevel2Key
, NULL
);
3307 Status
= ZwCreateKey(
3313 REG_OPTION_VOLATILE
,
3315 if (!NT_SUCCESS(Status
))
3317 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3318 ZwDeleteKey(hLevel2Key
);
3321 if (BootResourcesLength
>= sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3323 CmResourceList
= ExAllocatePool(PagedPool
, BootResourcesLength
+ sizeof(ULONG
));
3324 if (!CmResourceList
)
3327 ZwDeleteKey(hLevel2Key
);
3331 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3333 RtlCopyMemory(CmResourceList
,
3337 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3338 RtlCopyMemory(CmResourceList
+ sizeof(ULONG
),
3340 BootResourcesLength
);
3342 /* Save boot resources to 'LogConf\BootConfig' */
3343 Status
= ZwSetValueKey(hLogConf
, &BootConfigU
, 0, REG_RESOURCE_LIST
, CmResourceList
, BootResourcesLength
+ sizeof(ULONG
));
3344 if (!NT_SUCCESS(Status
))
3346 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3348 ZwDeleteKey(hLevel2Key
);
3355 if (BootResources
&& BootResources
!= ParentBootResources
)
3357 ExFreePool(BootResources
);
3358 BootResources
= NULL
;
3362 ZwClose(hLevel2Key
);
3367 ZwClose(hDeviceKey
);
3372 Status
= STATUS_SUCCESS
;
3375 if (hDevicesKey
&& hDevicesKey
!= hBaseKey
)
3376 ZwClose(hDevicesKey
);
3378 ZwClose(hDeviceKey
);
3379 if (pDeviceInformation
)
3380 ExFreePool(pDeviceInformation
);
3381 if (pValueInformation
)
3382 ExFreePool(pValueInformation
);
3386 static BOOLEAN INIT_FUNCTION
3387 IopIsFirmwareMapperDisabled(VOID
)
3389 UNICODE_STRING KeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3390 UNICODE_STRING KeyNameU
= RTL_CONSTANT_STRING(L
"DisableFirmwareMapper");
3391 OBJECT_ATTRIBUTES ObjectAttributes
;
3393 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
;
3394 ULONG DesiredLength
, Length
;
3398 InitializeObjectAttributes(&ObjectAttributes
, &KeyPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3399 Status
= ZwOpenKey(&hPnpKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
3400 if (NT_SUCCESS(Status
))
3402 Status
= ZwQueryValueKey(hPnpKey
,
3404 KeyValuePartialInformation
,
3408 if ((Status
== STATUS_BUFFER_TOO_SMALL
) ||
3409 (Status
== STATUS_BUFFER_OVERFLOW
))
3411 Length
= DesiredLength
;
3412 KeyInformation
= ExAllocatePool(PagedPool
, Length
);
3415 Status
= ZwQueryValueKey(hPnpKey
,
3417 KeyValuePartialInformation
,
3421 if (NT_SUCCESS(Status
) && KeyInformation
->DataLength
== sizeof(ULONG
))
3423 KeyValue
= (ULONG
)(*KeyInformation
->Data
);
3427 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU
, &KeyNameU
);
3430 ExFreePool(KeyInformation
);
3434 DPRINT1("Failed to allocate memory for registry query\n");
3439 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU
, &KeyNameU
, Status
);
3446 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU
, Status
);
3449 DPRINT("Firmware mapper is %s\n", KeyValue
!= 0 ? "disabled" : "enabled");
3451 return (KeyValue
!= 0) ? TRUE
: FALSE
;
3457 IopUpdateRootKey(VOID
)
3459 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3460 UNICODE_STRING RootPathU
= RTL_CONSTANT_STRING(L
"Root");
3461 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3462 OBJECT_ATTRIBUTES ObjectAttributes
;
3463 HANDLE hEnum
, hRoot
;
3466 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3467 Status
= ZwCreateKey(&hEnum
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, REG_OPTION_NON_VOLATILE
, NULL
);
3468 if (!NT_SUCCESS(Status
))
3470 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3474 InitializeObjectAttributes(&ObjectAttributes
, &RootPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
3475 Status
= ZwCreateKey(&hRoot
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, REG_OPTION_NON_VOLATILE
, NULL
);
3477 if (!NT_SUCCESS(Status
))
3479 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3483 if (!IopIsFirmwareMapperDisabled())
3485 Status
= IopOpenRegistryKeyEx(&hEnum
, NULL
, &MultiKeyPathU
, KEY_ENUMERATE_SUB_KEYS
);
3486 if (!NT_SUCCESS(Status
))
3488 /* Nothing to do, don't return with an error status */
3489 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3491 return STATUS_SUCCESS
;
3493 Status
= IopEnumerateDetectedDevices(
3504 /* Enumeration is disabled */
3505 Status
= STATUS_SUCCESS
;
3515 IopOpenRegistryKeyEx(PHANDLE KeyHandle
,
3517 PUNICODE_STRING Name
,
3518 ACCESS_MASK DesiredAccess
)
3520 OBJECT_ATTRIBUTES ObjectAttributes
;
3527 InitializeObjectAttributes(&ObjectAttributes
,
3529 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3533 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
3540 IopCreateRegistryKeyEx(OUT PHANDLE Handle
,
3541 IN HANDLE RootHandle OPTIONAL
,
3542 IN PUNICODE_STRING KeyName
,
3543 IN ACCESS_MASK DesiredAccess
,
3544 IN ULONG CreateOptions
,
3545 OUT PULONG Disposition OPTIONAL
)
3547 OBJECT_ATTRIBUTES ObjectAttributes
;
3548 ULONG KeyDisposition
, RootHandleIndex
= 0, i
= 1, NestedCloseLevel
= 0;
3550 HANDLE HandleArray
[2];
3551 BOOLEAN Recursing
= TRUE
;
3553 UNICODE_STRING KeyString
;
3554 NTSTATUS Status
= STATUS_SUCCESS
;
3557 /* P1 is start, pp is end */
3558 p1
= KeyName
->Buffer
;
3559 pp
= (PVOID
)((ULONG_PTR
)p1
+ KeyName
->Length
);
3561 /* Create the target key */
3562 InitializeObjectAttributes(&ObjectAttributes
,
3564 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3567 Status
= ZwCreateKey(&HandleArray
[i
],
3575 /* Now we check if this failed */
3576 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) && (RootHandle
))
3578 /* Target key failed, so we'll need to create its parent. Setup array */
3579 HandleArray
[0] = NULL
;
3580 HandleArray
[1] = RootHandle
;
3582 /* Keep recursing for each missing parent */
3585 /* And if we're deep enough, close the last handle */
3586 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3588 /* We're setup to ping-pong between the two handle array entries */
3589 RootHandleIndex
= i
;
3592 /* Clear the one we're attempting to open now */
3593 HandleArray
[i
] = NULL
;
3595 /* Process the parent key name */
3596 for (p
= p1
; ((p
< pp
) && (*p
!= OBJ_NAME_PATH_SEPARATOR
)); p
++);
3597 Length
= (USHORT
)(p
- p1
) * sizeof(WCHAR
);
3599 /* Is there a parent name? */
3602 /* Build the unicode string for it */
3603 KeyString
.Buffer
= p1
;
3604 KeyString
.Length
= KeyString
.MaximumLength
= Length
;
3606 /* Now try opening the parent */
3607 InitializeObjectAttributes(&ObjectAttributes
,
3609 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3610 HandleArray
[RootHandleIndex
],
3612 Status
= ZwCreateKey(&HandleArray
[i
],
3619 if (NT_SUCCESS(Status
))
3621 /* It worked, we have one more handle */
3626 /* Parent key creation failed, abandon loop */
3633 /* We don't have a parent name, probably corrupted key name */
3634 Status
= STATUS_INVALID_PARAMETER
;
3639 /* Now see if there's more parents to create */
3641 if ((p
== pp
) || (p1
== pp
))
3643 /* We're done, hopefully successfully, so stop */
3648 /* Outer loop check for handle nesting that requires closing the top handle */
3649 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3652 /* Check if we broke out of the loop due to success */
3653 if (NT_SUCCESS(Status
))
3655 /* Return the target handle (we closed all the parent ones) and disposition */
3656 *Handle
= HandleArray
[i
];
3657 if (Disposition
) *Disposition
= KeyDisposition
;
3660 /* Return the success state */
3666 IopGetRegistryValue(IN HANDLE Handle
,
3668 OUT PKEY_VALUE_FULL_INFORMATION
*Information
)
3670 UNICODE_STRING ValueString
;
3672 PKEY_VALUE_FULL_INFORMATION FullInformation
;
3676 RtlInitUnicodeString(&ValueString
, ValueName
);
3678 Status
= ZwQueryValueKey(Handle
,
3680 KeyValueFullInformation
,
3684 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
3685 (Status
!= STATUS_BUFFER_TOO_SMALL
))
3690 FullInformation
= ExAllocatePool(NonPagedPool
, Size
);
3691 if (!FullInformation
) return STATUS_INSUFFICIENT_RESOURCES
;
3693 Status
= ZwQueryValueKey(Handle
,
3695 KeyValueFullInformation
,
3699 if (!NT_SUCCESS(Status
))
3701 ExFreePool(FullInformation
);
3705 *Information
= FullInformation
;
3706 return STATUS_SUCCESS
;
3709 RTL_GENERIC_COMPARE_RESULTS
3711 PiCompareInstancePath(IN PRTL_AVL_TABLE Table
,
3712 IN PVOID FirstStruct
,
3713 IN PVOID SecondStruct
)
3721 // The allocation function is called by the generic table package whenever
3722 // it needs to allocate memory for the table.
3727 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3737 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3746 PpInitializeDeviceReferenceTable(VOID
)
3748 /* Setup the guarded mutex and AVL table */
3749 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock
);
3750 RtlInitializeGenericTableAvl(
3751 &PpDeviceReferenceTable
,
3752 (PRTL_AVL_COMPARE_ROUTINE
)PiCompareInstancePath
,
3753 (PRTL_AVL_ALLOCATE_ROUTINE
)PiAllocateGenericTableEntry
,
3754 (PRTL_AVL_FREE_ROUTINE
)PiFreeGenericTableEntry
,
3762 /* Initialize the resource when accessing device registry data */
3763 ExInitializeResourceLite(&PpRegistryDeviceResource
);
3765 /* Setup the device reference AVL table */
3766 PpInitializeDeviceReferenceTable();
3774 /* Check the initialization phase */
3775 switch (ExpInitializationPhase
)
3780 return PiInitPhase0();
3786 //return PiInitPhase1();
3790 /* Don't know any other phase! Bugcheck! */
3791 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL
);
3796 LONG IopNumberDeviceNodes
;
3800 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3802 PDEVICE_NODE DeviceNode
;
3806 DeviceNode
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), TAG_IO_DEVNODE
);
3807 if (!DeviceNode
) return DeviceNode
;
3810 InterlockedIncrement(&IopNumberDeviceNodes
);
3813 RtlZeroMemory(DeviceNode
, sizeof(DEVICE_NODE
));
3814 DeviceNode
->InterfaceType
= InterfaceTypeUndefined
;
3815 DeviceNode
->BusNumber
= -1;
3816 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
3817 DeviceNode
->ChildBusNumber
= -1;
3818 DeviceNode
->ChildBusTypeIndex
= -1;
3819 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3820 InitializeListHead(&DeviceNode
->DeviceArbiterList
);
3821 InitializeListHead(&DeviceNode
->DeviceTranslatorList
);
3822 InitializeListHead(&DeviceNode
->TargetDeviceNotify
);
3823 InitializeListHead(&DeviceNode
->DockInfo
.ListEntry
);
3824 InitializeListHead(&DeviceNode
->PendedSetInterfaceState
);
3826 /* Check if there is a PDO */
3827 if (PhysicalDeviceObject
)
3829 /* Link it and remove the init flag */
3830 DeviceNode
->PhysicalDeviceObject
= PhysicalDeviceObject
;
3831 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= DeviceNode
;
3832 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
3835 /* Return the node */
3839 /* PUBLIC FUNCTIONS **********************************************************/
3843 PnpBusTypeGuidGet(IN USHORT Index
,
3844 IN LPGUID BusTypeGuid
)
3846 NTSTATUS Status
= STATUS_SUCCESS
;
3848 /* Acquire the lock */
3849 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
3852 if (Index
< PnpBusTypeGuidList
->GuidCount
)
3855 RtlCopyMemory(BusTypeGuid
, &PnpBusTypeGuidList
->Guids
[Index
], sizeof(GUID
));
3860 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
3863 /* Release lock and return status */
3864 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
3870 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject
,
3871 IN PHANDLE DeviceInstanceHandle
,
3872 IN ACCESS_MASK DesiredAccess
)
3876 PDEVICE_NODE DeviceNode
;
3877 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3880 /* Open the enum key */
3881 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
3885 if (!NT_SUCCESS(Status
)) return Status
;
3887 /* Make sure we have an instance path */
3888 DeviceNode
= IopGetDeviceNode(DeviceObject
);
3889 if ((DeviceNode
) && (DeviceNode
->InstancePath
.Length
))
3891 /* Get the instance key */
3892 Status
= IopOpenRegistryKeyEx(DeviceInstanceHandle
,
3894 &DeviceNode
->InstancePath
,
3900 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3903 /* Close the handle and return status */
3910 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList
)
3912 ULONG FinalSize
, PartialSize
, EntrySize
, i
, j
;
3913 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
3914 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
3916 /* If we don't have one, that's easy */
3917 if (!ResourceList
) return 0;
3919 /* Start with the minimum size possible */
3920 FinalSize
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
3922 /* Loop each full descriptor */
3923 FullDescriptor
= ResourceList
->List
;
3924 for (i
= 0; i
< ResourceList
->Count
; i
++)
3926 /* Start with the minimum size possible */
3927 PartialSize
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
) +
3928 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST
, PartialDescriptors
);
3930 /* Loop each partial descriptor */
3931 PartialDescriptor
= FullDescriptor
->PartialResourceList
.PartialDescriptors
;
3932 for (j
= 0; j
< FullDescriptor
->PartialResourceList
.Count