2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 PDEVICE_NODE IopRootDeviceNode
;
19 KSPIN_LOCK IopDeviceTreeLock
;
20 ERESOURCE PpRegistryDeviceResource
;
21 KGUARDED_MUTEX PpDeviceReferenceTableLock
;
22 RTL_AVL_TABLE PpDeviceReferenceTable
;
24 extern ULONG ExpInitializationPhase
;
25 extern BOOLEAN ExpInTextModeSetup
;
26 extern BOOLEAN PnpSystemInit
;
28 /* DATA **********************************************************************/
30 PDRIVER_OBJECT IopRootDriverObject
;
31 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList
= NULL
;
33 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
35 PDEVICE_OBJECT DeviceObject
;
36 DEVICE_RELATION_TYPE Type
;
37 PIO_WORKITEM WorkItem
;
38 } INVALIDATE_DEVICE_RELATION_DATA
, *PINVALIDATE_DEVICE_RELATION_DATA
;
40 /* FUNCTIONS *****************************************************************/
43 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
44 IN ULONG CreateOptions
,
48 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
);
51 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
);
55 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject
)
57 return ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
61 IopFixupDeviceId(PWCHAR String
)
63 ULONG Length
= wcslen(String
), i
;
65 for (i
= 0; i
< Length
; i
++)
67 if (String
[i
] == L
'\\')
74 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode
)
77 HANDLE CriticalDeviceKey
, InstanceKey
;
78 OBJECT_ATTRIBUTES ObjectAttributes
;
79 UNICODE_STRING CriticalDeviceKeyU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
80 UNICODE_STRING CompatibleIdU
= RTL_CONSTANT_STRING(L
"CompatibleIDs");
81 UNICODE_STRING HardwareIdU
= RTL_CONSTANT_STRING(L
"HardwareID");
82 UNICODE_STRING ServiceU
= RTL_CONSTANT_STRING(L
"Service");
83 UNICODE_STRING ClassGuidU
= RTL_CONSTANT_STRING(L
"ClassGUID");
84 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
85 ULONG HidLength
= 0, CidLength
= 0, BufferLength
;
86 PWCHAR IdBuffer
, OriginalIdBuffer
;
88 /* Open the device instance key */
89 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
90 if (Status
!= STATUS_SUCCESS
)
93 Status
= ZwQueryValueKey(InstanceKey
,
95 KeyValuePartialInformation
,
99 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
101 ZwClose(InstanceKey
);
105 Status
= ZwQueryValueKey(InstanceKey
,
107 KeyValuePartialInformation
,
111 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
116 BufferLength
= HidLength
+ CidLength
;
117 BufferLength
-= (((CidLength
!= 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
));
119 /* Allocate a buffer to hold data from both */
120 OriginalIdBuffer
= IdBuffer
= ExAllocatePool(PagedPool
, BufferLength
);
123 ZwClose(InstanceKey
);
127 /* Compute the buffer size */
128 if (HidLength
> CidLength
)
129 BufferLength
= HidLength
;
131 BufferLength
= CidLength
;
133 PartialInfo
= ExAllocatePool(PagedPool
, BufferLength
);
136 ZwClose(InstanceKey
);
137 ExFreePool(OriginalIdBuffer
);
141 Status
= ZwQueryValueKey(InstanceKey
,
143 KeyValuePartialInformation
,
147 if (Status
!= STATUS_SUCCESS
)
149 ExFreePool(PartialInfo
);
150 ExFreePool(OriginalIdBuffer
);
151 ZwClose(InstanceKey
);
155 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
156 HidLength
= PartialInfo
->DataLength
- ((CidLength
!= 0) ? sizeof(WCHAR
) : 0);
157 RtlCopyMemory(IdBuffer
, PartialInfo
->Data
, HidLength
);
161 Status
= ZwQueryValueKey(InstanceKey
,
163 KeyValuePartialInformation
,
167 if (Status
!= STATUS_SUCCESS
)
169 ExFreePool(PartialInfo
);
170 ExFreePool(OriginalIdBuffer
);
171 ZwClose(InstanceKey
);
176 CidLength
= PartialInfo
->DataLength
;
177 RtlCopyMemory(((PUCHAR
)IdBuffer
) + HidLength
, PartialInfo
->Data
, CidLength
);
180 /* Free our temp buffer */
181 ExFreePool(PartialInfo
);
183 InitializeObjectAttributes(&ObjectAttributes
,
185 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
188 Status
= ZwOpenKey(&CriticalDeviceKey
,
189 KEY_ENUMERATE_SUB_KEYS
,
191 if (!NT_SUCCESS(Status
))
193 /* The critical device database doesn't exist because
194 * we're probably in 1st stage setup, but it's ok */
195 ExFreePool(OriginalIdBuffer
);
196 ZwClose(InstanceKey
);
202 ULONG StringLength
= (ULONG
)wcslen(IdBuffer
) + 1, Index
;
204 IopFixupDeviceId(IdBuffer
);
206 /* Look through all subkeys for a match */
207 for (Index
= 0; TRUE
; Index
++)
210 PKEY_BASIC_INFORMATION BasicInfo
;
212 Status
= ZwEnumerateKey(CriticalDeviceKey
,
218 if (Status
== STATUS_NO_MORE_ENTRIES
)
220 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
222 UNICODE_STRING ChildIdNameU
, RegKeyNameU
;
224 BasicInfo
= ExAllocatePool(PagedPool
, NeededLength
);
228 ExFreePool(OriginalIdBuffer
);
229 ZwClose(CriticalDeviceKey
);
230 ZwClose(InstanceKey
);
234 Status
= ZwEnumerateKey(CriticalDeviceKey
,
240 if (Status
!= STATUS_SUCCESS
)
242 /* This shouldn't happen */
243 ExFreePool(BasicInfo
);
247 ChildIdNameU
.Buffer
= IdBuffer
;
248 ChildIdNameU
.MaximumLength
= ChildIdNameU
.Length
= (StringLength
- 1) * sizeof(WCHAR
);
249 RegKeyNameU
.Buffer
= BasicInfo
->Name
;
250 RegKeyNameU
.MaximumLength
= RegKeyNameU
.Length
= BasicInfo
->NameLength
;
252 if (RtlEqualUnicodeString(&ChildIdNameU
, &RegKeyNameU
, TRUE
))
254 HANDLE ChildKeyHandle
;
256 InitializeObjectAttributes(&ObjectAttributes
,
258 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
262 Status
= ZwOpenKey(&ChildKeyHandle
,
265 if (Status
!= STATUS_SUCCESS
)
267 ExFreePool(BasicInfo
);
271 /* Check if there's already a driver installed */
272 Status
= ZwQueryValueKey(InstanceKey
,
274 KeyValuePartialInformation
,
278 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
280 ExFreePool(BasicInfo
);
284 Status
= ZwQueryValueKey(ChildKeyHandle
,
286 KeyValuePartialInformation
,
290 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
292 ExFreePool(BasicInfo
);
296 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
299 ExFreePool(OriginalIdBuffer
);
300 ExFreePool(BasicInfo
);
301 ZwClose(InstanceKey
);
302 ZwClose(ChildKeyHandle
);
303 ZwClose(CriticalDeviceKey
);
307 /* Read ClassGUID entry in the CDDB */
308 Status
= ZwQueryValueKey(ChildKeyHandle
,
310 KeyValuePartialInformation
,
314 if (Status
!= STATUS_SUCCESS
)
316 ExFreePool(BasicInfo
);
320 /* Write it to the ENUM key */
321 Status
= ZwSetValueKey(InstanceKey
,
326 PartialInfo
->DataLength
);
327 if (Status
!= STATUS_SUCCESS
)
329 ExFreePool(BasicInfo
);
330 ExFreePool(PartialInfo
);
331 ZwClose(ChildKeyHandle
);
335 Status
= ZwQueryValueKey(ChildKeyHandle
,
337 KeyValuePartialInformation
,
341 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
343 ExFreePool(PartialInfo
);
344 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
347 ExFreePool(OriginalIdBuffer
);
348 ExFreePool(BasicInfo
);
349 ZwClose(InstanceKey
);
350 ZwClose(ChildKeyHandle
);
351 ZwClose(CriticalDeviceKey
);
355 /* Read the service entry from the CDDB */
356 Status
= ZwQueryValueKey(ChildKeyHandle
,
358 KeyValuePartialInformation
,
362 if (Status
!= STATUS_SUCCESS
)
364 ExFreePool(BasicInfo
);
365 ExFreePool(PartialInfo
);
366 ZwClose(ChildKeyHandle
);
370 /* Write it to the ENUM key */
371 Status
= ZwSetValueKey(InstanceKey
,
376 PartialInfo
->DataLength
);
377 if (Status
!= STATUS_SUCCESS
)
379 ExFreePool(BasicInfo
);
380 ExFreePool(PartialInfo
);
381 ZwClose(ChildKeyHandle
);
385 DPRINT1("Installed service '%S' for critical device '%wZ'\n", PartialInfo
->Data
, &ChildIdNameU
);
389 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU
);
392 /* We need to enumerate children */
393 DeviceNode
->Flags
|= DNF_NEED_TO_ENUM
;
395 ExFreePool(OriginalIdBuffer
);
396 ExFreePool(PartialInfo
);
397 ExFreePool(BasicInfo
);
398 ZwClose(InstanceKey
);
399 ZwClose(ChildKeyHandle
);
400 ZwClose(CriticalDeviceKey
);
406 ExFreePool(BasicInfo
);
410 /* Umm, not sure what happened here */
415 /* Advance to the next ID */
416 IdBuffer
+= StringLength
;
419 ExFreePool(OriginalIdBuffer
);
420 ZwClose(InstanceKey
);
421 ZwClose(CriticalDeviceKey
);
426 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
427 PDRIVER_OBJECT DriverObject
)
434 /* Special case for bus driven devices */
435 DeviceNode
->Flags
|= DNF_ADDED
;
436 return STATUS_SUCCESS
;
439 if (!DriverObject
->DriverExtension
->AddDevice
)
441 DeviceNode
->Flags
|= DNF_LEGACY_DRIVER
;
444 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
446 DeviceNode
->Flags
|= DNF_ADDED
+ DNF_STARTED
;
447 return STATUS_SUCCESS
;
450 /* This is a Plug and Play driver */
451 DPRINT("Plug and Play driver found\n");
452 ASSERT(DeviceNode
->PhysicalDeviceObject
);
454 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
455 &DriverObject
->DriverName
,
456 &DeviceNode
->InstancePath
);
457 Status
= DriverObject
->DriverExtension
->AddDevice(
458 DriverObject
, DeviceNode
->PhysicalDeviceObject
);
459 if (!NT_SUCCESS(Status
))
461 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
462 &DriverObject
->DriverName
,
463 &DeviceNode
->InstancePath
,
465 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
469 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
471 /* Check if we have a ACPI device (needed for power management) */
472 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
474 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
476 /* There can be only one system power device */
477 if (!SystemPowerDeviceNodeCreated
)
479 PopSystemPowerDeviceNode
= DeviceNode
;
480 ObReferenceObject(PopSystemPowerDeviceNode
->PhysicalDeviceObject
);
481 SystemPowerDeviceNodeCreated
= TRUE
;
485 ObDereferenceObject(Fdo
);
487 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
489 return STATUS_SUCCESS
;
495 IopSendEject(IN PDEVICE_OBJECT DeviceObject
)
497 IO_STACK_LOCATION Stack
;
500 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
501 Stack
.MajorFunction
= IRP_MJ_PNP
;
502 Stack
.MinorFunction
= IRP_MN_EJECT
;
504 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
510 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject
)
512 IO_STACK_LOCATION Stack
;
515 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
516 Stack
.MajorFunction
= IRP_MJ_PNP
;
517 Stack
.MinorFunction
= IRP_MN_SURPRISE_REMOVAL
;
519 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
520 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
526 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
528 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
529 IO_STACK_LOCATION Stack
;
535 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING
,
536 &DeviceNode
->InstancePath
);
538 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
539 Stack
.MajorFunction
= IRP_MJ_PNP
;
540 Stack
.MinorFunction
= IRP_MN_QUERY_REMOVE_DEVICE
;
542 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
544 IopNotifyPlugPlayNotification(DeviceObject
,
545 EventCategoryTargetDeviceChange
,
546 &GUID_TARGET_DEVICE_QUERY_REMOVE
,
550 if (!NT_SUCCESS(Status
))
552 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode
->InstancePath
);
553 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED
,
554 &DeviceNode
->InstancePath
);
563 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject
)
565 IO_STACK_LOCATION Stack
;
568 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
569 Stack
.MajorFunction
= IRP_MJ_PNP
;
570 Stack
.MinorFunction
= IRP_MN_QUERY_STOP_DEVICE
;
572 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
578 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
580 IO_STACK_LOCATION Stack
;
583 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
584 Stack
.MajorFunction
= IRP_MJ_PNP
;
585 Stack
.MinorFunction
= IRP_MN_REMOVE_DEVICE
;
587 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
588 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
590 IopNotifyPlugPlayNotification(DeviceObject
,
591 EventCategoryTargetDeviceChange
,
592 &GUID_TARGET_DEVICE_REMOVE_COMPLETE
,
600 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
602 IO_STACK_LOCATION Stack
;
605 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
606 Stack
.MajorFunction
= IRP_MJ_PNP
;
607 Stack
.MinorFunction
= IRP_MN_CANCEL_REMOVE_DEVICE
;
609 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
610 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
612 IopNotifyPlugPlayNotification(DeviceObject
,
613 EventCategoryTargetDeviceChange
,
614 &GUID_TARGET_DEVICE_REMOVE_CANCELLED
,
622 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject
)
624 IO_STACK_LOCATION Stack
;
627 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
628 Stack
.MajorFunction
= IRP_MJ_PNP
;
629 Stack
.MinorFunction
= IRP_MN_STOP_DEVICE
;
631 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
632 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
637 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject
)
639 IO_STACK_LOCATION Stack
;
640 PDEVICE_NODE DeviceNode
;
643 DEVICE_CAPABILITIES DeviceCapabilities
;
645 /* Get the device node */
646 DeviceNode
= IopGetDeviceNode(DeviceObject
);
648 ASSERT(!(DeviceNode
->Flags
& DNF_DISABLED
));
650 /* Build the I/O stack locaiton */
651 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
652 Stack
.MajorFunction
= IRP_MJ_PNP
;
653 Stack
.MinorFunction
= IRP_MN_START_DEVICE
;
655 Stack
.Parameters
.StartDevice
.AllocatedResources
=
656 DeviceNode
->ResourceList
;
657 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
=
658 DeviceNode
->ResourceListTranslated
;
661 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
662 if (!NT_SUCCESS(Status
))
664 /* Send an IRP_MN_REMOVE_DEVICE request */
665 IopRemoveDevice(DeviceNode
);
667 /* Set the appropriate flag */
668 DeviceNode
->Flags
|= DNF_START_FAILED
;
670 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode
->InstancePath
, Status
);
674 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
676 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
677 if (!NT_SUCCESS(Status
))
679 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
682 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
683 IoInvalidateDeviceState(DeviceObject
);
685 /* Otherwise, mark us as started */
686 DeviceNode
->Flags
|= DNF_STARTED
;
687 DeviceNode
->Flags
&= ~DNF_STOPPED
;
689 /* We now need enumeration */
690 DeviceNode
->Flags
|= DNF_NEED_ENUMERATION_ONLY
;
695 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode
)
697 PDEVICE_OBJECT DeviceObject
;
702 ASSERT((DeviceNode
->Flags
& DNF_ADDED
));
703 ASSERT((DeviceNode
->Flags
& (DNF_RESOURCE_ASSIGNED
|
704 DNF_RESOURCE_REPORTED
|
705 DNF_NO_RESOURCE_REQUIRED
)));
707 /* Get the device object */
708 DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
710 /* Check if we're not started yet */
711 if (!(DeviceNode
->Flags
& DNF_STARTED
))
714 IopStartDevice2(DeviceObject
);
717 /* Do we need to query IDs? This happens in the case of manual reporting */
719 if (DeviceNode
->Flags
& DNF_NEED_QUERY_IDS
)
721 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
722 /* And that case shouldn't happen yet */
727 /* Make sure we're started, and check if we need enumeration */
728 if ((DeviceNode
->Flags
& DNF_STARTED
) &&
729 (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
))
732 IoSynchronousInvalidateDeviceRelations(DeviceObject
, BusRelations
);
733 Status
= STATUS_SUCCESS
;
738 Status
= STATUS_SUCCESS
;
747 PDEVICE_NODE DeviceNode
)
751 DPRINT("Stopping device: %wZ\n", &DeviceNode
->InstancePath
);
753 Status
= IopQueryStopDevice(DeviceNode
->PhysicalDeviceObject
);
754 if (NT_SUCCESS(Status
))
756 IopSendStopDevice(DeviceNode
->PhysicalDeviceObject
);
758 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
759 DeviceNode
->Flags
|= DNF_STOPPED
;
761 return STATUS_SUCCESS
;
769 PDEVICE_NODE DeviceNode
)
772 HANDLE InstanceHandle
= INVALID_HANDLE_VALUE
, ControlHandle
= INVALID_HANDLE_VALUE
;
773 UNICODE_STRING KeyName
;
774 OBJECT_ATTRIBUTES ObjectAttributes
;
776 if (DeviceNode
->Flags
& DNF_DISABLED
)
777 return STATUS_SUCCESS
;
779 Status
= IopAssignDeviceResources(DeviceNode
);
780 if (!NT_SUCCESS(Status
))
784 IopStartAndEnumerateDevice(DeviceNode
);
786 /* FIX: Should be done in new device instance code */
787 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceHandle
);
788 if (!NT_SUCCESS(Status
))
791 /* FIX: Should be done in IoXxxPrepareDriverLoading */
793 RtlInitUnicodeString(&KeyName
, L
"Control");
794 InitializeObjectAttributes(&ObjectAttributes
,
796 OBJ_CASE_INSENSITIVE
,
799 Status
= ZwCreateKey(&ControlHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
800 if (!NT_SUCCESS(Status
))
803 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
804 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, DeviceNode
->ServiceName
.Buffer
, DeviceNode
->ServiceName
.Length
);
808 if (ControlHandle
!= INVALID_HANDLE_VALUE
)
809 ZwClose(ControlHandle
);
811 if (InstanceHandle
!= INVALID_HANDLE_VALUE
)
812 ZwClose(InstanceHandle
);
819 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
820 PDEVICE_CAPABILITIES DeviceCaps
)
822 IO_STATUS_BLOCK StatusBlock
;
823 IO_STACK_LOCATION Stack
;
826 UNICODE_STRING ValueName
;
828 /* Set up the Header */
829 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
830 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
831 DeviceCaps
->Version
= 1;
832 DeviceCaps
->Address
= -1;
833 DeviceCaps
->UINumber
= -1;
835 /* Set up the Stack */
836 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
837 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
840 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
842 IRP_MN_QUERY_CAPABILITIES
,
844 if (!NT_SUCCESS(Status
))
846 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%x\n", Status
);
850 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCaps
->Version
+ sizeof(DeviceCaps
->Version
));
852 if (DeviceCaps
->NoDisplayInUI
)
853 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
855 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
857 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
858 if (NT_SUCCESS(Status
))
860 /* Set 'Capabilities' value */
861 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
862 Status
= ZwSetValueKey(InstanceKey
,
866 (PVOID
)&DeviceNode
->CapabilityFlags
,
869 /* Set 'UINumber' value */
870 if (DeviceCaps
->UINumber
!= MAXULONG
)
872 RtlInitUnicodeString(&ValueName
, L
"UINumber");
873 Status
= ZwSetValueKey(InstanceKey
,
877 &DeviceCaps
->UINumber
,
886 IopAsynchronousInvalidateDeviceRelations(
887 IN PDEVICE_OBJECT DeviceObject
,
888 IN PVOID InvalidateContext
)
890 PINVALIDATE_DEVICE_RELATION_DATA Data
= InvalidateContext
;
892 IoSynchronousInvalidateDeviceRelations(
896 ObDereferenceObject(Data
->DeviceObject
);
897 IoFreeWorkItem(Data
->WorkItem
);
902 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
906 if (PopSystemPowerDeviceNode
)
908 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
909 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
910 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
912 return STATUS_SUCCESS
;
915 return STATUS_UNSUCCESSFUL
;
920 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
922 USHORT i
= 0, FoundIndex
= 0xFFFF;
926 /* Acquire the lock */
927 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
929 /* Loop all entries */
930 while (i
< PnpBusTypeGuidList
->GuidCount
)
932 /* Try to find a match */
933 if (RtlCompareMemory(BusTypeGuid
,
934 &PnpBusTypeGuidList
->Guids
[i
],
935 sizeof(GUID
)) == sizeof(GUID
))
944 /* Check if we have to grow the list */
945 if (PnpBusTypeGuidList
->GuidCount
)
947 /* Calculate the new size */
948 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
949 (sizeof(GUID
) * PnpBusTypeGuidList
->GuidCount
);
951 /* Allocate the new copy */
952 NewList
= ExAllocatePool(PagedPool
, NewSize
);
956 ExFreePool(PnpBusTypeGuidList
);
960 /* Now copy them, decrease the size too */
961 NewSize
-= sizeof(GUID
);
962 RtlCopyMemory(NewList
, PnpBusTypeGuidList
, NewSize
);
964 /* Free the old list */
965 ExFreePool(PnpBusTypeGuidList
);
967 /* Use the new buffer */
968 PnpBusTypeGuidList
= NewList
;
971 /* Copy the new GUID */
972 RtlCopyMemory(&PnpBusTypeGuidList
->Guids
[PnpBusTypeGuidList
->GuidCount
],
976 /* The new entry is the index */
977 FoundIndex
= (USHORT
)PnpBusTypeGuidList
->GuidCount
;
978 PnpBusTypeGuidList
->GuidCount
++;
981 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
987 * Creates a device node
990 * ParentNode = Pointer to parent device node
991 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
992 * to have the root device node create one
993 * (eg. for legacy drivers)
994 * DeviceNode = Pointer to storage for created device node
1000 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
1001 PDEVICE_OBJECT PhysicalDeviceObject
,
1002 PUNICODE_STRING ServiceName
,
1003 PDEVICE_NODE
*DeviceNode
)
1008 UNICODE_STRING FullServiceName
;
1009 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
1010 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
1011 UNICODE_STRING KeyName
, ClassName
;
1012 PUNICODE_STRING ServiceName1
;
1015 UNICODE_STRING ClassGUID
;
1017 HANDLE InstanceHandle
;
1019 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1020 ParentNode
, PhysicalDeviceObject
, ServiceName
);
1022 Node
= (PDEVICE_NODE
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_NODE
));
1025 return STATUS_INSUFFICIENT_RESOURCES
;
1028 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
1031 ServiceName1
= &UnknownDeviceName
;
1033 ServiceName1
= ServiceName
;
1035 if (!PhysicalDeviceObject
)
1037 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName1
->Length
;
1038 FullServiceName
.Length
= 0;
1039 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
1040 if (!FullServiceName
.Buffer
)
1043 return STATUS_INSUFFICIENT_RESOURCES
;
1046 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
1047 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName1
);
1049 Status
= PnpRootCreateDevice(&FullServiceName
, NULL
, &PhysicalDeviceObject
, &Node
->InstancePath
);
1050 if (!NT_SUCCESS(Status
))
1052 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
1057 /* Create the device key for legacy drivers */
1058 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, REG_OPTION_VOLATILE
, &InstanceHandle
);
1059 if (!NT_SUCCESS(Status
))
1061 ZwClose(InstanceHandle
);
1063 ExFreePool(FullServiceName
.Buffer
);
1067 Node
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, ServiceName1
->Length
);
1068 if (!Node
->ServiceName
.Buffer
)
1070 ZwClose(InstanceHandle
);
1072 ExFreePool(FullServiceName
.Buffer
);
1076 Node
->ServiceName
.MaximumLength
= ServiceName1
->Length
;
1077 Node
->ServiceName
.Length
= 0;
1079 RtlAppendUnicodeStringToString(&Node
->ServiceName
, ServiceName1
);
1083 RtlInitUnicodeString(&KeyName
, L
"Service");
1084 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName
->Buffer
, ServiceName
->Length
);
1087 if (NT_SUCCESS(Status
))
1089 RtlInitUnicodeString(&KeyName
, L
"Legacy");
1092 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
1093 if (NT_SUCCESS(Status
))
1095 RtlInitUnicodeString(&KeyName
, L
"Class");
1097 RtlInitUnicodeString(&ClassName
, L
"LegacyDriver");
1098 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassName
.Buffer
, ClassName
.Length
);
1100 if (NT_SUCCESS(Status
))
1102 RtlInitUnicodeString(&KeyName
, L
"ClassGUID");
1104 RtlInitUnicodeString(&ClassGUID
, L
"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
1105 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassGUID
.Buffer
, ClassGUID
.Length
);
1111 ZwClose(InstanceHandle
);
1112 ExFreePool(FullServiceName
.Buffer
);
1114 if (!NT_SUCCESS(Status
))
1120 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
1121 IopDeviceNodeSetFlag(Node
, DNF_PROCESSED
);
1122 IopDeviceNodeSetFlag(Node
, DNF_ADDED
);
1123 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
1126 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
1128 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
1132 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1133 Node
->Parent
= ParentNode
;
1134 Node
->Sibling
= ParentNode
->Child
;
1135 ParentNode
->Child
= Node
;
1136 if (ParentNode
->LastChild
== NULL
)
1137 ParentNode
->LastChild
= Node
;
1138 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1139 Node
->Level
= ParentNode
->Level
+ 1;
1142 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1146 return STATUS_SUCCESS
;
1150 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
1153 PDEVICE_NODE PrevSibling
= NULL
;
1155 /* All children must be deleted before a parent is deleted */
1156 ASSERT(!DeviceNode
->Child
);
1158 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1160 ASSERT(DeviceNode
->PhysicalDeviceObject
);
1162 ObDereferenceObject(DeviceNode
->PhysicalDeviceObject
);
1164 /* Get previous sibling */
1165 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
1167 PrevSibling
= DeviceNode
->Parent
->Child
;
1168 while (PrevSibling
->Sibling
!= DeviceNode
)
1169 PrevSibling
= PrevSibling
->Sibling
;
1172 /* Unlink from parent if it exists */
1173 if (DeviceNode
->Parent
)
1175 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
1177 DeviceNode
->Parent
->LastChild
= PrevSibling
;
1179 PrevSibling
->Sibling
= NULL
;
1181 if (DeviceNode
->Parent
->Child
== DeviceNode
)
1182 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
1185 /* Unlink from sibling list */
1187 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
1189 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1191 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
1193 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
1195 if (DeviceNode
->ResourceList
)
1197 ExFreePool(DeviceNode
->ResourceList
);
1200 if (DeviceNode
->ResourceListTranslated
)
1202 ExFreePool(DeviceNode
->ResourceListTranslated
);
1205 if (DeviceNode
->ResourceRequirements
)
1207 ExFreePool(DeviceNode
->ResourceRequirements
);
1210 if (DeviceNode
->BootResources
)
1212 ExFreePool(DeviceNode
->BootResources
);
1215 ExFreePool(DeviceNode
);
1217 return STATUS_SUCCESS
;
1222 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject
,
1223 IN PIO_STACK_LOCATION IoStackLocation
,
1224 OUT PVOID
*Information
)
1227 PIO_STACK_LOCATION IrpStack
;
1228 IO_STATUS_BLOCK IoStatusBlock
;
1231 PDEVICE_OBJECT TopDeviceObject
;
1234 /* Call the top of the device stack */
1235 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
1237 /* Allocate an IRP */
1238 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
, FALSE
);
1239 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
1241 /* Initialize to failure */
1242 Irp
->IoStatus
.Status
= IoStatusBlock
.Status
= STATUS_NOT_SUPPORTED
;
1243 Irp
->IoStatus
.Information
= IoStatusBlock
.Information
= 0;
1245 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1246 if (IoStackLocation
->MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
)
1248 /* Copy the resource requirements list into the IOSB */
1249 Irp
->IoStatus
.Information
=
1250 IoStatusBlock
.Information
= (ULONG_PTR
)IoStackLocation
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
1253 /* Initialize the event */
1254 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1257 Irp
->UserIosb
= &IoStatusBlock
;
1258 Irp
->UserEvent
= &Event
;
1261 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1262 IoQueueThreadIrp(Irp
);
1264 /* Copy-in the stack */
1265 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1266 *IrpStack
= *IoStackLocation
;
1268 /* Call the driver */
1269 Status
= IoCallDriver(TopDeviceObject
, Irp
);
1270 if (Status
== STATUS_PENDING
)
1273 KeWaitForSingleObject(&Event
,
1278 Status
= IoStatusBlock
.Status
;
1281 /* Return the information */
1282 *Information
= (PVOID
)IoStatusBlock
.Information
;
1288 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject
,
1289 IN OUT PIO_STATUS_BLOCK IoStatusBlock
,
1290 IN UCHAR MinorFunction
,
1291 IN PIO_STACK_LOCATION Stack OPTIONAL
)
1293 IO_STACK_LOCATION IoStackLocation
;
1295 /* Fill out the stack information */
1296 RtlZeroMemory(&IoStackLocation
, sizeof(IO_STACK_LOCATION
));
1297 IoStackLocation
.MajorFunction
= IRP_MJ_PNP
;
1298 IoStackLocation
.MinorFunction
= MinorFunction
;
1302 RtlCopyMemory(&IoStackLocation
.Parameters
,
1304 sizeof(Stack
->Parameters
));
1307 /* Do the PnP call */
1308 IoStatusBlock
->Status
= IopSynchronousCall(DeviceObject
,
1310 (PVOID
)&IoStatusBlock
->Information
);
1311 return IoStatusBlock
->Status
;
1315 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1317 PDEVICE_NODE ParentDeviceNode
;
1318 PDEVICE_NODE ChildDeviceNode
;
1321 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1322 ParentDeviceNode
= Context
->DeviceNode
;
1324 /* Call the action routine */
1325 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
1326 if (!NT_SUCCESS(Status
))
1331 /* Traversal of all children nodes */
1332 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
1333 ChildDeviceNode
!= NULL
;
1334 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
1336 /* Pass the current device node to the action routine */
1337 Context
->DeviceNode
= ChildDeviceNode
;
1339 Status
= IopTraverseDeviceTreeNode(Context
);
1340 if (!NT_SUCCESS(Status
))
1351 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1355 DPRINT("Context 0x%p\n", Context
);
1357 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
1358 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
1360 /* Start from the specified device node */
1361 Context
->DeviceNode
= Context
->FirstDeviceNode
;
1363 /* Recursively traverse the device tree */
1364 Status
= IopTraverseDeviceTreeNode(Context
);
1365 if (Status
== STATUS_UNSUCCESSFUL
)
1367 /* The action routine just wanted to terminate the traversal with status
1368 code STATUS_SUCCESS */
1369 Status
= STATUS_SUCCESS
;
1377 * IopCreateDeviceKeyPath
1379 * Creates a registry key
1383 * Name of the key to be created.
1385 * Handle to the newly created key
1388 * This method can create nested trees, so parent of RegistryPath can
1389 * be not existant, and will be created if needed.
1393 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
1394 IN ULONG CreateOptions
,
1397 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
1398 HANDLE hParent
= NULL
, hKey
;
1399 OBJECT_ATTRIBUTES ObjectAttributes
;
1400 UNICODE_STRING KeyName
;
1401 LPCWSTR Current
, Last
;
1405 /* Assume failure */
1408 /* Create a volatile device tree in 1st stage so we have a clean slate
1409 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1410 if (ExpInTextModeSetup
) CreateOptions
|= REG_OPTION_VOLATILE
;
1412 /* Open root key for device instances */
1413 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
1414 if (!NT_SUCCESS(Status
))
1416 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
1420 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
1421 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
1423 /* Go up to the end of the string */
1424 while (Current
<= Last
)
1426 if (Current
!= Last
&& *Current
!= '\\')
1428 /* Not the end of the string and not a separator */
1433 /* Prepare relative key name */
1434 Length
= (USHORT
)((ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
);
1435 KeyName
.MaximumLength
= KeyName
.Length
= Length
;
1436 DPRINT("Create '%wZ'\n", &KeyName
);
1439 InitializeObjectAttributes(&ObjectAttributes
,
1441 OBJ_CASE_INSENSITIVE
,
1444 Status
= ZwCreateKey(&hKey
,
1445 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
1452 /* Close parent key handle, we don't need it anymore */
1456 /* Key opening/creating failed? */
1457 if (!NT_SUCCESS(Status
))
1459 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
1463 /* Check if it is the end of the string */
1464 if (Current
== Last
)
1466 /* Yes, return success */
1468 return STATUS_SUCCESS
;
1471 /* Start with this new parent key */
1474 KeyName
.Buffer
= (LPWSTR
)Current
;
1477 return STATUS_UNSUCCESSFUL
;
1481 IopSetDeviceInstanceData(HANDLE InstanceKey
,
1482 PDEVICE_NODE DeviceNode
)
1484 OBJECT_ATTRIBUTES ObjectAttributes
;
1485 UNICODE_STRING KeyName
;
1490 HANDLE ControlHandle
;
1492 DPRINT("IopSetDeviceInstanceData() called\n");
1494 /* Create the 'LogConf' key */
1495 RtlInitUnicodeString(&KeyName
, L
"LogConf");
1496 InitializeObjectAttributes(&ObjectAttributes
,
1498 OBJ_CASE_INSENSITIVE
,
1501 Status
= ZwCreateKey(&LogConfKey
,
1506 REG_OPTION_VOLATILE
,
1508 if (NT_SUCCESS(Status
))
1510 /* Set 'BootConfig' value */
1511 if (DeviceNode
->BootResources
!= NULL
)
1513 ResCount
= DeviceNode
->BootResources
->Count
;
1516 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
1517 Status
= ZwSetValueKey(LogConfKey
,
1521 DeviceNode
->BootResources
,
1522 PnpDetermineResourceListSize(DeviceNode
->BootResources
));
1526 /* Set 'BasicConfigVector' value */
1527 if (DeviceNode
->ResourceRequirements
!= NULL
&&
1528 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
1530 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
1531 Status
= ZwSetValueKey(LogConfKey
,
1534 REG_RESOURCE_REQUIREMENTS_LIST
,
1535 DeviceNode
->ResourceRequirements
,
1536 DeviceNode
->ResourceRequirements
->ListSize
);
1539 ZwClose(LogConfKey
);
1542 /* Set the 'ConfigFlags' value */
1543 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1544 Status
= ZwQueryValueKey(InstanceKey
,
1546 KeyValueBasicInformation
,
1550 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1552 /* Write the default value */
1553 ULONG DefaultConfigFlags
= 0;
1554 Status
= ZwSetValueKey(InstanceKey
,
1558 &DefaultConfigFlags
,
1559 sizeof(DefaultConfigFlags
));
1562 /* Create the 'Control' key */
1563 RtlInitUnicodeString(&KeyName
, L
"Control");
1564 InitializeObjectAttributes(&ObjectAttributes
,
1566 OBJ_CASE_INSENSITIVE
,
1569 Status
= ZwCreateKey(&ControlHandle
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
1571 if (NT_SUCCESS(Status
))
1572 ZwClose(ControlHandle
);
1574 DPRINT("IopSetDeviceInstanceData() done\n");
1580 * IopGetParentIdPrefix
1582 * Retrieve (or create) a string which identifies a device.
1586 * Pointer to device node.
1588 * Pointer to the string where is returned the parent node identifier
1591 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1592 * valid and its Buffer field is NULL-terminated. The caller needs to
1593 * to free the string with RtlFreeUnicodeString when it is no longer
1598 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1599 PUNICODE_STRING ParentIdPrefix
)
1601 ULONG KeyNameBufferLength
;
1602 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1603 UNICODE_STRING KeyName
= {0, 0, NULL
};
1604 UNICODE_STRING KeyValue
;
1605 UNICODE_STRING ValueName
;
1610 /* HACK: As long as some devices have a NULL device
1611 * instance path, the following test is required :(
1613 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1615 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1616 &DeviceNode
->InstancePath
);
1617 return STATUS_UNSUCCESSFUL
;
1620 /* 1. Try to retrieve ParentIdPrefix from registry */
1621 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1622 ParentIdPrefixInformation
= ExAllocatePool(PagedPool
, KeyNameBufferLength
+ sizeof(WCHAR
));
1623 if (!ParentIdPrefixInformation
)
1625 return STATUS_INSUFFICIENT_RESOURCES
;
1628 KeyName
.Buffer
= ExAllocatePool(PagedPool
, (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
);
1629 if (!KeyName
.Buffer
)
1631 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1635 KeyName
.MaximumLength
= (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
;
1637 RtlAppendUnicodeToString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1638 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1640 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1641 if (!NT_SUCCESS(Status
))
1643 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1644 Status
= ZwQueryValueKey(
1646 KeyValuePartialInformation
, ParentIdPrefixInformation
,
1647 KeyNameBufferLength
, &KeyNameBufferLength
);
1648 if (NT_SUCCESS(Status
))
1650 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1651 Status
= STATUS_UNSUCCESSFUL
;
1654 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1655 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1659 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1661 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1662 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1666 /* 2. Create the ParentIdPrefix value */
1667 crc32
= RtlComputeCrc32(0,
1668 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1669 DeviceNode
->Parent
->InstancePath
.Length
);
1671 swprintf((PWSTR
)ParentIdPrefixInformation
->Data
, L
"%lx&%lx", DeviceNode
->Parent
->Level
, crc32
);
1672 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
->Data
);
1674 /* 3. Try to write the ParentIdPrefix to registry */
1675 Status
= ZwSetValueKey(hKey
,
1679 (PVOID
)KeyValue
.Buffer
,
1680 ((ULONG
)wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
1683 if (NT_SUCCESS(Status
))
1685 /* Duplicate the string to return it */
1686 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &KeyValue
, ParentIdPrefix
);
1688 ExFreePool(ParentIdPrefixInformation
);
1689 RtlFreeUnicodeString(&KeyName
);
1696 IopQueryHardwareIds(PDEVICE_NODE DeviceNode
,
1699 IO_STACK_LOCATION Stack
;
1700 IO_STATUS_BLOCK IoStatusBlock
;
1702 UNICODE_STRING ValueName
;
1704 ULONG Length
, TotalLength
;
1706 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1708 RtlZeroMemory(&Stack
, sizeof(Stack
));
1709 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
1710 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1714 if (NT_SUCCESS(Status
))
1717 * FIXME: Check for valid characters, if there is invalid characters
1721 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1722 DPRINT("Hardware IDs:\n");
1725 DPRINT(" %S\n", Ptr
);
1726 Length
= (ULONG
)wcslen(Ptr
) + 1;
1729 TotalLength
+= Length
;
1731 DPRINT("TotalLength: %hu\n", TotalLength
);
1734 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
1735 Status
= ZwSetValueKey(InstanceKey
,
1739 (PVOID
)IoStatusBlock
.Information
,
1740 (TotalLength
+ 1) * sizeof(WCHAR
));
1741 if (!NT_SUCCESS(Status
))
1743 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1748 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1755 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode
,
1758 IO_STACK_LOCATION Stack
;
1759 IO_STATUS_BLOCK IoStatusBlock
;
1761 UNICODE_STRING ValueName
;
1763 ULONG Length
, TotalLength
;
1765 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1767 RtlZeroMemory(&Stack
, sizeof(Stack
));
1768 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1769 Status
= IopInitiatePnpIrp(
1770 DeviceNode
->PhysicalDeviceObject
,
1774 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1777 * FIXME: Check for valid characters, if there is invalid characters
1781 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1782 DPRINT("Compatible IDs:\n");
1785 DPRINT(" %S\n", Ptr
);
1786 Length
= (ULONG
)wcslen(Ptr
) + 1;
1789 TotalLength
+= Length
;
1791 DPRINT("TotalLength: %hu\n", TotalLength
);
1794 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
1795 Status
= ZwSetValueKey(InstanceKey
,
1799 (PVOID
)IoStatusBlock
.Information
,
1800 (TotalLength
+ 1) * sizeof(WCHAR
));
1801 if (!NT_SUCCESS(Status
))
1803 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
1808 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1816 * IopActionInterrogateDeviceStack
1818 * Retrieve information for all (direct) child nodes of a parent node.
1822 * Pointer to device node.
1824 * Pointer to parent node to retrieve child node information for.
1827 * Any errors that occur are logged instead so that all child services have a chance
1828 * of being interrogated.
1832 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
1835 IO_STATUS_BLOCK IoStatusBlock
;
1836 PDEVICE_NODE ParentDeviceNode
;
1837 WCHAR InstancePath
[MAX_PATH
];
1838 IO_STACK_LOCATION Stack
;
1840 ULONG RequiredLength
;
1842 HANDLE InstanceKey
= NULL
;
1843 UNICODE_STRING ValueName
;
1844 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
1845 DEVICE_CAPABILITIES DeviceCapabilities
;
1847 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
1848 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
1850 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1853 * We are called for the parent too, but we don't need to do special
1854 * handling for this node
1857 if (DeviceNode
== ParentDeviceNode
)
1859 DPRINT("Success\n");
1860 return STATUS_SUCCESS
;
1864 * Make sure this device node is a direct child of the parent device node
1865 * that is given as an argument
1868 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1870 DPRINT("Skipping 2+ level child\n");
1871 return STATUS_SUCCESS
;
1874 /* Skip processing if it was already completed before */
1875 if (DeviceNode
->Flags
& DNF_PROCESSED
)
1878 return STATUS_SUCCESS
;
1882 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
1883 if (!NT_SUCCESS(Status
))
1885 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
1890 * FIXME: For critical errors, cleanup and disable device, but always
1891 * return STATUS_SUCCESS.
1894 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1896 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
1897 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1901 if (NT_SUCCESS(Status
))
1903 /* Copy the device id string */
1904 wcscpy(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1907 * FIXME: Check for valid characters, if there is invalid characters
1913 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1915 /* We have to return success otherwise we abort the traverse operation */
1916 return STATUS_SUCCESS
;
1919 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1921 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
1922 if (!NT_SUCCESS(Status
))
1924 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
1926 /* We have to return success otherwise we abort the traverse operation */
1927 return STATUS_SUCCESS
;
1930 /* This bit is only check after enumeration */
1931 if (DeviceCapabilities
.HardwareDisabled
)
1933 /* FIXME: Cleanup device */
1934 DeviceNode
->Flags
|= DNF_DISABLED
;
1935 return STATUS_SUCCESS
;
1938 DeviceNode
->Flags
&= ~DNF_DISABLED
;
1940 if (!DeviceCapabilities
.UniqueID
)
1942 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1943 DPRINT("Instance ID is not unique\n");
1944 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
1945 if (!NT_SUCCESS(Status
))
1947 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
1949 /* We have to return success otherwise we abort the traverse operation */
1950 return STATUS_SUCCESS
;
1954 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1956 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
1957 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1961 if (NT_SUCCESS(Status
))
1963 /* Append the instance id string */
1964 wcscat(InstancePath
, L
"\\");
1965 if (ParentIdPrefix
.Length
> 0)
1967 /* Add information from parent bus device to InstancePath */
1968 wcscat(InstancePath
, ParentIdPrefix
.Buffer
);
1969 if (IoStatusBlock
.Information
&& *(PWSTR
)IoStatusBlock
.Information
)
1970 wcscat(InstancePath
, L
"&");
1972 if (IoStatusBlock
.Information
)
1973 wcscat(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1976 * FIXME: Check for valid characters, if there is invalid characters
1982 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1984 RtlFreeUnicodeString(&ParentIdPrefix
);
1986 if (!RtlCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
))
1988 DPRINT("No resources\n");
1989 /* FIXME: Cleanup and disable device */
1992 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
1995 * Create registry key for the instance id, if it doesn't exist yet
1997 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
1998 if (!NT_SUCCESS(Status
))
2000 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2002 /* We have to return success otherwise we abort the traverse operation */
2003 return STATUS_SUCCESS
;
2006 IopQueryHardwareIds(DeviceNode
, InstanceKey
);
2008 IopQueryCompatibleIds(DeviceNode
, InstanceKey
);
2010 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2012 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2013 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2014 Status
= IopInitiatePnpIrp(
2015 DeviceNode
->PhysicalDeviceObject
,
2017 IRP_MN_QUERY_DEVICE_TEXT
,
2019 /* This key is mandatory, so even if the Irp fails, we still write it */
2020 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2021 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2023 if (NT_SUCCESS(Status
) &&
2024 IoStatusBlock
.Information
&&
2025 (*(PWSTR
)IoStatusBlock
.Information
!= 0))
2027 /* This key is overriden when a driver is installed. Don't write the
2028 * new description if another one already exists */
2029 Status
= ZwSetValueKey(InstanceKey
,
2033 (PVOID
)IoStatusBlock
.Information
,
2034 ((ULONG
)wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2038 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2039 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2041 Status
= ZwSetValueKey(InstanceKey
,
2046 DeviceDesc
.MaximumLength
);
2048 if (!NT_SUCCESS(Status
))
2050 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2056 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2058 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2059 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2060 Status
= IopInitiatePnpIrp(
2061 DeviceNode
->PhysicalDeviceObject
,
2063 IRP_MN_QUERY_DEVICE_TEXT
,
2065 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2067 DPRINT("LocationInformation: %S\n", (PWSTR
)IoStatusBlock
.Information
);
2068 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2069 Status
= ZwSetValueKey(InstanceKey
,
2073 (PVOID
)IoStatusBlock
.Information
,
2074 ((ULONG
)wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2075 if (!NT_SUCCESS(Status
))
2077 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2082 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2085 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2087 Status
= IopInitiatePnpIrp(
2088 DeviceNode
->PhysicalDeviceObject
,
2090 IRP_MN_QUERY_BUS_INFORMATION
,
2092 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2094 PPNP_BUS_INFORMATION BusInformation
=
2095 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2097 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2098 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2099 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2100 ExFreePool(BusInformation
);
2104 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2106 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2107 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2108 DeviceNode
->ChildBusTypeIndex
= -1;
2111 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2113 Status
= IopInitiatePnpIrp(
2114 DeviceNode
->PhysicalDeviceObject
,
2116 IRP_MN_QUERY_RESOURCES
,
2118 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2120 DeviceNode
->BootResources
=
2121 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2122 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
2126 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2127 DeviceNode
->BootResources
= NULL
;
2130 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2132 Status
= IopInitiatePnpIrp(
2133 DeviceNode
->PhysicalDeviceObject
,
2135 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2137 if (NT_SUCCESS(Status
))
2139 DeviceNode
->ResourceRequirements
=
2140 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2144 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2145 DeviceNode
->ResourceRequirements
= NULL
;
2148 if (InstanceKey
!= NULL
)
2150 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2153 ZwClose(InstanceKey
);
2155 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2157 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2159 /* Report the device to the user-mode pnp manager */
2160 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2161 &DeviceNode
->InstancePath
);
2164 return STATUS_SUCCESS
;
2169 IopHandleDeviceRemoval(
2170 IN PDEVICE_NODE DeviceNode
,
2171 IN PDEVICE_RELATIONS DeviceRelations
)
2173 PDEVICE_NODE Child
= DeviceNode
->Child
, NextChild
;
2177 while (Child
!= NULL
)
2179 NextChild
= Child
->Sibling
;
2182 for (i
= 0; DeviceRelations
&& i
< DeviceRelations
->Count
; i
++)
2184 if (IopGetDeviceNode(DeviceRelations
->Objects
[i
]) == Child
)
2191 if (!Found
&& !(Child
->Flags
& DNF_WILL_BE_REMOVED
))
2193 /* Send removal IRPs to all of its children */
2194 IopPrepareDeviceForRemoval(Child
->PhysicalDeviceObject
, TRUE
);
2196 /* Send the surprise removal IRP */
2197 IopSendSurpriseRemoval(Child
->PhysicalDeviceObject
);
2199 /* Tell the user-mode PnP manager that a device was removed */
2200 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
2201 &Child
->InstancePath
);
2203 /* Send the remove device IRP */
2204 IopSendRemoveDevice(Child
->PhysicalDeviceObject
);
2213 IN PDEVICE_OBJECT DeviceObject
)
2215 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2216 DEVICETREE_TRAVERSE_CONTEXT Context
;
2217 PDEVICE_RELATIONS DeviceRelations
;
2218 PDEVICE_OBJECT ChildDeviceObject
;
2219 IO_STATUS_BLOCK IoStatusBlock
;
2220 PDEVICE_NODE ChildDeviceNode
;
2221 IO_STACK_LOCATION Stack
;
2225 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2227 if (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
)
2229 DeviceNode
->Flags
&= ~DNF_NEED_ENUMERATION_ONLY
;
2231 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2232 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2233 &DeviceNode
->InstancePath
);
2236 DeviceNode
->Flags
&= ~DNF_NEED_TO_ENUM
;
2238 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2240 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2242 Status
= IopInitiatePnpIrp(
2245 IRP_MN_QUERY_DEVICE_RELATIONS
,
2247 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2249 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2253 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2256 * Send removal IRPs for devices that have disappeared
2257 * NOTE: This code handles the case where no relations are specified
2259 IopHandleDeviceRemoval(DeviceNode
, DeviceRelations
);
2261 /* Now we bail if nothing was returned */
2262 if (!DeviceRelations
)
2264 /* We're all done */
2265 DPRINT("No PDOs\n");
2266 return STATUS_SUCCESS
;
2269 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2272 * Create device nodes for all discovered devices
2274 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2276 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2277 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2279 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2280 if (!ChildDeviceNode
)
2282 /* One doesn't exist, create it */
2283 Status
= IopCreateDeviceNode(
2288 if (NT_SUCCESS(Status
))
2290 /* Mark the node as enumerated */
2291 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2293 /* Mark the DO as bus enumerated */
2294 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2298 /* Ignore this DO */
2299 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2300 ObDereferenceObject(ChildDeviceObject
);
2305 /* Mark it as enumerated */
2306 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2307 ObDereferenceObject(ChildDeviceObject
);
2310 ExFreePool(DeviceRelations
);
2313 * Retrieve information about all discovered children from the bus driver
2315 IopInitDeviceTreeTraverseContext(
2318 IopActionInterrogateDeviceStack
,
2321 Status
= IopTraverseDeviceTree(&Context
);
2322 if (!NT_SUCCESS(Status
))
2324 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2329 * Retrieve configuration from the registry for discovered children
2331 IopInitDeviceTreeTraverseContext(
2334 IopActionConfigureChildServices
,
2337 Status
= IopTraverseDeviceTree(&Context
);
2338 if (!NT_SUCCESS(Status
))
2340 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2345 * Initialize services for discovered children.
2347 Status
= IopInitializePnpServices(DeviceNode
);
2348 if (!NT_SUCCESS(Status
))
2350 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2354 DPRINT("IopEnumerateDevice() finished\n");
2355 return STATUS_SUCCESS
;
2360 * IopActionConfigureChildServices
2362 * Retrieve configuration for all (direct) child nodes of a parent node.
2366 * Pointer to device node.
2368 * Pointer to parent node to retrieve child node configuration for.
2371 * Any errors that occur are logged instead so that all child services have a chance of beeing
2376 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2379 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2380 PDEVICE_NODE ParentDeviceNode
;
2381 PUNICODE_STRING Service
;
2382 UNICODE_STRING ClassGUID
;
2384 DEVICE_CAPABILITIES DeviceCaps
;
2386 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2388 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2391 * We are called for the parent too, but we don't need to do special
2392 * handling for this node
2394 if (DeviceNode
== ParentDeviceNode
)
2396 DPRINT("Success\n");
2397 return STATUS_SUCCESS
;
2401 * Make sure this device node is a direct child of the parent device node
2402 * that is given as an argument
2405 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2407 DPRINT("Skipping 2+ level child\n");
2408 return STATUS_SUCCESS
;
2411 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2413 DPRINT1("Child not ready to be configured\n");
2414 return STATUS_SUCCESS
;
2417 if (!(DeviceNode
->Flags
& (DNF_DISABLED
| DNF_STARTED
| DNF_ADDED
)))
2419 WCHAR RegKeyBuffer
[MAX_PATH
];
2420 UNICODE_STRING RegKey
;
2422 /* Install the service for this if it's in the CDDB */
2423 //IopInstallCriticalDevice(DeviceNode);
2426 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2427 RegKey
.Buffer
= RegKeyBuffer
;
2430 * Retrieve configuration from Enum key
2433 Service
= &DeviceNode
->ServiceName
;
2435 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2436 RtlInitUnicodeString(Service
, NULL
);
2437 RtlInitUnicodeString(&ClassGUID
, NULL
);
2439 QueryTable
[0].Name
= L
"Service";
2440 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2441 QueryTable
[0].EntryContext
= Service
;
2443 QueryTable
[1].Name
= L
"ClassGUID";
2444 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2445 QueryTable
[1].EntryContext
= &ClassGUID
;
2446 QueryTable
[1].DefaultType
= REG_SZ
;
2447 QueryTable
[1].DefaultData
= L
"";
2448 QueryTable
[1].DefaultLength
= 0;
2450 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2451 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2453 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2454 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2456 if (!NT_SUCCESS(Status
))
2458 /* FIXME: Log the error */
2459 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2460 &DeviceNode
->InstancePath
, Status
);
2461 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2462 return STATUS_SUCCESS
;
2465 if (Service
->Buffer
== NULL
)
2467 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2468 DeviceCaps
.RawDeviceOK
)
2470 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2472 DeviceNode
->ServiceName
.Length
= 0;
2473 DeviceNode
->ServiceName
.MaximumLength
= 0;
2474 DeviceNode
->ServiceName
.Buffer
= NULL
;
2476 else if (ClassGUID
.Length
!= 0)
2478 /* Device has a ClassGUID value, but no Service value.
2479 * Suppose it is using the NULL driver, so state the
2480 * device is started */
2481 DPRINT("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2482 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2486 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2488 return STATUS_SUCCESS
;
2491 DPRINT("Got Service %S\n", Service
->Buffer
);
2494 return STATUS_SUCCESS
;
2498 * IopActionInitChildServices
2500 * Initialize the service for all (direct) child nodes of a parent node
2504 * Pointer to device node.
2506 * Pointer to parent node to initialize child node services for.
2509 * If the driver image for a service is not loaded and initialized
2510 * it is done here too. Any errors that occur are logged instead so
2511 * that all child services have a chance of being initialized.
2515 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2518 PDEVICE_NODE ParentDeviceNode
;
2520 BOOLEAN BootDrivers
= !PnpSystemInit
;
2522 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2524 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2527 * We are called for the parent too, but we don't need to do special
2528 * handling for this node
2530 if (DeviceNode
== ParentDeviceNode
)
2532 DPRINT("Success\n");
2533 return STATUS_SUCCESS
;
2537 * Make sure this device node is a direct child of the parent device node
2538 * that is given as an argument
2541 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2543 DPRINT("Skipping 2+ level child\n");
2544 return STATUS_SUCCESS
;
2547 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2549 DPRINT1("Child not ready to be added\n");
2550 return STATUS_SUCCESS
;
2553 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
) ||
2554 IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) ||
2555 IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2557 if (DeviceNode
->Flags
& DNF_NEED_TO_ENUM
)
2559 Status
= IopInitializeDevice(DeviceNode
, NULL
);
2560 if (NT_SUCCESS(Status
))
2563 DeviceNode
->Flags
&= ~DNF_STARTED
;
2564 Status
= IopStartDevice(DeviceNode
);
2565 if (!NT_SUCCESS(Status
))
2567 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2568 &DeviceNode
->InstancePath
, Status
);
2571 DeviceNode
->Flags
&= ~DNF_NEED_TO_ENUM
;
2573 return STATUS_SUCCESS
;
2576 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
2578 /* We don't need to worry about loading the driver because we're
2579 * being driven in raw mode so our parent must be loaded to get here */
2580 Status
= IopInitializeDevice(DeviceNode
, NULL
);
2581 if (NT_SUCCESS(Status
))
2583 Status
= IopStartDevice(DeviceNode
);
2584 if (!NT_SUCCESS(Status
))
2586 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2587 &DeviceNode
->InstancePath
, Status
);
2593 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2594 PDRIVER_OBJECT DriverObject
;
2596 /* Get existing DriverObject pointer (in case the driver has
2597 already been loaded and initialized) */
2598 Status
= IopGetDriverObject(
2600 &DeviceNode
->ServiceName
,
2603 if (!NT_SUCCESS(Status
))
2605 /* Driver is not initialized, try to load it */
2606 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2608 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2610 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2611 was loaded by the bootloader */
2612 if ((Status
!= STATUS_IMAGE_ALREADY_LOADED
) ||
2613 (Status
== STATUS_IMAGE_ALREADY_LOADED
&& !DriverObject
))
2615 /* Initialize the driver */
2616 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2617 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2621 Status
= STATUS_SUCCESS
;
2626 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2627 &DeviceNode
->ServiceName
, Status
);
2631 /* Driver is loaded and initialized at this point */
2632 if (NT_SUCCESS(Status
))
2634 /* Initialize the device, including all filters */
2635 Status
= PipCallDriverAddDevice(DeviceNode
, FALSE
, DriverObject
);
2640 * Don't disable when trying to load only boot drivers
2644 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2645 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
2646 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2647 DPRINT1("Initialization of service %S failed (Status %x)\n",
2648 DeviceNode
->ServiceName
.Buffer
, Status
);
2653 return STATUS_SUCCESS
;
2657 * IopInitializePnpServices
2659 * Initialize services for discovered children
2663 * Top device node to start initializing services.
2669 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2671 DEVICETREE_TRAVERSE_CONTEXT Context
;
2673 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2675 IopInitDeviceTreeTraverseContext(
2678 IopActionInitChildServices
,
2681 return IopTraverseDeviceTree(&Context
);
2684 static NTSTATUS INIT_FUNCTION
2685 IopEnumerateDetectedDevices(
2687 IN PUNICODE_STRING RelativePath OPTIONAL
,
2689 IN BOOLEAN EnumerateSubKeys
,
2690 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2691 IN ULONG ParentBootResourcesLength
)
2693 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2694 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2695 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2696 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2697 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2698 OBJECT_ATTRIBUTES ObjectAttributes
;
2699 HANDLE hDevicesKey
= NULL
;
2700 HANDLE hDeviceKey
= NULL
;
2701 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2702 UNICODE_STRING Level2NameU
;
2703 WCHAR Level2Name
[5];
2704 ULONG IndexDevice
= 0;
2706 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2707 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2708 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2709 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2710 UNICODE_STRING DeviceName
, ValueName
;
2712 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2713 ULONG BootResourcesLength
;
2716 const UNICODE_STRING IdentifierPci
= RTL_CONSTANT_STRING(L
"PCI");
2717 UNICODE_STRING HardwareIdPci
= RTL_CONSTANT_STRING(L
"*PNP0A03\0");
2718 static ULONG DeviceIndexPci
= 0;
2719 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2720 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2721 static ULONG DeviceIndexSerial
= 0;
2722 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2723 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2724 static ULONG DeviceIndexKeyboard
= 0;
2725 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2726 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2727 static ULONG DeviceIndexMouse
= 0;
2728 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
2729 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
2730 static ULONG DeviceIndexParallel
= 0;
2731 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
2732 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
2733 static ULONG DeviceIndexFloppy
= 0;
2734 const UNICODE_STRING IdentifierIsa
= RTL_CONSTANT_STRING(L
"ISA");
2735 UNICODE_STRING HardwareIdIsa
= RTL_CONSTANT_STRING(L
"*PNP0A00\0");
2736 static ULONG DeviceIndexIsa
= 0;
2737 UNICODE_STRING HardwareIdKey
;
2738 PUNICODE_STRING pHardwareId
;
2739 ULONG DeviceIndex
= 0;
2740 PUCHAR CmResourceList
;
2745 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
2746 if (!NT_SUCCESS(Status
))
2748 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2753 hDevicesKey
= hBaseKey
;
2755 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2756 if (!pDeviceInformation
)
2758 DPRINT("ExAllocatePool() failed\n");
2759 Status
= STATUS_NO_MEMORY
;
2763 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2764 if (!pValueInformation
)
2766 DPRINT("ExAllocatePool() failed\n");
2767 Status
= STATUS_NO_MEMORY
;
2773 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2774 if (Status
== STATUS_NO_MORE_ENTRIES
)
2776 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2778 ExFreePool(pDeviceInformation
);
2779 DeviceInfoLength
= RequiredSize
;
2780 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2781 if (!pDeviceInformation
)
2783 DPRINT("ExAllocatePool() failed\n");
2784 Status
= STATUS_NO_MEMORY
;
2787 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2789 if (!NT_SUCCESS(Status
))
2791 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2796 /* Open device key */
2797 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2798 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2800 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
2801 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
2802 if (!NT_SUCCESS(Status
))
2804 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2808 /* Read boot resources, and add then to parent ones */
2809 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2810 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2812 ExFreePool(pValueInformation
);
2813 ValueInfoLength
= RequiredSize
;
2814 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2815 if (!pValueInformation
)
2817 DPRINT("ExAllocatePool() failed\n");
2818 ZwDeleteKey(hLevel2Key
);
2819 Status
= STATUS_NO_MEMORY
;
2822 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2824 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
2826 BootResources
= ParentBootResources
;
2827 BootResourcesLength
= ParentBootResourcesLength
;
2829 else if (!NT_SUCCESS(Status
))
2831 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2834 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
2836 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
2841 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
2843 /* Concatenate current resources and parent ones */
2844 if (ParentBootResourcesLength
== 0)
2845 BootResourcesLength
= pValueInformation
->DataLength
;
2847 BootResourcesLength
= ParentBootResourcesLength
2848 + pValueInformation
->DataLength
2850 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
2853 DPRINT("ExAllocatePool() failed\n");
2856 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
2858 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2860 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
2862 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2864 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
2865 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2866 ParentBootResourcesLength
- Header
);
2867 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2871 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
2873 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
2874 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2875 ParentBootResourcesLength
- Header
);
2877 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
2878 pValueInformation
->Data
+ Header
,
2879 pValueInformation
->DataLength
- Header
);
2880 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2884 if (EnumerateSubKeys
)
2889 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2890 if (Status
== STATUS_NO_MORE_ENTRIES
)
2892 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2894 ExFreePool(pDeviceInformation
);
2895 DeviceInfoLength
= RequiredSize
;
2896 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2897 if (!pDeviceInformation
)
2899 DPRINT("ExAllocatePool() failed\n");
2900 Status
= STATUS_NO_MEMORY
;
2903 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2905 if (!NT_SUCCESS(Status
))
2907 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2911 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2912 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2914 Status
= IopEnumerateDetectedDevices(
2920 BootResourcesLength
);
2921 if (!NT_SUCCESS(Status
))
2926 /* Read identifier */
2927 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2928 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2930 ExFreePool(pValueInformation
);
2931 ValueInfoLength
= RequiredSize
;
2932 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2933 if (!pValueInformation
)
2935 DPRINT("ExAllocatePool() failed\n");
2936 Status
= STATUS_NO_MEMORY
;
2939 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2941 if (!NT_SUCCESS(Status
))
2943 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
2945 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2948 ValueName
.Length
= ValueName
.MaximumLength
= 0;
2950 else if (pValueInformation
->Type
!= REG_SZ
)
2952 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
2957 /* Assign hardware id to this device */
2958 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
2959 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
2960 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
2961 ValueName
.Length
-= sizeof(WCHAR
);
2964 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
2966 pHardwareId
= &HardwareIdSerial
;
2967 DeviceIndex
= DeviceIndexSerial
++;
2969 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
2971 pHardwareId
= &HardwareIdKeyboard
;
2972 DeviceIndex
= DeviceIndexKeyboard
++;
2974 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
2976 pHardwareId
= &HardwareIdMouse
;
2977 DeviceIndex
= DeviceIndexMouse
++;
2979 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
2981 pHardwareId
= &HardwareIdParallel
;
2982 DeviceIndex
= DeviceIndexParallel
++;
2984 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
2986 pHardwareId
= &HardwareIdFloppy
;
2987 DeviceIndex
= DeviceIndexFloppy
++;
2989 else if (NT_SUCCESS(Status
))
2991 /* Try to also match the device identifier */
2992 if (RtlCompareUnicodeString(&ValueName
, &IdentifierPci
, FALSE
) == 0)
2994 pHardwareId
= &HardwareIdPci
;
2995 DeviceIndex
= DeviceIndexPci
++;
2997 else if (RtlCompareUnicodeString(&ValueName
, &IdentifierIsa
, FALSE
) == 0)
2999 pHardwareId
= &HardwareIdIsa
;
3000 DeviceIndex
= DeviceIndexIsa
++;
3004 DPRINT("Unknown device '%wZ'\n", &ValueName
);
3010 /* Unknown key path */
3011 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
3015 /* Prepare hardware id key (hardware id value without final \0) */
3016 HardwareIdKey
= *pHardwareId
;
3017 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
3019 /* Add the detected device to Root key */
3020 InitializeObjectAttributes(&ObjectAttributes
, &HardwareIdKey
, OBJ_KERNEL_HANDLE
, hRootKey
, NULL
);
3021 Status
= ZwCreateKey(
3027 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
3029 if (!NT_SUCCESS(Status
))
3031 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3034 swprintf(Level2Name
, L
"%04lu", DeviceIndex
);
3035 RtlInitUnicodeString(&Level2NameU
, Level2Name
);
3036 InitializeObjectAttributes(&ObjectAttributes
, &Level2NameU
, OBJ_KERNEL_HANDLE
, hLevel1Key
, NULL
);
3037 Status
= ZwCreateKey(
3039 KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
,
3043 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
3045 ZwClose(hLevel1Key
);
3046 if (!NT_SUCCESS(Status
))
3048 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3051 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName
, DeviceIndex
, &HardwareIdKey
);
3052 Status
= ZwSetValueKey(hLevel2Key
, &HardwareIDU
, 0, REG_MULTI_SZ
, pHardwareId
->Buffer
, pHardwareId
->MaximumLength
);
3053 if (!NT_SUCCESS(Status
))
3055 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3056 ZwDeleteKey(hLevel2Key
);
3059 /* Create 'LogConf' subkey */
3060 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
, hLevel2Key
, NULL
);
3061 Status
= ZwCreateKey(
3067 REG_OPTION_VOLATILE
,
3069 if (!NT_SUCCESS(Status
))
3071 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3072 ZwDeleteKey(hLevel2Key
);
3075 if (BootResourcesLength
>= sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3077 CmResourceList
= ExAllocatePool(PagedPool
, BootResourcesLength
+ sizeof(ULONG
));
3078 if (!CmResourceList
)
3081 ZwDeleteKey(hLevel2Key
);
3085 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3087 RtlCopyMemory(CmResourceList
,
3091 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3092 RtlCopyMemory(CmResourceList
+ sizeof(ULONG
),
3094 BootResourcesLength
);
3096 /* Save boot resources to 'LogConf\BootConfig' */
3097 Status
= ZwSetValueKey(hLogConf
, &BootConfigU
, 0, REG_RESOURCE_LIST
, CmResourceList
, BootResourcesLength
+ sizeof(ULONG
));
3098 if (!NT_SUCCESS(Status
))
3100 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3102 ZwDeleteKey(hLevel2Key
);
3109 if (BootResources
&& BootResources
!= ParentBootResources
)
3111 ExFreePool(BootResources
);
3112 BootResources
= NULL
;
3116 ZwClose(hLevel2Key
);
3121 ZwClose(hDeviceKey
);
3126 Status
= STATUS_SUCCESS
;
3129 if (hDevicesKey
&& hDevicesKey
!= hBaseKey
)
3130 ZwClose(hDevicesKey
);
3132 ZwClose(hDeviceKey
);
3133 if (pDeviceInformation
)
3134 ExFreePool(pDeviceInformation
);
3135 if (pValueInformation
)
3136 ExFreePool(pValueInformation
);
3140 static BOOLEAN INIT_FUNCTION
3141 IopIsFirmwareMapperDisabled(VOID
)
3143 UNICODE_STRING KeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3144 UNICODE_STRING KeyNameU
= RTL_CONSTANT_STRING(L
"DisableFirmwareMapper");
3145 OBJECT_ATTRIBUTES ObjectAttributes
;
3147 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
;
3148 ULONG DesiredLength
, Length
;
3152 InitializeObjectAttributes(&ObjectAttributes
, &KeyPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3153 Status
= ZwOpenKey(&hPnpKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
3154 if (NT_SUCCESS(Status
))
3156 Status
= ZwQueryValueKey(hPnpKey
,
3158 KeyValuePartialInformation
,
3162 if ((Status
== STATUS_BUFFER_TOO_SMALL
) ||
3163 (Status
== STATUS_BUFFER_OVERFLOW
))
3165 Length
= DesiredLength
;
3166 KeyInformation
= ExAllocatePool(PagedPool
, Length
);
3169 Status
= ZwQueryValueKey(hPnpKey
,
3171 KeyValuePartialInformation
,
3175 if (NT_SUCCESS(Status
) && KeyInformation
->DataLength
== sizeof(ULONG
))
3177 KeyValue
= (ULONG
)(*KeyInformation
->Data
);
3181 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU
, &KeyNameU
);
3184 ExFreePool(KeyInformation
);
3188 DPRINT1("Failed to allocate memory for registry query\n");
3193 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU
, &KeyNameU
, Status
);
3200 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU
, Status
);
3203 DPRINT1("Firmware mapper is %s\n", KeyValue
!= 0 ? "disabled" : "enabled");
3205 return (KeyValue
!= 0) ? TRUE
: FALSE
;
3211 IopUpdateRootKey(VOID
)
3213 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3214 UNICODE_STRING RootPathU
= RTL_CONSTANT_STRING(L
"Root");
3215 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3216 OBJECT_ATTRIBUTES ObjectAttributes
;
3217 HANDLE hEnum
, hRoot
;
3220 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3221 Status
= ZwCreateKey(&hEnum
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
3222 if (!NT_SUCCESS(Status
))
3224 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3228 InitializeObjectAttributes(&ObjectAttributes
, &RootPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
3229 Status
= ZwCreateKey(&hRoot
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
3231 if (!NT_SUCCESS(Status
))
3233 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3237 if (!IopIsFirmwareMapperDisabled())
3239 Status
= IopOpenRegistryKeyEx(&hEnum
, NULL
, &MultiKeyPathU
, KEY_ENUMERATE_SUB_KEYS
);
3240 if (!NT_SUCCESS(Status
))
3242 /* Nothing to do, don't return with an error status */
3243 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3245 return STATUS_SUCCESS
;
3247 Status
= IopEnumerateDetectedDevices(
3258 /* Enumeration is disabled */
3259 Status
= STATUS_SUCCESS
;
3269 IopOpenRegistryKeyEx(PHANDLE KeyHandle
,
3271 PUNICODE_STRING Name
,
3272 ACCESS_MASK DesiredAccess
)
3274 OBJECT_ATTRIBUTES ObjectAttributes
;
3281 InitializeObjectAttributes(&ObjectAttributes
,
3283 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3287 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
3294 IopCreateRegistryKeyEx(OUT PHANDLE Handle
,
3295 IN HANDLE RootHandle OPTIONAL
,
3296 IN PUNICODE_STRING KeyName
,
3297 IN ACCESS_MASK DesiredAccess
,
3298 IN ULONG CreateOptions
,
3299 OUT PULONG Disposition OPTIONAL
)
3301 OBJECT_ATTRIBUTES ObjectAttributes
;
3302 ULONG KeyDisposition
, RootHandleIndex
= 0, i
= 1, NestedCloseLevel
= 0;
3304 HANDLE HandleArray
[2];
3305 BOOLEAN Recursing
= TRUE
;
3307 UNICODE_STRING KeyString
;
3308 NTSTATUS Status
= STATUS_SUCCESS
;
3311 /* P1 is start, pp is end */
3312 p1
= KeyName
->Buffer
;
3313 pp
= (PVOID
)((ULONG_PTR
)p1
+ KeyName
->Length
);
3315 /* Create the target key */
3316 InitializeObjectAttributes(&ObjectAttributes
,
3318 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3321 Status
= ZwCreateKey(&HandleArray
[i
],
3329 /* Now we check if this failed */
3330 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) && (RootHandle
))
3332 /* Target key failed, so we'll need to create its parent. Setup array */
3333 HandleArray
[0] = NULL
;
3334 HandleArray
[1] = RootHandle
;
3336 /* Keep recursing for each missing parent */
3339 /* And if we're deep enough, close the last handle */
3340 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3342 /* We're setup to ping-pong between the two handle array entries */
3343 RootHandleIndex
= i
;
3346 /* Clear the one we're attempting to open now */
3347 HandleArray
[i
] = NULL
;
3349 /* Process the parent key name */
3350 for (p
= p1
; ((p
< pp
) && (*p
!= OBJ_NAME_PATH_SEPARATOR
)); p
++);
3351 Length
= (USHORT
)(p
- p1
) * sizeof(WCHAR
);
3353 /* Is there a parent name? */
3356 /* Build the unicode string for it */
3357 KeyString
.Buffer
= p1
;
3358 KeyString
.Length
= KeyString
.MaximumLength
= Length
;
3360 /* Now try opening the parent */
3361 InitializeObjectAttributes(&ObjectAttributes
,
3363 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3364 HandleArray
[RootHandleIndex
],
3366 Status
= ZwCreateKey(&HandleArray
[i
],
3373 if (NT_SUCCESS(Status
))
3375 /* It worked, we have one more handle */
3380 /* Parent key creation failed, abandon loop */
3387 /* We don't have a parent name, probably corrupted key name */
3388 Status
= STATUS_INVALID_PARAMETER
;
3393 /* Now see if there's more parents to create */
3395 if ((p
== pp
) || (p1
== pp
))
3397 /* We're done, hopefully successfully, so stop */
3402 /* Outer loop check for handle nesting that requires closing the top handle */
3403 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3406 /* Check if we broke out of the loop due to success */
3407 if (NT_SUCCESS(Status
))
3409 /* Return the target handle (we closed all the parent ones) and disposition */
3410 *Handle
= HandleArray
[i
];
3411 if (Disposition
) *Disposition
= KeyDisposition
;
3414 /* Return the success state */
3420 IopGetRegistryValue(IN HANDLE Handle
,
3422 OUT PKEY_VALUE_FULL_INFORMATION
*Information
)
3424 UNICODE_STRING ValueString
;
3426 PKEY_VALUE_FULL_INFORMATION FullInformation
;
3430 RtlInitUnicodeString(&ValueString
, ValueName
);
3432 Status
= ZwQueryValueKey(Handle
,
3434 KeyValueFullInformation
,
3438 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
3439 (Status
!= STATUS_BUFFER_TOO_SMALL
))
3444 FullInformation
= ExAllocatePool(NonPagedPool
, Size
);
3445 if (!FullInformation
) return STATUS_INSUFFICIENT_RESOURCES
;
3447 Status
= ZwQueryValueKey(Handle
,
3449 KeyValueFullInformation
,
3453 if (!NT_SUCCESS(Status
))
3455 ExFreePool(FullInformation
);
3459 *Information
= FullInformation
;
3460 return STATUS_SUCCESS
;
3463 RTL_GENERIC_COMPARE_RESULTS
3465 PiCompareInstancePath(IN PRTL_AVL_TABLE Table
,
3466 IN PVOID FirstStruct
,
3467 IN PVOID SecondStruct
)
3475 // The allocation function is called by the generic table package whenever
3476 // it needs to allocate memory for the table.
3481 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3491 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3500 PpInitializeDeviceReferenceTable(VOID
)
3502 /* Setup the guarded mutex and AVL table */
3503 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock
);
3504 RtlInitializeGenericTableAvl(
3505 &PpDeviceReferenceTable
,
3506 (PRTL_AVL_COMPARE_ROUTINE
)PiCompareInstancePath
,
3507 (PRTL_AVL_ALLOCATE_ROUTINE
)PiAllocateGenericTableEntry
,
3508 (PRTL_AVL_FREE_ROUTINE
)PiFreeGenericTableEntry
,
3516 /* Initialize the resource when accessing device registry data */
3517 ExInitializeResourceLite(&PpRegistryDeviceResource
);
3519 /* Setup the device reference AVL table */
3520 PpInitializeDeviceReferenceTable();
3528 /* Check the initialization phase */
3529 switch (ExpInitializationPhase
)
3534 return PiInitPhase0();
3540 //return PiInitPhase1();
3544 /* Don't know any other phase! Bugcheck! */
3545 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL
);
3550 LONG IopNumberDeviceNodes
;
3554 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3556 PDEVICE_NODE DeviceNode
;
3560 DeviceNode
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), 'donD');
3561 if (!DeviceNode
) return DeviceNode
;
3564 InterlockedIncrement(&IopNumberDeviceNodes
);
3567 RtlZeroMemory(DeviceNode
, sizeof(DEVICE_NODE
));
3568 DeviceNode
->InterfaceType
= InterfaceTypeUndefined
;
3569 DeviceNode
->BusNumber
= -1;
3570 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
3571 DeviceNode
->ChildBusNumber
= -1;
3572 DeviceNode
->ChildBusTypeIndex
= -1;
3573 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3574 InitializeListHead(&DeviceNode
->DeviceArbiterList
);
3575 InitializeListHead(&DeviceNode
->DeviceTranslatorList
);
3576 InitializeListHead(&DeviceNode
->TargetDeviceNotify
);
3577 InitializeListHead(&DeviceNode
->DockInfo
.ListEntry
);
3578 InitializeListHead(&DeviceNode
->PendedSetInterfaceState
);
3580 /* Check if there is a PDO */
3581 if (PhysicalDeviceObject
)
3583 /* Link it and remove the init flag */
3584 DeviceNode
->PhysicalDeviceObject
= PhysicalDeviceObject
;
3585 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= DeviceNode
;
3586 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
3589 /* Return the node */
3593 /* PUBLIC FUNCTIONS **********************************************************/
3597 PnpBusTypeGuidGet(IN USHORT Index
,
3598 IN LPGUID BusTypeGuid
)
3600 NTSTATUS Status
= STATUS_SUCCESS
;
3602 /* Acquire the lock */
3603 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
3606 if (Index
< PnpBusTypeGuidList
->GuidCount
)
3609 RtlCopyMemory(BusTypeGuid
, &PnpBusTypeGuidList
->Guids
[Index
], sizeof(GUID
));
3614 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
3617 /* Release lock and return status */
3618 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
3624 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject
,
3625 IN PHANDLE DeviceInstanceHandle
,
3626 IN ACCESS_MASK DesiredAccess
)
3630 PDEVICE_NODE DeviceNode
;
3631 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3634 /* Open the enum key */
3635 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
3639 if (!NT_SUCCESS(Status
)) return Status
;
3641 /* Make sure we have an instance path */
3642 DeviceNode
= IopGetDeviceNode(DeviceObject
);
3643 if ((DeviceNode
) && (DeviceNode
->InstancePath
.Length
))
3645 /* Get the instance key */
3646 Status
= IopOpenRegistryKeyEx(DeviceInstanceHandle
,
3648 &DeviceNode
->InstancePath
,
3654 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3657 /* Close the handle and return status */
3664 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList
)
3666 ULONG FinalSize
, PartialSize
, EntrySize
, i
, j
;
3667 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
3668 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
3670 /* If we don't have one, that's easy */
3671 if (!ResourceList
) return 0;
3673 /* Start with the minimum size possible */
3674 FinalSize
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
3676 /* Loop each full descriptor */
3677 FullDescriptor
= ResourceList
->List
;
3678 for (i
= 0; i
< ResourceList
->Count
; i
++)
3680 /* Start with the minimum size possible */
3681 PartialSize
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
) +
3682 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST
, PartialDescriptors
);
3684 /* Loop each partial descriptor */
3685 PartialDescriptor
= FullDescriptor
->PartialResourceList
.PartialDescriptors
;
3686 for (j
= 0; j
< FullDescriptor
->PartialResourceList
.Count
; j
++)
3688 /* Start with the minimum size possible */
3689 EntrySize
= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
3691 /* Check if there is extra data */
3692 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
3695 EntrySize
+= PartialDescriptor
->u
.DeviceSpecificData
.DataSize
;
3698 /* The size of partial descriptors is bigger */
3699 PartialSize
+= EntrySize
;
3701 /* Go to the next partial descriptor */
3702 PartialDescriptor
= (PVOID
)((ULONG_PTR
)PartialDescriptor
+ EntrySize
);
3705 /* The size of full descriptors is bigger */
3706 FinalSize
+= PartialSize
;
3708 /* Go to the next full descriptor */
3709 FullDescriptor
= (PVOID
)((ULONG_PTR
)FullDescriptor
+ PartialSize
);
3712 /* Return the final size */
3718 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject
,
3723 IN PULONG BufferLength
)
3726 HANDLE KeyHandle
, SubHandle
;
3727 UNICODE_STRING KeyString
;
3728 PKEY_VALUE_FULL_INFORMATION KeyValueInfo
= NULL
;
3732 /* Find the instance key */
3733 Status
= PnpDeviceObjectToDeviceInstance(DeviceObject
, &KeyHandle
, KEY_READ
);
3734 if (NT_SUCCESS(Status
))
3736 /* Check for name given by caller */
3740 RtlInitUnicodeString(&KeyString
, KeyName
);
3741 Status
= IopOpenRegistryKeyEx(&SubHandle
,
3745 if (NT_SUCCESS(Status
))
3747 /* And use this handle instead */
3749 KeyHandle
= SubHandle
;
3753 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3754 if (NT_SUCCESS(Status
))
3756 /* Now get the size of the property */
3757 Status
= IopGetRegistryValue(KeyHandle
,
3766 /* Fail if any of the registry operations failed */
3767 if (!NT_SUCCESS(Status
)) return Status
;
3769 /* Check how much data we have to copy */
3770 Length
= KeyValueInfo
->DataLength
;
3771 if (*BufferLength
>= Length
)
3773 /* Check for a match in the value type */
3774 if (KeyValueInfo
->Type
== ValueType
)
3777 RtlCopyMemory(Buffer
,
3778 (PVOID
)((ULONG_PTR
)KeyValueInfo
+
3779 KeyValueInfo
->DataOffset
),
3784 /* Invalid registry property type, fail */
3785 Status
= STATUS_INVALID_PARAMETER_2
;
3790 /* Buffer is too small to hold data */
3791 Status
= STATUS_BUFFER_TOO_SMALL
;
3794 /* Return the required buffer length, free the buffer, and return status */
3795 *BufferLength
= Length
;
3796 ExFreePool(KeyValueInfo
);
3800 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3801 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3802 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED; while(TRUE); break;}
3809 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
3810 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
3811 IN ULONG BufferLength
,
3812 OUT PVOID PropertyBuffer
,
3813 OUT PULONG ResultLength
)
3815 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
3816 DEVICE_CAPABILITIES DeviceCaps
;
3817 ULONG ReturnLength
= 0, Length
= 0, ValueType
;
3818 PWCHAR ValueName
= NULL
, EnumeratorNameEnd
, DeviceInstanceName
;
3820 NTSTATUS Status
= STATUS_BUFFER_TOO_SMALL
;
3822 POBJECT_NAME_INFORMATION ObjectNameInfo
= NULL
;
3823 BOOLEAN NullTerminate
= FALSE
;
3825 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject
, DeviceProperty
);
3827 /* Assume failure */
3830 /* Only PDOs can call this */
3831 if (!DeviceNode
) return STATUS_INVALID_DEVICE_REQUEST
;
3833 /* Handle all properties */
3834 switch (DeviceProperty
)
3836 case DevicePropertyBusTypeGuid
:
3838 /* Get the GUID from the internal cache */
3839 Status
= PnpBusTypeGuidGet(DeviceNode
->ChildBusTypeIndex
, &BusTypeGuid
);
3840 if (!NT_SUCCESS(Status
)) return Status
;
3842 /* This is the format of the returned data */
3843 PIP_RETURN_DATA(sizeof(GUID
), &BusTypeGuid
);
3845 case DevicePropertyLegacyBusType
:
3847 /* Validate correct interface type */
3848 if (DeviceNode
->ChildInterfaceType
== InterfaceTypeUndefined
)
3849 return STATUS_OBJECT_NAME_NOT_FOUND
;
3851 /* This is the format of the returned data */
3852 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE
), &DeviceNode
->ChildInterfaceType
);
3854 case DevicePropertyBusNumber
:
3856 /* Validate correct bus number */
3857 if ((DeviceNode
->ChildBusNumber
& 0x80000000) == 0x80000000)
3858 return STATUS_OBJECT_NAME_NOT_FOUND
;
3860 /* This is the format of the returned data */
3861 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceNode
->ChildBusNumber
);
3863 case DevicePropertyEnumeratorName
:
3865 /* Get the instance path */
3866 DeviceInstanceName
= DeviceNode
->InstancePath
.Buffer
;
3869 ASSERT((BufferLength
& 1) == 0);
3870 ASSERT(DeviceInstanceName
!= NULL
);
3872 /* Get the name from the path */
3873 EnumeratorNameEnd
= wcschr(DeviceInstanceName
, OBJ_NAME_PATH_SEPARATOR
);
3874 ASSERT(EnumeratorNameEnd
);
3876 /* This string needs to be NULL-terminated */
3877 NullTerminate
= TRUE
;
3879 /* This is the format of the returned data */
3880 PIP_RETURN_DATA((ULONG
)(EnumeratorNameEnd
- DeviceInstanceName
) * sizeof(WCHAR
),
3881 DeviceInstanceName
);
3883 case DevicePropertyAddress
:
3885 /* Query the device caps */
3886 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
);
3887 if (!NT_SUCCESS(Status
) || (DeviceCaps
.Address
== MAXULONG
))
3888 return STATUS_OBJECT_NAME_NOT_FOUND
;
3890 /* This is the format of the returned data */
3891 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceCaps
.Address
);
3893 case DevicePropertyBootConfigurationTranslated
:
3895 /* Validate we have resources */
3896 if (!DeviceNode
->BootResources
)
3897 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3899 /* No resources will still fake success, but with 0 bytes */
3901 return STATUS_SUCCESS
;
3904 /* This is the format of the returned data */
3905 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode
->BootResources
), // FIXFIX: Should use BootResourcesTranslated
3906 DeviceNode
->BootResources
); // FIXFIX: Should use BootResourcesTranslated
3908 case DevicePropertyPhysicalDeviceObjectName
:
3910 /* Sanity check for Unicode-sized string */
3911 ASSERT((BufferLength
& 1) == 0);
3913 /* Allocate name buffer */
3914 Length
= BufferLength
+ sizeof(OBJECT_NAME_INFORMATION
);
3915 ObjectNameInfo
= ExAllocatePool(PagedPool
, Length
);
3916 if (!ObjectNameInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
3918 /* Query the PDO name */
3919 Status
= ObQueryNameString(DeviceObject
,
3923 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
3925 /* It's up to the caller to try again */
3926 Status
= STATUS_BUFFER_TOO_SMALL
;
3929 /* This string needs to be NULL-terminated */
3930 NullTerminate
= TRUE
;
3932 /* Return if successful */
3933 if (NT_SUCCESS(Status
)) PIP_RETURN_DATA(ObjectNameInfo
->Name
.Length
,
3934 ObjectNameInfo
->Name
.Buffer
);
3936 /* Let the caller know how big the name is */
3937 *ResultLength
-= sizeof(OBJECT_NAME_INFORMATION
);
3940 /* Handle the registry-based properties */
3941 case DevicePropertyUINumber
:
3942 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER
, REG_DWORD
);
3943 case DevicePropertyLocationInformation
:
3944 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION
, REG_SZ
);
3945 case DevicePropertyDeviceDescription
:
3946 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC
, REG_SZ
);
3947 case DevicePropertyHardwareID
:
3948 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID
, REG_MULTI_SZ
);
3949 case DevicePropertyCompatibleIDs
:
3950 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS
, REG_MULTI_SZ
);
3951 case DevicePropertyBootConfiguration
:
3952 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG
, REG_RESOURCE_LIST
);
3953 case DevicePropertyClassName
:
3954 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS
, REG_SZ
);
3955 case DevicePropertyClassGuid
:
3956 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID
, REG_SZ
);
3957 case DevicePropertyDriverKeyName
:
3958 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER
, REG_SZ
);
3959 case DevicePropertyManufacturer
:
3960 PIP_REGISTRY_DATA(REGSTR_VAL_MFG
, REG_SZ
);
3961 case DevicePropertyFriendlyName
:
3962 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME
, REG_SZ
);
3963 case DevicePropertyContainerID
:
3964 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3965 PIP_UNIMPLEMENTED();
3966 case DevicePropertyRemovalPolicy
:
3967 PIP_UNIMPLEMENTED();
3968 case DevicePropertyInstallState
:
3969 PIP_UNIMPLEMENTED();
3970 case DevicePropertyResourceRequirements
:
3971 PIP_UNIMPLEMENTED();
3972 case DevicePropertyAllocatedResources
:
3973 PIP_UNIMPLEMENTED();
3975 return STATUS_INVALID_PARAMETER_2
;
3978 /* Having a registry value name implies registry data */
3981 /* We know up-front how much data to expect */
3982 *ResultLength
= BufferLength
;
3984 /* Go get the data, use the LogConf subkey if necessary */
3985 Status
= PiGetDeviceRegistryProperty(DeviceObject
,
3989 DevicePropertyBootConfiguration
) ?
3994 else if (NT_SUCCESS(Status
))
3996 /* We know up-front how much data to expect, check the caller's buffer */
3997 *ResultLength
= ReturnLength
+ (NullTerminate
? sizeof(UNICODE_NULL
) : 0);
3998 if (*ResultLength
<= BufferLength
)
4000 /* Buffer is all good, copy the data */
4001 RtlCopyMemory(PropertyBuffer
, Data
, ReturnLength
);
4003 /* Check if we need to NULL-terminate the string */
4006 /* Terminate the string */
4007 ((PWCHAR
)PropertyBuffer
)[ReturnLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
4010 /* This is the success path */
4011 Status
= STATUS_SUCCESS
;
4016 Status
= STATUS_BUFFER_TOO_SMALL
;
4020 /* Free any allocation we may have made, and return the status code */
4021 if (ObjectNameInfo
) ExFreePool(ObjectNameInfo
);
4030 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject
)
4032 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
4033 IO_STACK_LOCATION Stack
;
4036 IO_STATUS_BLOCK IoStatusBlock
;
4038 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
4039 Stack
.MajorFunction
= IRP_MJ_PNP
;
4040 Stack
.MinorFunction
= IRP_MN_QUERY_PNP_DEVICE_STATE
;
4042 Status
= IopSynchronousCall(PhysicalDeviceObject
, &Stack
, (PVOID
*)&PnPFlags
);
4043 if (!NT_SUCCESS(Status
))
4045 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status
);
4049 if (PnPFlags
& PNP_DEVICE_NOT_DISABLEABLE
)
4050 DeviceNode
->UserFlags
|= DNUF_NOT_DISABLEABLE
;
4052 DeviceNode
->UserFlags
&= ~DNUF_NOT_DISABLEABLE
;
4054 if (PnPFlags
& PNP_DEVICE_DONT_DISPLAY_IN_UI
)
4055 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
4057 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
4059 if ((PnPFlags
& PNP_DEVICE_REMOVED
) ||
4060 ((PnPFlags
& PNP_DEVICE_FAILED
) && !(PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)))
4062 /* Surprise removal */
4064 IopSendSurpriseRemoval(PhysicalDeviceObject
);
4066 /* Tell the user-mode PnP manager that a device was removed */
4067 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
4068 &DeviceNode
->InstancePath
);
4070 IopSendRemoveDevice(PhysicalDeviceObject
);
4072 else if ((PnPFlags
& PNP_DEVICE_FAILED
) && (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
))
4074 /* Stop for resource rebalance */
4076 Status
= IopStopDevice(DeviceNode
);
4077 if (!NT_SUCCESS(Status
))
4079 DPRINT1("Failed to stop device for rebalancing\n");
4081 /* Stop failed so don't rebalance */
4082 PnPFlags
&= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
;
4086 /* Resource rebalance */
4087 if (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)
4089 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4091 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4093 IRP_MN_QUERY_RESOURCES
,
4095 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
4097 DeviceNode
->BootResources
=
4098 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
4099 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
4103 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
4104 DeviceNode
->BootResources
= NULL
;
4107 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4109 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4111 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
4113 if (NT_SUCCESS(Status
))
4115 DeviceNode
->ResourceRequirements
=
4116 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
4120 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
4121 DeviceNode
->ResourceRequirements
= NULL
;
4124 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4125 if (IopStartDevice(DeviceNode
) != STATUS_SUCCESS
)
4127 DPRINT1("Restart after resource rebalance failed\n");
4129 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
4130 DeviceNode
->Flags
|= DNF_START_FAILED
;
4132 IopRemoveDevice(DeviceNode
);
4138 * @name IoOpenDeviceRegistryKey
4140 * Open a registry key unique for a specified driver or device instance.
4142 * @param DeviceObject Device to get the registry key for.
4143 * @param DevInstKeyType Type of the key to return.
4144 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4145 * @param DevInstRegKey Handle to the opened registry key on
4146 * successful return.
4154 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject
,
4155 IN ULONG DevInstKeyType
,
4156 IN ACCESS_MASK DesiredAccess
,
4157 OUT PHANDLE DevInstRegKey
)
4159 static WCHAR RootKeyName
[] =
4160 L
"\\Registry\\Machine\\System\\CurrentControlSet\\";
4161 static WCHAR ProfileKeyName
[] =
4162 L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4163 static WCHAR ClassKeyName
[] = L
"Control\\Class\\";
4164 static WCHAR EnumKeyName
[] = L
"Enum\\";
4165 static WCHAR DeviceParametersKeyName
[] = L
"Device Parameters";
4166 ULONG KeyNameLength
;
4167 LPWSTR KeyNameBuffer
;
4168 UNICODE_STRING KeyName
;
4169 ULONG DriverKeyLength
;
4170 OBJECT_ATTRIBUTES ObjectAttributes
;
4171 PDEVICE_NODE DeviceNode
= NULL
;
4174 DPRINT("IoOpenDeviceRegistryKey() called\n");
4176 if ((DevInstKeyType
& (PLUGPLAY_REGKEY_DEVICE
| PLUGPLAY_REGKEY_DRIVER
)) == 0)
4178 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4179 return STATUS_INVALID_PARAMETER
;
4182 if (!IopIsValidPhysicalDeviceObject(DeviceObject
))
4183 return STATUS_INVALID_DEVICE_REQUEST
;
4184 DeviceNode
= IopGetDeviceNode(DeviceObject
);
4187 * Calculate the length of the base key name. This is the full
4188 * name for driver key or the name excluding "Device Parameters"
4189 * subkey for device key.
4192 KeyNameLength
= sizeof(RootKeyName
);
4193 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4194 KeyNameLength
+= sizeof(ProfileKeyName
) - sizeof(UNICODE_NULL
);
4195 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4197 KeyNameLength
+= sizeof(ClassKeyName
) - sizeof(UNICODE_NULL
);
4198 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4199 0, NULL
, &DriverKeyLength
);
4200 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
4202 KeyNameLength
+= DriverKeyLength
;
4206 KeyNameLength
+= sizeof(EnumKeyName
) - sizeof(UNICODE_NULL
) +
4207 DeviceNode
->InstancePath
.Length
;
4211 * Now allocate the buffer for the key name...
4214 KeyNameBuffer
= ExAllocatePool(PagedPool
, KeyNameLength
);
4215 if (KeyNameBuffer
== NULL
)
4216 return STATUS_INSUFFICIENT_RESOURCES
;
4219 KeyName
.MaximumLength
= (USHORT
)KeyNameLength
;
4220 KeyName
.Buffer
= KeyNameBuffer
;
4223 * ...and build the key name.
4226 KeyName
.Length
+= sizeof(RootKeyName
) - sizeof(UNICODE_NULL
);
4227 RtlCopyMemory(KeyNameBuffer
, RootKeyName
, KeyName
.Length
);
4229 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4230 RtlAppendUnicodeToString(&KeyName
, ProfileKeyName
);
4232 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4234 RtlAppendUnicodeToString(&KeyName
, ClassKeyName
);
4235 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4236 DriverKeyLength
, KeyNameBuffer
+
4237 (KeyName
.Length
/ sizeof(WCHAR
)),
4239 if (!NT_SUCCESS(Status
))
4241 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status
);
4242 ExFreePool(KeyNameBuffer
);
4245 KeyName
.Length
+= (USHORT
)DriverKeyLength
- sizeof(UNICODE_NULL
);
4249 RtlAppendUnicodeToString(&KeyName
, EnumKeyName
);
4250 Status
= RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->InstancePath
);
4251 if (DeviceNode
->InstancePath
.Length
== 0)
4253 ExFreePool(KeyNameBuffer
);
4259 * Open the base key.
4261 Status
= IopOpenRegistryKeyEx(DevInstRegKey
, NULL
, &KeyName
, DesiredAccess
);
4262 if (!NT_SUCCESS(Status
))
4264 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName
, Status
);
4265 ExFreePool(KeyNameBuffer
);
4268 ExFreePool(KeyNameBuffer
);
4271 * For driver key we're done now.
4274 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4278 * Let's go further. For device key we must open "Device Parameters"
4279 * subkey and create it if it doesn't exist yet.
4282 RtlInitUnicodeString(&KeyName
, DeviceParametersKeyName
);
4283 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
,
4284 OBJ_CASE_INSENSITIVE
, *DevInstRegKey
, NULL
);
4285 Status
= ZwCreateKey(DevInstRegKey
, DesiredAccess
, &ObjectAttributes
,
4286 0, NULL
, ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0, NULL
);
4287 ZwClose(ObjectAttributes
.RootDirectory
);
4294 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
, BOOLEAN Force
)
4296 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
, FailedRemoveDevice
;
4300 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4301 ChildDeviceNode
= ParentDeviceNode
->Child
;
4302 while (ChildDeviceNode
!= NULL
)
4304 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4305 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4307 Status
= IopPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
, Force
);
4308 if (!NT_SUCCESS(Status
))
4310 FailedRemoveDevice
= ChildDeviceNode
;
4314 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4315 ChildDeviceNode
= NextDeviceNode
;
4317 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4319 return STATUS_SUCCESS
;
4322 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4323 ChildDeviceNode
= ParentDeviceNode
->Child
;
4324 while (ChildDeviceNode
!= NULL
)
4326 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4327 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4329 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4331 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4332 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4333 if (ChildDeviceNode
== FailedRemoveDevice
)
4336 ChildDeviceNode
= NextDeviceNode
;
4338 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4340 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4347 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4349 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4352 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4353 ChildDeviceNode
= ParentDeviceNode
->Child
;
4354 while (ChildDeviceNode
!= NULL
)
4356 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4357 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4359 IopSendRemoveDevice(ChildDeviceNode
->PhysicalDeviceObject
);
4361 ChildDeviceNode
= NextDeviceNode
;
4363 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4365 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4370 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4372 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4375 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4376 ChildDeviceNode
= ParentDeviceNode
->Child
;
4377 while (ChildDeviceNode
!= NULL
)
4379 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4380 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4382 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4384 ChildDeviceNode
= NextDeviceNode
;
4386 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4388 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4393 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
, BOOLEAN Force
)
4395 /* This function DOES NOT dereference the device objects on SUCCESS
4396 * but it DOES dereference device objects on FAILURE */
4401 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4403 Status
= IopPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
], Force
);
4404 if (!NT_SUCCESS(Status
))
4411 return STATUS_SUCCESS
;
4414 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4415 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4416 for (i
= 0; i
<= j
; i
++)
4418 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4419 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4420 DeviceRelations
->Objects
[i
] = NULL
;
4422 for (; i
< DeviceRelations
->Count
; i
++)
4424 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4425 DeviceRelations
->Objects
[i
] = NULL
;
4427 ExFreePool(DeviceRelations
);
4434 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4436 /* This function DOES dereference the device objects in all cases */
4440 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4442 IopSendRemoveDevice(DeviceRelations
->Objects
[i
]);
4443 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4444 DeviceRelations
->Objects
[i
] = NULL
;
4447 ExFreePool(DeviceRelations
);
4452 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4454 /* This function DOES dereference the device objects in all cases */
4458 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4460 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4461 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4462 DeviceRelations
->Objects
[i
] = NULL
;
4465 ExFreePool(DeviceRelations
);
4469 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
)
4471 IO_STACK_LOCATION Stack
;
4472 IO_STATUS_BLOCK IoStatusBlock
;
4473 PDEVICE_RELATIONS DeviceRelations
;
4476 IopCancelRemoveDevice(DeviceObject
);
4478 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4480 Status
= IopInitiatePnpIrp(DeviceObject
,
4482 IRP_MN_QUERY_DEVICE_RELATIONS
,
4484 if (!NT_SUCCESS(Status
))
4486 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4487 DeviceRelations
= NULL
;
4491 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4494 if (DeviceRelations
)
4495 IopCancelRemoveDeviceRelations(DeviceRelations
);
4499 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
)
4501 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
4502 IO_STACK_LOCATION Stack
;
4503 IO_STATUS_BLOCK IoStatusBlock
;
4504 PDEVICE_RELATIONS DeviceRelations
;
4507 if ((DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
) && !Force
)
4509 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode
->InstancePath
);
4510 return STATUS_UNSUCCESSFUL
;
4513 if (!Force
&& IopQueryRemoveDevice(DeviceObject
) != STATUS_SUCCESS
)
4515 DPRINT1("Removal vetoed by failing the query remove request\n");
4517 IopCancelRemoveDevice(DeviceObject
);
4519 return STATUS_UNSUCCESSFUL
;
4522 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4524 Status
= IopInitiatePnpIrp(DeviceObject
,
4526 IRP_MN_QUERY_DEVICE_RELATIONS
,
4528 if (!NT_SUCCESS(Status
))
4530 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4531 DeviceRelations
= NULL
;
4535 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4538 if (DeviceRelations
)
4540 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, Force
);
4541 if (!NT_SUCCESS(Status
))
4545 Status
= IopQueryRemoveChildDevices(DeviceNode
, Force
);
4546 if (!NT_SUCCESS(Status
))
4548 if (DeviceRelations
)
4549 IopCancelRemoveDeviceRelations(DeviceRelations
);
4553 DeviceNode
->Flags
|= DNF_WILL_BE_REMOVED
;
4554 if (DeviceRelations
)
4555 IopSendRemoveDeviceRelations(DeviceRelations
);
4556 IopSendRemoveChildDevices(DeviceNode
);
4558 return STATUS_SUCCESS
;
4562 IopRemoveDevice(PDEVICE_NODE DeviceNode
)
4566 DPRINT("Removing device: %wZ\n", &DeviceNode
->InstancePath
);
4568 Status
= IopPrepareDeviceForRemoval(DeviceNode
->PhysicalDeviceObject
, FALSE
);
4569 if (NT_SUCCESS(Status
))
4571 IopSendRemoveDevice(DeviceNode
->PhysicalDeviceObject
);
4572 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL
,
4573 &DeviceNode
->InstancePath
);
4574 return STATUS_SUCCESS
;
4585 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject
)
4587 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
4588 PDEVICE_RELATIONS DeviceRelations
;
4589 IO_STATUS_BLOCK IoStatusBlock
;
4590 IO_STACK_LOCATION Stack
;
4591 DEVICE_CAPABILITIES Capabilities
;
4594 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT
,
4595 &DeviceNode
->InstancePath
);
4597 if (IopQueryDeviceCapabilities(DeviceNode
, &Capabilities
) != STATUS_SUCCESS
)
4602 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
4604 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4606 IRP_MN_QUERY_DEVICE_RELATIONS
,
4608 if (!NT_SUCCESS(Status
))
4610 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4611 DeviceRelations
= NULL
;
4615 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4618 if (DeviceRelations
)
4620 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, FALSE
);
4621 if (!NT_SUCCESS(Status
))
4625 Status
= IopQueryRemoveChildDevices(DeviceNode
, FALSE
);
4626 if (!NT_SUCCESS(Status
))
4628 if (DeviceRelations
)
4629 IopCancelRemoveDeviceRelations(DeviceRelations
);
4633 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject
, FALSE
) != STATUS_SUCCESS
)
4635 if (DeviceRelations
)
4636 IopCancelRemoveDeviceRelations(DeviceRelations
);
4637 IopCancelRemoveChildDevices(DeviceNode
);
4641 if (DeviceRelations
)
4642 IopSendRemoveDeviceRelations(DeviceRelations
);
4643 IopSendRemoveChildDevices(DeviceNode
);
4645 if (Capabilities
.EjectSupported
)
4647 if (IopSendEject(PhysicalDeviceObject
) != STATUS_SUCCESS
)
4654 DeviceNode
->Flags
|= DNF_DISABLED
;
4657 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT
,
4658 &DeviceNode
->InstancePath
);
4663 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED
,
4664 &DeviceNode
->InstancePath
);
4672 IoInvalidateDeviceRelations(
4673 IN PDEVICE_OBJECT DeviceObject
,
4674 IN DEVICE_RELATION_TYPE Type
)
4676 PIO_WORKITEM WorkItem
;
4677 PINVALIDATE_DEVICE_RELATION_DATA Data
;
4679 Data
= ExAllocatePool(NonPagedPool
, sizeof(INVALIDATE_DEVICE_RELATION_DATA
));
4682 WorkItem
= IoAllocateWorkItem(DeviceObject
);
4689 ObReferenceObject(DeviceObject
);
4690 Data
->DeviceObject
= DeviceObject
;
4692 Data
->WorkItem
= WorkItem
;
4696 IopAsynchronousInvalidateDeviceRelations
,
4706 IoSynchronousInvalidateDeviceRelations(
4707 IN PDEVICE_OBJECT DeviceObject
,
4708 IN DEVICE_RELATION_TYPE Type
)
4715 /* Enumerate the device */
4716 return IopEnumerateDevice(DeviceObject
);
4717 case PowerRelations
:
4718 /* Not handled yet */
4719 return STATUS_NOT_IMPLEMENTED
;
4720 case TargetDeviceRelation
:
4722 return STATUS_SUCCESS
;
4724 /* Ejection relations are not supported */
4725 return STATUS_NOT_SUPPORTED
;
4734 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType
,
4736 IN PHYSICAL_ADDRESS BusAddress
,
4737 IN OUT PULONG AddressSpace
,
4738 OUT PPHYSICAL_ADDRESS TranslatedAddress
)
4740 /* FIXME: Notify the resource arbiter */
4742 return HalTranslateBusAddress(InterfaceType
,