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 ULONG ExpInitializationPhase
;
25 extern BOOLEAN ExpInTextModeSetup
;
26 extern BOOLEAN PnpSystemInit
;
28 /* DATA **********************************************************************/
30 PDRIVER_OBJECT IopRootDriverObject
;
31 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList
= NULL
;
33 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
35 PDEVICE_OBJECT DeviceObject
;
36 DEVICE_RELATION_TYPE Type
;
37 PIO_WORKITEM WorkItem
;
38 } INVALIDATE_DEVICE_RELATION_DATA
, *PINVALIDATE_DEVICE_RELATION_DATA
;
40 /* FUNCTIONS *****************************************************************/
43 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
44 IN ULONG CreateOptions
,
48 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
);
51 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
);
55 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject
)
57 return ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
62 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
63 PDRIVER_OBJECT DriverObject
)
70 /* Special case for bus driven devices */
71 DeviceNode
->Flags
|= DNF_ADDED
;
72 return STATUS_SUCCESS
;
75 if (!DriverObject
->DriverExtension
->AddDevice
)
77 DeviceNode
->Flags
|= DNF_LEGACY_DRIVER
;
80 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
82 DeviceNode
->Flags
|= DNF_ADDED
+ DNF_STARTED
;
83 return STATUS_SUCCESS
;
86 /* This is a Plug and Play driver */
87 DPRINT("Plug and Play driver found\n");
88 ASSERT(DeviceNode
->PhysicalDeviceObject
);
90 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
91 &DriverObject
->DriverName
,
92 &DeviceNode
->InstancePath
);
93 Status
= DriverObject
->DriverExtension
->AddDevice(
94 DriverObject
, DeviceNode
->PhysicalDeviceObject
);
95 if (!NT_SUCCESS(Status
))
97 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
98 &DriverObject
->DriverName
,
99 &DeviceNode
->InstancePath
,
101 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
105 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
107 /* Check if we have a ACPI device (needed for power management) */
108 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
110 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
112 /* There can be only one system power device */
113 if (!SystemPowerDeviceNodeCreated
)
115 PopSystemPowerDeviceNode
= DeviceNode
;
116 ObReferenceObject(PopSystemPowerDeviceNode
->PhysicalDeviceObject
);
117 SystemPowerDeviceNodeCreated
= TRUE
;
121 ObDereferenceObject(Fdo
);
123 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
125 return STATUS_SUCCESS
;
131 IopSendEject(IN PDEVICE_OBJECT DeviceObject
)
133 IO_STACK_LOCATION Stack
;
136 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
137 Stack
.MajorFunction
= IRP_MJ_PNP
;
138 Stack
.MinorFunction
= IRP_MN_EJECT
;
140 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
146 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject
)
148 IO_STACK_LOCATION Stack
;
151 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
152 Stack
.MajorFunction
= IRP_MJ_PNP
;
153 Stack
.MinorFunction
= IRP_MN_SURPRISE_REMOVAL
;
155 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
156 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
162 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
164 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
165 IO_STACK_LOCATION Stack
;
171 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING
,
172 &DeviceNode
->InstancePath
);
174 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
175 Stack
.MajorFunction
= IRP_MJ_PNP
;
176 Stack
.MinorFunction
= IRP_MN_QUERY_REMOVE_DEVICE
;
178 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
180 IopNotifyPlugPlayNotification(DeviceObject
,
181 EventCategoryTargetDeviceChange
,
182 &GUID_TARGET_DEVICE_QUERY_REMOVE
,
186 if (!NT_SUCCESS(Status
))
188 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode
->InstancePath
);
189 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED
,
190 &DeviceNode
->InstancePath
);
199 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject
)
201 IO_STACK_LOCATION Stack
;
204 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
205 Stack
.MajorFunction
= IRP_MJ_PNP
;
206 Stack
.MinorFunction
= IRP_MN_QUERY_STOP_DEVICE
;
208 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
214 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
216 IO_STACK_LOCATION Stack
;
219 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
220 Stack
.MajorFunction
= IRP_MJ_PNP
;
221 Stack
.MinorFunction
= IRP_MN_REMOVE_DEVICE
;
223 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
224 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
226 IopNotifyPlugPlayNotification(DeviceObject
,
227 EventCategoryTargetDeviceChange
,
228 &GUID_TARGET_DEVICE_REMOVE_COMPLETE
,
236 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
238 IO_STACK_LOCATION Stack
;
241 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
242 Stack
.MajorFunction
= IRP_MJ_PNP
;
243 Stack
.MinorFunction
= IRP_MN_CANCEL_REMOVE_DEVICE
;
245 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
246 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
248 IopNotifyPlugPlayNotification(DeviceObject
,
249 EventCategoryTargetDeviceChange
,
250 &GUID_TARGET_DEVICE_REMOVE_CANCELLED
,
258 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject
)
260 IO_STACK_LOCATION Stack
;
263 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
264 Stack
.MajorFunction
= IRP_MJ_PNP
;
265 Stack
.MinorFunction
= IRP_MN_STOP_DEVICE
;
267 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
268 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
273 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject
)
275 IO_STACK_LOCATION Stack
;
276 PDEVICE_NODE DeviceNode
;
279 DEVICE_CAPABILITIES DeviceCapabilities
;
281 /* Get the device node */
282 DeviceNode
= IopGetDeviceNode(DeviceObject
);
284 ASSERT(!(DeviceNode
->Flags
& DNF_DISABLED
));
286 /* Build the I/O stack locaiton */
287 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
288 Stack
.MajorFunction
= IRP_MJ_PNP
;
289 Stack
.MinorFunction
= IRP_MN_START_DEVICE
;
291 Stack
.Parameters
.StartDevice
.AllocatedResources
=
292 DeviceNode
->ResourceList
;
293 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
=
294 DeviceNode
->ResourceListTranslated
;
297 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
298 if (!NT_SUCCESS(Status
))
300 /* Send an IRP_MN_REMOVE_DEVICE request */
301 IopRemoveDevice(DeviceNode
);
303 /* Set the appropriate flag */
304 DeviceNode
->Flags
|= DNF_START_FAILED
;
306 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode
->InstancePath
, Status
);
310 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
312 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
313 if (!NT_SUCCESS(Status
))
315 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
318 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
319 IoInvalidateDeviceState(DeviceObject
);
321 /* Otherwise, mark us as started */
322 DeviceNode
->Flags
|= DNF_STARTED
;
323 DeviceNode
->Flags
&= ~DNF_STOPPED
;
325 /* We now need enumeration */
326 DeviceNode
->Flags
|= DNF_NEED_ENUMERATION_ONLY
;
331 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode
)
333 PDEVICE_OBJECT DeviceObject
;
338 ASSERT((DeviceNode
->Flags
& DNF_ADDED
));
339 ASSERT((DeviceNode
->Flags
& (DNF_RESOURCE_ASSIGNED
|
340 DNF_RESOURCE_REPORTED
|
341 DNF_NO_RESOURCE_REQUIRED
)));
343 /* Get the device object */
344 DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
346 /* Check if we're not started yet */
347 if (!(DeviceNode
->Flags
& DNF_STARTED
))
350 IopStartDevice2(DeviceObject
);
353 /* Do we need to query IDs? This happens in the case of manual reporting */
355 if (DeviceNode
->Flags
& DNF_NEED_QUERY_IDS
)
357 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
358 /* And that case shouldn't happen yet */
363 /* Make sure we're started, and check if we need enumeration */
364 if ((DeviceNode
->Flags
& DNF_STARTED
) &&
365 (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
))
368 IoSynchronousInvalidateDeviceRelations(DeviceObject
, BusRelations
);
369 Status
= STATUS_SUCCESS
;
374 Status
= STATUS_SUCCESS
;
383 PDEVICE_NODE DeviceNode
)
387 DPRINT("Stopping device: %wZ\n", &DeviceNode
->InstancePath
);
389 Status
= IopQueryStopDevice(DeviceNode
->PhysicalDeviceObject
);
390 if (NT_SUCCESS(Status
))
392 IopSendStopDevice(DeviceNode
->PhysicalDeviceObject
);
394 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
395 DeviceNode
->Flags
|= DNF_STOPPED
;
397 return STATUS_SUCCESS
;
405 PDEVICE_NODE DeviceNode
)
408 HANDLE InstanceHandle
= INVALID_HANDLE_VALUE
, ControlHandle
= INVALID_HANDLE_VALUE
;
409 UNICODE_STRING KeyName
;
410 OBJECT_ATTRIBUTES ObjectAttributes
;
412 if (DeviceNode
->Flags
& DNF_DISABLED
)
413 return STATUS_SUCCESS
;
415 Status
= IopAssignDeviceResources(DeviceNode
);
416 if (!NT_SUCCESS(Status
))
420 IopStartAndEnumerateDevice(DeviceNode
);
422 /* FIX: Should be done in new device instance code */
423 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceHandle
);
424 if (!NT_SUCCESS(Status
))
427 /* FIX: Should be done in IoXxxPrepareDriverLoading */
429 RtlInitUnicodeString(&KeyName
, L
"Control");
430 InitializeObjectAttributes(&ObjectAttributes
,
432 OBJ_CASE_INSENSITIVE
,
435 Status
= ZwCreateKey(&ControlHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
436 if (!NT_SUCCESS(Status
))
439 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
440 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, DeviceNode
->ServiceName
.Buffer
, DeviceNode
->ServiceName
.Length
);
444 if (ControlHandle
!= INVALID_HANDLE_VALUE
)
445 ZwClose(ControlHandle
);
447 if (InstanceHandle
!= INVALID_HANDLE_VALUE
)
448 ZwClose(InstanceHandle
);
455 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
456 PDEVICE_CAPABILITIES DeviceCaps
)
458 IO_STATUS_BLOCK StatusBlock
;
459 IO_STACK_LOCATION Stack
;
462 UNICODE_STRING ValueName
;
464 /* Set up the Header */
465 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
466 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
467 DeviceCaps
->Version
= 1;
468 DeviceCaps
->Address
= -1;
469 DeviceCaps
->UINumber
= -1;
471 /* Set up the Stack */
472 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
473 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
476 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
478 IRP_MN_QUERY_CAPABILITIES
,
480 if (!NT_SUCCESS(Status
))
482 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%x\n", Status
);
486 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCaps
->Version
+ sizeof(DeviceCaps
->Version
));
488 if (DeviceCaps
->NoDisplayInUI
)
489 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
491 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
493 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
494 if (NT_SUCCESS(Status
))
496 /* Set 'Capabilities' value */
497 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
498 Status
= ZwSetValueKey(InstanceKey
,
502 (PVOID
)&DeviceNode
->CapabilityFlags
,
505 /* Set 'UINumber' value */
506 if (DeviceCaps
->UINumber
!= MAXULONG
)
508 RtlInitUnicodeString(&ValueName
, L
"UINumber");
509 Status
= ZwSetValueKey(InstanceKey
,
513 &DeviceCaps
->UINumber
,
522 IopAsynchronousInvalidateDeviceRelations(
523 IN PDEVICE_OBJECT DeviceObject
,
524 IN PVOID InvalidateContext
)
526 PINVALIDATE_DEVICE_RELATION_DATA Data
= InvalidateContext
;
528 IoSynchronousInvalidateDeviceRelations(
532 ObDereferenceObject(Data
->DeviceObject
);
533 IoFreeWorkItem(Data
->WorkItem
);
538 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
542 if (PopSystemPowerDeviceNode
)
544 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
545 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
546 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
548 return STATUS_SUCCESS
;
551 return STATUS_UNSUCCESSFUL
;
556 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
558 USHORT i
= 0, FoundIndex
= 0xFFFF;
562 /* Acquire the lock */
563 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
565 /* Loop all entries */
566 while (i
< PnpBusTypeGuidList
->GuidCount
)
568 /* Try to find a match */
569 if (RtlCompareMemory(BusTypeGuid
,
570 &PnpBusTypeGuidList
->Guids
[i
],
571 sizeof(GUID
)) == sizeof(GUID
))
580 /* Check if we have to grow the list */
581 if (PnpBusTypeGuidList
->GuidCount
)
583 /* Calculate the new size */
584 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
585 (sizeof(GUID
) * PnpBusTypeGuidList
->GuidCount
);
587 /* Allocate the new copy */
588 NewList
= ExAllocatePool(PagedPool
, NewSize
);
592 ExFreePool(PnpBusTypeGuidList
);
596 /* Now copy them, decrease the size too */
597 NewSize
-= sizeof(GUID
);
598 RtlCopyMemory(NewList
, PnpBusTypeGuidList
, NewSize
);
600 /* Free the old list */
601 ExFreePool(PnpBusTypeGuidList
);
603 /* Use the new buffer */
604 PnpBusTypeGuidList
= NewList
;
607 /* Copy the new GUID */
608 RtlCopyMemory(&PnpBusTypeGuidList
->Guids
[PnpBusTypeGuidList
->GuidCount
],
612 /* The new entry is the index */
613 FoundIndex
= (USHORT
)PnpBusTypeGuidList
->GuidCount
;
614 PnpBusTypeGuidList
->GuidCount
++;
617 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
623 * Creates a device node
626 * ParentNode = Pointer to parent device node
627 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
628 * to have the root device node create one
629 * (eg. for legacy drivers)
630 * DeviceNode = Pointer to storage for created device node
636 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
637 PDEVICE_OBJECT PhysicalDeviceObject
,
638 PUNICODE_STRING ServiceName
,
639 PDEVICE_NODE
*DeviceNode
)
644 UNICODE_STRING FullServiceName
;
645 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
646 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
647 UNICODE_STRING KeyName
, ClassName
;
648 PUNICODE_STRING ServiceName1
;
651 UNICODE_STRING ClassGUID
;
653 HANDLE InstanceHandle
;
655 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
656 ParentNode
, PhysicalDeviceObject
, ServiceName
);
658 Node
= (PDEVICE_NODE
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_NODE
));
661 return STATUS_INSUFFICIENT_RESOURCES
;
664 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
667 ServiceName1
= &UnknownDeviceName
;
669 ServiceName1
= ServiceName
;
671 if (!PhysicalDeviceObject
)
673 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName1
->Length
;
674 FullServiceName
.Length
= 0;
675 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
676 if (!FullServiceName
.Buffer
)
679 return STATUS_INSUFFICIENT_RESOURCES
;
682 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
683 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName1
);
685 Status
= PnpRootCreateDevice(&FullServiceName
, NULL
, &PhysicalDeviceObject
, &Node
->InstancePath
);
686 if (!NT_SUCCESS(Status
))
688 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
693 /* Create the device key for legacy drivers */
694 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, REG_OPTION_VOLATILE
, &InstanceHandle
);
695 if (!NT_SUCCESS(Status
))
697 ZwClose(InstanceHandle
);
699 ExFreePool(FullServiceName
.Buffer
);
703 Node
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, ServiceName1
->Length
);
704 if (!Node
->ServiceName
.Buffer
)
706 ZwClose(InstanceHandle
);
708 ExFreePool(FullServiceName
.Buffer
);
712 Node
->ServiceName
.MaximumLength
= ServiceName1
->Length
;
713 Node
->ServiceName
.Length
= 0;
715 RtlAppendUnicodeStringToString(&Node
->ServiceName
, ServiceName1
);
719 RtlInitUnicodeString(&KeyName
, L
"Service");
720 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName
->Buffer
, ServiceName
->Length
);
723 if (NT_SUCCESS(Status
))
725 RtlInitUnicodeString(&KeyName
, L
"Legacy");
728 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
729 if (NT_SUCCESS(Status
))
731 RtlInitUnicodeString(&KeyName
, L
"Class");
733 RtlInitUnicodeString(&ClassName
, L
"LegacyDriver");
734 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassName
.Buffer
, ClassName
.Length
);
736 if (NT_SUCCESS(Status
))
738 RtlInitUnicodeString(&KeyName
, L
"ClassGUID");
740 RtlInitUnicodeString(&ClassGUID
, L
"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
741 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassGUID
.Buffer
, ClassGUID
.Length
);
747 ZwClose(InstanceHandle
);
748 ExFreePool(FullServiceName
.Buffer
);
750 if (!NT_SUCCESS(Status
))
756 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
757 IopDeviceNodeSetFlag(Node
, DNF_PROCESSED
);
758 IopDeviceNodeSetFlag(Node
, DNF_ADDED
);
759 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
762 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
764 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
768 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
769 Node
->Parent
= ParentNode
;
770 Node
->Sibling
= ParentNode
->Child
;
771 ParentNode
->Child
= Node
;
772 if (ParentNode
->LastChild
== NULL
)
773 ParentNode
->LastChild
= Node
;
774 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
775 Node
->Level
= ParentNode
->Level
+ 1;
778 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
782 return STATUS_SUCCESS
;
786 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
789 PDEVICE_NODE PrevSibling
= NULL
;
791 /* All children must be deleted before a parent is deleted */
792 ASSERT(!DeviceNode
->Child
);
794 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
796 ASSERT(DeviceNode
->PhysicalDeviceObject
);
798 ObDereferenceObject(DeviceNode
->PhysicalDeviceObject
);
800 /* Get previous sibling */
801 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
803 PrevSibling
= DeviceNode
->Parent
->Child
;
804 while (PrevSibling
->Sibling
!= DeviceNode
)
805 PrevSibling
= PrevSibling
->Sibling
;
808 /* Unlink from parent if it exists */
809 if (DeviceNode
->Parent
)
811 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
813 DeviceNode
->Parent
->LastChild
= PrevSibling
;
815 PrevSibling
->Sibling
= NULL
;
817 if (DeviceNode
->Parent
->Child
== DeviceNode
)
818 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
821 /* Unlink from sibling list */
823 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
825 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
827 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
829 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
831 if (DeviceNode
->ResourceList
)
833 ExFreePool(DeviceNode
->ResourceList
);
836 if (DeviceNode
->ResourceListTranslated
)
838 ExFreePool(DeviceNode
->ResourceListTranslated
);
841 if (DeviceNode
->ResourceRequirements
)
843 ExFreePool(DeviceNode
->ResourceRequirements
);
846 if (DeviceNode
->BootResources
)
848 ExFreePool(DeviceNode
->BootResources
);
851 ExFreePool(DeviceNode
);
853 return STATUS_SUCCESS
;
858 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject
,
859 IN PIO_STACK_LOCATION IoStackLocation
,
860 OUT PVOID
*Information
)
863 PIO_STACK_LOCATION IrpStack
;
864 IO_STATUS_BLOCK IoStatusBlock
;
867 PDEVICE_OBJECT TopDeviceObject
;
870 /* Call the top of the device stack */
871 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
873 /* Allocate an IRP */
874 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
, FALSE
);
875 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
877 /* Initialize to failure */
878 Irp
->IoStatus
.Status
= IoStatusBlock
.Status
= STATUS_NOT_SUPPORTED
;
879 Irp
->IoStatus
.Information
= IoStatusBlock
.Information
= 0;
881 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
882 if (IoStackLocation
->MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
)
884 /* Copy the resource requirements list into the IOSB */
885 Irp
->IoStatus
.Information
=
886 IoStatusBlock
.Information
= (ULONG_PTR
)IoStackLocation
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
889 /* Initialize the event */
890 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
893 Irp
->UserIosb
= &IoStatusBlock
;
894 Irp
->UserEvent
= &Event
;
897 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
898 IoQueueThreadIrp(Irp
);
900 /* Copy-in the stack */
901 IrpStack
= IoGetNextIrpStackLocation(Irp
);
902 *IrpStack
= *IoStackLocation
;
904 /* Call the driver */
905 Status
= IoCallDriver(TopDeviceObject
, Irp
);
906 if (Status
== STATUS_PENDING
)
909 KeWaitForSingleObject(&Event
,
914 Status
= IoStatusBlock
.Status
;
917 /* Return the information */
918 *Information
= (PVOID
)IoStatusBlock
.Information
;
924 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject
,
925 IN OUT PIO_STATUS_BLOCK IoStatusBlock
,
926 IN UCHAR MinorFunction
,
927 IN PIO_STACK_LOCATION Stack OPTIONAL
)
929 IO_STACK_LOCATION IoStackLocation
;
931 /* Fill out the stack information */
932 RtlZeroMemory(&IoStackLocation
, sizeof(IO_STACK_LOCATION
));
933 IoStackLocation
.MajorFunction
= IRP_MJ_PNP
;
934 IoStackLocation
.MinorFunction
= MinorFunction
;
938 RtlCopyMemory(&IoStackLocation
.Parameters
,
940 sizeof(Stack
->Parameters
));
943 /* Do the PnP call */
944 IoStatusBlock
->Status
= IopSynchronousCall(DeviceObject
,
946 (PVOID
)&IoStatusBlock
->Information
);
947 return IoStatusBlock
->Status
;
951 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
953 PDEVICE_NODE ParentDeviceNode
;
954 PDEVICE_NODE ChildDeviceNode
;
957 /* Copy context data so we don't overwrite it in subsequent calls to this function */
958 ParentDeviceNode
= Context
->DeviceNode
;
960 /* Call the action routine */
961 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
962 if (!NT_SUCCESS(Status
))
967 /* Traversal of all children nodes */
968 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
969 ChildDeviceNode
!= NULL
;
970 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
972 /* Pass the current device node to the action routine */
973 Context
->DeviceNode
= ChildDeviceNode
;
975 Status
= IopTraverseDeviceTreeNode(Context
);
976 if (!NT_SUCCESS(Status
))
987 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
991 DPRINT("Context 0x%p\n", Context
);
993 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
994 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
996 /* Start from the specified device node */
997 Context
->DeviceNode
= Context
->FirstDeviceNode
;
999 /* Recursively traverse the device tree */
1000 Status
= IopTraverseDeviceTreeNode(Context
);
1001 if (Status
== STATUS_UNSUCCESSFUL
)
1003 /* The action routine just wanted to terminate the traversal with status
1004 code STATUS_SUCCESS */
1005 Status
= STATUS_SUCCESS
;
1013 * IopCreateDeviceKeyPath
1015 * Creates a registry key
1019 * Name of the key to be created.
1021 * Handle to the newly created key
1024 * This method can create nested trees, so parent of RegistryPath can
1025 * be not existant, and will be created if needed.
1029 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
1030 IN ULONG CreateOptions
,
1033 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
1034 HANDLE hParent
= NULL
, hKey
;
1035 OBJECT_ATTRIBUTES ObjectAttributes
;
1036 UNICODE_STRING KeyName
;
1037 LPCWSTR Current
, Last
;
1041 /* Assume failure */
1044 /* Create a volatile device tree in 1st stage so we have a clean slate
1045 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1046 if (ExpInTextModeSetup
) CreateOptions
|= REG_OPTION_VOLATILE
;
1048 /* Open root key for device instances */
1049 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
1050 if (!NT_SUCCESS(Status
))
1052 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
1056 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
1057 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
1059 /* Go up to the end of the string */
1060 while (Current
<= Last
)
1062 if (Current
!= Last
&& *Current
!= '\\')
1064 /* Not the end of the string and not a separator */
1069 /* Prepare relative key name */
1070 Length
= (USHORT
)((ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
);
1071 KeyName
.MaximumLength
= KeyName
.Length
= Length
;
1072 DPRINT("Create '%wZ'\n", &KeyName
);
1075 InitializeObjectAttributes(&ObjectAttributes
,
1077 OBJ_CASE_INSENSITIVE
,
1080 Status
= ZwCreateKey(&hKey
,
1081 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
1088 /* Close parent key handle, we don't need it anymore */
1092 /* Key opening/creating failed? */
1093 if (!NT_SUCCESS(Status
))
1095 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
1099 /* Check if it is the end of the string */
1100 if (Current
== Last
)
1102 /* Yes, return success */
1104 return STATUS_SUCCESS
;
1107 /* Start with this new parent key */
1110 KeyName
.Buffer
= (LPWSTR
)Current
;
1113 return STATUS_UNSUCCESSFUL
;
1117 IopSetDeviceInstanceData(HANDLE InstanceKey
,
1118 PDEVICE_NODE DeviceNode
)
1120 OBJECT_ATTRIBUTES ObjectAttributes
;
1121 UNICODE_STRING KeyName
;
1126 HANDLE ControlHandle
;
1128 DPRINT("IopSetDeviceInstanceData() called\n");
1130 /* Create the 'LogConf' key */
1131 RtlInitUnicodeString(&KeyName
, L
"LogConf");
1132 InitializeObjectAttributes(&ObjectAttributes
,
1134 OBJ_CASE_INSENSITIVE
,
1137 Status
= ZwCreateKey(&LogConfKey
,
1142 REG_OPTION_VOLATILE
,
1144 if (NT_SUCCESS(Status
))
1146 /* Set 'BootConfig' value */
1147 if (DeviceNode
->BootResources
!= NULL
)
1149 ResCount
= DeviceNode
->BootResources
->Count
;
1152 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
1153 Status
= ZwSetValueKey(LogConfKey
,
1157 DeviceNode
->BootResources
,
1158 PnpDetermineResourceListSize(DeviceNode
->BootResources
));
1162 /* Set 'BasicConfigVector' value */
1163 if (DeviceNode
->ResourceRequirements
!= NULL
&&
1164 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
1166 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
1167 Status
= ZwSetValueKey(LogConfKey
,
1170 REG_RESOURCE_REQUIREMENTS_LIST
,
1171 DeviceNode
->ResourceRequirements
,
1172 DeviceNode
->ResourceRequirements
->ListSize
);
1175 ZwClose(LogConfKey
);
1178 /* Set the 'ConfigFlags' value */
1179 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1180 Status
= ZwQueryValueKey(InstanceKey
,
1182 KeyValueBasicInformation
,
1186 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1188 /* Write the default value */
1189 ULONG DefaultConfigFlags
= 0;
1190 Status
= ZwSetValueKey(InstanceKey
,
1194 &DefaultConfigFlags
,
1195 sizeof(DefaultConfigFlags
));
1198 /* Create the 'Control' key */
1199 RtlInitUnicodeString(&KeyName
, L
"Control");
1200 InitializeObjectAttributes(&ObjectAttributes
,
1202 OBJ_CASE_INSENSITIVE
,
1205 Status
= ZwCreateKey(&ControlHandle
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
1207 if (NT_SUCCESS(Status
))
1208 ZwClose(ControlHandle
);
1210 DPRINT("IopSetDeviceInstanceData() done\n");
1216 * IopGetParentIdPrefix
1218 * Retrieve (or create) a string which identifies a device.
1222 * Pointer to device node.
1224 * Pointer to the string where is returned the parent node identifier
1227 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1228 * valid and its Buffer field is NULL-terminated. The caller needs to
1229 * to free the string with RtlFreeUnicodeString when it is no longer
1234 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1235 PUNICODE_STRING ParentIdPrefix
)
1237 ULONG KeyNameBufferLength
;
1238 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1239 UNICODE_STRING KeyName
= {0, 0, NULL
};
1240 UNICODE_STRING KeyValue
;
1241 UNICODE_STRING ValueName
;
1246 /* HACK: As long as some devices have a NULL device
1247 * instance path, the following test is required :(
1249 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1251 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1252 &DeviceNode
->InstancePath
);
1253 return STATUS_UNSUCCESSFUL
;
1256 /* 1. Try to retrieve ParentIdPrefix from registry */
1257 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1258 ParentIdPrefixInformation
= ExAllocatePool(PagedPool
, KeyNameBufferLength
+ sizeof(WCHAR
));
1259 if (!ParentIdPrefixInformation
)
1261 return STATUS_INSUFFICIENT_RESOURCES
;
1264 KeyName
.Buffer
= ExAllocatePool(PagedPool
, (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
);
1265 if (!KeyName
.Buffer
)
1267 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1271 KeyName
.MaximumLength
= (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
;
1273 RtlAppendUnicodeToString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1274 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1276 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1277 if (!NT_SUCCESS(Status
))
1279 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1280 Status
= ZwQueryValueKey(
1282 KeyValuePartialInformation
, ParentIdPrefixInformation
,
1283 KeyNameBufferLength
, &KeyNameBufferLength
);
1284 if (NT_SUCCESS(Status
))
1286 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1287 Status
= STATUS_UNSUCCESSFUL
;
1290 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1291 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1295 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1297 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1298 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1302 /* 2. Create the ParentIdPrefix value */
1303 crc32
= RtlComputeCrc32(0,
1304 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1305 DeviceNode
->Parent
->InstancePath
.Length
);
1307 swprintf((PWSTR
)ParentIdPrefixInformation
->Data
, L
"%lx&%lx", DeviceNode
->Parent
->Level
, crc32
);
1308 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
->Data
);
1310 /* 3. Try to write the ParentIdPrefix to registry */
1311 Status
= ZwSetValueKey(hKey
,
1315 (PVOID
)KeyValue
.Buffer
,
1316 ((ULONG
)wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
1319 if (NT_SUCCESS(Status
))
1321 /* Duplicate the string to return it */
1322 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &KeyValue
, ParentIdPrefix
);
1324 ExFreePool(ParentIdPrefixInformation
);
1325 RtlFreeUnicodeString(&KeyName
);
1332 IopQueryHardwareIds(PDEVICE_NODE DeviceNode
,
1335 IO_STACK_LOCATION Stack
;
1336 IO_STATUS_BLOCK IoStatusBlock
;
1338 UNICODE_STRING ValueName
;
1340 ULONG Length
, TotalLength
;
1342 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1344 RtlZeroMemory(&Stack
, sizeof(Stack
));
1345 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
1346 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1350 if (NT_SUCCESS(Status
))
1353 * FIXME: Check for valid characters, if there is invalid characters
1357 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1358 DPRINT("Hardware IDs:\n");
1361 DPRINT(" %S\n", Ptr
);
1362 Length
= (ULONG
)wcslen(Ptr
) + 1;
1365 TotalLength
+= Length
;
1367 DPRINT("TotalLength: %hu\n", TotalLength
);
1370 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
1371 Status
= ZwSetValueKey(InstanceKey
,
1375 (PVOID
)IoStatusBlock
.Information
,
1376 (TotalLength
+ 1) * sizeof(WCHAR
));
1377 if (!NT_SUCCESS(Status
))
1379 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1384 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1391 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode
,
1394 IO_STACK_LOCATION Stack
;
1395 IO_STATUS_BLOCK IoStatusBlock
;
1397 UNICODE_STRING ValueName
;
1399 ULONG Length
, TotalLength
;
1401 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1403 RtlZeroMemory(&Stack
, sizeof(Stack
));
1404 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1405 Status
= IopInitiatePnpIrp(
1406 DeviceNode
->PhysicalDeviceObject
,
1410 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1413 * FIXME: Check for valid characters, if there is invalid characters
1417 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1418 DPRINT("Compatible IDs:\n");
1421 DPRINT(" %S\n", Ptr
);
1422 Length
= (ULONG
)wcslen(Ptr
) + 1;
1425 TotalLength
+= Length
;
1427 DPRINT("TotalLength: %hu\n", TotalLength
);
1430 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
1431 Status
= ZwSetValueKey(InstanceKey
,
1435 (PVOID
)IoStatusBlock
.Information
,
1436 (TotalLength
+ 1) * sizeof(WCHAR
));
1437 if (!NT_SUCCESS(Status
))
1439 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
1444 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1452 * IopActionInterrogateDeviceStack
1454 * Retrieve information for all (direct) child nodes of a parent node.
1458 * Pointer to device node.
1460 * Pointer to parent node to retrieve child node information for.
1463 * Any errors that occur are logged instead so that all child services have a chance
1464 * of being interrogated.
1468 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
1471 IO_STATUS_BLOCK IoStatusBlock
;
1472 PDEVICE_NODE ParentDeviceNode
;
1473 WCHAR InstancePath
[MAX_PATH
];
1474 IO_STACK_LOCATION Stack
;
1476 ULONG RequiredLength
;
1478 HANDLE InstanceKey
= NULL
;
1479 UNICODE_STRING ValueName
;
1480 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
1481 DEVICE_CAPABILITIES DeviceCapabilities
;
1483 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
1484 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
1486 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1489 * We are called for the parent too, but we don't need to do special
1490 * handling for this node
1493 if (DeviceNode
== ParentDeviceNode
)
1495 DPRINT("Success\n");
1496 return STATUS_SUCCESS
;
1500 * Make sure this device node is a direct child of the parent device node
1501 * that is given as an argument
1504 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1506 DPRINT("Skipping 2+ level child\n");
1507 return STATUS_SUCCESS
;
1510 /* Skip processing if it was already completed before */
1511 if (DeviceNode
->Flags
& DNF_PROCESSED
)
1514 return STATUS_SUCCESS
;
1518 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
1519 if (!NT_SUCCESS(Status
))
1521 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
1526 * FIXME: For critical errors, cleanup and disable device, but always
1527 * return STATUS_SUCCESS.
1530 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1532 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
1533 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1537 if (NT_SUCCESS(Status
))
1539 /* Copy the device id string */
1540 wcscpy(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1543 * FIXME: Check for valid characters, if there is invalid characters
1549 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1551 /* We have to return success otherwise we abort the traverse operation */
1552 return STATUS_SUCCESS
;
1555 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1557 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
1558 if (!NT_SUCCESS(Status
))
1560 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
1562 /* We have to return success otherwise we abort the traverse operation */
1563 return STATUS_SUCCESS
;
1566 /* This bit is only check after enumeration */
1567 if (DeviceCapabilities
.HardwareDisabled
)
1569 /* FIXME: Cleanup device */
1570 DeviceNode
->Flags
|= DNF_DISABLED
;
1571 return STATUS_SUCCESS
;
1574 DeviceNode
->Flags
&= ~DNF_DISABLED
;
1576 if (!DeviceCapabilities
.UniqueID
)
1578 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1579 DPRINT("Instance ID is not unique\n");
1580 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
1581 if (!NT_SUCCESS(Status
))
1583 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
1585 /* We have to return success otherwise we abort the traverse operation */
1586 return STATUS_SUCCESS
;
1590 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1592 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
1593 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1597 if (NT_SUCCESS(Status
))
1599 /* Append the instance id string */
1600 wcscat(InstancePath
, L
"\\");
1601 if (ParentIdPrefix
.Length
> 0)
1603 /* Add information from parent bus device to InstancePath */
1604 wcscat(InstancePath
, ParentIdPrefix
.Buffer
);
1605 if (IoStatusBlock
.Information
&& *(PWSTR
)IoStatusBlock
.Information
)
1606 wcscat(InstancePath
, L
"&");
1608 if (IoStatusBlock
.Information
)
1609 wcscat(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1612 * FIXME: Check for valid characters, if there is invalid characters
1618 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1620 RtlFreeUnicodeString(&ParentIdPrefix
);
1622 if (!RtlCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
))
1624 DPRINT("No resources\n");
1625 /* FIXME: Cleanup and disable device */
1628 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
1631 * Create registry key for the instance id, if it doesn't exist yet
1633 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
1634 if (!NT_SUCCESS(Status
))
1636 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
1638 /* We have to return success otherwise we abort the traverse operation */
1639 return STATUS_SUCCESS
;
1642 IopQueryHardwareIds(DeviceNode
, InstanceKey
);
1644 IopQueryCompatibleIds(DeviceNode
, InstanceKey
);
1646 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1648 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
1649 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
1650 Status
= IopInitiatePnpIrp(
1651 DeviceNode
->PhysicalDeviceObject
,
1653 IRP_MN_QUERY_DEVICE_TEXT
,
1655 /* This key is mandatory, so even if the Irp fails, we still write it */
1656 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
1657 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
1659 if (NT_SUCCESS(Status
) &&
1660 IoStatusBlock
.Information
&&
1661 (*(PWSTR
)IoStatusBlock
.Information
!= 0))
1663 /* This key is overriden when a driver is installed. Don't write the
1664 * new description if another one already exists */
1665 Status
= ZwSetValueKey(InstanceKey
,
1669 (PVOID
)IoStatusBlock
.Information
,
1670 ((ULONG
)wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
1674 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
1675 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
1677 Status
= ZwSetValueKey(InstanceKey
,
1682 DeviceDesc
.MaximumLength
);
1684 if (!NT_SUCCESS(Status
))
1686 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
1692 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1694 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
1695 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
1696 Status
= IopInitiatePnpIrp(
1697 DeviceNode
->PhysicalDeviceObject
,
1699 IRP_MN_QUERY_DEVICE_TEXT
,
1701 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1703 DPRINT("LocationInformation: %S\n", (PWSTR
)IoStatusBlock
.Information
);
1704 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
1705 Status
= ZwSetValueKey(InstanceKey
,
1709 (PVOID
)IoStatusBlock
.Information
,
1710 ((ULONG
)wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
1711 if (!NT_SUCCESS(Status
))
1713 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1718 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1721 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1723 Status
= IopInitiatePnpIrp(
1724 DeviceNode
->PhysicalDeviceObject
,
1726 IRP_MN_QUERY_BUS_INFORMATION
,
1728 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1730 PPNP_BUS_INFORMATION BusInformation
=
1731 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
1733 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
1734 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
1735 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
1736 ExFreePool(BusInformation
);
1740 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1742 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
1743 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
1744 DeviceNode
->ChildBusTypeIndex
= -1;
1747 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1749 Status
= IopInitiatePnpIrp(
1750 DeviceNode
->PhysicalDeviceObject
,
1752 IRP_MN_QUERY_RESOURCES
,
1754 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1756 DeviceNode
->BootResources
=
1757 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
1758 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
1762 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
1763 DeviceNode
->BootResources
= NULL
;
1766 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1768 Status
= IopInitiatePnpIrp(
1769 DeviceNode
->PhysicalDeviceObject
,
1771 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
1773 if (NT_SUCCESS(Status
))
1775 DeviceNode
->ResourceRequirements
=
1776 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
1780 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
1781 DeviceNode
->ResourceRequirements
= NULL
;
1784 if (InstanceKey
!= NULL
)
1786 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
1789 ZwClose(InstanceKey
);
1791 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
1793 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
1795 /* Report the device to the user-mode pnp manager */
1796 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
1797 &DeviceNode
->InstancePath
);
1800 return STATUS_SUCCESS
;
1805 IopHandleDeviceRemoval(
1806 IN PDEVICE_NODE DeviceNode
,
1807 IN PDEVICE_RELATIONS DeviceRelations
)
1809 PDEVICE_NODE Child
= DeviceNode
->Child
, NextChild
;
1813 while (Child
!= NULL
)
1815 NextChild
= Child
->Sibling
;
1818 for (i
= 0; DeviceRelations
&& i
< DeviceRelations
->Count
; i
++)
1820 if (IopGetDeviceNode(DeviceRelations
->Objects
[i
]) == Child
)
1829 IopSendSurpriseRemoval(Child
->PhysicalDeviceObject
);
1831 /* Tell the user-mode PnP manager that a device was removed */
1832 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
1833 &Child
->InstancePath
);
1835 IopSendRemoveDevice(Child
->PhysicalDeviceObject
);
1844 IN PDEVICE_OBJECT DeviceObject
)
1846 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
1847 DEVICETREE_TRAVERSE_CONTEXT Context
;
1848 PDEVICE_RELATIONS DeviceRelations
;
1849 PDEVICE_OBJECT ChildDeviceObject
;
1850 IO_STATUS_BLOCK IoStatusBlock
;
1851 PDEVICE_NODE ChildDeviceNode
;
1852 IO_STACK_LOCATION Stack
;
1856 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
1858 if (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
)
1860 DeviceNode
->Flags
&= ~DNF_NEED_ENUMERATION_ONLY
;
1862 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
1863 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
1864 &DeviceNode
->InstancePath
);
1867 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1869 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
1871 Status
= IopInitiatePnpIrp(
1874 IRP_MN_QUERY_DEVICE_RELATIONS
,
1876 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
1878 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
1882 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
1885 * Send removal IRPs for devices that have disappeared
1886 * NOTE: This code handles the case where no relations are specified
1888 IopHandleDeviceRemoval(DeviceNode
, DeviceRelations
);
1890 /* Now we bail if nothing was returned */
1891 if (!DeviceRelations
)
1893 /* We're all done */
1894 DPRINT("No PDOs\n");
1895 return STATUS_SUCCESS
;
1898 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
1901 * Create device nodes for all discovered devices
1903 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
1905 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
1906 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
1908 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
1909 if (!ChildDeviceNode
)
1911 /* One doesn't exist, create it */
1912 Status
= IopCreateDeviceNode(
1917 if (NT_SUCCESS(Status
))
1919 /* Mark the node as enumerated */
1920 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
1922 /* Mark the DO as bus enumerated */
1923 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
1927 /* Ignore this DO */
1928 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
1929 ObDereferenceObject(ChildDeviceObject
);
1934 /* Mark it as enumerated */
1935 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
1936 ObDereferenceObject(ChildDeviceObject
);
1939 ExFreePool(DeviceRelations
);
1942 * Retrieve information about all discovered children from the bus driver
1944 IopInitDeviceTreeTraverseContext(
1947 IopActionInterrogateDeviceStack
,
1950 Status
= IopTraverseDeviceTree(&Context
);
1951 if (!NT_SUCCESS(Status
))
1953 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
1958 * Retrieve configuration from the registry for discovered children
1960 IopInitDeviceTreeTraverseContext(
1963 IopActionConfigureChildServices
,
1966 Status
= IopTraverseDeviceTree(&Context
);
1967 if (!NT_SUCCESS(Status
))
1969 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
1974 * Initialize services for discovered children.
1976 Status
= IopInitializePnpServices(DeviceNode
);
1977 if (!NT_SUCCESS(Status
))
1979 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
1983 DPRINT("IopEnumerateDevice() finished\n");
1984 return STATUS_SUCCESS
;
1989 * IopActionConfigureChildServices
1991 * Retrieve configuration for all (direct) child nodes of a parent node.
1995 * Pointer to device node.
1997 * Pointer to parent node to retrieve child node configuration for.
2000 * Any errors that occur are logged instead so that all child services have a chance of beeing
2005 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2008 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2009 PDEVICE_NODE ParentDeviceNode
;
2010 PUNICODE_STRING Service
;
2011 UNICODE_STRING ClassGUID
;
2013 DEVICE_CAPABILITIES DeviceCaps
;
2015 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2017 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2020 * We are called for the parent too, but we don't need to do special
2021 * handling for this node
2023 if (DeviceNode
== ParentDeviceNode
)
2025 DPRINT("Success\n");
2026 return STATUS_SUCCESS
;
2030 * Make sure this device node is a direct child of the parent device node
2031 * that is given as an argument
2034 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2036 DPRINT("Skipping 2+ level child\n");
2037 return STATUS_SUCCESS
;
2040 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2042 DPRINT1("Child not ready to be configured\n");
2043 return STATUS_SUCCESS
;
2046 if (!(DeviceNode
->Flags
& (DNF_DISABLED
| DNF_STARTED
| DNF_ADDED
)))
2048 WCHAR RegKeyBuffer
[MAX_PATH
];
2049 UNICODE_STRING RegKey
;
2052 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2053 RegKey
.Buffer
= RegKeyBuffer
;
2056 * Retrieve configuration from Enum key
2059 Service
= &DeviceNode
->ServiceName
;
2061 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2062 RtlInitUnicodeString(Service
, NULL
);
2063 RtlInitUnicodeString(&ClassGUID
, NULL
);
2065 QueryTable
[0].Name
= L
"Service";
2066 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2067 QueryTable
[0].EntryContext
= Service
;
2069 QueryTable
[1].Name
= L
"ClassGUID";
2070 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2071 QueryTable
[1].EntryContext
= &ClassGUID
;
2072 QueryTable
[1].DefaultType
= REG_SZ
;
2073 QueryTable
[1].DefaultData
= L
"";
2074 QueryTable
[1].DefaultLength
= 0;
2076 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2077 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2079 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2080 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2082 if (!NT_SUCCESS(Status
))
2084 /* FIXME: Log the error */
2085 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2086 &DeviceNode
->InstancePath
, Status
);
2087 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2088 return STATUS_SUCCESS
;
2091 if (Service
->Buffer
== NULL
)
2093 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2094 DeviceCaps
.RawDeviceOK
)
2096 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2098 DeviceNode
->ServiceName
.Length
= 0;
2099 DeviceNode
->ServiceName
.MaximumLength
= 0;
2100 DeviceNode
->ServiceName
.Buffer
= NULL
;
2102 else if (ClassGUID
.Length
!= 0)
2104 /* Device has a ClassGUID value, but no Service value.
2105 * Suppose it is using the NULL driver, so state the
2106 * device is started */
2107 DPRINT("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2108 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2112 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2114 return STATUS_SUCCESS
;
2117 DPRINT("Got Service %S\n", Service
->Buffer
);
2120 return STATUS_SUCCESS
;
2124 * IopActionInitChildServices
2126 * Initialize the service for all (direct) child nodes of a parent node
2130 * Pointer to device node.
2132 * Pointer to parent node to initialize child node services for.
2135 * If the driver image for a service is not loaded and initialized
2136 * it is done here too. Any errors that occur are logged instead so
2137 * that all child services have a chance of being initialized.
2141 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2144 PDEVICE_NODE ParentDeviceNode
;
2146 BOOLEAN BootDrivers
= !PnpSystemInit
;
2148 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2150 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2153 * We are called for the parent too, but we don't need to do special
2154 * handling for this node
2156 if (DeviceNode
== ParentDeviceNode
)
2158 DPRINT("Success\n");
2159 return STATUS_SUCCESS
;
2163 * Make sure this device node is a direct child of the parent device node
2164 * that is given as an argument
2167 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2169 DPRINT("Skipping 2+ level child\n");
2170 return STATUS_SUCCESS
;
2173 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2175 DPRINT1("Child not ready to be added\n");
2176 return STATUS_SUCCESS
;
2179 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
) ||
2180 IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) ||
2181 IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2182 return STATUS_SUCCESS
;
2184 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
2186 /* We don't need to worry about loading the driver because we're
2187 * being driven in raw mode so our parent must be loaded to get here */
2188 Status
= IopInitializeDevice(DeviceNode
, NULL
);
2189 if (NT_SUCCESS(Status
))
2191 Status
= IopStartDevice(DeviceNode
);
2192 if (!NT_SUCCESS(Status
))
2194 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2195 &DeviceNode
->InstancePath
, Status
);
2201 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2202 PDRIVER_OBJECT DriverObject
;
2204 /* Get existing DriverObject pointer (in case the driver has
2205 already been loaded and initialized) */
2206 Status
= IopGetDriverObject(
2208 &DeviceNode
->ServiceName
,
2211 if (!NT_SUCCESS(Status
))
2213 /* Driver is not initialized, try to load it */
2214 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2216 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2218 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2219 was loaded by the bootloader */
2220 if ((Status
!= STATUS_IMAGE_ALREADY_LOADED
) ||
2221 (Status
== STATUS_IMAGE_ALREADY_LOADED
&& !DriverObject
))
2223 /* Initialize the driver */
2224 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2225 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2229 Status
= STATUS_SUCCESS
;
2234 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2235 &DeviceNode
->ServiceName
, Status
);
2239 /* Driver is loaded and initialized at this point */
2240 if (NT_SUCCESS(Status
))
2242 /* Initialize the device, including all filters */
2243 Status
= PipCallDriverAddDevice(DeviceNode
, FALSE
, DriverObject
);
2248 * Don't disable when trying to load only boot drivers
2252 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2253 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
2254 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2255 DPRINT1("Initialization of service %S failed (Status %x)\n",
2256 DeviceNode
->ServiceName
.Buffer
, Status
);
2261 return STATUS_SUCCESS
;
2265 * IopInitializePnpServices
2267 * Initialize services for discovered children
2271 * Top device node to start initializing services.
2277 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2279 DEVICETREE_TRAVERSE_CONTEXT Context
;
2281 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2283 IopInitDeviceTreeTraverseContext(
2286 IopActionInitChildServices
,
2289 return IopTraverseDeviceTree(&Context
);
2292 static NTSTATUS INIT_FUNCTION
2293 IopEnumerateDetectedDevices(
2295 IN PUNICODE_STRING RelativePath OPTIONAL
,
2297 IN BOOLEAN EnumerateSubKeys
,
2298 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2299 IN ULONG ParentBootResourcesLength
)
2301 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2302 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2303 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2304 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2305 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2306 OBJECT_ATTRIBUTES ObjectAttributes
;
2307 HANDLE hDevicesKey
= NULL
;
2308 HANDLE hDeviceKey
= NULL
;
2309 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2310 UNICODE_STRING Level2NameU
;
2311 WCHAR Level2Name
[5];
2312 ULONG IndexDevice
= 0;
2314 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2315 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2316 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2317 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2318 UNICODE_STRING DeviceName
, ValueName
;
2320 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2321 ULONG BootResourcesLength
;
2324 const UNICODE_STRING IdentifierPci
= RTL_CONSTANT_STRING(L
"PCI");
2325 UNICODE_STRING HardwareIdPci
= RTL_CONSTANT_STRING(L
"*PNP0A03\0");
2326 static ULONG DeviceIndexPci
= 0;
2327 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2328 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2329 static ULONG DeviceIndexSerial
= 0;
2330 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2331 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2332 static ULONG DeviceIndexKeyboard
= 0;
2333 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2334 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2335 static ULONG DeviceIndexMouse
= 0;
2336 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
2337 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
2338 static ULONG DeviceIndexParallel
= 0;
2339 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
2340 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
2341 static ULONG DeviceIndexFloppy
= 0;
2342 const UNICODE_STRING IdentifierIsa
= RTL_CONSTANT_STRING(L
"ISA");
2343 UNICODE_STRING HardwareIdIsa
= RTL_CONSTANT_STRING(L
"*PNP0A00\0");
2344 static ULONG DeviceIndexIsa
= 0;
2345 UNICODE_STRING HardwareIdKey
;
2346 PUNICODE_STRING pHardwareId
;
2347 ULONG DeviceIndex
= 0;
2348 PUCHAR CmResourceList
;
2353 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
2354 if (!NT_SUCCESS(Status
))
2356 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2361 hDevicesKey
= hBaseKey
;
2363 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2364 if (!pDeviceInformation
)
2366 DPRINT("ExAllocatePool() failed\n");
2367 Status
= STATUS_NO_MEMORY
;
2371 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2372 if (!pValueInformation
)
2374 DPRINT("ExAllocatePool() failed\n");
2375 Status
= STATUS_NO_MEMORY
;
2381 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2382 if (Status
== STATUS_NO_MORE_ENTRIES
)
2384 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2386 ExFreePool(pDeviceInformation
);
2387 DeviceInfoLength
= RequiredSize
;
2388 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2389 if (!pDeviceInformation
)
2391 DPRINT("ExAllocatePool() failed\n");
2392 Status
= STATUS_NO_MEMORY
;
2395 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2397 if (!NT_SUCCESS(Status
))
2399 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2404 /* Open device key */
2405 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2406 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2408 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
2409 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
2410 if (!NT_SUCCESS(Status
))
2412 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2416 /* Read boot resources, and add then to parent ones */
2417 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2418 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2420 ExFreePool(pValueInformation
);
2421 ValueInfoLength
= RequiredSize
;
2422 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2423 if (!pValueInformation
)
2425 DPRINT("ExAllocatePool() failed\n");
2426 ZwDeleteKey(hLevel2Key
);
2427 Status
= STATUS_NO_MEMORY
;
2430 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2432 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
2434 BootResources
= ParentBootResources
;
2435 BootResourcesLength
= ParentBootResourcesLength
;
2437 else if (!NT_SUCCESS(Status
))
2439 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2442 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
2444 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
2449 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
2451 /* Concatenate current resources and parent ones */
2452 if (ParentBootResourcesLength
== 0)
2453 BootResourcesLength
= pValueInformation
->DataLength
;
2455 BootResourcesLength
= ParentBootResourcesLength
2456 + pValueInformation
->DataLength
2458 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
2461 DPRINT("ExAllocatePool() failed\n");
2464 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
2466 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2468 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
2470 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2472 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
2473 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2474 ParentBootResourcesLength
- Header
);
2475 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2479 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
2481 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
2482 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2483 ParentBootResourcesLength
- Header
);
2485 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
2486 pValueInformation
->Data
+ Header
,
2487 pValueInformation
->DataLength
- Header
);
2488 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2492 if (EnumerateSubKeys
)
2497 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2498 if (Status
== STATUS_NO_MORE_ENTRIES
)
2500 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2502 ExFreePool(pDeviceInformation
);
2503 DeviceInfoLength
= RequiredSize
;
2504 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2505 if (!pDeviceInformation
)
2507 DPRINT("ExAllocatePool() failed\n");
2508 Status
= STATUS_NO_MEMORY
;
2511 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2513 if (!NT_SUCCESS(Status
))
2515 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2519 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2520 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2522 Status
= IopEnumerateDetectedDevices(
2528 BootResourcesLength
);
2529 if (!NT_SUCCESS(Status
))
2534 /* Read identifier */
2535 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2536 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2538 ExFreePool(pValueInformation
);
2539 ValueInfoLength
= RequiredSize
;
2540 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2541 if (!pValueInformation
)
2543 DPRINT("ExAllocatePool() failed\n");
2544 Status
= STATUS_NO_MEMORY
;
2547 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2549 if (!NT_SUCCESS(Status
))
2551 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
2553 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2556 ValueName
.Length
= ValueName
.MaximumLength
= 0;
2558 else if (pValueInformation
->Type
!= REG_SZ
)
2560 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
2565 /* Assign hardware id to this device */
2566 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
2567 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
2568 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
2569 ValueName
.Length
-= sizeof(WCHAR
);
2572 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
2574 pHardwareId
= &HardwareIdSerial
;
2575 DeviceIndex
= DeviceIndexSerial
++;
2577 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
2579 pHardwareId
= &HardwareIdKeyboard
;
2580 DeviceIndex
= DeviceIndexKeyboard
++;
2582 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
2584 pHardwareId
= &HardwareIdMouse
;
2585 DeviceIndex
= DeviceIndexMouse
++;
2587 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
2589 pHardwareId
= &HardwareIdParallel
;
2590 DeviceIndex
= DeviceIndexParallel
++;
2592 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
2594 pHardwareId
= &HardwareIdFloppy
;
2595 DeviceIndex
= DeviceIndexFloppy
++;
2597 else if (NT_SUCCESS(Status
))
2599 /* Try to also match the device identifier */
2600 if (RtlCompareUnicodeString(&ValueName
, &IdentifierPci
, FALSE
) == 0)
2602 pHardwareId
= &HardwareIdPci
;
2603 DeviceIndex
= DeviceIndexPci
++;
2605 else if (RtlCompareUnicodeString(&ValueName
, &IdentifierIsa
, FALSE
) == 0)
2607 pHardwareId
= &HardwareIdIsa
;
2608 DeviceIndex
= DeviceIndexIsa
++;
2612 DPRINT("Unknown device '%wZ'\n", &ValueName
);
2618 /* Unknown key path */
2619 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
2623 /* Prepare hardware id key (hardware id value without final \0) */
2624 HardwareIdKey
= *pHardwareId
;
2625 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
2627 /* Add the detected device to Root key */
2628 InitializeObjectAttributes(&ObjectAttributes
, &HardwareIdKey
, OBJ_KERNEL_HANDLE
, hRootKey
, NULL
);
2629 Status
= ZwCreateKey(
2635 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
2637 if (!NT_SUCCESS(Status
))
2639 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2642 swprintf(Level2Name
, L
"%04lu", DeviceIndex
);
2643 RtlInitUnicodeString(&Level2NameU
, Level2Name
);
2644 InitializeObjectAttributes(&ObjectAttributes
, &Level2NameU
, OBJ_KERNEL_HANDLE
, hLevel1Key
, NULL
);
2645 Status
= ZwCreateKey(
2647 KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
,
2651 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
2653 ZwClose(hLevel1Key
);
2654 if (!NT_SUCCESS(Status
))
2656 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2659 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName
, DeviceIndex
, &HardwareIdKey
);
2660 Status
= ZwSetValueKey(hLevel2Key
, &HardwareIDU
, 0, REG_MULTI_SZ
, pHardwareId
->Buffer
, pHardwareId
->MaximumLength
);
2661 if (!NT_SUCCESS(Status
))
2663 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
2664 ZwDeleteKey(hLevel2Key
);
2667 /* Create 'LogConf' subkey */
2668 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
, hLevel2Key
, NULL
);
2669 Status
= ZwCreateKey(
2675 REG_OPTION_VOLATILE
,
2677 if (!NT_SUCCESS(Status
))
2679 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2680 ZwDeleteKey(hLevel2Key
);
2683 if (BootResourcesLength
>= sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
2685 CmResourceList
= ExAllocatePool(PagedPool
, BootResourcesLength
+ sizeof(ULONG
));
2686 if (!CmResourceList
)
2689 ZwDeleteKey(hLevel2Key
);
2693 /* Add the list count (1st member of CM_RESOURCE_LIST) */
2695 RtlCopyMemory(CmResourceList
,
2699 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
2700 RtlCopyMemory(CmResourceList
+ sizeof(ULONG
),
2702 BootResourcesLength
);
2704 /* Save boot resources to 'LogConf\BootConfig' */
2705 Status
= ZwSetValueKey(hLogConf
, &BootConfigU
, 0, REG_RESOURCE_LIST
, CmResourceList
, BootResourcesLength
+ sizeof(ULONG
));
2706 if (!NT_SUCCESS(Status
))
2708 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
2710 ZwDeleteKey(hLevel2Key
);
2717 if (BootResources
&& BootResources
!= ParentBootResources
)
2719 ExFreePool(BootResources
);
2720 BootResources
= NULL
;
2724 ZwClose(hLevel2Key
);
2729 ZwClose(hDeviceKey
);
2734 Status
= STATUS_SUCCESS
;
2737 if (hDevicesKey
&& hDevicesKey
!= hBaseKey
)
2738 ZwClose(hDevicesKey
);
2740 ZwClose(hDeviceKey
);
2741 if (pDeviceInformation
)
2742 ExFreePool(pDeviceInformation
);
2743 if (pValueInformation
)
2744 ExFreePool(pValueInformation
);
2748 static BOOLEAN INIT_FUNCTION
2749 IopIsFirmwareMapperDisabled(VOID
)
2751 UNICODE_STRING KeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
2752 UNICODE_STRING KeyNameU
= RTL_CONSTANT_STRING(L
"DisableFirmwareMapper");
2753 OBJECT_ATTRIBUTES ObjectAttributes
;
2755 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
;
2756 ULONG DesiredLength
, Length
;
2760 InitializeObjectAttributes(&ObjectAttributes
, &KeyPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
2761 Status
= ZwOpenKey(&hPnpKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
2762 if (NT_SUCCESS(Status
))
2764 Status
= ZwQueryValueKey(hPnpKey
,
2766 KeyValuePartialInformation
,
2770 if ((Status
== STATUS_BUFFER_TOO_SMALL
) ||
2771 (Status
== STATUS_BUFFER_OVERFLOW
))
2773 Length
= DesiredLength
;
2774 KeyInformation
= ExAllocatePool(PagedPool
, Length
);
2777 Status
= ZwQueryValueKey(hPnpKey
,
2779 KeyValuePartialInformation
,
2783 if (NT_SUCCESS(Status
) && KeyInformation
->DataLength
== sizeof(ULONG
))
2785 KeyValue
= (ULONG
)(*KeyInformation
->Data
);
2789 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU
, &KeyNameU
);
2792 ExFreePool(KeyInformation
);
2796 DPRINT1("Failed to allocate memory for registry query\n");
2801 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU
, &KeyNameU
, Status
);
2808 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU
, Status
);
2811 DPRINT1("Firmware mapper is %s\n", KeyValue
!= 0 ? "disabled" : "enabled");
2813 return (KeyValue
!= 0) ? TRUE
: FALSE
;
2819 IopUpdateRootKey(VOID
)
2821 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
2822 UNICODE_STRING RootPathU
= RTL_CONSTANT_STRING(L
"Root");
2823 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2824 OBJECT_ATTRIBUTES ObjectAttributes
;
2825 HANDLE hEnum
, hRoot
;
2828 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
2829 Status
= ZwCreateKey(&hEnum
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
2830 if (!NT_SUCCESS(Status
))
2832 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2836 InitializeObjectAttributes(&ObjectAttributes
, &RootPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
2837 Status
= ZwCreateKey(&hRoot
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
2839 if (!NT_SUCCESS(Status
))
2841 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2845 if (!IopIsFirmwareMapperDisabled())
2847 Status
= IopOpenRegistryKeyEx(&hEnum
, NULL
, &MultiKeyPathU
, KEY_ENUMERATE_SUB_KEYS
);
2848 if (!NT_SUCCESS(Status
))
2850 /* Nothing to do, don't return with an error status */
2851 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2853 return STATUS_SUCCESS
;
2855 Status
= IopEnumerateDetectedDevices(
2866 /* Enumeration is disabled */
2867 Status
= STATUS_SUCCESS
;
2877 IopOpenRegistryKeyEx(PHANDLE KeyHandle
,
2879 PUNICODE_STRING Name
,
2880 ACCESS_MASK DesiredAccess
)
2882 OBJECT_ATTRIBUTES ObjectAttributes
;
2889 InitializeObjectAttributes(&ObjectAttributes
,
2891 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2895 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
2902 IopCreateRegistryKeyEx(OUT PHANDLE Handle
,
2903 IN HANDLE RootHandle OPTIONAL
,
2904 IN PUNICODE_STRING KeyName
,
2905 IN ACCESS_MASK DesiredAccess
,
2906 IN ULONG CreateOptions
,
2907 OUT PULONG Disposition OPTIONAL
)
2909 OBJECT_ATTRIBUTES ObjectAttributes
;
2910 ULONG KeyDisposition
, RootHandleIndex
= 0, i
= 1, NestedCloseLevel
= 0;
2912 HANDLE HandleArray
[2];
2913 BOOLEAN Recursing
= TRUE
;
2915 UNICODE_STRING KeyString
;
2916 NTSTATUS Status
= STATUS_SUCCESS
;
2919 /* P1 is start, pp is end */
2920 p1
= KeyName
->Buffer
;
2921 pp
= (PVOID
)((ULONG_PTR
)p1
+ KeyName
->Length
);
2923 /* Create the target key */
2924 InitializeObjectAttributes(&ObjectAttributes
,
2926 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2929 Status
= ZwCreateKey(&HandleArray
[i
],
2937 /* Now we check if this failed */
2938 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) && (RootHandle
))
2940 /* Target key failed, so we'll need to create its parent. Setup array */
2941 HandleArray
[0] = NULL
;
2942 HandleArray
[1] = RootHandle
;
2944 /* Keep recursing for each missing parent */
2947 /* And if we're deep enough, close the last handle */
2948 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
2950 /* We're setup to ping-pong between the two handle array entries */
2951 RootHandleIndex
= i
;
2954 /* Clear the one we're attempting to open now */
2955 HandleArray
[i
] = NULL
;
2957 /* Process the parent key name */
2958 for (p
= p1
; ((p
< pp
) && (*p
!= OBJ_NAME_PATH_SEPARATOR
)); p
++);
2959 Length
= (USHORT
)(p
- p1
) * sizeof(WCHAR
);
2961 /* Is there a parent name? */
2964 /* Build the unicode string for it */
2965 KeyString
.Buffer
= p1
;
2966 KeyString
.Length
= KeyString
.MaximumLength
= Length
;
2968 /* Now try opening the parent */
2969 InitializeObjectAttributes(&ObjectAttributes
,
2971 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2972 HandleArray
[RootHandleIndex
],
2974 Status
= ZwCreateKey(&HandleArray
[i
],
2981 if (NT_SUCCESS(Status
))
2983 /* It worked, we have one more handle */
2988 /* Parent key creation failed, abandon loop */
2995 /* We don't have a parent name, probably corrupted key name */
2996 Status
= STATUS_INVALID_PARAMETER
;
3001 /* Now see if there's more parents to create */
3003 if ((p
== pp
) || (p1
== pp
))
3005 /* We're done, hopefully successfully, so stop */
3010 /* Outer loop check for handle nesting that requires closing the top handle */
3011 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3014 /* Check if we broke out of the loop due to success */
3015 if (NT_SUCCESS(Status
))
3017 /* Return the target handle (we closed all the parent ones) and disposition */
3018 *Handle
= HandleArray
[i
];
3019 if (Disposition
) *Disposition
= KeyDisposition
;
3022 /* Return the success state */
3028 IopGetRegistryValue(IN HANDLE Handle
,
3030 OUT PKEY_VALUE_FULL_INFORMATION
*Information
)
3032 UNICODE_STRING ValueString
;
3034 PKEY_VALUE_FULL_INFORMATION FullInformation
;
3038 RtlInitUnicodeString(&ValueString
, ValueName
);
3040 Status
= ZwQueryValueKey(Handle
,
3042 KeyValueFullInformation
,
3046 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
3047 (Status
!= STATUS_BUFFER_TOO_SMALL
))
3052 FullInformation
= ExAllocatePool(NonPagedPool
, Size
);
3053 if (!FullInformation
) return STATUS_INSUFFICIENT_RESOURCES
;
3055 Status
= ZwQueryValueKey(Handle
,
3057 KeyValueFullInformation
,
3061 if (!NT_SUCCESS(Status
))
3063 ExFreePool(FullInformation
);
3067 *Information
= FullInformation
;
3068 return STATUS_SUCCESS
;
3071 RTL_GENERIC_COMPARE_RESULTS
3073 PiCompareInstancePath(IN PRTL_AVL_TABLE Table
,
3074 IN PVOID FirstStruct
,
3075 IN PVOID SecondStruct
)
3083 // The allocation function is called by the generic table package whenever
3084 // it needs to allocate memory for the table.
3089 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3099 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3108 PpInitializeDeviceReferenceTable(VOID
)
3110 /* Setup the guarded mutex and AVL table */
3111 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock
);
3112 RtlInitializeGenericTableAvl(
3113 &PpDeviceReferenceTable
,
3114 (PRTL_AVL_COMPARE_ROUTINE
)PiCompareInstancePath
,
3115 (PRTL_AVL_ALLOCATE_ROUTINE
)PiAllocateGenericTableEntry
,
3116 (PRTL_AVL_FREE_ROUTINE
)PiFreeGenericTableEntry
,
3124 /* Initialize the resource when accessing device registry data */
3125 ExInitializeResourceLite(&PpRegistryDeviceResource
);
3127 /* Setup the device reference AVL table */
3128 PpInitializeDeviceReferenceTable();
3136 /* Check the initialization phase */
3137 switch (ExpInitializationPhase
)
3142 return PiInitPhase0();
3148 //return PiInitPhase1();
3152 /* Don't know any other phase! Bugcheck! */
3153 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL
);
3158 LONG IopNumberDeviceNodes
;
3162 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3164 PDEVICE_NODE DeviceNode
;
3168 DeviceNode
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), 'donD');
3169 if (!DeviceNode
) return DeviceNode
;
3172 InterlockedIncrement(&IopNumberDeviceNodes
);
3175 RtlZeroMemory(DeviceNode
, sizeof(DEVICE_NODE
));
3176 DeviceNode
->InterfaceType
= InterfaceTypeUndefined
;
3177 DeviceNode
->BusNumber
= -1;
3178 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
3179 DeviceNode
->ChildBusNumber
= -1;
3180 DeviceNode
->ChildBusTypeIndex
= -1;
3181 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3182 InitializeListHead(&DeviceNode
->DeviceArbiterList
);
3183 InitializeListHead(&DeviceNode
->DeviceTranslatorList
);
3184 InitializeListHead(&DeviceNode
->TargetDeviceNotify
);
3185 InitializeListHead(&DeviceNode
->DockInfo
.ListEntry
);
3186 InitializeListHead(&DeviceNode
->PendedSetInterfaceState
);
3188 /* Check if there is a PDO */
3189 if (PhysicalDeviceObject
)
3191 /* Link it and remove the init flag */
3192 DeviceNode
->PhysicalDeviceObject
= PhysicalDeviceObject
;
3193 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= DeviceNode
;
3194 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
3197 /* Return the node */
3201 /* PUBLIC FUNCTIONS **********************************************************/
3205 PnpBusTypeGuidGet(IN USHORT Index
,
3206 IN LPGUID BusTypeGuid
)
3208 NTSTATUS Status
= STATUS_SUCCESS
;
3210 /* Acquire the lock */
3211 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
3214 if (Index
< PnpBusTypeGuidList
->GuidCount
)
3217 RtlCopyMemory(BusTypeGuid
, &PnpBusTypeGuidList
->Guids
[Index
], sizeof(GUID
));
3222 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
3225 /* Release lock and return status */
3226 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
3232 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject
,
3233 IN PHANDLE DeviceInstanceHandle
,
3234 IN ACCESS_MASK DesiredAccess
)
3238 PDEVICE_NODE DeviceNode
;
3239 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3242 /* Open the enum key */
3243 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
3247 if (!NT_SUCCESS(Status
)) return Status
;
3249 /* Make sure we have an instance path */
3250 DeviceNode
= IopGetDeviceNode(DeviceObject
);
3251 if ((DeviceNode
) && (DeviceNode
->InstancePath
.Length
))
3253 /* Get the instance key */
3254 Status
= IopOpenRegistryKeyEx(DeviceInstanceHandle
,
3256 &DeviceNode
->InstancePath
,
3262 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3265 /* Close the handle and return status */
3272 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList
)
3274 ULONG FinalSize
, PartialSize
, EntrySize
, i
, j
;
3275 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
3276 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
3278 /* If we don't have one, that's easy */
3279 if (!ResourceList
) return 0;
3281 /* Start with the minimum size possible */
3282 FinalSize
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
3284 /* Loop each full descriptor */
3285 FullDescriptor
= ResourceList
->List
;
3286 for (i
= 0; i
< ResourceList
->Count
; i
++)
3288 /* Start with the minimum size possible */
3289 PartialSize
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
) +
3290 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST
, PartialDescriptors
);
3292 /* Loop each partial descriptor */
3293 PartialDescriptor
= FullDescriptor
->PartialResourceList
.PartialDescriptors
;
3294 for (j
= 0; j
< FullDescriptor
->PartialResourceList
.Count
; j
++)
3296 /* Start with the minimum size possible */
3297 EntrySize
= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
3299 /* Check if there is extra data */
3300 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
3303 EntrySize
+= PartialDescriptor
->u
.DeviceSpecificData
.DataSize
;
3306 /* The size of partial descriptors is bigger */
3307 PartialSize
+= EntrySize
;
3309 /* Go to the next partial descriptor */
3310 PartialDescriptor
= (PVOID
)((ULONG_PTR
)PartialDescriptor
+ EntrySize
);
3313 /* The size of full descriptors is bigger */
3314 FinalSize
+= PartialSize
;
3316 /* Go to the next full descriptor */
3317 FullDescriptor
= (PVOID
)((ULONG_PTR
)FullDescriptor
+ PartialSize
);
3320 /* Return the final size */
3326 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject
,
3331 IN PULONG BufferLength
)
3334 HANDLE KeyHandle
, SubHandle
;
3335 UNICODE_STRING KeyString
;
3336 PKEY_VALUE_FULL_INFORMATION KeyValueInfo
= NULL
;
3340 /* Find the instance key */
3341 Status
= PnpDeviceObjectToDeviceInstance(DeviceObject
, &KeyHandle
, KEY_READ
);
3342 if (NT_SUCCESS(Status
))
3344 /* Check for name given by caller */
3348 RtlInitUnicodeString(&KeyString
, KeyName
);
3349 Status
= IopOpenRegistryKeyEx(&SubHandle
,
3353 if (NT_SUCCESS(Status
))
3355 /* And use this handle instead */
3357 KeyHandle
= SubHandle
;
3361 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3362 if (NT_SUCCESS(Status
))
3364 /* Now get the size of the property */
3365 Status
= IopGetRegistryValue(KeyHandle
,
3374 /* Fail if any of the registry operations failed */
3375 if (!NT_SUCCESS(Status
)) return Status
;
3377 /* Check how much data we have to copy */
3378 Length
= KeyValueInfo
->DataLength
;
3379 if (*BufferLength
>= Length
)
3381 /* Check for a match in the value type */
3382 if (KeyValueInfo
->Type
== ValueType
)
3385 RtlCopyMemory(Buffer
,
3386 (PVOID
)((ULONG_PTR
)KeyValueInfo
+
3387 KeyValueInfo
->DataOffset
),
3392 /* Invalid registry property type, fail */
3393 Status
= STATUS_INVALID_PARAMETER_2
;
3398 /* Buffer is too small to hold data */
3399 Status
= STATUS_BUFFER_TOO_SMALL
;
3402 /* Return the required buffer length, free the buffer, and return status */
3403 *BufferLength
= Length
;
3404 ExFreePool(KeyValueInfo
);
3408 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3409 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3410 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED; while(TRUE); break;}
3417 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
3418 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
3419 IN ULONG BufferLength
,
3420 OUT PVOID PropertyBuffer
,
3421 OUT PULONG ResultLength
)
3423 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
3424 DEVICE_CAPABILITIES DeviceCaps
;
3425 ULONG ReturnLength
= 0, Length
= 0, ValueType
;
3426 PWCHAR ValueName
= NULL
, EnumeratorNameEnd
, DeviceInstanceName
;
3428 NTSTATUS Status
= STATUS_BUFFER_TOO_SMALL
;
3430 POBJECT_NAME_INFORMATION ObjectNameInfo
= NULL
;
3431 BOOLEAN NullTerminate
= FALSE
;
3433 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject
, DeviceProperty
);
3435 /* Assume failure */
3438 /* Only PDOs can call this */
3439 if (!DeviceNode
) return STATUS_INVALID_DEVICE_REQUEST
;
3441 /* Handle all properties */
3442 switch (DeviceProperty
)
3444 case DevicePropertyBusTypeGuid
:
3446 /* Get the GUID from the internal cache */
3447 Status
= PnpBusTypeGuidGet(DeviceNode
->ChildBusTypeIndex
, &BusTypeGuid
);
3448 if (!NT_SUCCESS(Status
)) return Status
;
3450 /* This is the format of the returned data */
3451 PIP_RETURN_DATA(sizeof(GUID
), &BusTypeGuid
);
3453 case DevicePropertyLegacyBusType
:
3455 /* Validate correct interface type */
3456 if (DeviceNode
->ChildInterfaceType
== InterfaceTypeUndefined
)
3457 return STATUS_OBJECT_NAME_NOT_FOUND
;
3459 /* This is the format of the returned data */
3460 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE
), &DeviceNode
->ChildInterfaceType
);
3462 case DevicePropertyBusNumber
:
3464 /* Validate correct bus number */
3465 if ((DeviceNode
->ChildBusNumber
& 0x80000000) == 0x80000000)
3466 return STATUS_OBJECT_NAME_NOT_FOUND
;
3468 /* This is the format of the returned data */
3469 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceNode
->ChildBusNumber
);
3471 case DevicePropertyEnumeratorName
:
3473 /* Get the instance path */
3474 DeviceInstanceName
= DeviceNode
->InstancePath
.Buffer
;
3477 ASSERT((BufferLength
& 1) == 0);
3478 ASSERT(DeviceInstanceName
!= NULL
);
3480 /* Get the name from the path */
3481 EnumeratorNameEnd
= wcschr(DeviceInstanceName
, OBJ_NAME_PATH_SEPARATOR
);
3482 ASSERT(EnumeratorNameEnd
);
3484 /* This string needs to be NULL-terminated */
3485 NullTerminate
= TRUE
;
3487 /* This is the format of the returned data */
3488 PIP_RETURN_DATA((ULONG
)(EnumeratorNameEnd
- DeviceInstanceName
) * sizeof(WCHAR
),
3489 DeviceInstanceName
);
3491 case DevicePropertyAddress
:
3493 /* Query the device caps */
3494 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
);
3495 if (!NT_SUCCESS(Status
) || (DeviceCaps
.Address
== MAXULONG
))
3496 return STATUS_OBJECT_NAME_NOT_FOUND
;
3498 /* This is the format of the returned data */
3499 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceCaps
.Address
);
3501 case DevicePropertyBootConfigurationTranslated
:
3503 /* Validate we have resources */
3504 if (!DeviceNode
->BootResources
)
3505 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3507 /* No resources will still fake success, but with 0 bytes */
3509 return STATUS_SUCCESS
;
3512 /* This is the format of the returned data */
3513 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode
->BootResources
), // FIXFIX: Should use BootResourcesTranslated
3514 DeviceNode
->BootResources
); // FIXFIX: Should use BootResourcesTranslated
3516 case DevicePropertyPhysicalDeviceObjectName
:
3518 /* Sanity check for Unicode-sized string */
3519 ASSERT((BufferLength
& 1) == 0);
3521 /* Allocate name buffer */
3522 Length
= BufferLength
+ sizeof(OBJECT_NAME_INFORMATION
);
3523 ObjectNameInfo
= ExAllocatePool(PagedPool
, Length
);
3524 if (!ObjectNameInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
3526 /* Query the PDO name */
3527 Status
= ObQueryNameString(DeviceObject
,
3531 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
3533 /* It's up to the caller to try again */
3534 Status
= STATUS_BUFFER_TOO_SMALL
;
3537 /* This string needs to be NULL-terminated */
3538 NullTerminate
= TRUE
;
3540 /* Return if successful */
3541 if (NT_SUCCESS(Status
)) PIP_RETURN_DATA(ObjectNameInfo
->Name
.Length
,
3542 ObjectNameInfo
->Name
.Buffer
);
3544 /* Let the caller know how big the name is */
3545 *ResultLength
-= sizeof(OBJECT_NAME_INFORMATION
);
3548 /* Handle the registry-based properties */
3549 case DevicePropertyUINumber
:
3550 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER
, REG_DWORD
);
3551 case DevicePropertyLocationInformation
:
3552 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION
, REG_SZ
);
3553 case DevicePropertyDeviceDescription
:
3554 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC
, REG_SZ
);
3555 case DevicePropertyHardwareID
:
3556 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID
, REG_MULTI_SZ
);
3557 case DevicePropertyCompatibleIDs
:
3558 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS
, REG_MULTI_SZ
);
3559 case DevicePropertyBootConfiguration
:
3560 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG
, REG_RESOURCE_LIST
);
3561 case DevicePropertyClassName
:
3562 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS
, REG_SZ
);
3563 case DevicePropertyClassGuid
:
3564 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID
, REG_SZ
);
3565 case DevicePropertyDriverKeyName
:
3566 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER
, REG_SZ
);
3567 case DevicePropertyManufacturer
:
3568 PIP_REGISTRY_DATA(REGSTR_VAL_MFG
, REG_SZ
);
3569 case DevicePropertyFriendlyName
:
3570 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME
, REG_SZ
);
3571 case DevicePropertyContainerID
:
3572 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3573 PIP_UNIMPLEMENTED();
3574 case DevicePropertyRemovalPolicy
:
3575 PIP_UNIMPLEMENTED();
3576 case DevicePropertyInstallState
:
3577 PIP_UNIMPLEMENTED();
3578 case DevicePropertyResourceRequirements
:
3579 PIP_UNIMPLEMENTED();
3580 case DevicePropertyAllocatedResources
:
3581 PIP_UNIMPLEMENTED();
3583 return STATUS_INVALID_PARAMETER_2
;
3586 /* Having a registry value name implies registry data */
3589 /* We know up-front how much data to expect */
3590 *ResultLength
= BufferLength
;
3592 /* Go get the data, use the LogConf subkey if necessary */
3593 Status
= PiGetDeviceRegistryProperty(DeviceObject
,
3597 DevicePropertyBootConfiguration
) ?
3602 else if (NT_SUCCESS(Status
))
3604 /* We know up-front how much data to expect, check the caller's buffer */
3605 *ResultLength
= ReturnLength
+ (NullTerminate
? sizeof(UNICODE_NULL
) : 0);
3606 if (*ResultLength
<= BufferLength
)
3608 /* Buffer is all good, copy the data */
3609 RtlCopyMemory(PropertyBuffer
, Data
, ReturnLength
);
3611 /* Check if we need to NULL-terminate the string */
3614 /* Terminate the string */
3615 ((PWCHAR
)PropertyBuffer
)[ReturnLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3618 /* This is the success path */
3619 Status
= STATUS_SUCCESS
;
3624 Status
= STATUS_BUFFER_TOO_SMALL
;
3628 /* Free any allocation we may have made, and return the status code */
3629 if (ObjectNameInfo
) ExFreePool(ObjectNameInfo
);
3638 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3640 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
3641 IO_STACK_LOCATION Stack
;
3644 IO_STATUS_BLOCK IoStatusBlock
;
3646 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
3647 Stack
.MajorFunction
= IRP_MJ_PNP
;
3648 Stack
.MinorFunction
= IRP_MN_QUERY_PNP_DEVICE_STATE
;
3650 Status
= IopSynchronousCall(PhysicalDeviceObject
, &Stack
, (PVOID
*)&PnPFlags
);
3651 if (!NT_SUCCESS(Status
))
3653 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status
);
3657 if (PnPFlags
& PNP_DEVICE_NOT_DISABLEABLE
)
3658 DeviceNode
->UserFlags
|= DNUF_NOT_DISABLEABLE
;
3660 DeviceNode
->UserFlags
&= ~DNUF_NOT_DISABLEABLE
;
3662 if (PnPFlags
& PNP_DEVICE_DONT_DISPLAY_IN_UI
)
3663 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
3665 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
3667 if ((PnPFlags
& PNP_DEVICE_REMOVED
) ||
3668 ((PnPFlags
& PNP_DEVICE_FAILED
) && !(PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)))
3670 /* Surprise removal */
3672 IopSendSurpriseRemoval(PhysicalDeviceObject
);
3674 /* Tell the user-mode PnP manager that a device was removed */
3675 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
3676 &DeviceNode
->InstancePath
);
3678 IopSendRemoveDevice(PhysicalDeviceObject
);
3680 else if ((PnPFlags
& PNP_DEVICE_FAILED
) && (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
))
3682 /* Stop for resource rebalance */
3684 Status
= IopStopDevice(DeviceNode
);
3685 if (!NT_SUCCESS(Status
))
3687 DPRINT1("Failed to stop device for rebalancing\n");
3689 /* Stop failed so don't rebalance */
3690 PnPFlags
&= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
;
3694 /* Resource rebalance */
3695 if (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)
3697 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
3699 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
3701 IRP_MN_QUERY_RESOURCES
,
3703 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
3705 DeviceNode
->BootResources
=
3706 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
3707 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
3711 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
3712 DeviceNode
->BootResources
= NULL
;
3715 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
3717 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
3719 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
3721 if (NT_SUCCESS(Status
))
3723 DeviceNode
->ResourceRequirements
=
3724 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
3728 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
3729 DeviceNode
->ResourceRequirements
= NULL
;
3732 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
3733 if (IopStartDevice(DeviceNode
) != STATUS_SUCCESS
)
3735 DPRINT1("Restart after resource rebalance failed\n");
3737 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
3738 DeviceNode
->Flags
|= DNF_START_FAILED
;
3740 IopRemoveDevice(DeviceNode
);
3746 * @name IoOpenDeviceRegistryKey
3748 * Open a registry key unique for a specified driver or device instance.
3750 * @param DeviceObject Device to get the registry key for.
3751 * @param DevInstKeyType Type of the key to return.
3752 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
3753 * @param DevInstRegKey Handle to the opened registry key on
3754 * successful return.
3762 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject
,
3763 IN ULONG DevInstKeyType
,
3764 IN ACCESS_MASK DesiredAccess
,
3765 OUT PHANDLE DevInstRegKey
)
3767 static WCHAR RootKeyName
[] =
3768 L
"\\Registry\\Machine\\System\\CurrentControlSet\\";
3769 static WCHAR ProfileKeyName
[] =
3770 L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
3771 static WCHAR ClassKeyName
[] = L
"Control\\Class\\";
3772 static WCHAR EnumKeyName
[] = L
"Enum\\";
3773 static WCHAR DeviceParametersKeyName
[] = L
"Device Parameters";
3774 ULONG KeyNameLength
;
3775 LPWSTR KeyNameBuffer
;
3776 UNICODE_STRING KeyName
;
3777 ULONG DriverKeyLength
;
3778 OBJECT_ATTRIBUTES ObjectAttributes
;
3779 PDEVICE_NODE DeviceNode
= NULL
;
3782 DPRINT("IoOpenDeviceRegistryKey() called\n");
3784 if ((DevInstKeyType
& (PLUGPLAY_REGKEY_DEVICE
| PLUGPLAY_REGKEY_DRIVER
)) == 0)
3786 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
3787 return STATUS_INVALID_PARAMETER
;
3790 if (!IopIsValidPhysicalDeviceObject(DeviceObject
))
3791 return STATUS_INVALID_DEVICE_REQUEST
;
3792 DeviceNode
= IopGetDeviceNode(DeviceObject
);
3795 * Calculate the length of the base key name. This is the full
3796 * name for driver key or the name excluding "Device Parameters"
3797 * subkey for device key.
3800 KeyNameLength
= sizeof(RootKeyName
);
3801 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
3802 KeyNameLength
+= sizeof(ProfileKeyName
) - sizeof(UNICODE_NULL
);
3803 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
3805 KeyNameLength
+= sizeof(ClassKeyName
) - sizeof(UNICODE_NULL
);
3806 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
3807 0, NULL
, &DriverKeyLength
);
3808 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
3810 KeyNameLength
+= DriverKeyLength
;
3814 KeyNameLength
+= sizeof(EnumKeyName
) - sizeof(UNICODE_NULL
) +
3815 DeviceNode
->InstancePath
.Length
;
3819 * Now allocate the buffer for the key name...
3822 KeyNameBuffer
= ExAllocatePool(PagedPool
, KeyNameLength
);
3823 if (KeyNameBuffer
== NULL
)
3824 return STATUS_INSUFFICIENT_RESOURCES
;
3827 KeyName
.MaximumLength
= (USHORT
)KeyNameLength
;
3828 KeyName
.Buffer
= KeyNameBuffer
;
3831 * ...and build the key name.
3834 KeyName
.Length
+= sizeof(RootKeyName
) - sizeof(UNICODE_NULL
);
3835 RtlCopyMemory(KeyNameBuffer
, RootKeyName
, KeyName
.Length
);
3837 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
3838 RtlAppendUnicodeToString(&KeyName
, ProfileKeyName
);
3840 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
3842 RtlAppendUnicodeToString(&KeyName
, ClassKeyName
);
3843 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
3844 DriverKeyLength
, KeyNameBuffer
+
3845 (KeyName
.Length
/ sizeof(WCHAR
)),
3847 if (!NT_SUCCESS(Status
))
3849 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status
);
3850 ExFreePool(KeyNameBuffer
);
3853 KeyName
.Length
+= (USHORT
)DriverKeyLength
- sizeof(UNICODE_NULL
);
3857 RtlAppendUnicodeToString(&KeyName
, EnumKeyName
);
3858 Status
= RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->InstancePath
);
3859 if (DeviceNode
->InstancePath
.Length
== 0)
3861 ExFreePool(KeyNameBuffer
);
3867 * Open the base key.
3869 Status
= IopOpenRegistryKeyEx(DevInstRegKey
, NULL
, &KeyName
, DesiredAccess
);
3870 if (!NT_SUCCESS(Status
))
3872 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName
, Status
);
3873 ExFreePool(KeyNameBuffer
);
3876 ExFreePool(KeyNameBuffer
);
3879 * For driver key we're done now.
3882 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
3886 * Let's go further. For device key we must open "Device Parameters"
3887 * subkey and create it if it doesn't exist yet.
3890 RtlInitUnicodeString(&KeyName
, DeviceParametersKeyName
);
3891 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
,
3892 OBJ_CASE_INSENSITIVE
, *DevInstRegKey
, NULL
);
3893 Status
= ZwCreateKey(DevInstRegKey
, DesiredAccess
, &ObjectAttributes
,
3894 0, NULL
, ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0, NULL
);
3895 ZwClose(ObjectAttributes
.RootDirectory
);
3902 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
3904 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
, FailedRemoveDevice
;
3908 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
3909 ChildDeviceNode
= ParentDeviceNode
->Child
;
3910 while (ChildDeviceNode
!= NULL
)
3912 NextDeviceNode
= ChildDeviceNode
->Sibling
;
3913 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
3915 Status
= IopPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
3916 if (!NT_SUCCESS(Status
))
3918 FailedRemoveDevice
= ChildDeviceNode
;
3922 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
3923 ChildDeviceNode
= NextDeviceNode
;
3925 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
3927 return STATUS_SUCCESS
;
3930 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
3931 ChildDeviceNode
= ParentDeviceNode
->Child
;
3932 while (ChildDeviceNode
!= NULL
)
3934 NextDeviceNode
= ChildDeviceNode
->Sibling
;
3935 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
3937 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
3939 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
3940 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
3941 if (ChildDeviceNode
== FailedRemoveDevice
)
3944 ChildDeviceNode
= NextDeviceNode
;
3946 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
3948 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
3955 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
3957 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;