2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 PDEVICE_NODE IopRootDeviceNode
;
19 KSPIN_LOCK IopDeviceTreeLock
;
20 ERESOURCE PpRegistryDeviceResource
;
21 KGUARDED_MUTEX PpDeviceReferenceTableLock
;
22 RTL_AVL_TABLE PpDeviceReferenceTable
;
24 extern ERESOURCE IopDriverLoadResource
;
25 extern ULONG ExpInitializationPhase
;
26 extern BOOLEAN ExpInTextModeSetup
;
27 extern BOOLEAN PnpSystemInit
;
29 /* DATA **********************************************************************/
31 PDRIVER_OBJECT IopRootDriverObject
;
32 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList
= NULL
;
33 LIST_ENTRY IopDeviceRelationsRequestList
;
34 WORK_QUEUE_ITEM IopDeviceRelationsWorkItem
;
35 BOOLEAN IopDeviceRelationsRequestInProgress
;
36 KSPIN_LOCK IopDeviceRelationsSpinLock
;
38 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
40 LIST_ENTRY RequestListEntry
;
41 PDEVICE_OBJECT DeviceObject
;
42 DEVICE_RELATION_TYPE Type
;
43 } INVALIDATE_DEVICE_RELATION_DATA
, *PINVALIDATE_DEVICE_RELATION_DATA
;
45 /* FUNCTIONS *****************************************************************/
48 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
49 IN ULONG CreateOptions
,
53 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
);
56 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
);
59 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
);
63 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject
)
65 return ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
69 IopFixupDeviceId(PWCHAR String
)
71 SIZE_T Length
= wcslen(String
), i
;
73 for (i
= 0; i
< Length
; i
++)
75 if (String
[i
] == L
'\\')
82 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode
)
85 HANDLE CriticalDeviceKey
, InstanceKey
;
86 OBJECT_ATTRIBUTES ObjectAttributes
;
87 UNICODE_STRING CriticalDeviceKeyU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
88 UNICODE_STRING CompatibleIdU
= RTL_CONSTANT_STRING(L
"CompatibleIDs");
89 UNICODE_STRING HardwareIdU
= RTL_CONSTANT_STRING(L
"HardwareID");
90 UNICODE_STRING ServiceU
= RTL_CONSTANT_STRING(L
"Service");
91 UNICODE_STRING ClassGuidU
= RTL_CONSTANT_STRING(L
"ClassGUID");
92 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
93 ULONG HidLength
= 0, CidLength
= 0, BufferLength
;
94 PWCHAR IdBuffer
, OriginalIdBuffer
;
96 /* Open the device instance key */
97 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
98 if (Status
!= STATUS_SUCCESS
)
101 Status
= ZwQueryValueKey(InstanceKey
,
103 KeyValuePartialInformation
,
107 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
109 ZwClose(InstanceKey
);
113 Status
= ZwQueryValueKey(InstanceKey
,
115 KeyValuePartialInformation
,
119 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
124 BufferLength
= HidLength
+ CidLength
;
125 BufferLength
-= (((CidLength
!= 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
));
127 /* Allocate a buffer to hold data from both */
128 OriginalIdBuffer
= IdBuffer
= ExAllocatePool(PagedPool
, BufferLength
);
131 ZwClose(InstanceKey
);
135 /* Compute the buffer size */
136 if (HidLength
> CidLength
)
137 BufferLength
= HidLength
;
139 BufferLength
= CidLength
;
141 PartialInfo
= ExAllocatePool(PagedPool
, BufferLength
);
144 ZwClose(InstanceKey
);
145 ExFreePool(OriginalIdBuffer
);
149 Status
= ZwQueryValueKey(InstanceKey
,
151 KeyValuePartialInformation
,
155 if (Status
!= STATUS_SUCCESS
)
157 ExFreePool(PartialInfo
);
158 ExFreePool(OriginalIdBuffer
);
159 ZwClose(InstanceKey
);
163 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
164 HidLength
= PartialInfo
->DataLength
- ((CidLength
!= 0) ? sizeof(WCHAR
) : 0);
165 RtlCopyMemory(IdBuffer
, PartialInfo
->Data
, HidLength
);
169 Status
= ZwQueryValueKey(InstanceKey
,
171 KeyValuePartialInformation
,
175 if (Status
!= STATUS_SUCCESS
)
177 ExFreePool(PartialInfo
);
178 ExFreePool(OriginalIdBuffer
);
179 ZwClose(InstanceKey
);
184 CidLength
= PartialInfo
->DataLength
;
185 RtlCopyMemory(((PUCHAR
)IdBuffer
) + HidLength
, PartialInfo
->Data
, CidLength
);
188 /* Free our temp buffer */
189 ExFreePool(PartialInfo
);
191 InitializeObjectAttributes(&ObjectAttributes
,
193 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
196 Status
= ZwOpenKey(&CriticalDeviceKey
,
197 KEY_ENUMERATE_SUB_KEYS
,
199 if (!NT_SUCCESS(Status
))
201 /* The critical device database doesn't exist because
202 * we're probably in 1st stage setup, but it's ok */
203 ExFreePool(OriginalIdBuffer
);
204 ZwClose(InstanceKey
);
210 USHORT StringLength
= (USHORT
)wcslen(IdBuffer
) + 1, Index
;
212 IopFixupDeviceId(IdBuffer
);
214 /* Look through all subkeys for a match */
215 for (Index
= 0; TRUE
; Index
++)
218 PKEY_BASIC_INFORMATION BasicInfo
;
220 Status
= ZwEnumerateKey(CriticalDeviceKey
,
226 if (Status
== STATUS_NO_MORE_ENTRIES
)
228 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
230 UNICODE_STRING ChildIdNameU
, RegKeyNameU
;
232 BasicInfo
= ExAllocatePool(PagedPool
, NeededLength
);
236 ExFreePool(OriginalIdBuffer
);
237 ZwClose(CriticalDeviceKey
);
238 ZwClose(InstanceKey
);
242 Status
= ZwEnumerateKey(CriticalDeviceKey
,
248 if (Status
!= STATUS_SUCCESS
)
250 /* This shouldn't happen */
251 ExFreePool(BasicInfo
);
255 ChildIdNameU
.Buffer
= IdBuffer
;
256 ChildIdNameU
.MaximumLength
= ChildIdNameU
.Length
= (StringLength
- 1) * sizeof(WCHAR
);
257 RegKeyNameU
.Buffer
= BasicInfo
->Name
;
258 RegKeyNameU
.MaximumLength
= RegKeyNameU
.Length
= (USHORT
)BasicInfo
->NameLength
;
260 if (RtlEqualUnicodeString(&ChildIdNameU
, &RegKeyNameU
, TRUE
))
262 HANDLE ChildKeyHandle
;
264 InitializeObjectAttributes(&ObjectAttributes
,
266 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
270 Status
= ZwOpenKey(&ChildKeyHandle
,
273 if (Status
!= STATUS_SUCCESS
)
275 ExFreePool(BasicInfo
);
279 /* Check if there's already a driver installed */
280 Status
= ZwQueryValueKey(InstanceKey
,
282 KeyValuePartialInformation
,
286 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
288 ExFreePool(BasicInfo
);
292 Status
= ZwQueryValueKey(ChildKeyHandle
,
294 KeyValuePartialInformation
,
298 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
300 ExFreePool(BasicInfo
);
304 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
307 ExFreePool(OriginalIdBuffer
);
308 ExFreePool(BasicInfo
);
309 ZwClose(InstanceKey
);
310 ZwClose(ChildKeyHandle
);
311 ZwClose(CriticalDeviceKey
);
315 /* Read ClassGUID entry in the CDDB */
316 Status
= ZwQueryValueKey(ChildKeyHandle
,
318 KeyValuePartialInformation
,
322 if (Status
!= STATUS_SUCCESS
)
324 ExFreePool(BasicInfo
);
328 /* Write it to the ENUM key */
329 Status
= ZwSetValueKey(InstanceKey
,
334 PartialInfo
->DataLength
);
335 if (Status
!= STATUS_SUCCESS
)
337 ExFreePool(BasicInfo
);
338 ExFreePool(PartialInfo
);
339 ZwClose(ChildKeyHandle
);
343 Status
= ZwQueryValueKey(ChildKeyHandle
,
345 KeyValuePartialInformation
,
349 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
351 ExFreePool(PartialInfo
);
352 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
355 ExFreePool(OriginalIdBuffer
);
356 ExFreePool(BasicInfo
);
357 ZwClose(InstanceKey
);
358 ZwClose(ChildKeyHandle
);
359 ZwClose(CriticalDeviceKey
);
363 /* Read the service entry from the CDDB */
364 Status
= ZwQueryValueKey(ChildKeyHandle
,
366 KeyValuePartialInformation
,
370 if (Status
!= STATUS_SUCCESS
)
372 ExFreePool(BasicInfo
);
373 ExFreePool(PartialInfo
);
374 ZwClose(ChildKeyHandle
);
378 /* Write it to the ENUM key */
379 Status
= ZwSetValueKey(InstanceKey
,
384 PartialInfo
->DataLength
);
385 if (Status
!= STATUS_SUCCESS
)
387 ExFreePool(BasicInfo
);
388 ExFreePool(PartialInfo
);
389 ZwClose(ChildKeyHandle
);
393 DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo
->Data
, &ChildIdNameU
);
397 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU
);
400 ExFreePool(OriginalIdBuffer
);
401 ExFreePool(PartialInfo
);
402 ExFreePool(BasicInfo
);
403 ZwClose(InstanceKey
);
404 ZwClose(ChildKeyHandle
);
405 ZwClose(CriticalDeviceKey
);
411 ExFreePool(BasicInfo
);
415 /* Umm, not sure what happened here */
420 /* Advance to the next ID */
421 IdBuffer
+= StringLength
;
424 ExFreePool(OriginalIdBuffer
);
425 ZwClose(InstanceKey
);
426 ZwClose(CriticalDeviceKey
);
431 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
432 PDRIVER_OBJECT DriverObject
)
439 /* Special case for bus driven devices */
440 DeviceNode
->Flags
|= DNF_ADDED
;
441 return STATUS_SUCCESS
;
444 if (!DriverObject
->DriverExtension
->AddDevice
)
446 DeviceNode
->Flags
|= DNF_LEGACY_DRIVER
;
449 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
451 DeviceNode
->Flags
|= DNF_ADDED
+ DNF_STARTED
;
452 return STATUS_SUCCESS
;
455 /* This is a Plug and Play driver */
456 DPRINT("Plug and Play driver found\n");
457 ASSERT(DeviceNode
->PhysicalDeviceObject
);
459 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
460 &DriverObject
->DriverName
,
461 &DeviceNode
->InstancePath
);
462 Status
= DriverObject
->DriverExtension
->AddDevice(
463 DriverObject
, DeviceNode
->PhysicalDeviceObject
);
464 if (!NT_SUCCESS(Status
))
466 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
467 &DriverObject
->DriverName
,
468 &DeviceNode
->InstancePath
,
470 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
471 DeviceNode
->Problem
= CM_PROB_FAILED_ADD
;
475 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
477 /* Check if we have a ACPI device (needed for power management) */
478 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
480 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
482 /* There can be only one system power device */
483 if (!SystemPowerDeviceNodeCreated
)
485 PopSystemPowerDeviceNode
= DeviceNode
;
486 ObReferenceObject(PopSystemPowerDeviceNode
->PhysicalDeviceObject
);
487 SystemPowerDeviceNodeCreated
= TRUE
;
491 ObDereferenceObject(Fdo
);
493 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
495 return STATUS_SUCCESS
;
501 IopSendEject(IN PDEVICE_OBJECT DeviceObject
)
503 IO_STACK_LOCATION Stack
;
506 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
507 Stack
.MajorFunction
= IRP_MJ_PNP
;
508 Stack
.MinorFunction
= IRP_MN_EJECT
;
510 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
516 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject
)
518 IO_STACK_LOCATION Stack
;
521 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
522 Stack
.MajorFunction
= IRP_MJ_PNP
;
523 Stack
.MinorFunction
= IRP_MN_SURPRISE_REMOVAL
;
525 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
526 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
532 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
534 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
535 IO_STACK_LOCATION Stack
;
541 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING
,
542 &DeviceNode
->InstancePath
);
544 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
545 Stack
.MajorFunction
= IRP_MJ_PNP
;
546 Stack
.MinorFunction
= IRP_MN_QUERY_REMOVE_DEVICE
;
548 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
550 IopNotifyPlugPlayNotification(DeviceObject
,
551 EventCategoryTargetDeviceChange
,
552 &GUID_TARGET_DEVICE_QUERY_REMOVE
,
556 if (!NT_SUCCESS(Status
))
558 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode
->InstancePath
);
559 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED
,
560 &DeviceNode
->InstancePath
);
569 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject
)
571 IO_STACK_LOCATION Stack
;
574 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
575 Stack
.MajorFunction
= IRP_MJ_PNP
;
576 Stack
.MinorFunction
= IRP_MN_QUERY_STOP_DEVICE
;
578 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
584 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
586 IO_STACK_LOCATION Stack
;
588 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
590 /* Drop all our state for this device in case it isn't really going away */
591 DeviceNode
->Flags
&= DNF_ENUMERATED
| DNF_PROCESSED
;
593 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
594 Stack
.MajorFunction
= IRP_MJ_PNP
;
595 Stack
.MinorFunction
= IRP_MN_REMOVE_DEVICE
;
597 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
598 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
600 IopNotifyPlugPlayNotification(DeviceObject
,
601 EventCategoryTargetDeviceChange
,
602 &GUID_TARGET_DEVICE_REMOVE_COMPLETE
,
605 ObDereferenceObject(DeviceObject
);
611 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
613 IO_STACK_LOCATION Stack
;
616 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
617 Stack
.MajorFunction
= IRP_MJ_PNP
;
618 Stack
.MinorFunction
= IRP_MN_CANCEL_REMOVE_DEVICE
;
620 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
621 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
623 IopNotifyPlugPlayNotification(DeviceObject
,
624 EventCategoryTargetDeviceChange
,
625 &GUID_TARGET_DEVICE_REMOVE_CANCELLED
,
633 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject
)
635 IO_STACK_LOCATION Stack
;
638 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
639 Stack
.MajorFunction
= IRP_MJ_PNP
;
640 Stack
.MinorFunction
= IRP_MN_STOP_DEVICE
;
642 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
643 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
648 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject
)
650 IO_STACK_LOCATION Stack
;
651 PDEVICE_NODE DeviceNode
;
654 DEVICE_CAPABILITIES DeviceCapabilities
;
656 /* Get the device node */
657 DeviceNode
= IopGetDeviceNode(DeviceObject
);
659 ASSERT(!(DeviceNode
->Flags
& DNF_DISABLED
));
661 /* Build the I/O stack location */
662 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
663 Stack
.MajorFunction
= IRP_MJ_PNP
;
664 Stack
.MinorFunction
= IRP_MN_START_DEVICE
;
666 Stack
.Parameters
.StartDevice
.AllocatedResources
=
667 DeviceNode
->ResourceList
;
668 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
=
669 DeviceNode
->ResourceListTranslated
;
672 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
673 if (!NT_SUCCESS(Status
))
675 /* Send an IRP_MN_REMOVE_DEVICE request */
676 IopRemoveDevice(DeviceNode
);
678 /* Set the appropriate flag */
679 DeviceNode
->Flags
|= DNF_START_FAILED
;
680 DeviceNode
->Problem
= CM_PROB_FAILED_START
;
682 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode
->InstancePath
, Status
);
686 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
688 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
689 if (!NT_SUCCESS(Status
))
691 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
694 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
695 IoInvalidateDeviceState(DeviceObject
);
697 /* Otherwise, mark us as started */
698 DeviceNode
->Flags
|= DNF_STARTED
;
699 DeviceNode
->Flags
&= ~DNF_STOPPED
;
701 /* We now need enumeration */
702 DeviceNode
->Flags
|= DNF_NEED_ENUMERATION_ONLY
;
707 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode
)
709 PDEVICE_OBJECT DeviceObject
;
714 ASSERT((DeviceNode
->Flags
& DNF_ADDED
));
715 ASSERT((DeviceNode
->Flags
& (DNF_RESOURCE_ASSIGNED
|
716 DNF_RESOURCE_REPORTED
|
717 DNF_NO_RESOURCE_REQUIRED
)));
719 /* Get the device object */
720 DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
722 /* Check if we're not started yet */
723 if (!(DeviceNode
->Flags
& DNF_STARTED
))
726 IopStartDevice2(DeviceObject
);
729 /* Do we need to query IDs? This happens in the case of manual reporting */
731 if (DeviceNode
->Flags
& DNF_NEED_QUERY_IDS
)
733 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
734 /* And that case shouldn't happen yet */
739 /* Make sure we're started, and check if we need enumeration */
740 if ((DeviceNode
->Flags
& DNF_STARTED
) &&
741 (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
))
744 IoSynchronousInvalidateDeviceRelations(DeviceObject
, BusRelations
);
745 Status
= STATUS_SUCCESS
;
750 Status
= STATUS_SUCCESS
;
759 PDEVICE_NODE DeviceNode
)
763 DPRINT("Stopping device: %wZ\n", &DeviceNode
->InstancePath
);
765 Status
= IopQueryStopDevice(DeviceNode
->PhysicalDeviceObject
);
766 if (NT_SUCCESS(Status
))
768 IopSendStopDevice(DeviceNode
->PhysicalDeviceObject
);
770 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
771 DeviceNode
->Flags
|= DNF_STOPPED
;
773 return STATUS_SUCCESS
;
781 PDEVICE_NODE DeviceNode
)
784 HANDLE InstanceHandle
= NULL
, ControlHandle
= NULL
;
785 UNICODE_STRING KeyName
;
786 OBJECT_ATTRIBUTES ObjectAttributes
;
788 if (DeviceNode
->Flags
& DNF_DISABLED
)
789 return STATUS_SUCCESS
;
791 Status
= IopAssignDeviceResources(DeviceNode
);
792 if (!NT_SUCCESS(Status
))
796 IopStartAndEnumerateDevice(DeviceNode
);
798 /* FIX: Should be done in new device instance code */
799 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceHandle
);
800 if (!NT_SUCCESS(Status
))
803 /* FIX: Should be done in IoXxxPrepareDriverLoading */
805 RtlInitUnicodeString(&KeyName
, L
"Control");
806 InitializeObjectAttributes(&ObjectAttributes
,
808 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
811 Status
= ZwCreateKey(&ControlHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
812 if (!NT_SUCCESS(Status
))
815 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
816 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, DeviceNode
->ServiceName
.Buffer
, DeviceNode
->ServiceName
.Length
);
820 if (ControlHandle
!= NULL
)
821 ZwClose(ControlHandle
);
823 if (InstanceHandle
!= NULL
)
824 ZwClose(InstanceHandle
);
831 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
832 PDEVICE_CAPABILITIES DeviceCaps
)
834 IO_STATUS_BLOCK StatusBlock
;
835 IO_STACK_LOCATION Stack
;
838 UNICODE_STRING ValueName
;
840 /* Set up the Header */
841 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
842 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
843 DeviceCaps
->Version
= 1;
844 DeviceCaps
->Address
= -1;
845 DeviceCaps
->UINumber
= -1;
847 /* Set up the Stack */
848 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
849 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
852 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
854 IRP_MN_QUERY_CAPABILITIES
,
856 if (!NT_SUCCESS(Status
))
858 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%x\n", Status
);
862 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCaps
->Version
+ sizeof(DeviceCaps
->Version
));
864 if (DeviceCaps
->NoDisplayInUI
)
865 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
867 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
869 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
870 if (NT_SUCCESS(Status
))
872 /* Set 'Capabilities' value */
873 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
874 Status
= ZwSetValueKey(InstanceKey
,
878 (PVOID
)&DeviceNode
->CapabilityFlags
,
881 /* Set 'UINumber' value */
882 if (DeviceCaps
->UINumber
!= MAXULONG
)
884 RtlInitUnicodeString(&ValueName
, L
"UINumber");
885 Status
= ZwSetValueKey(InstanceKey
,
889 &DeviceCaps
->UINumber
,
900 IopDeviceRelationsWorker(
903 PLIST_ENTRY ListEntry
;
904 PINVALIDATE_DEVICE_RELATION_DATA Data
;
907 KeAcquireSpinLock(&IopDeviceRelationsSpinLock
, &OldIrql
);
908 while (!IsListEmpty(&IopDeviceRelationsRequestList
))
910 ListEntry
= RemoveHeadList(&IopDeviceRelationsRequestList
);
911 KeReleaseSpinLock(&IopDeviceRelationsSpinLock
, OldIrql
);
912 Data
= CONTAINING_RECORD(ListEntry
,
913 INVALIDATE_DEVICE_RELATION_DATA
,
916 IoSynchronousInvalidateDeviceRelations(Data
->DeviceObject
,
919 ObDereferenceObject(Data
->DeviceObject
);
921 KeAcquireSpinLock(&IopDeviceRelationsSpinLock
, &OldIrql
);
923 IopDeviceRelationsRequestInProgress
= FALSE
;
924 KeReleaseSpinLock(&IopDeviceRelationsSpinLock
, OldIrql
);
928 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
932 if (PopSystemPowerDeviceNode
)
934 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
935 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
936 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
938 return STATUS_SUCCESS
;
941 return STATUS_UNSUCCESSFUL
;
946 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
948 USHORT i
= 0, FoundIndex
= 0xFFFF;
952 /* Acquire the lock */
953 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
955 /* Loop all entries */
956 while (i
< PnpBusTypeGuidList
->GuidCount
)
958 /* Try to find a match */
959 if (RtlCompareMemory(BusTypeGuid
,
960 &PnpBusTypeGuidList
->Guids
[i
],
961 sizeof(GUID
)) == sizeof(GUID
))
970 /* Check if we have to grow the list */
971 if (PnpBusTypeGuidList
->GuidCount
)
973 /* Calculate the new size */
974 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
975 (sizeof(GUID
) * PnpBusTypeGuidList
->GuidCount
);
977 /* Allocate the new copy */
978 NewList
= ExAllocatePool(PagedPool
, NewSize
);
982 ExFreePool(PnpBusTypeGuidList
);
986 /* Now copy them, decrease the size too */
987 NewSize
-= sizeof(GUID
);
988 RtlCopyMemory(NewList
, PnpBusTypeGuidList
, NewSize
);
990 /* Free the old list */
991 ExFreePool(PnpBusTypeGuidList
);
993 /* Use the new buffer */
994 PnpBusTypeGuidList
= NewList
;
997 /* Copy the new GUID */
998 RtlCopyMemory(&PnpBusTypeGuidList
->Guids
[PnpBusTypeGuidList
->GuidCount
],
1002 /* The new entry is the index */
1003 FoundIndex
= (USHORT
)PnpBusTypeGuidList
->GuidCount
;
1004 PnpBusTypeGuidList
->GuidCount
++;
1007 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
1013 * Creates a device node
1016 * ParentNode = Pointer to parent device node
1017 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
1018 * to have the root device node create one
1019 * (eg. for legacy drivers)
1020 * DeviceNode = Pointer to storage for created device node
1026 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
1027 PDEVICE_OBJECT PhysicalDeviceObject
,
1028 PUNICODE_STRING ServiceName
,
1029 PDEVICE_NODE
*DeviceNode
)
1034 UNICODE_STRING FullServiceName
;
1035 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
1036 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
1037 UNICODE_STRING KeyName
, ClassName
;
1038 PUNICODE_STRING ServiceName1
;
1040 UNICODE_STRING ClassGUID
;
1041 HANDLE InstanceHandle
;
1043 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1044 ParentNode
, PhysicalDeviceObject
, ServiceName
);
1046 Node
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), TAG_IO_DEVNODE
);
1049 return STATUS_INSUFFICIENT_RESOURCES
;
1052 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
1055 ServiceName1
= &UnknownDeviceName
;
1057 ServiceName1
= ServiceName
;
1059 if (!PhysicalDeviceObject
)
1061 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName1
->Length
;
1062 FullServiceName
.Length
= 0;
1063 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
1064 if (!FullServiceName
.Buffer
)
1066 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1067 return STATUS_INSUFFICIENT_RESOURCES
;
1070 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
1071 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName1
);
1073 Status
= PnpRootCreateDevice(&FullServiceName
, NULL
, &PhysicalDeviceObject
, &Node
->InstancePath
);
1074 if (!NT_SUCCESS(Status
))
1076 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
1077 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1081 /* Create the device key for legacy drivers */
1082 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, REG_OPTION_VOLATILE
, &InstanceHandle
);
1083 if (!NT_SUCCESS(Status
))
1085 ZwClose(InstanceHandle
);
1086 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1087 ExFreePool(FullServiceName
.Buffer
);
1091 Node
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, ServiceName1
->Length
);
1092 if (!Node
->ServiceName
.Buffer
)
1094 ZwClose(InstanceHandle
);
1095 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1096 ExFreePool(FullServiceName
.Buffer
);
1100 Node
->ServiceName
.MaximumLength
= ServiceName1
->Length
;
1101 Node
->ServiceName
.Length
= 0;
1103 RtlAppendUnicodeStringToString(&Node
->ServiceName
, ServiceName1
);
1107 RtlInitUnicodeString(&KeyName
, L
"Service");
1108 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName
->Buffer
, ServiceName
->Length
);
1111 if (NT_SUCCESS(Status
))
1113 RtlInitUnicodeString(&KeyName
, L
"Legacy");
1116 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
1117 if (NT_SUCCESS(Status
))
1119 RtlInitUnicodeString(&KeyName
, L
"Class");
1121 RtlInitUnicodeString(&ClassName
, L
"LegacyDriver\0");
1122 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassName
.Buffer
, ClassName
.Length
+ sizeof(UNICODE_NULL
));
1123 if (NT_SUCCESS(Status
))
1125 RtlInitUnicodeString(&KeyName
, L
"ClassGUID");
1127 RtlInitUnicodeString(&ClassGUID
, L
"{8ECC055D-047F-11D1-A537-0000F8753ED1}\0");
1128 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassGUID
.Buffer
, ClassGUID
.Length
+ sizeof(UNICODE_NULL
));
1129 if (NT_SUCCESS(Status
))
1131 RtlInitUnicodeString(&KeyName
, L
"DeviceDesc");
1133 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName1
->Buffer
, ServiceName1
->Length
+ sizeof(UNICODE_NULL
));
1139 ZwClose(InstanceHandle
);
1140 ExFreePool(FullServiceName
.Buffer
);
1142 if (!NT_SUCCESS(Status
))
1144 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1148 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
1149 IopDeviceNodeSetFlag(Node
, DNF_PROCESSED
);
1150 IopDeviceNodeSetFlag(Node
, DNF_ADDED
);
1151 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
1154 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
1156 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
1160 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1161 Node
->Parent
= ParentNode
;
1162 Node
->Sibling
= NULL
;
1163 if (ParentNode
->LastChild
== NULL
)
1165 ParentNode
->Child
= Node
;
1166 ParentNode
->LastChild
= Node
;
1170 ParentNode
->LastChild
->Sibling
= Node
;
1171 ParentNode
->LastChild
= Node
;
1173 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1174 Node
->Level
= ParentNode
->Level
+ 1;
1177 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1181 return STATUS_SUCCESS
;
1185 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
1188 PDEVICE_NODE PrevSibling
= NULL
;
1190 /* All children must be deleted before a parent is deleted */
1191 ASSERT(!DeviceNode
->Child
);
1192 ASSERT(DeviceNode
->PhysicalDeviceObject
);
1194 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1196 /* Get previous sibling */
1197 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
1199 PrevSibling
= DeviceNode
->Parent
->Child
;
1200 while (PrevSibling
->Sibling
!= DeviceNode
)
1201 PrevSibling
= PrevSibling
->Sibling
;
1204 /* Unlink from parent if it exists */
1205 if (DeviceNode
->Parent
)
1207 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
1209 DeviceNode
->Parent
->LastChild
= PrevSibling
;
1211 PrevSibling
->Sibling
= NULL
;
1213 if (DeviceNode
->Parent
->Child
== DeviceNode
)
1214 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
1217 /* Unlink from sibling list */
1219 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
1221 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1223 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
1225 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
1227 if (DeviceNode
->ResourceList
)
1229 ExFreePool(DeviceNode
->ResourceList
);
1232 if (DeviceNode
->ResourceListTranslated
)
1234 ExFreePool(DeviceNode
->ResourceListTranslated
);
1237 if (DeviceNode
->ResourceRequirements
)
1239 ExFreePool(DeviceNode
->ResourceRequirements
);
1242 if (DeviceNode
->BootResources
)
1244 ExFreePool(DeviceNode
->BootResources
);
1247 ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceNode
->PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= NULL
;
1248 ExFreePoolWithTag(DeviceNode
, TAG_IO_DEVNODE
);
1250 return STATUS_SUCCESS
;
1255 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject
,
1256 IN PIO_STACK_LOCATION IoStackLocation
,
1257 OUT PVOID
*Information
)
1260 PIO_STACK_LOCATION IrpStack
;
1261 IO_STATUS_BLOCK IoStatusBlock
;
1264 PDEVICE_OBJECT TopDeviceObject
;
1267 /* Call the top of the device stack */
1268 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
1270 /* Allocate an IRP */
1271 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
, FALSE
);
1272 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
1274 /* Initialize to failure */
1275 Irp
->IoStatus
.Status
= IoStatusBlock
.Status
= STATUS_NOT_SUPPORTED
;
1276 Irp
->IoStatus
.Information
= IoStatusBlock
.Information
= 0;
1278 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1279 if (IoStackLocation
->MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
)
1281 /* Copy the resource requirements list into the IOSB */
1282 Irp
->IoStatus
.Information
=
1283 IoStatusBlock
.Information
= (ULONG_PTR
)IoStackLocation
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
1286 /* Initialize the event */
1287 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1290 Irp
->UserIosb
= &IoStatusBlock
;
1291 Irp
->UserEvent
= &Event
;
1294 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1295 IoQueueThreadIrp(Irp
);
1297 /* Copy-in the stack */
1298 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1299 *IrpStack
= *IoStackLocation
;
1301 /* Call the driver */
1302 Status
= IoCallDriver(TopDeviceObject
, Irp
);
1303 if (Status
== STATUS_PENDING
)
1306 KeWaitForSingleObject(&Event
,
1311 Status
= IoStatusBlock
.Status
;
1314 /* Remove the reference */
1315 ObDereferenceObject(TopDeviceObject
);
1317 /* Return the information */
1318 *Information
= (PVOID
)IoStatusBlock
.Information
;
1324 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject
,
1325 IN OUT PIO_STATUS_BLOCK IoStatusBlock
,
1326 IN UCHAR MinorFunction
,
1327 IN PIO_STACK_LOCATION Stack OPTIONAL
)
1329 IO_STACK_LOCATION IoStackLocation
;
1331 /* Fill out the stack information */
1332 RtlZeroMemory(&IoStackLocation
, sizeof(IO_STACK_LOCATION
));
1333 IoStackLocation
.MajorFunction
= IRP_MJ_PNP
;
1334 IoStackLocation
.MinorFunction
= MinorFunction
;
1338 RtlCopyMemory(&IoStackLocation
.Parameters
,
1340 sizeof(Stack
->Parameters
));
1343 /* Do the PnP call */
1344 IoStatusBlock
->Status
= IopSynchronousCall(DeviceObject
,
1346 (PVOID
)&IoStatusBlock
->Information
);
1347 return IoStatusBlock
->Status
;
1351 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1353 PDEVICE_NODE ParentDeviceNode
;
1354 PDEVICE_NODE ChildDeviceNode
;
1357 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1358 ParentDeviceNode
= Context
->DeviceNode
;
1360 /* Call the action routine */
1361 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
1362 if (!NT_SUCCESS(Status
))
1367 /* Traversal of all children nodes */
1368 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
1369 ChildDeviceNode
!= NULL
;
1370 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
1372 /* Pass the current device node to the action routine */
1373 Context
->DeviceNode
= ChildDeviceNode
;
1375 Status
= IopTraverseDeviceTreeNode(Context
);
1376 if (!NT_SUCCESS(Status
))
1387 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1391 DPRINT("Context 0x%p\n", Context
);
1393 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
1394 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
1396 /* Start from the specified device node */
1397 Context
->DeviceNode
= Context
->FirstDeviceNode
;
1399 /* Recursively traverse the device tree */
1400 Status
= IopTraverseDeviceTreeNode(Context
);
1401 if (Status
== STATUS_UNSUCCESSFUL
)
1403 /* The action routine just wanted to terminate the traversal with status
1404 code STATUS_SUCCESS */
1405 Status
= STATUS_SUCCESS
;
1413 * IopCreateDeviceKeyPath
1415 * Creates a registry key
1419 * Name of the key to be created.
1421 * Handle to the newly created key
1424 * This method can create nested trees, so parent of RegistryPath can
1425 * be not existant, and will be created if needed.
1429 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
1430 IN ULONG CreateOptions
,
1433 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
1434 HANDLE hParent
= NULL
, hKey
;
1435 OBJECT_ATTRIBUTES ObjectAttributes
;
1436 UNICODE_STRING KeyName
;
1437 LPCWSTR Current
, Last
;
1441 /* Assume failure */
1444 /* Create a volatile device tree in 1st stage so we have a clean slate
1445 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1446 if (ExpInTextModeSetup
) CreateOptions
|= REG_OPTION_VOLATILE
;
1448 /* Open root key for device instances */
1449 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
1450 if (!NT_SUCCESS(Status
))
1452 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
1456 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
1457 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
1459 /* Go up to the end of the string */
1460 while (Current
<= Last
)
1462 if (Current
!= Last
&& *Current
!= '\\')
1464 /* Not the end of the string and not a separator */
1469 /* Prepare relative key name */
1470 Length
= (USHORT
)((ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
);
1471 KeyName
.MaximumLength
= KeyName
.Length
= Length
;
1472 DPRINT("Create '%wZ'\n", &KeyName
);
1475 InitializeObjectAttributes(&ObjectAttributes
,
1477 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1480 Status
= ZwCreateKey(&hKey
,
1481 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
1488 /* Close parent key handle, we don't need it anymore */
1492 /* Key opening/creating failed? */
1493 if (!NT_SUCCESS(Status
))
1495 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
1499 /* Check if it is the end of the string */
1500 if (Current
== Last
)
1502 /* Yes, return success */
1504 return STATUS_SUCCESS
;
1507 /* Start with this new parent key */
1510 KeyName
.Buffer
= (LPWSTR
)Current
;
1513 return STATUS_UNSUCCESSFUL
;
1517 IopSetDeviceInstanceData(HANDLE InstanceKey
,
1518 PDEVICE_NODE DeviceNode
)
1520 OBJECT_ATTRIBUTES ObjectAttributes
;
1521 UNICODE_STRING KeyName
;
1526 HANDLE ControlHandle
;
1528 DPRINT("IopSetDeviceInstanceData() called\n");
1530 /* Create the 'LogConf' key */
1531 RtlInitUnicodeString(&KeyName
, L
"LogConf");
1532 InitializeObjectAttributes(&ObjectAttributes
,
1534 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1537 Status
= ZwCreateKey(&LogConfKey
,
1542 REG_OPTION_VOLATILE
,
1544 if (NT_SUCCESS(Status
))
1546 /* Set 'BootConfig' value */
1547 if (DeviceNode
->BootResources
!= NULL
)
1549 ResCount
= DeviceNode
->BootResources
->Count
;
1552 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
1553 Status
= ZwSetValueKey(LogConfKey
,
1557 DeviceNode
->BootResources
,
1558 PnpDetermineResourceListSize(DeviceNode
->BootResources
));
1562 /* Set 'BasicConfigVector' value */
1563 if (DeviceNode
->ResourceRequirements
!= NULL
&&
1564 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
1566 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
1567 Status
= ZwSetValueKey(LogConfKey
,
1570 REG_RESOURCE_REQUIREMENTS_LIST
,
1571 DeviceNode
->ResourceRequirements
,
1572 DeviceNode
->ResourceRequirements
->ListSize
);
1575 ZwClose(LogConfKey
);
1578 /* Set the 'ConfigFlags' value */
1579 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1580 Status
= ZwQueryValueKey(InstanceKey
,
1582 KeyValueBasicInformation
,
1586 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1588 /* Write the default value */
1589 ULONG DefaultConfigFlags
= 0;
1590 Status
= ZwSetValueKey(InstanceKey
,
1594 &DefaultConfigFlags
,
1595 sizeof(DefaultConfigFlags
));
1598 /* Create the 'Control' key */
1599 RtlInitUnicodeString(&KeyName
, L
"Control");
1600 InitializeObjectAttributes(&ObjectAttributes
,
1602 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1605 Status
= ZwCreateKey(&ControlHandle
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
1607 if (NT_SUCCESS(Status
))
1608 ZwClose(ControlHandle
);
1610 DPRINT("IopSetDeviceInstanceData() done\n");
1616 * IopGetParentIdPrefix
1618 * Retrieve (or create) a string which identifies a device.
1622 * Pointer to device node.
1624 * Pointer to the string where is returned the parent node identifier
1627 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1628 * valid and its Buffer field is NULL-terminated. The caller needs to
1629 * to free the string with RtlFreeUnicodeString when it is no longer
1634 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1635 PUNICODE_STRING ParentIdPrefix
)
1637 const UNICODE_STRING EnumKeyPath
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1638 ULONG KeyNameBufferLength
;
1639 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1640 UNICODE_STRING KeyName
= {0, 0, NULL
};
1641 UNICODE_STRING KeyValue
;
1642 UNICODE_STRING ValueName
;
1647 /* HACK: As long as some devices have a NULL device
1648 * instance path, the following test is required :(
1650 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1652 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1653 &DeviceNode
->InstancePath
);
1654 return STATUS_UNSUCCESSFUL
;
1657 /* 1. Try to retrieve ParentIdPrefix from registry */
1658 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1659 ParentIdPrefixInformation
= ExAllocatePoolWithTag(PagedPool
,
1660 KeyNameBufferLength
+ sizeof(UNICODE_NULL
),
1662 if (!ParentIdPrefixInformation
)
1664 return STATUS_INSUFFICIENT_RESOURCES
;
1668 KeyName
.MaximumLength
= EnumKeyPath
.Length
+
1669 DeviceNode
->Parent
->InstancePath
.Length
+
1670 sizeof(UNICODE_NULL
);
1671 KeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1672 KeyName
.MaximumLength
,
1674 if (!KeyName
.Buffer
)
1676 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1680 RtlCopyUnicodeString(&KeyName
, &EnumKeyPath
);
1681 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1683 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1684 if (!NT_SUCCESS(Status
))
1688 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1689 Status
= ZwQueryValueKey(hKey
,
1691 KeyValuePartialInformation
,
1692 ParentIdPrefixInformation
,
1693 KeyNameBufferLength
,
1694 &KeyNameBufferLength
);
1695 if (NT_SUCCESS(Status
))
1697 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1699 Status
= STATUS_UNSUCCESSFUL
;
1703 KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1704 KeyValue
.Length
= KeyValue
.MaximumLength
- sizeof(UNICODE_NULL
);
1705 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1706 ASSERT(KeyValue
.Buffer
[KeyValue
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
);
1710 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1712 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
1713 KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1714 KeyValue
.Length
= KeyValue
.MaximumLength
- sizeof(UNICODE_NULL
);
1715 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1716 ASSERT(KeyValue
.Buffer
[KeyValue
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
);
1720 /* 2. Create the ParentIdPrefix value */
1721 crc32
= RtlComputeCrc32(0,
1722 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1723 DeviceNode
->Parent
->InstancePath
.Length
);
1725 RtlStringCbPrintfW((PWSTR
)ParentIdPrefixInformation
,
1726 KeyNameBufferLength
,
1728 DeviceNode
->Parent
->Level
,
1730 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
);
1732 /* 3. Try to write the ParentIdPrefix to registry */
1733 Status
= ZwSetValueKey(hKey
,
1737 (PVOID
)KeyValue
.Buffer
,
1738 ((ULONG
)wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
1741 if (NT_SUCCESS(Status
))
1743 /* Duplicate the string to return it */
1744 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1748 ExFreePoolWithTag(ParentIdPrefixInformation
, TAG_IO
);
1749 RtlFreeUnicodeString(&KeyName
);
1758 IopQueryHardwareIds(PDEVICE_NODE DeviceNode
,
1761 IO_STACK_LOCATION Stack
;
1762 IO_STATUS_BLOCK IoStatusBlock
;
1764 UNICODE_STRING ValueName
;
1766 ULONG Length
, TotalLength
;
1768 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1770 RtlZeroMemory(&Stack
, sizeof(Stack
));
1771 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
1772 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1776 if (NT_SUCCESS(Status
))
1779 * FIXME: Check for valid characters, if there is invalid characters
1783 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1784 DPRINT("Hardware IDs:\n");
1787 DPRINT(" %S\n", Ptr
);
1788 Length
= (ULONG
)wcslen(Ptr
) + 1;
1791 TotalLength
+= Length
;
1793 DPRINT("TotalLength: %hu\n", TotalLength
);
1796 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
1797 Status
= ZwSetValueKey(InstanceKey
,
1801 (PVOID
)IoStatusBlock
.Information
,
1802 (TotalLength
+ 1) * sizeof(WCHAR
));
1803 if (!NT_SUCCESS(Status
))
1805 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1810 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1817 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode
,
1820 IO_STACK_LOCATION Stack
;
1821 IO_STATUS_BLOCK IoStatusBlock
;
1823 UNICODE_STRING ValueName
;
1825 ULONG Length
, TotalLength
;
1827 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1829 RtlZeroMemory(&Stack
, sizeof(Stack
));
1830 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1831 Status
= IopInitiatePnpIrp(
1832 DeviceNode
->PhysicalDeviceObject
,
1836 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1839 * FIXME: Check for valid characters, if there is invalid characters
1843 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1844 DPRINT("Compatible IDs:\n");
1847 DPRINT(" %S\n", Ptr
);
1848 Length
= (ULONG
)wcslen(Ptr
) + 1;
1851 TotalLength
+= Length
;
1853 DPRINT("TotalLength: %hu\n", TotalLength
);
1856 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
1857 Status
= ZwSetValueKey(InstanceKey
,
1861 (PVOID
)IoStatusBlock
.Information
,
1862 (TotalLength
+ 1) * sizeof(WCHAR
));
1863 if (!NT_SUCCESS(Status
))
1865 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
1870 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1877 IopCreateDeviceInstancePath(
1878 _In_ PDEVICE_NODE DeviceNode
,
1879 _Out_ PUNICODE_STRING InstancePath
)
1881 IO_STATUS_BLOCK IoStatusBlock
;
1882 UNICODE_STRING DeviceId
;
1883 UNICODE_STRING InstanceId
;
1884 IO_STACK_LOCATION Stack
;
1886 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
1887 DEVICE_CAPABILITIES DeviceCapabilities
;
1889 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1891 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
1892 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1896 if (!NT_SUCCESS(Status
))
1898 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status
);
1902 /* Save the device id string */
1903 RtlInitUnicodeString(&DeviceId
, (PWSTR
)IoStatusBlock
.Information
);
1906 * FIXME: Check for valid characters, if there is invalid characters
1910 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1912 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
1913 if (!NT_SUCCESS(Status
))
1915 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status
);
1916 RtlFreeUnicodeString(&DeviceId
);
1920 /* This bit is only check after enumeration */
1921 if (DeviceCapabilities
.HardwareDisabled
)
1923 /* FIXME: Cleanup device */
1924 DeviceNode
->Flags
|= DNF_DISABLED
;
1925 RtlFreeUnicodeString(&DeviceId
);
1926 return STATUS_PLUGPLAY_NO_DEVICE
;
1930 DeviceNode
->Flags
&= ~DNF_DISABLED
;
1933 if (!DeviceCapabilities
.UniqueID
)
1935 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1936 DPRINT("Instance ID is not unique\n");
1937 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
1938 if (!NT_SUCCESS(Status
))
1940 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
1941 RtlFreeUnicodeString(&DeviceId
);
1946 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1948 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
1949 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1953 if (!NT_SUCCESS(Status
))
1955 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status
);
1956 ASSERT(IoStatusBlock
.Information
== 0);
1959 RtlInitUnicodeString(&InstanceId
,
1960 (PWSTR
)IoStatusBlock
.Information
);
1962 InstancePath
->Length
= 0;
1963 InstancePath
->MaximumLength
= DeviceId
.Length
+ sizeof(WCHAR
) +
1964 ParentIdPrefix
.Length
+
1966 sizeof(UNICODE_NULL
);
1967 if (ParentIdPrefix
.Length
&& InstanceId
.Length
)
1969 InstancePath
->MaximumLength
+= sizeof(WCHAR
);
1972 InstancePath
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
1973 InstancePath
->MaximumLength
,
1975 if (!InstancePath
->Buffer
)
1977 RtlFreeUnicodeString(&InstanceId
);
1978 RtlFreeUnicodeString(&ParentIdPrefix
);
1979 RtlFreeUnicodeString(&DeviceId
);
1980 return STATUS_INSUFFICIENT_RESOURCES
;
1983 /* Start with the device id */
1984 RtlCopyUnicodeString(InstancePath
, &DeviceId
);
1985 RtlAppendUnicodeToString(InstancePath
, L
"\\");
1987 /* Add information from parent bus device to InstancePath */
1988 RtlAppendUnicodeStringToString(InstancePath
, &ParentIdPrefix
);
1989 if (ParentIdPrefix
.Length
&& InstanceId
.Length
)
1991 RtlAppendUnicodeToString(InstancePath
, L
"&");
1994 /* Finally, add the id returned by the driver stack */
1995 RtlAppendUnicodeStringToString(InstancePath
, &InstanceId
);
1998 * FIXME: Check for valid characters, if there is invalid characters
2002 RtlFreeUnicodeString(&InstanceId
);
2003 RtlFreeUnicodeString(&DeviceId
);
2004 RtlFreeUnicodeString(&ParentIdPrefix
);
2006 return STATUS_SUCCESS
;
2011 * IopActionInterrogateDeviceStack
2013 * Retrieve information for all (direct) child nodes of a parent node.
2017 * Pointer to device node.
2019 * Pointer to parent node to retrieve child node information for.
2022 * Any errors that occur are logged instead so that all child services have a chance
2023 * of being interrogated.
2027 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
2030 IO_STATUS_BLOCK IoStatusBlock
;
2031 PWSTR DeviceDescription
;
2032 PWSTR LocationInformation
;
2033 PDEVICE_NODE ParentDeviceNode
;
2034 IO_STACK_LOCATION Stack
;
2036 ULONG RequiredLength
;
2038 HANDLE InstanceKey
= NULL
;
2039 UNICODE_STRING ValueName
;
2040 UNICODE_STRING InstancePathU
;
2041 PDEVICE_OBJECT OldDeviceObject
;
2043 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
2044 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
2046 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2049 * We are called for the parent too, but we don't need to do special
2050 * handling for this node
2052 if (DeviceNode
== ParentDeviceNode
)
2054 DPRINT("Success\n");
2055 return STATUS_SUCCESS
;
2059 * Make sure this device node is a direct child of the parent device node
2060 * that is given as an argument
2062 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2064 DPRINT("Skipping 2+ level child\n");
2065 return STATUS_SUCCESS
;
2068 /* Skip processing if it was already completed before */
2069 if (DeviceNode
->Flags
& DNF_PROCESSED
)
2072 return STATUS_SUCCESS
;
2076 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
2077 if (!NT_SUCCESS(Status
))
2079 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
2084 * FIXME: For critical errors, cleanup and disable device, but always
2085 * return STATUS_SUCCESS.
2088 Status
= IopCreateDeviceInstancePath(DeviceNode
, &InstancePathU
);
2089 if (!NT_SUCCESS(Status
))
2091 if (Status
!= STATUS_PLUGPLAY_NO_DEVICE
)
2093 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status
);
2096 /* We have to return success otherwise we abort the traverse operation */
2097 return STATUS_SUCCESS
;
2100 /* Verify that this is not a duplicate */
2101 OldDeviceObject
= IopGetDeviceObjectFromDeviceInstance(&InstancePathU
);
2102 if (OldDeviceObject
!= NULL
)
2104 PDEVICE_NODE OldDeviceNode
= IopGetDeviceNode(OldDeviceObject
);
2106 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU
);
2107 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode
->Parent
->InstancePath
);
2108 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode
->Parent
->InstancePath
);
2110 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR
,
2112 (ULONG_PTR
)DeviceNode
->PhysicalDeviceObject
,
2113 (ULONG_PTR
)OldDeviceObject
,
2117 DeviceNode
->InstancePath
= InstancePathU
;
2119 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
2122 * Create registry key for the instance id, if it doesn't exist yet
2124 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
2125 if (!NT_SUCCESS(Status
))
2127 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2129 /* We have to return success otherwise we abort the traverse operation */
2130 return STATUS_SUCCESS
;
2133 IopQueryHardwareIds(DeviceNode
, InstanceKey
);
2135 IopQueryCompatibleIds(DeviceNode
, InstanceKey
);
2137 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2139 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2140 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2141 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2143 IRP_MN_QUERY_DEVICE_TEXT
,
2145 DeviceDescription
= NT_SUCCESS(Status
) ? (PWSTR
)IoStatusBlock
.Information
2147 /* This key is mandatory, so even if the Irp fails, we still write it */
2148 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2149 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2151 if (DeviceDescription
&&
2152 *DeviceDescription
!= UNICODE_NULL
)
2154 /* This key is overriden when a driver is installed. Don't write the
2155 * new description if another one already exists */
2156 Status
= ZwSetValueKey(InstanceKey
,
2161 ((ULONG
)wcslen(DeviceDescription
) + 1) * sizeof(WCHAR
));
2165 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2166 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2168 Status
= ZwSetValueKey(InstanceKey
,
2173 DeviceDesc
.MaximumLength
);
2174 if (!NT_SUCCESS(Status
))
2176 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2182 if (DeviceDescription
)
2184 ExFreePoolWithTag(DeviceDescription
, 0);
2187 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2189 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2190 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2191 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2193 IRP_MN_QUERY_DEVICE_TEXT
,
2195 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2197 LocationInformation
= (PWSTR
)IoStatusBlock
.Information
;
2198 DPRINT("LocationInformation: %S\n", LocationInformation
);
2199 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2200 Status
= ZwSetValueKey(InstanceKey
,
2204 LocationInformation
,
2205 ((ULONG
)wcslen(LocationInformation
) + 1) * sizeof(WCHAR
));
2206 if (!NT_SUCCESS(Status
))
2208 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2211 ExFreePoolWithTag(LocationInformation
, 0);
2215 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2218 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2220 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2222 IRP_MN_QUERY_BUS_INFORMATION
,
2224 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2226 PPNP_BUS_INFORMATION BusInformation
= (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2228 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2229 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2230 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2231 ExFreePoolWithTag(BusInformation
, 0);
2235 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2237 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2238 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2239 DeviceNode
->ChildBusTypeIndex
= -1;
2242 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2244 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2246 IRP_MN_QUERY_RESOURCES
,
2248 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2250 DeviceNode
->BootResources
= (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2251 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
2255 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2256 DeviceNode
->BootResources
= NULL
;
2259 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2261 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2263 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2265 if (NT_SUCCESS(Status
))
2267 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2271 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2272 DeviceNode
->ResourceRequirements
= NULL
;
2275 if (InstanceKey
!= NULL
)
2277 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2280 ZwClose(InstanceKey
);
2282 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2284 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2286 /* Report the device to the user-mode pnp manager */
2287 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2288 &DeviceNode
->InstancePath
);
2291 return STATUS_SUCCESS
;
2296 IopHandleDeviceRemoval(
2297 IN PDEVICE_NODE DeviceNode
,
2298 IN PDEVICE_RELATIONS DeviceRelations
)
2300 PDEVICE_NODE Child
= DeviceNode
->Child
, NextChild
;
2304 if (DeviceNode
== IopRootDeviceNode
)
2307 while (Child
!= NULL
)
2309 NextChild
= Child
->Sibling
;
2312 for (i
= 0; DeviceRelations
&& i
< DeviceRelations
->Count
; i
++)
2314 if (IopGetDeviceNode(DeviceRelations
->Objects
[i
]) == Child
)
2321 if (!Found
&& !(Child
->Flags
& DNF_WILL_BE_REMOVED
))
2323 /* Send removal IRPs to all of its children */
2324 IopPrepareDeviceForRemoval(Child
->PhysicalDeviceObject
, TRUE
);
2326 /* Send the surprise removal IRP */
2327 IopSendSurpriseRemoval(Child
->PhysicalDeviceObject
);
2329 /* Tell the user-mode PnP manager that a device was removed */
2330 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
2331 &Child
->InstancePath
);
2333 /* Send the remove device IRP */
2334 IopSendRemoveDevice(Child
->PhysicalDeviceObject
);
2343 IN PDEVICE_OBJECT DeviceObject
)
2345 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2346 DEVICETREE_TRAVERSE_CONTEXT Context
;
2347 PDEVICE_RELATIONS DeviceRelations
;
2348 PDEVICE_OBJECT ChildDeviceObject
;
2349 IO_STATUS_BLOCK IoStatusBlock
;
2350 PDEVICE_NODE ChildDeviceNode
;
2351 IO_STACK_LOCATION Stack
;
2355 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2357 if (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
)
2359 DeviceNode
->Flags
&= ~DNF_NEED_ENUMERATION_ONLY
;
2361 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2362 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2363 &DeviceNode
->InstancePath
);
2366 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2368 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2370 Status
= IopInitiatePnpIrp(
2373 IRP_MN_QUERY_DEVICE_RELATIONS
,
2375 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2377 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2381 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2384 * Send removal IRPs for devices that have disappeared
2385 * NOTE: This code handles the case where no relations are specified
2387 IopHandleDeviceRemoval(DeviceNode
, DeviceRelations
);
2389 /* Now we bail if nothing was returned */
2390 if (!DeviceRelations
)
2392 /* We're all done */
2393 DPRINT("No PDOs\n");
2394 return STATUS_SUCCESS
;
2397 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2400 * Create device nodes for all discovered devices
2402 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2404 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2405 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2407 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2408 if (!ChildDeviceNode
)
2410 /* One doesn't exist, create it */
2411 Status
= IopCreateDeviceNode(
2416 if (NT_SUCCESS(Status
))
2418 /* Mark the node as enumerated */
2419 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2421 /* Mark the DO as bus enumerated */
2422 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2426 /* Ignore this DO */
2427 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2428 ObDereferenceObject(ChildDeviceObject
);
2433 /* Mark it as enumerated */
2434 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2435 ObDereferenceObject(ChildDeviceObject
);
2438 ExFreePool(DeviceRelations
);
2441 * Retrieve information about all discovered children from the bus driver
2443 IopInitDeviceTreeTraverseContext(
2446 IopActionInterrogateDeviceStack
,
2449 Status
= IopTraverseDeviceTree(&Context
);
2450 if (!NT_SUCCESS(Status
))
2452 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2457 * Retrieve configuration from the registry for discovered children
2459 IopInitDeviceTreeTraverseContext(
2462 IopActionConfigureChildServices
,
2465 Status
= IopTraverseDeviceTree(&Context
);
2466 if (!NT_SUCCESS(Status
))
2468 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2473 * Initialize services for discovered children.
2475 Status
= IopInitializePnpServices(DeviceNode
);
2476 if (!NT_SUCCESS(Status
))
2478 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2482 DPRINT("IopEnumerateDevice() finished\n");
2483 return STATUS_SUCCESS
;
2488 * IopActionConfigureChildServices
2490 * Retrieve configuration for all (direct) child nodes of a parent node.
2494 * Pointer to device node.
2496 * Pointer to parent node to retrieve child node configuration for.
2499 * Any errors that occur are logged instead so that all child services have a chance of beeing
2504 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2507 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2508 PDEVICE_NODE ParentDeviceNode
;
2509 PUNICODE_STRING Service
;
2510 UNICODE_STRING ClassGUID
;
2512 DEVICE_CAPABILITIES DeviceCaps
;
2514 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2516 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2519 * We are called for the parent too, but we don't need to do special
2520 * handling for this node
2522 if (DeviceNode
== ParentDeviceNode
)
2524 DPRINT("Success\n");
2525 return STATUS_SUCCESS
;
2529 * Make sure this device node is a direct child of the parent device node
2530 * that is given as an argument
2533 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2535 DPRINT("Skipping 2+ level child\n");
2536 return STATUS_SUCCESS
;
2539 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2541 DPRINT1("Child not ready to be configured\n");
2542 return STATUS_SUCCESS
;
2545 if (!(DeviceNode
->Flags
& (DNF_DISABLED
| DNF_STARTED
| DNF_ADDED
)))
2547 WCHAR RegKeyBuffer
[MAX_PATH
];
2548 UNICODE_STRING RegKey
;
2550 /* Install the service for this if it's in the CDDB */
2551 IopInstallCriticalDevice(DeviceNode
);
2554 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2555 RegKey
.Buffer
= RegKeyBuffer
;
2558 * Retrieve configuration from Enum key
2561 Service
= &DeviceNode
->ServiceName
;
2563 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2564 RtlInitUnicodeString(Service
, NULL
);
2565 RtlInitUnicodeString(&ClassGUID
, NULL
);
2567 QueryTable
[0].Name
= L
"Service";
2568 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2569 QueryTable
[0].EntryContext
= Service
;
2571 QueryTable
[1].Name
= L
"ClassGUID";
2572 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2573 QueryTable
[1].EntryContext
= &ClassGUID
;
2574 QueryTable
[1].DefaultType
= REG_SZ
;
2575 QueryTable
[1].DefaultData
= L
"";
2576 QueryTable
[1].DefaultLength
= 0;
2578 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2579 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2581 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2582 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2584 if (!NT_SUCCESS(Status
))
2586 /* FIXME: Log the error */
2587 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2588 &DeviceNode
->InstancePath
, Status
);
2589 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2590 return STATUS_SUCCESS
;
2593 if (Service
->Buffer
== NULL
)
2595 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2596 DeviceCaps
.RawDeviceOK
)
2598 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2600 DeviceNode
->ServiceName
.Length
= 0;
2601 DeviceNode
->ServiceName
.MaximumLength
= 0;
2602 DeviceNode
->ServiceName
.Buffer
= NULL
;
2604 else if (ClassGUID
.Length
!= 0)
2606 /* Device has a ClassGUID value, but no Service value.
2607 * Suppose it is using the NULL driver, so state the
2608 * device is started */
2609 DPRINT("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2610 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2614 DeviceNode
->Problem
= CM_PROB_FAILED_INSTALL
;
2615 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2617 return STATUS_SUCCESS
;
2620 DPRINT("Got Service %S\n", Service
->Buffer
);
2623 return STATUS_SUCCESS
;
2627 * IopActionInitChildServices
2629 * Initialize the service for all (direct) child nodes of a parent node
2633 * Pointer to device node.
2635 * Pointer to parent node to initialize child node services for.
2638 * If the driver image for a service is not loaded and initialized
2639 * it is done here too. Any errors that occur are logged instead so
2640 * that all child services have a chance of being initialized.
2644 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2647 PDEVICE_NODE ParentDeviceNode
;
2649 BOOLEAN BootDrivers
= !PnpSystemInit
;
2651 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2653 ParentDeviceNode
= Context
;
2656 * We are called for the parent too, but we don't need to do special
2657 * handling for this node
2659 if (DeviceNode
== ParentDeviceNode
)
2661 DPRINT("Success\n");
2662 return STATUS_SUCCESS
;
2666 * We don't want to check for a direct child because
2667 * this function is called during boot to reinitialize
2668 * devices with drivers that couldn't load yet due to
2669 * stage 0 limitations (ie can't load from disk yet).
2672 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2674 DPRINT1("Child not ready to be added\n");
2675 return STATUS_SUCCESS
;
2678 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
) ||
2679 IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) ||
2680 IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2681 return STATUS_SUCCESS
;
2683 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
2685 /* We don't need to worry about loading the driver because we're
2686 * being driven in raw mode so our parent must be loaded to get here */
2687 Status
= IopInitializeDevice(DeviceNode
, NULL
);
2688 if (NT_SUCCESS(Status
))
2690 Status
= IopStartDevice(DeviceNode
);
2691 if (!NT_SUCCESS(Status
))
2693 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2694 &DeviceNode
->InstancePath
, Status
);
2700 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2701 PDRIVER_OBJECT DriverObject
;
2703 KeEnterCriticalRegion();
2704 ExAcquireResourceExclusiveLite(&IopDriverLoadResource
, TRUE
);
2705 /* Get existing DriverObject pointer (in case the driver has
2706 already been loaded and initialized) */
2707 Status
= IopGetDriverObject(
2709 &DeviceNode
->ServiceName
,
2712 if (!NT_SUCCESS(Status
))
2714 /* Driver is not initialized, try to load it */
2715 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2717 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2719 /* Initialize the driver */
2720 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2721 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2722 if (!NT_SUCCESS(Status
)) DeviceNode
->Problem
= CM_PROB_FAILED_DRIVER_ENTRY
;
2724 else if (Status
== STATUS_DRIVER_UNABLE_TO_LOAD
)
2726 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode
->ServiceName
);
2727 DeviceNode
->Problem
= CM_PROB_DISABLED_SERVICE
;
2731 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2732 &DeviceNode
->ServiceName
, Status
);
2733 if (!BootDrivers
) DeviceNode
->Problem
= CM_PROB_DRIVER_FAILED_LOAD
;
2736 ExReleaseResourceLite(&IopDriverLoadResource
);
2737 KeLeaveCriticalRegion();
2739 /* Driver is loaded and initialized at this point */
2740 if (NT_SUCCESS(Status
))
2742 /* Initialize the device, including all filters */
2743 Status
= PipCallDriverAddDevice(DeviceNode
, FALSE
, DriverObject
);
2745 /* Remove the extra reference */
2746 ObDereferenceObject(DriverObject
);
2751 * Don't disable when trying to load only boot drivers
2755 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2760 return STATUS_SUCCESS
;
2764 * IopInitializePnpServices
2766 * Initialize services for discovered children
2770 * Top device node to start initializing services.
2776 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2778 DEVICETREE_TRAVERSE_CONTEXT Context
;
2780 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2782 IopInitDeviceTreeTraverseContext(
2785 IopActionInitChildServices
,
2788 return IopTraverseDeviceTree(&Context
);
2791 static NTSTATUS INIT_FUNCTION
2792 IopEnumerateDetectedDevices(
2794 IN PUNICODE_STRING RelativePath OPTIONAL
,
2796 IN BOOLEAN EnumerateSubKeys
,
2797 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2798 IN ULONG ParentBootResourcesLength
)
2800 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2801 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2802 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2803 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2804 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2805 OBJECT_ATTRIBUTES ObjectAttributes
;
2806 HANDLE hDevicesKey
= NULL
;
2807 HANDLE hDeviceKey
= NULL
;
2808 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2809 UNICODE_STRING Level2NameU
;
2810 WCHAR Level2Name
[5];
2811 ULONG IndexDevice
= 0;
2813 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2814 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2815 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2816 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2817 UNICODE_STRING DeviceName
, ValueName
;
2819 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2820 ULONG BootResourcesLength
;
2823 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2824 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2825 static ULONG DeviceIndexSerial
= 0;
2826 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2827 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2828 static ULONG DeviceIndexKeyboard
= 0;
2829 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2830 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2831 static ULONG DeviceIndexMouse
= 0;
2832 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
2833 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
2834 static ULONG DeviceIndexParallel
= 0;
2835 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
2836 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
2837 static ULONG DeviceIndexFloppy
= 0;
2838 UNICODE_STRING HardwareIdKey
;
2839 PUNICODE_STRING pHardwareId
;
2840 ULONG DeviceIndex
= 0;
2841 PUCHAR CmResourceList
;
2846 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
2847 if (!NT_SUCCESS(Status
))
2849 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2854 hDevicesKey
= hBaseKey
;
2856 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2857 if (!pDeviceInformation
)
2859 DPRINT("ExAllocatePool() failed\n");
2860 Status
= STATUS_NO_MEMORY
;
2864 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2865 if (!pValueInformation
)
2867 DPRINT("ExAllocatePool() failed\n");
2868 Status
= STATUS_NO_MEMORY
;
2874 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2875 if (Status
== STATUS_NO_MORE_ENTRIES
)
2877 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2879 ExFreePool(pDeviceInformation
);
2880 DeviceInfoLength
= RequiredSize
;
2881 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2882 if (!pDeviceInformation
)
2884 DPRINT("ExAllocatePool() failed\n");
2885 Status
= STATUS_NO_MEMORY
;
2888 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2890 if (!NT_SUCCESS(Status
))
2892 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2897 /* Open device key */
2898 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2899 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2901 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
2902 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
2903 if (!NT_SUCCESS(Status
))
2905 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2909 /* Read boot resources, and add then to parent ones */
2910 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2911 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2913 ExFreePool(pValueInformation
);
2914 ValueInfoLength
= RequiredSize
;
2915 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2916 if (!pValueInformation
)
2918 DPRINT("ExAllocatePool() failed\n");
2919 ZwDeleteKey(hLevel2Key
);
2920 Status
= STATUS_NO_MEMORY
;
2923 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2925 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
2927 BootResources
= ParentBootResources
;
2928 BootResourcesLength
= ParentBootResourcesLength
;
2930 else if (!NT_SUCCESS(Status
))
2932 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2935 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
2937 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
2942 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
2944 /* Concatenate current resources and parent ones */
2945 if (ParentBootResourcesLength
== 0)
2946 BootResourcesLength
= pValueInformation
->DataLength
;
2948 BootResourcesLength
= ParentBootResourcesLength
2949 + pValueInformation
->DataLength
2951 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
2954 DPRINT("ExAllocatePool() failed\n");
2957 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
2959 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2961 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
2963 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2965 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
2966 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2967 ParentBootResourcesLength
- Header
);
2968 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2972 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
2974 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
2975 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2976 ParentBootResourcesLength
- Header
);
2978 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
2979 pValueInformation
->Data
+ Header
,
2980 pValueInformation
->DataLength
- Header
);
2981 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2985 if (EnumerateSubKeys
)
2990 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2991 if (Status
== STATUS_NO_MORE_ENTRIES
)
2993 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2995 ExFreePool(pDeviceInformation
);
2996 DeviceInfoLength
= RequiredSize
;
2997 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2998 if (!pDeviceInformation
)
3000 DPRINT("ExAllocatePool() failed\n");
3001 Status
= STATUS_NO_MEMORY
;
3004 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3006 if (!NT_SUCCESS(Status
))
3008 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3012 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3013 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3015 Status
= IopEnumerateDetectedDevices(
3021 BootResourcesLength
);
3022 if (!NT_SUCCESS(Status
))
3027 /* Read identifier */
3028 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3029 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3031 ExFreePool(pValueInformation
);
3032 ValueInfoLength
= RequiredSize
;
3033 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3034 if (!pValueInformation
)
3036 DPRINT("ExAllocatePool() failed\n");
3037 Status
= STATUS_NO_MEMORY
;
3040 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3042 if (!NT_SUCCESS(Status
))
3044 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
3046 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3049 ValueName
.Length
= ValueName
.MaximumLength
= 0;
3051 else if (pValueInformation
->Type
!= REG_SZ
)
3053 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
3058 /* Assign hardware id to this device */
3059 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
3060 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
3061 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
3062 ValueName
.Length
-= sizeof(WCHAR
);
3065 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
3067 pHardwareId
= &HardwareIdSerial
;
3068 DeviceIndex
= DeviceIndexSerial
++;
3070 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
3072 pHardwareId
= &HardwareIdKeyboard
;
3073 DeviceIndex
= DeviceIndexKeyboard
++;
3075 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
3077 pHardwareId
= &HardwareIdMouse
;
3078 DeviceIndex
= DeviceIndexMouse
++;
3080 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
3082 pHardwareId
= &HardwareIdParallel
;
3083 DeviceIndex
= DeviceIndexParallel
++;
3085 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
3087 pHardwareId
= &HardwareIdFloppy
;
3088 DeviceIndex
= DeviceIndexFloppy
++;
3092 /* Unknown key path */
3093 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
3097 /* Prepare hardware id key (hardware id value without final \0) */
3098 HardwareIdKey
= *pHardwareId
;
3099 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
3101 /* Add the detected device to Root key */
3102 InitializeObjectAttributes(&ObjectAttributes
, &HardwareIdKey
, OBJ_KERNEL_HANDLE
, hRootKey
, NULL
);
3103 Status
= ZwCreateKey(
3109 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
3111 if (!NT_SUCCESS(Status
))
3113 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3116 swprintf(Level2Name
, L
"%04lu", DeviceIndex
);
3117 RtlInitUnicodeString(&Level2NameU
, Level2Name
);
3118 InitializeObjectAttributes(&ObjectAttributes
, &Level2NameU
, OBJ_KERNEL_HANDLE
, hLevel1Key
, NULL
);
3119 Status
= ZwCreateKey(
3121 KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
,
3125 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
3127 ZwClose(hLevel1Key
);
3128 if (!NT_SUCCESS(Status
))
3130 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3133 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName
, DeviceIndex
, &HardwareIdKey
);
3134 Status
= ZwSetValueKey(hLevel2Key
, &HardwareIDU
, 0, REG_MULTI_SZ
, pHardwareId
->Buffer
, pHardwareId
->MaximumLength
);
3135 if (!NT_SUCCESS(Status
))
3137 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3138 ZwDeleteKey(hLevel2Key
);
3141 /* Create 'LogConf' subkey */
3142 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
, hLevel2Key
, NULL
);
3143 Status
= ZwCreateKey(
3149 REG_OPTION_VOLATILE
,
3151 if (!NT_SUCCESS(Status
))
3153 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3154 ZwDeleteKey(hLevel2Key
);
3157 if (BootResourcesLength
>= sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3159 CmResourceList
= ExAllocatePool(PagedPool
, BootResourcesLength
+ sizeof(ULONG
));
3160 if (!CmResourceList
)
3163 ZwDeleteKey(hLevel2Key
);
3167 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3169 RtlCopyMemory(CmResourceList
,
3173 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3174 RtlCopyMemory(CmResourceList
+ sizeof(ULONG
),
3176 BootResourcesLength
);
3178 /* Save boot resources to 'LogConf\BootConfig' */
3179 Status
= ZwSetValueKey(hLogConf
, &BootConfigU
, 0, REG_RESOURCE_LIST
, CmResourceList
, BootResourcesLength
+ sizeof(ULONG
));
3180 if (!NT_SUCCESS(Status
))
3182 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3184 ZwDeleteKey(hLevel2Key
);
3191 if (BootResources
&& BootResources
!= ParentBootResources
)
3193 ExFreePool(BootResources
);
3194 BootResources
= NULL
;
3198 ZwClose(hLevel2Key
);
3203 ZwClose(hDeviceKey
);
3208 Status
= STATUS_SUCCESS
;
3211 if (hDevicesKey
&& hDevicesKey
!= hBaseKey
)
3212 ZwClose(hDevicesKey
);
3214 ZwClose(hDeviceKey
);
3215 if (pDeviceInformation
)
3216 ExFreePool(pDeviceInformation
);
3217 if (pValueInformation
)
3218 ExFreePool(pValueInformation
);
3222 static BOOLEAN INIT_FUNCTION
3223 IopIsFirmwareMapperDisabled(VOID
)
3225 UNICODE_STRING KeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3226 UNICODE_STRING KeyNameU
= RTL_CONSTANT_STRING(L
"DisableFirmwareMapper");
3227 OBJECT_ATTRIBUTES ObjectAttributes
;
3229 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
;
3230 ULONG DesiredLength
, Length
;
3234 InitializeObjectAttributes(&ObjectAttributes
, &KeyPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3235 Status
= ZwOpenKey(&hPnpKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
3236 if (NT_SUCCESS(Status
))
3238 Status
= ZwQueryValueKey(hPnpKey
,
3240 KeyValuePartialInformation
,
3244 if ((Status
== STATUS_BUFFER_TOO_SMALL
) ||
3245 (Status
== STATUS_BUFFER_OVERFLOW
))
3247 Length
= DesiredLength
;
3248 KeyInformation
= ExAllocatePool(PagedPool
, Length
);
3251 Status
= ZwQueryValueKey(hPnpKey
,
3253 KeyValuePartialInformation
,
3257 if (NT_SUCCESS(Status
) && KeyInformation
->DataLength
== sizeof(ULONG
))
3259 KeyValue
= (ULONG
)(*KeyInformation
->Data
);
3263 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU
, &KeyNameU
);
3266 ExFreePool(KeyInformation
);
3270 DPRINT1("Failed to allocate memory for registry query\n");
3275 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU
, &KeyNameU
, Status
);
3282 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU
, Status
);
3285 DPRINT("Firmware mapper is %s\n", KeyValue
!= 0 ? "disabled" : "enabled");
3287 return (KeyValue
!= 0) ? TRUE
: FALSE
;
3293 IopUpdateRootKey(VOID
)
3295 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3296 UNICODE_STRING RootPathU
= RTL_CONSTANT_STRING(L
"Root");
3297 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3298 OBJECT_ATTRIBUTES ObjectAttributes
;
3299 HANDLE hEnum
, hRoot
;
3302 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3303 Status
= ZwCreateKey(&hEnum
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
3304 if (!NT_SUCCESS(Status
))
3306 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3310 InitializeObjectAttributes(&ObjectAttributes
, &RootPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
3311 Status
= ZwCreateKey(&hRoot
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
3313 if (!NT_SUCCESS(Status
))
3315 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3319 if (!IopIsFirmwareMapperDisabled())
3321 Status
= IopOpenRegistryKeyEx(&hEnum
, NULL
, &MultiKeyPathU
, KEY_ENUMERATE_SUB_KEYS
);
3322 if (!NT_SUCCESS(Status
))
3324 /* Nothing to do, don't return with an error status */
3325 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3327 return STATUS_SUCCESS
;
3329 Status
= IopEnumerateDetectedDevices(
3340 /* Enumeration is disabled */
3341 Status
= STATUS_SUCCESS
;
3351 IopOpenRegistryKeyEx(PHANDLE KeyHandle
,
3353 PUNICODE_STRING Name
,
3354 ACCESS_MASK DesiredAccess
)
3356 OBJECT_ATTRIBUTES ObjectAttributes
;
3363 InitializeObjectAttributes(&ObjectAttributes
,
3365 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3369 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
3376 IopCreateRegistryKeyEx(OUT PHANDLE Handle
,
3377 IN HANDLE RootHandle OPTIONAL
,
3378 IN PUNICODE_STRING KeyName
,
3379 IN ACCESS_MASK DesiredAccess
,
3380 IN ULONG CreateOptions
,
3381 OUT PULONG Disposition OPTIONAL
)
3383 OBJECT_ATTRIBUTES ObjectAttributes
;
3384 ULONG KeyDisposition
, RootHandleIndex
= 0, i
= 1, NestedCloseLevel
= 0;
3386 HANDLE HandleArray
[2];
3387 BOOLEAN Recursing
= TRUE
;
3389 UNICODE_STRING KeyString
;
3390 NTSTATUS Status
= STATUS_SUCCESS
;
3393 /* P1 is start, pp is end */
3394 p1
= KeyName
->Buffer
;
3395 pp
= (PVOID
)((ULONG_PTR
)p1
+ KeyName
->Length
);
3397 /* Create the target key */
3398 InitializeObjectAttributes(&ObjectAttributes
,
3400 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3403 Status
= ZwCreateKey(&HandleArray
[i
],
3411 /* Now we check if this failed */
3412 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) && (RootHandle
))
3414 /* Target key failed, so we'll need to create its parent. Setup array */
3415 HandleArray
[0] = NULL
;
3416 HandleArray
[1] = RootHandle
;
3418 /* Keep recursing for each missing parent */
3421 /* And if we're deep enough, close the last handle */
3422 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3424 /* We're setup to ping-pong between the two handle array entries */
3425 RootHandleIndex
= i
;
3428 /* Clear the one we're attempting to open now */
3429 HandleArray
[i
] = NULL
;
3431 /* Process the parent key name */
3432 for (p
= p1
; ((p
< pp
) && (*p
!= OBJ_NAME_PATH_SEPARATOR
)); p
++);
3433 Length
= (USHORT
)(p
- p1
) * sizeof(WCHAR
);
3435 /* Is there a parent name? */
3438 /* Build the unicode string for it */
3439 KeyString
.Buffer
= p1
;
3440 KeyString
.Length
= KeyString
.MaximumLength
= Length
;
3442 /* Now try opening the parent */
3443 InitializeObjectAttributes(&ObjectAttributes
,
3445 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3446 HandleArray
[RootHandleIndex
],
3448 Status
= ZwCreateKey(&HandleArray
[i
],
3455 if (NT_SUCCESS(Status
))
3457 /* It worked, we have one more handle */
3462 /* Parent key creation failed, abandon loop */
3469 /* We don't have a parent name, probably corrupted key name */
3470 Status
= STATUS_INVALID_PARAMETER
;
3475 /* Now see if there's more parents to create */
3477 if ((p
== pp
) || (p1
== pp
))
3479 /* We're done, hopefully successfully, so stop */
3484 /* Outer loop check for handle nesting that requires closing the top handle */
3485 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3488 /* Check if we broke out of the loop due to success */
3489 if (NT_SUCCESS(Status
))
3491 /* Return the target handle (we closed all the parent ones) and disposition */
3492 *Handle
= HandleArray
[i
];
3493 if (Disposition
) *Disposition
= KeyDisposition
;
3496 /* Return the success state */
3502 IopGetRegistryValue(IN HANDLE Handle
,
3504 OUT PKEY_VALUE_FULL_INFORMATION
*Information
)
3506 UNICODE_STRING ValueString
;
3508 PKEY_VALUE_FULL_INFORMATION FullInformation
;
3512 RtlInitUnicodeString(&ValueString
, ValueName
);
3514 Status
= ZwQueryValueKey(Handle
,
3516 KeyValueFullInformation
,
3520 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
3521 (Status
!= STATUS_BUFFER_TOO_SMALL
))
3526 FullInformation
= ExAllocatePool(NonPagedPool
, Size
);
3527 if (!FullInformation
) return STATUS_INSUFFICIENT_RESOURCES
;
3529 Status
= ZwQueryValueKey(Handle
,
3531 KeyValueFullInformation
,
3535 if (!NT_SUCCESS(Status
))
3537 ExFreePool(FullInformation
);
3541 *Information
= FullInformation
;
3542 return STATUS_SUCCESS
;
3545 RTL_GENERIC_COMPARE_RESULTS
3547 PiCompareInstancePath(IN PRTL_AVL_TABLE Table
,
3548 IN PVOID FirstStruct
,
3549 IN PVOID SecondStruct
)
3557 // The allocation function is called by the generic table package whenever
3558 // it needs to allocate memory for the table.
3563 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3573 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3582 PpInitializeDeviceReferenceTable(VOID
)
3584 /* Setup the guarded mutex and AVL table */
3585 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock
);
3586 RtlInitializeGenericTableAvl(
3587 &PpDeviceReferenceTable
,
3588 (PRTL_AVL_COMPARE_ROUTINE
)PiCompareInstancePath
,
3589 (PRTL_AVL_ALLOCATE_ROUTINE
)PiAllocateGenericTableEntry
,
3590 (PRTL_AVL_FREE_ROUTINE
)PiFreeGenericTableEntry
,
3598 /* Initialize the resource when accessing device registry data */
3599 ExInitializeResourceLite(&PpRegistryDeviceResource
);
3601 /* Setup the device reference AVL table */
3602 PpInitializeDeviceReferenceTable();
3610 /* Check the initialization phase */
3611 switch (ExpInitializationPhase
)
3616 return PiInitPhase0();
3622 //return PiInitPhase1();
3626 /* Don't know any other phase! Bugcheck! */
3627 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL
);
3632 LONG IopNumberDeviceNodes
;
3636 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3638 PDEVICE_NODE DeviceNode
;
3642 DeviceNode
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), TAG_IO_DEVNODE
);
3643 if (!DeviceNode
) return DeviceNode
;
3646 InterlockedIncrement(&IopNumberDeviceNodes
);
3649 RtlZeroMemory(DeviceNode
, sizeof(DEVICE_NODE
));
3650 DeviceNode
->InterfaceType
= InterfaceTypeUndefined
;
3651 DeviceNode
->BusNumber
= -1;
3652 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
3653 DeviceNode
->ChildBusNumber
= -1;
3654 DeviceNode
->ChildBusTypeIndex
= -1;
3655 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3656 InitializeListHead(&DeviceNode
->DeviceArbiterList
);
3657 InitializeListHead(&DeviceNode
->DeviceTranslatorList
);
3658 InitializeListHead(&DeviceNode
->TargetDeviceNotify
);
3659 InitializeListHead(&DeviceNode
->DockInfo
.ListEntry
);
3660 InitializeListHead(&DeviceNode
->PendedSetInterfaceState
);
3662 /* Check if there is a PDO */
3663 if (PhysicalDeviceObject
)
3665 /* Link it and remove the init flag */
3666 DeviceNode
->PhysicalDeviceObject
= PhysicalDeviceObject
;
3667 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= DeviceNode
;
3668 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
3671 /* Return the node */
3675 /* PUBLIC FUNCTIONS **********************************************************/
3679 PnpBusTypeGuidGet(IN USHORT Index
,
3680 IN LPGUID BusTypeGuid
)
3682 NTSTATUS Status
= STATUS_SUCCESS
;
3684 /* Acquire the lock */
3685 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
3688 if (Index
< PnpBusTypeGuidList
->GuidCount
)
3691 RtlCopyMemory(BusTypeGuid
, &PnpBusTypeGuidList
->Guids
[Index
], sizeof(GUID
));
3696 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
3699 /* Release lock and return status */
3700 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
3706 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject
,
3707 IN PHANDLE DeviceInstanceHandle
,
3708 IN ACCESS_MASK DesiredAccess
)
3712 PDEVICE_NODE DeviceNode
;
3713 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3716 /* Open the enum key */
3717 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
3721 if (!NT_SUCCESS(Status
)) return Status
;
3723 /* Make sure we have an instance path */
3724 DeviceNode
= IopGetDeviceNode(DeviceObject
);
3725 if ((DeviceNode
) && (DeviceNode
->InstancePath
.Length
))
3727 /* Get the instance key */
3728 Status
= IopOpenRegistryKeyEx(DeviceInstanceHandle
,
3730 &DeviceNode
->InstancePath
,
3736 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3739 /* Close the handle and return status */
3746 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList
)
3748 ULONG FinalSize
, PartialSize
, EntrySize
, i
, j
;
3749 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
3750 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
3752 /* If we don't have one, that's easy */
3753 if (!ResourceList
) return 0;
3755 /* Start with the minimum size possible */
3756 FinalSize
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
3758 /* Loop each full descriptor */
3759 FullDescriptor
= ResourceList
->List
;
3760 for (i
= 0; i
< ResourceList
->Count
; i
++)
3762 /* Start with the minimum size possible */
3763 PartialSize
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
) +
3764 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST
, PartialDescriptors
);
3766 /* Loop each partial descriptor */
3767 PartialDescriptor
= FullDescriptor
->PartialResourceList
.PartialDescriptors
;
3768 for (j
= 0; j
< FullDescriptor
->PartialResourceList
.Count
; j
++)
3770 /* Start with the minimum size possible */
3771 EntrySize
= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
3773 /* Check if there is extra data */
3774 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
3777 EntrySize
+= PartialDescriptor
->u
.DeviceSpecificData
.DataSize
;
3780 /* The size of partial descriptors is bigger */
3781 PartialSize
+= EntrySize
;
3783 /* Go to the next partial descriptor */
3784 PartialDescriptor
= (PVOID
)((ULONG_PTR
)PartialDescriptor
+ EntrySize
);
3787 /* The size of full descriptors is bigger */
3788 FinalSize
+= PartialSize
;
3790 /* Go to the next full descriptor */
3791 FullDescriptor
= (PVOID
)((ULONG_PTR
)FullDescriptor
+ PartialSize
);
3794 /* Return the final size */
3800 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject
,
3805 IN PULONG BufferLength
)
3808 HANDLE KeyHandle
, SubHandle
;
3809 UNICODE_STRING KeyString
;
3810 PKEY_VALUE_FULL_INFORMATION KeyValueInfo
= NULL
;
3814 /* Find the instance key */
3815 Status
= PnpDeviceObjectToDeviceInstance(DeviceObject
, &KeyHandle
, KEY_READ
);
3816 if (NT_SUCCESS(Status
))
3818 /* Check for name given by caller */
3822 RtlInitUnicodeString(&KeyString
, KeyName
);
3823 Status
= IopOpenRegistryKeyEx(&SubHandle
,
3827 if (NT_SUCCESS(Status
))
3829 /* And use this handle instead */
3831 KeyHandle
= SubHandle
;
3835 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3836 if (NT_SUCCESS(Status
))
3838 /* Now get the size of the property */
3839 Status
= IopGetRegistryValue(KeyHandle
,
3848 /* Fail if any of the registry operations failed */
3849 if (!NT_SUCCESS(Status
)) return Status
;
3851 /* Check how much data we have to copy */
3852 Length
= KeyValueInfo
->DataLength
;
3853 if (*BufferLength
>= Length
)
3855 /* Check for a match in the value type */
3856 if (KeyValueInfo
->Type
== ValueType
)
3859 RtlCopyMemory(Buffer
,
3860 (PVOID
)((ULONG_PTR
)KeyValueInfo
+
3861 KeyValueInfo
->DataOffset
),
3866 /* Invalid registry property type, fail */
3867 Status
= STATUS_INVALID_PARAMETER_2
;
3872 /* Buffer is too small to hold data */
3873 Status
= STATUS_BUFFER_TOO_SMALL
;
3876 /* Return the required buffer length, free the buffer, and return status */
3877 *BufferLength
= Length
;
3878 ExFreePool(KeyValueInfo
);
3882 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3883 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3884 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
3891 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
3892 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
3893 IN ULONG BufferLength
,
3894 OUT PVOID PropertyBuffer
,
3895 OUT PULONG ResultLength
)
3897 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
3898 DEVICE_CAPABILITIES DeviceCaps
;
3899 ULONG ReturnLength
= 0, Length
= 0, ValueType
;
3900 PWCHAR ValueName
= NULL
, EnumeratorNameEnd
, DeviceInstanceName
;
3902 NTSTATUS Status
= STATUS_BUFFER_TOO_SMALL
;
3904 POBJECT_NAME_INFORMATION ObjectNameInfo
= NULL
;
3905 BOOLEAN NullTerminate
= FALSE
;
3907 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject
, DeviceProperty
);
3909 /* Assume failure */
3912 /* Only PDOs can call this */
3913 if (!DeviceNode
) return STATUS_INVALID_DEVICE_REQUEST
;
3915 /* Handle all properties */
3916 switch (DeviceProperty
)
3918 case DevicePropertyBusTypeGuid
:
3920 /* Get the GUID from the internal cache */
3921 Status
= PnpBusTypeGuidGet(DeviceNode
->ChildBusTypeIndex
, &BusTypeGuid
);
3922 if (!NT_SUCCESS(Status
)) return Status
;
3924 /* This is the format of the returned data */
3925 PIP_RETURN_DATA(sizeof(GUID
), &BusTypeGuid
);
3927 case DevicePropertyLegacyBusType
:
3929 /* Validate correct interface type */
3930 if (DeviceNode
->ChildInterfaceType
== InterfaceTypeUndefined
)
3931 return STATUS_OBJECT_NAME_NOT_FOUND
;
3933 /* This is the format of the returned data */
3934 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE
), &DeviceNode
->ChildInterfaceType
);
3936 case DevicePropertyBusNumber
:
3938 /* Validate correct bus number */
3939 if ((DeviceNode
->ChildBusNumber
& 0x80000000) == 0x80000000)
3940 return STATUS_OBJECT_NAME_NOT_FOUND
;
3942 /* This is the format of the returned data */
3943 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceNode
->ChildBusNumber
);
3945 case DevicePropertyEnumeratorName
:
3947 /* Get the instance path */
3948 DeviceInstanceName
= DeviceNode
->InstancePath
.Buffer
;
3951 ASSERT((BufferLength
& 1) == 0);
3952 ASSERT(DeviceInstanceName
!= NULL
);
3954 /* Get the name from the path */
3955 EnumeratorNameEnd
= wcschr(DeviceInstanceName
, OBJ_NAME_PATH_SEPARATOR
);
3956 ASSERT(EnumeratorNameEnd
);
3958 /* This string needs to be NULL-terminated */
3959 NullTerminate
= TRUE
;
3961 /* This is the format of the returned data */
3962 PIP_RETURN_DATA((ULONG
)(EnumeratorNameEnd
- DeviceInstanceName
) * sizeof(WCHAR
),
3963 DeviceInstanceName
);
3965 case DevicePropertyAddress
:
3967 /* Query the device caps */
3968 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
);
3969 if (!NT_SUCCESS(Status
) || (DeviceCaps
.Address
== MAXULONG
))
3970 return STATUS_OBJECT_NAME_NOT_FOUND
;
3972 /* This is the format of the returned data */
3973 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceCaps
.Address
);
3975 case DevicePropertyBootConfigurationTranslated
:
3977 /* Validate we have resources */
3978 if (!DeviceNode
->BootResources
)
3979 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3981 /* No resources will still fake success, but with 0 bytes */
3983 return STATUS_SUCCESS
;
3986 /* This is the format of the returned data */
3987 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode
->BootResources
), // FIXFIX: Should use BootResourcesTranslated
3988 DeviceNode
->BootResources
); // FIXFIX: Should use BootResourcesTranslated
3990 case DevicePropertyPhysicalDeviceObjectName
:
3992 /* Sanity check for Unicode-sized string */
3993 ASSERT((BufferLength
& 1) == 0);
3995 /* Allocate name buffer */
3996 Length
= BufferLength
+ sizeof(OBJECT_NAME_INFORMATION
);
3997 ObjectNameInfo
= ExAllocatePool(PagedPool
, Length
);
3998 if (!ObjectNameInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
4000 /* Query the PDO name */
4001 Status
= ObQueryNameString(DeviceObject
,
4005 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
4007 /* It's up to the caller to try again */
4008 Status
= STATUS_BUFFER_TOO_SMALL
;
4011 /* This string needs to be NULL-terminated */
4012 NullTerminate
= TRUE
;
4014 /* Return if successful */
4015 if (NT_SUCCESS(Status
)) PIP_RETURN_DATA(ObjectNameInfo
->Name
.Length
,
4016 ObjectNameInfo
->Name
.Buffer
);
4018 /* Let the caller know how big the name is */
4019 *ResultLength
-= sizeof(OBJECT_NAME_INFORMATION
);
4022 /* Handle the registry-based properties */
4023 case DevicePropertyUINumber
:
4024 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER
, REG_DWORD
);
4025 case DevicePropertyLocationInformation
:
4026 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION
, REG_SZ
);
4027 case DevicePropertyDeviceDescription
:
4028 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC
, REG_SZ
);
4029 case DevicePropertyHardwareID
:
4030 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID
, REG_MULTI_SZ
);
4031 case DevicePropertyCompatibleIDs
:
4032 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS
, REG_MULTI_SZ
);
4033 case DevicePropertyBootConfiguration
:
4034 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG
, REG_RESOURCE_LIST
);
4035 case DevicePropertyClassName
:
4036 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS
, REG_SZ
);
4037 case DevicePropertyClassGuid
:
4038 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID
, REG_SZ
);
4039 case DevicePropertyDriverKeyName
:
4040 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER
, REG_SZ
);
4041 case DevicePropertyManufacturer
:
4042 PIP_REGISTRY_DATA(REGSTR_VAL_MFG
, REG_SZ
);
4043 case DevicePropertyFriendlyName
:
4044 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME
, REG_SZ
);
4045 case DevicePropertyContainerID
:
4046 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
4047 PIP_UNIMPLEMENTED();
4048 case DevicePropertyRemovalPolicy
:
4049 PIP_UNIMPLEMENTED();
4051 case DevicePropertyInstallState
:
4052 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS
, REG_DWORD
);
4054 case DevicePropertyResourceRequirements
:
4055 PIP_UNIMPLEMENTED();
4056 case DevicePropertyAllocatedResources
:
4057 PIP_UNIMPLEMENTED();
4059 return STATUS_INVALID_PARAMETER_2
;
4062 /* Having a registry value name implies registry data */
4065 /* We know up-front how much data to expect */
4066 *ResultLength
= BufferLength
;
4068 /* Go get the data, use the LogConf subkey if necessary */
4069 Status
= PiGetDeviceRegistryProperty(DeviceObject
,
4073 DevicePropertyBootConfiguration
) ?
4078 else if (NT_SUCCESS(Status
))
4080 /* We know up-front how much data to expect, check the caller's buffer */
4081 *ResultLength
= ReturnLength
+ (NullTerminate
? sizeof(UNICODE_NULL
) : 0);
4082 if (*ResultLength
<= BufferLength
)
4084 /* Buffer is all good, copy the data */
4085 RtlCopyMemory(PropertyBuffer
, Data
, ReturnLength
);
4087 /* Check if we need to NULL-terminate the string */
4090 /* Terminate the string */
4091 ((PWCHAR
)PropertyBuffer
)[ReturnLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
4094 /* This is the success path */
4095 Status
= STATUS_SUCCESS
;
4100 Status
= STATUS_BUFFER_TOO_SMALL
;
4104 /* Free any allocation we may have made, and return the status code */
4105 if (ObjectNameInfo
) ExFreePool(ObjectNameInfo
);
4114 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject
)
4116 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
4117 IO_STACK_LOCATION Stack
;
4120 IO_STATUS_BLOCK IoStatusBlock
;
4122 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
4123 Stack
.MajorFunction
= IRP_MJ_PNP
;
4124 Stack
.MinorFunction
= IRP_MN_QUERY_PNP_DEVICE_STATE
;
4126 Status
= IopSynchronousCall(PhysicalDeviceObject
, &Stack
, (PVOID
*)&PnPFlags
);
4127 if (!NT_SUCCESS(Status
))
4129 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status
);
4133 if (PnPFlags
& PNP_DEVICE_NOT_DISABLEABLE
)
4134 DeviceNode
->UserFlags
|= DNUF_NOT_DISABLEABLE
;
4136 DeviceNode
->UserFlags
&= ~DNUF_NOT_DISABLEABLE
;
4138 if (PnPFlags
& PNP_DEVICE_DONT_DISPLAY_IN_UI
)
4139 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
4141 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
4143 if ((PnPFlags
& PNP_DEVICE_REMOVED
) ||
4144 ((PnPFlags
& PNP_DEVICE_FAILED
) && !(PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)))
4146 /* Flag it if it's failed */
4147 if (PnPFlags
& PNP_DEVICE_FAILED
) DeviceNode
->Problem
= CM_PROB_FAILED_POST_START
;
4149 /* Send removal IRPs to all of its children */
4150 IopPrepareDeviceForRemoval(PhysicalDeviceObject
, TRUE
);
4152 /* Send surprise removal */
4153 IopSendSurpriseRemoval(PhysicalDeviceObject
);
4155 /* Tell the user-mode PnP manager that a device was removed */
4156 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
4157 &DeviceNode
->InstancePath
);
4159 IopSendRemoveDevice(PhysicalDeviceObject
);
4161 else if ((PnPFlags
& PNP_DEVICE_FAILED
) && (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
))
4163 /* Stop for resource rebalance */
4164 Status
= IopStopDevice(DeviceNode
);
4165 if (!NT_SUCCESS(Status
))
4167 DPRINT1("Failed to stop device for rebalancing\n");
4169 /* Stop failed so don't rebalance */
4170 PnPFlags
&= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
;
4174 /* Resource rebalance */
4175 if (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)
4177 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4179 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4181 IRP_MN_QUERY_RESOURCES
,
4183 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
4185 DeviceNode
->BootResources
=
4186 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
4187 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
4191 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
4192 DeviceNode
->BootResources
= NULL
;
4195 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4197 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4199 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
4201 if (NT_SUCCESS(Status
))
4203 DeviceNode
->ResourceRequirements
=
4204 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
4208 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
4209 DeviceNode
->ResourceRequirements
= NULL
;
4212 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4213 if (IopStartDevice(DeviceNode
) != STATUS_SUCCESS
)
4215 DPRINT1("Restart after resource rebalance failed\n");
4217 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
4218 DeviceNode
->Flags
|= DNF_START_FAILED
;
4220 IopRemoveDevice(DeviceNode
);
4226 * @name IoOpenDeviceRegistryKey
4228 * Open a registry key unique for a specified driver or device instance.
4230 * @param DeviceObject Device to get the registry key for.
4231 * @param DevInstKeyType Type of the key to return.
4232 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4233 * @param DevInstRegKey Handle to the opened registry key on
4234 * successful return.
4242 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject
,
4243 IN ULONG DevInstKeyType
,
4244 IN ACCESS_MASK DesiredAccess
,
4245 OUT PHANDLE DevInstRegKey
)
4247 static WCHAR RootKeyName
[] =
4248 L
"\\Registry\\Machine\\System\\CurrentControlSet\\";
4249 static WCHAR ProfileKeyName
[] =
4250 L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4251 static WCHAR ClassKeyName
[] = L
"Control\\Class\\";
4252 static WCHAR EnumKeyName
[] = L
"Enum\\";
4253 static WCHAR DeviceParametersKeyName
[] = L
"Device Parameters";
4254 ULONG KeyNameLength
;
4255 LPWSTR KeyNameBuffer
;
4256 UNICODE_STRING KeyName
;
4257 ULONG DriverKeyLength
;
4258 OBJECT_ATTRIBUTES ObjectAttributes
;
4259 PDEVICE_NODE DeviceNode
= NULL
;
4262 DPRINT("IoOpenDeviceRegistryKey() called\n");
4264 if ((DevInstKeyType
& (PLUGPLAY_REGKEY_DEVICE
| PLUGPLAY_REGKEY_DRIVER
)) == 0)
4266 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4267 return STATUS_INVALID_PARAMETER
;
4270 if (!IopIsValidPhysicalDeviceObject(DeviceObject
))
4271 return STATUS_INVALID_DEVICE_REQUEST
;
4272 DeviceNode
= IopGetDeviceNode(DeviceObject
);
4275 * Calculate the length of the base key name. This is the full
4276 * name for driver key or the name excluding "Device Parameters"
4277 * subkey for device key.
4280 KeyNameLength
= sizeof(RootKeyName
);
4281 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4282 KeyNameLength
+= sizeof(ProfileKeyName
) - sizeof(UNICODE_NULL
);
4283 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4285 KeyNameLength
+= sizeof(ClassKeyName
) - sizeof(UNICODE_NULL
);
4286 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4287 0, NULL
, &DriverKeyLength
);
4288 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
4290 KeyNameLength
+= DriverKeyLength
;
4294 KeyNameLength
+= sizeof(EnumKeyName
) - sizeof(UNICODE_NULL
) +
4295 DeviceNode
->InstancePath
.Length
;
4299 * Now allocate the buffer for the key name...
4302 KeyNameBuffer
= ExAllocatePool(PagedPool
, KeyNameLength
);
4303 if (KeyNameBuffer
== NULL
)
4304 return STATUS_INSUFFICIENT_RESOURCES
;
4307 KeyName
.MaximumLength
= (USHORT
)KeyNameLength
;
4308 KeyName
.Buffer
= KeyNameBuffer
;
4311 * ...and build the key name.
4314 KeyName
.Length
+= sizeof(RootKeyName
) - sizeof(UNICODE_NULL
);
4315 RtlCopyMemory(KeyNameBuffer
, RootKeyName
, KeyName
.Length
);
4317 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4318 RtlAppendUnicodeToString(&KeyName
, ProfileKeyName
);
4320 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4322 RtlAppendUnicodeToString(&KeyName
, ClassKeyName
);
4323 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4324 DriverKeyLength
, KeyNameBuffer
+
4325 (KeyName
.Length
/ sizeof(WCHAR
)),
4327 if (!NT_SUCCESS(Status
))
4329 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status
);
4330 ExFreePool(KeyNameBuffer
);
4333 KeyName
.Length
+= (USHORT
)DriverKeyLength
- sizeof(UNICODE_NULL
);
4337 RtlAppendUnicodeToString(&KeyName
, EnumKeyName
);
4338 Status
= RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->InstancePath
);
4339 if (DeviceNode
->InstancePath
.Length
== 0)
4341 ExFreePool(KeyNameBuffer
);
4347 * Open the base key.
4349 Status
= IopOpenRegistryKeyEx(DevInstRegKey
, NULL
, &KeyName
, DesiredAccess
);
4350 if (!NT_SUCCESS(Status
))
4352 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName
, Status
);
4353 ExFreePool(KeyNameBuffer
);
4356 ExFreePool(KeyNameBuffer
);
4359 * For driver key we're done now.
4362 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4366 * Let's go further. For device key we must open "Device Parameters"
4367 * subkey and create it if it doesn't exist yet.
4370 RtlInitUnicodeString(&KeyName
, DeviceParametersKeyName
);
4371 InitializeObjectAttributes(&ObjectAttributes
,
4373 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
4376 Status
= ZwCreateKey(DevInstRegKey
, DesiredAccess
, &ObjectAttributes
,
4377 0, NULL
, ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0, NULL
);
4378 ZwClose(ObjectAttributes
.RootDirectory
);
4385 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
, BOOLEAN Force
)
4387 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
, FailedRemoveDevice
;
4391 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4392 ChildDeviceNode
= ParentDeviceNode
->Child
;
4393 while (ChildDeviceNode
!= NULL
)
4395 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4396 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4398 Status
= IopPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
, Force
);
4399 if (!NT_SUCCESS(Status
))
4401 FailedRemoveDevice
= ChildDeviceNode
;
4405 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4406 ChildDeviceNode
= NextDeviceNode
;
4408 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4410 return STATUS_SUCCESS
;
4413 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4414 ChildDeviceNode
= ParentDeviceNode
->Child
;
4415 while (ChildDeviceNode
!= NULL
)
4417 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4418 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4420 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4422 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4423 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4424 if (ChildDeviceNode
== FailedRemoveDevice
)
4427 ChildDeviceNode
= NextDeviceNode
;
4429 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4431 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4438 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4440 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4443 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4444 ChildDeviceNode
= ParentDeviceNode
->Child
;
4445 while (ChildDeviceNode
!= NULL
)
4447 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4448 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4450 IopSendRemoveDevice(ChildDeviceNode
->PhysicalDeviceObject
);
4452 ChildDeviceNode
= NextDeviceNode
;
4454 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4456 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4461 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4463 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4466 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4467 ChildDeviceNode
= ParentDeviceNode
->Child
;
4468 while (ChildDeviceNode
!= NULL
)
4470 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4471 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4473 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4475 ChildDeviceNode
= NextDeviceNode
;
4477 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4479 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4484 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
, BOOLEAN Force
)
4486 /* This function DOES NOT dereference the device objects on SUCCESS
4487 * but it DOES dereference device objects on FAILURE */
4492 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4494 Status
= IopPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
], Force
);
4495 if (!NT_SUCCESS(Status
))
4502 return STATUS_SUCCESS
;
4505 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4506 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4507 for (i
= 0; i
<= j
; i
++)
4509 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4510 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4511 DeviceRelations
->Objects
[i
] = NULL
;
4513 for (; i
< DeviceRelations
->Count
; i
++)
4515 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4516 DeviceRelations
->Objects
[i
] = NULL
;
4518 ExFreePool(DeviceRelations
);
4525 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4527 /* This function DOES dereference the device objects in all cases */
4531 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4533 IopSendRemoveDevice(DeviceRelations
->Objects
[i
]);
4534 DeviceRelations
->Objects
[i
] = NULL
;
4537 ExFreePool(DeviceRelations
);
4542 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4544 /* This function DOES dereference the device objects in all cases */
4548 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4550 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4551 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4552 DeviceRelations
->Objects
[i
] = NULL
;
4555 ExFreePool(DeviceRelations
);
4559 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
)
4561 IO_STACK_LOCATION Stack
;
4562 IO_STATUS_BLOCK IoStatusBlock
;
4563 PDEVICE_RELATIONS DeviceRelations
;
4566 IopCancelRemoveDevice(DeviceObject
);
4568 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4570 Status
= IopInitiatePnpIrp(DeviceObject
,
4572 IRP_MN_QUERY_DEVICE_RELATIONS
,
4574 if (!NT_SUCCESS(Status
))
4576 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4577 DeviceRelations
= NULL
;
4581 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4584 if (DeviceRelations
)
4585 IopCancelRemoveDeviceRelations(DeviceRelations
);
4589 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
)
4591 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
4592 IO_STACK_LOCATION Stack
;
4593 IO_STATUS_BLOCK IoStatusBlock
;
4594 PDEVICE_RELATIONS DeviceRelations
;
4597 if ((DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
) && !Force
)
4599 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode
->InstancePath
);
4600 return STATUS_UNSUCCESSFUL
;
4603 if (!Force
&& IopQueryRemoveDevice(DeviceObject
) != STATUS_SUCCESS
)
4605 DPRINT1("Removal vetoed by failing the query remove request\n");
4607 IopCancelRemoveDevice(DeviceObject
);
4609 return STATUS_UNSUCCESSFUL
;
4612 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4614 Status
= IopInitiatePnpIrp(DeviceObject
,
4616 IRP_MN_QUERY_DEVICE_RELATIONS
,
4618 if (!NT_SUCCESS(Status
))
4620 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4621 DeviceRelations
= NULL
;
4625 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4628 if (DeviceRelations
)
4630 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, Force
);
4631 if (!NT_SUCCESS(Status
))
4635 Status
= IopQueryRemoveChildDevices(DeviceNode
, Force
);
4636 if (!NT_SUCCESS(Status
))
4638 if (DeviceRelations
)
4639 IopCancelRemoveDeviceRelations(DeviceRelations
);
4643 if (DeviceRelations
)
4644 IopSendRemoveDeviceRelations(DeviceRelations
);
4645 IopSendRemoveChildDevices(DeviceNode
);
4647 return STATUS_SUCCESS
;
4651 IopRemoveDevice(PDEVICE_NODE DeviceNode
)
4655 DPRINT("Removing device: %wZ\n", &DeviceNode
->InstancePath
);
4657 Status
= IopPrepareDeviceForRemoval(DeviceNode
->PhysicalDeviceObject
, FALSE
);
4658 if (NT_SUCCESS(Status
))
4660 IopSendRemoveDevice(DeviceNode
->PhysicalDeviceObject
);
4661 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL
,
4662 &DeviceNode
->InstancePath
);
4663 return STATUS_SUCCESS
;
4674 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject
)
4676 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
4677 PDEVICE_RELATIONS DeviceRelations
;
4678 IO_STATUS_BLOCK IoStatusBlock
;
4679 IO_STACK_LOCATION Stack
;
4680 DEVICE_CAPABILITIES Capabilities
;
4683 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT
,
4684 &DeviceNode
->InstancePath
);
4686 if (IopQueryDeviceCapabilities(DeviceNode
, &Capabilities
) != STATUS_SUCCESS
)
4691 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
4693 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4695 IRP_MN_QUERY_DEVICE_RELATIONS
,
4697 if (!NT_SUCCESS(Status
))
4699 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4700 DeviceRelations
= NULL
;
4704 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4707 if (DeviceRelations
)
4709 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, FALSE
);
4710 if (!NT_SUCCESS(Status
))
4714 Status
= IopQueryRemoveChildDevices(DeviceNode
, FALSE
);
4715 if (!NT_SUCCESS(Status
))
4717 if (DeviceRelations
)
4718 IopCancelRemoveDeviceRelations(DeviceRelations
);
4722 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject
, FALSE
) != STATUS_SUCCESS
)
4724 if (DeviceRelations
)
4725 IopCancelRemoveDeviceRelations(DeviceRelations
);
4726 IopCancelRemoveChildDevices(DeviceNode
);
4730 if (DeviceRelations
)
4731 IopSendRemoveDeviceRelations(DeviceRelations
);
4732 IopSendRemoveChildDevices(DeviceNode
);
4734 DeviceNode
->Problem
= CM_PROB_HELD_FOR_EJECT
;
4735 if (Capabilities
.EjectSupported
)
4737 if (IopSendEject(PhysicalDeviceObject
) != STATUS_SUCCESS
)
4744 DeviceNode
->Flags
|= DNF_DISABLED
;
4747 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT
,
4748 &DeviceNode
->InstancePath
);
4753 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED
,
4754 &DeviceNode
->InstancePath
);
4762 IoInvalidateDeviceRelations(
4763 IN PDEVICE_OBJECT DeviceObject
,
4764 IN DEVICE_RELATION_TYPE Type
)
4766 PINVALIDATE_DEVICE_RELATION_DATA Data
;
4769 Data
= ExAllocatePool(NonPagedPool
, sizeof(INVALIDATE_DEVICE_RELATION_DATA
));
4773 ObReferenceObject(DeviceObject
);
4774 Data
->DeviceObject
= DeviceObject
;
4777 KeAcquireSpinLock(&IopDeviceRelationsSpinLock
, &OldIrql
);
4778 InsertTailList(&IopDeviceRelationsRequestList
, &Data
->RequestListEntry
);
4779 if (IopDeviceRelationsRequestInProgress
)
4781 KeReleaseSpinLock(&IopDeviceRelationsSpinLock
, OldIrql
);
4784 IopDeviceRelationsRequestInProgress
= TRUE
;
4785 KeReleaseSpinLock(&IopDeviceRelationsSpinLock
, OldIrql
);
4787 ExInitializeWorkItem(&IopDeviceRelationsWorkItem
,
4788 IopDeviceRelationsWorker
,
4790 ExQueueWorkItem(&IopDeviceRelationsWorkItem
,
4799 IoSynchronousInvalidateDeviceRelations(
4800 IN PDEVICE_OBJECT DeviceObject
,
4801 IN DEVICE_RELATION_TYPE Type
)
4808 /* Enumerate the device */
4809 return IopEnumerateDevice(DeviceObject
);
4810 case PowerRelations
:
4811 /* Not handled yet */
4812 return STATUS_NOT_IMPLEMENTED
;
4813 case TargetDeviceRelation
:
4815 return STATUS_SUCCESS
;
4817 /* Ejection relations are not supported */
4818 return STATUS_NOT_SUPPORTED
;
4827 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType
,
4829 IN PHYSICAL_ADDRESS BusAddress
,
4830 IN OUT PULONG AddressSpace
,
4831 OUT PPHYSICAL_ADDRESS TranslatedAddress
)
4833 /* FIXME: Notify the resource arbiter */
4835 return HalTranslateBusAddress(InterfaceType
,