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 USHORT StringLength
= (USHORT
)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
= (USHORT
)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 ExFreePool(OriginalIdBuffer
);
393 ExFreePool(PartialInfo
);
394 ExFreePool(BasicInfo
);
395 ZwClose(InstanceKey
);
396 ZwClose(ChildKeyHandle
);
397 ZwClose(CriticalDeviceKey
);
403 ExFreePool(BasicInfo
);
407 /* Umm, not sure what happened here */
412 /* Advance to the next ID */
413 IdBuffer
+= StringLength
;
416 ExFreePool(OriginalIdBuffer
);
417 ZwClose(InstanceKey
);
418 ZwClose(CriticalDeviceKey
);
423 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
424 PDRIVER_OBJECT DriverObject
)
431 /* Special case for bus driven devices */
432 DeviceNode
->Flags
|= DNF_ADDED
;
433 return STATUS_SUCCESS
;
436 if (!DriverObject
->DriverExtension
->AddDevice
)
438 DeviceNode
->Flags
|= DNF_LEGACY_DRIVER
;
441 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
443 DeviceNode
->Flags
|= DNF_ADDED
+ DNF_STARTED
;
444 return STATUS_SUCCESS
;
447 /* This is a Plug and Play driver */
448 DPRINT("Plug and Play driver found\n");
449 ASSERT(DeviceNode
->PhysicalDeviceObject
);
451 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
452 &DriverObject
->DriverName
,
453 &DeviceNode
->InstancePath
);
454 Status
= DriverObject
->DriverExtension
->AddDevice(
455 DriverObject
, DeviceNode
->PhysicalDeviceObject
);
456 if (!NT_SUCCESS(Status
))
458 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
459 &DriverObject
->DriverName
,
460 &DeviceNode
->InstancePath
,
462 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
466 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
468 /* Check if we have a ACPI device (needed for power management) */
469 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
471 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
473 /* There can be only one system power device */
474 if (!SystemPowerDeviceNodeCreated
)
476 PopSystemPowerDeviceNode
= DeviceNode
;
477 ObReferenceObject(PopSystemPowerDeviceNode
->PhysicalDeviceObject
);
478 SystemPowerDeviceNodeCreated
= TRUE
;
482 ObDereferenceObject(Fdo
);
484 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
486 return STATUS_SUCCESS
;
492 IopSendEject(IN PDEVICE_OBJECT DeviceObject
)
494 IO_STACK_LOCATION Stack
;
497 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
498 Stack
.MajorFunction
= IRP_MJ_PNP
;
499 Stack
.MinorFunction
= IRP_MN_EJECT
;
501 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
507 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject
)
509 IO_STACK_LOCATION Stack
;
512 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
513 Stack
.MajorFunction
= IRP_MJ_PNP
;
514 Stack
.MinorFunction
= IRP_MN_SURPRISE_REMOVAL
;
516 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
517 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
523 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
525 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
526 IO_STACK_LOCATION Stack
;
532 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING
,
533 &DeviceNode
->InstancePath
);
535 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
536 Stack
.MajorFunction
= IRP_MJ_PNP
;
537 Stack
.MinorFunction
= IRP_MN_QUERY_REMOVE_DEVICE
;
539 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
541 IopNotifyPlugPlayNotification(DeviceObject
,
542 EventCategoryTargetDeviceChange
,
543 &GUID_TARGET_DEVICE_QUERY_REMOVE
,
547 if (!NT_SUCCESS(Status
))
549 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode
->InstancePath
);
550 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED
,
551 &DeviceNode
->InstancePath
);
560 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject
)
562 IO_STACK_LOCATION Stack
;
565 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
566 Stack
.MajorFunction
= IRP_MJ_PNP
;
567 Stack
.MinorFunction
= IRP_MN_QUERY_STOP_DEVICE
;
569 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
575 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
577 IO_STACK_LOCATION Stack
;
580 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
581 Stack
.MajorFunction
= IRP_MJ_PNP
;
582 Stack
.MinorFunction
= IRP_MN_REMOVE_DEVICE
;
584 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
585 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
587 IopNotifyPlugPlayNotification(DeviceObject
,
588 EventCategoryTargetDeviceChange
,
589 &GUID_TARGET_DEVICE_REMOVE_COMPLETE
,
597 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
599 IO_STACK_LOCATION Stack
;
602 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
603 Stack
.MajorFunction
= IRP_MJ_PNP
;
604 Stack
.MinorFunction
= IRP_MN_CANCEL_REMOVE_DEVICE
;
606 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
607 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
609 IopNotifyPlugPlayNotification(DeviceObject
,
610 EventCategoryTargetDeviceChange
,
611 &GUID_TARGET_DEVICE_REMOVE_CANCELLED
,
619 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject
)
621 IO_STACK_LOCATION Stack
;
624 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
625 Stack
.MajorFunction
= IRP_MJ_PNP
;
626 Stack
.MinorFunction
= IRP_MN_STOP_DEVICE
;
628 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
629 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
634 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject
)
636 IO_STACK_LOCATION Stack
;
637 PDEVICE_NODE DeviceNode
;
640 DEVICE_CAPABILITIES DeviceCapabilities
;
642 /* Get the device node */
643 DeviceNode
= IopGetDeviceNode(DeviceObject
);
645 ASSERT(!(DeviceNode
->Flags
& DNF_DISABLED
));
647 /* Build the I/O stack locaiton */
648 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
649 Stack
.MajorFunction
= IRP_MJ_PNP
;
650 Stack
.MinorFunction
= IRP_MN_START_DEVICE
;
652 Stack
.Parameters
.StartDevice
.AllocatedResources
=
653 DeviceNode
->ResourceList
;
654 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
=
655 DeviceNode
->ResourceListTranslated
;
658 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
659 if (!NT_SUCCESS(Status
))
661 /* Send an IRP_MN_REMOVE_DEVICE request */
662 IopRemoveDevice(DeviceNode
);
664 /* Set the appropriate flag */
665 DeviceNode
->Flags
|= DNF_START_FAILED
;
667 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode
->InstancePath
, Status
);
671 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
673 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
674 if (!NT_SUCCESS(Status
))
676 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
679 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
680 IoInvalidateDeviceState(DeviceObject
);
682 /* Otherwise, mark us as started */
683 DeviceNode
->Flags
|= DNF_STARTED
;
684 DeviceNode
->Flags
&= ~DNF_STOPPED
;
686 /* We now need enumeration */
687 DeviceNode
->Flags
|= DNF_NEED_ENUMERATION_ONLY
;
692 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode
)
694 PDEVICE_OBJECT DeviceObject
;
699 ASSERT((DeviceNode
->Flags
& DNF_ADDED
));
700 ASSERT((DeviceNode
->Flags
& (DNF_RESOURCE_ASSIGNED
|
701 DNF_RESOURCE_REPORTED
|
702 DNF_NO_RESOURCE_REQUIRED
)));
704 /* Get the device object */
705 DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
707 /* Check if we're not started yet */
708 if (!(DeviceNode
->Flags
& DNF_STARTED
))
711 IopStartDevice2(DeviceObject
);
714 /* Do we need to query IDs? This happens in the case of manual reporting */
716 if (DeviceNode
->Flags
& DNF_NEED_QUERY_IDS
)
718 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
719 /* And that case shouldn't happen yet */
724 /* Make sure we're started, and check if we need enumeration */
725 if ((DeviceNode
->Flags
& DNF_STARTED
) &&
726 (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
))
729 IoSynchronousInvalidateDeviceRelations(DeviceObject
, BusRelations
);
730 Status
= STATUS_SUCCESS
;
735 Status
= STATUS_SUCCESS
;
744 PDEVICE_NODE DeviceNode
)
748 DPRINT("Stopping device: %wZ\n", &DeviceNode
->InstancePath
);
750 Status
= IopQueryStopDevice(DeviceNode
->PhysicalDeviceObject
);
751 if (NT_SUCCESS(Status
))
753 IopSendStopDevice(DeviceNode
->PhysicalDeviceObject
);
755 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
756 DeviceNode
->Flags
|= DNF_STOPPED
;
758 return STATUS_SUCCESS
;
766 PDEVICE_NODE DeviceNode
)
769 HANDLE InstanceHandle
= INVALID_HANDLE_VALUE
, ControlHandle
= INVALID_HANDLE_VALUE
;
770 UNICODE_STRING KeyName
;
771 OBJECT_ATTRIBUTES ObjectAttributes
;
773 if (DeviceNode
->Flags
& DNF_DISABLED
)
774 return STATUS_SUCCESS
;
776 Status
= IopAssignDeviceResources(DeviceNode
);
777 if (!NT_SUCCESS(Status
))
781 IopStartAndEnumerateDevice(DeviceNode
);
783 /* FIX: Should be done in new device instance code */
784 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceHandle
);
785 if (!NT_SUCCESS(Status
))
788 /* FIX: Should be done in IoXxxPrepareDriverLoading */
790 RtlInitUnicodeString(&KeyName
, L
"Control");
791 InitializeObjectAttributes(&ObjectAttributes
,
793 OBJ_CASE_INSENSITIVE
,
796 Status
= ZwCreateKey(&ControlHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
797 if (!NT_SUCCESS(Status
))
800 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
801 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, DeviceNode
->ServiceName
.Buffer
, DeviceNode
->ServiceName
.Length
);
805 if (ControlHandle
!= INVALID_HANDLE_VALUE
)
806 ZwClose(ControlHandle
);
808 if (InstanceHandle
!= INVALID_HANDLE_VALUE
)
809 ZwClose(InstanceHandle
);
816 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
817 PDEVICE_CAPABILITIES DeviceCaps
)
819 IO_STATUS_BLOCK StatusBlock
;
820 IO_STACK_LOCATION Stack
;
823 UNICODE_STRING ValueName
;
825 /* Set up the Header */
826 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
827 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
828 DeviceCaps
->Version
= 1;
829 DeviceCaps
->Address
= -1;
830 DeviceCaps
->UINumber
= -1;
832 /* Set up the Stack */
833 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
834 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
837 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
839 IRP_MN_QUERY_CAPABILITIES
,
841 if (!NT_SUCCESS(Status
))
843 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%x\n", Status
);
847 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCaps
->Version
+ sizeof(DeviceCaps
->Version
));
849 if (DeviceCaps
->NoDisplayInUI
)
850 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
852 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
854 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
855 if (NT_SUCCESS(Status
))
857 /* Set 'Capabilities' value */
858 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
859 Status
= ZwSetValueKey(InstanceKey
,
863 (PVOID
)&DeviceNode
->CapabilityFlags
,
866 /* Set 'UINumber' value */
867 if (DeviceCaps
->UINumber
!= MAXULONG
)
869 RtlInitUnicodeString(&ValueName
, L
"UINumber");
870 Status
= ZwSetValueKey(InstanceKey
,
874 &DeviceCaps
->UINumber
,
883 IopAsynchronousInvalidateDeviceRelations(
884 IN PDEVICE_OBJECT DeviceObject
,
885 IN PVOID InvalidateContext
)
887 PINVALIDATE_DEVICE_RELATION_DATA Data
= InvalidateContext
;
889 IoSynchronousInvalidateDeviceRelations(
893 ObDereferenceObject(Data
->DeviceObject
);
894 IoFreeWorkItem(Data
->WorkItem
);
899 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
903 if (PopSystemPowerDeviceNode
)
905 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
906 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
907 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
909 return STATUS_SUCCESS
;
912 return STATUS_UNSUCCESSFUL
;
917 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
919 USHORT i
= 0, FoundIndex
= 0xFFFF;
923 /* Acquire the lock */
924 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
926 /* Loop all entries */
927 while (i
< PnpBusTypeGuidList
->GuidCount
)
929 /* Try to find a match */
930 if (RtlCompareMemory(BusTypeGuid
,
931 &PnpBusTypeGuidList
->Guids
[i
],
932 sizeof(GUID
)) == sizeof(GUID
))
941 /* Check if we have to grow the list */
942 if (PnpBusTypeGuidList
->GuidCount
)
944 /* Calculate the new size */
945 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
946 (sizeof(GUID
) * PnpBusTypeGuidList
->GuidCount
);
948 /* Allocate the new copy */
949 NewList
= ExAllocatePool(PagedPool
, NewSize
);
953 ExFreePool(PnpBusTypeGuidList
);
957 /* Now copy them, decrease the size too */
958 NewSize
-= sizeof(GUID
);
959 RtlCopyMemory(NewList
, PnpBusTypeGuidList
, NewSize
);
961 /* Free the old list */
962 ExFreePool(PnpBusTypeGuidList
);
964 /* Use the new buffer */
965 PnpBusTypeGuidList
= NewList
;
968 /* Copy the new GUID */
969 RtlCopyMemory(&PnpBusTypeGuidList
->Guids
[PnpBusTypeGuidList
->GuidCount
],
973 /* The new entry is the index */
974 FoundIndex
= (USHORT
)PnpBusTypeGuidList
->GuidCount
;
975 PnpBusTypeGuidList
->GuidCount
++;
978 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
984 * Creates a device node
987 * ParentNode = Pointer to parent device node
988 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
989 * to have the root device node create one
990 * (eg. for legacy drivers)
991 * DeviceNode = Pointer to storage for created device node
997 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
998 PDEVICE_OBJECT PhysicalDeviceObject
,
999 PUNICODE_STRING ServiceName
,
1000 PDEVICE_NODE
*DeviceNode
)
1005 UNICODE_STRING FullServiceName
;
1006 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
1007 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
1008 UNICODE_STRING KeyName
, ClassName
;
1009 PUNICODE_STRING ServiceName1
;
1012 UNICODE_STRING ClassGUID
;
1014 HANDLE InstanceHandle
;
1016 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1017 ParentNode
, PhysicalDeviceObject
, ServiceName
);
1019 Node
= (PDEVICE_NODE
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_NODE
));
1022 return STATUS_INSUFFICIENT_RESOURCES
;
1025 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
1028 ServiceName1
= &UnknownDeviceName
;
1030 ServiceName1
= ServiceName
;
1032 if (!PhysicalDeviceObject
)
1034 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName1
->Length
;
1035 FullServiceName
.Length
= 0;
1036 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
1037 if (!FullServiceName
.Buffer
)
1040 return STATUS_INSUFFICIENT_RESOURCES
;
1043 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
1044 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName1
);
1046 Status
= PnpRootCreateDevice(&FullServiceName
, NULL
, &PhysicalDeviceObject
, &Node
->InstancePath
);
1047 if (!NT_SUCCESS(Status
))
1049 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
1054 /* Create the device key for legacy drivers */
1055 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, REG_OPTION_VOLATILE
, &InstanceHandle
);
1056 if (!NT_SUCCESS(Status
))
1058 ZwClose(InstanceHandle
);
1060 ExFreePool(FullServiceName
.Buffer
);
1064 Node
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, ServiceName1
->Length
);
1065 if (!Node
->ServiceName
.Buffer
)
1067 ZwClose(InstanceHandle
);
1069 ExFreePool(FullServiceName
.Buffer
);
1073 Node
->ServiceName
.MaximumLength
= ServiceName1
->Length
;
1074 Node
->ServiceName
.Length
= 0;
1076 RtlAppendUnicodeStringToString(&Node
->ServiceName
, ServiceName1
);
1080 RtlInitUnicodeString(&KeyName
, L
"Service");
1081 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName
->Buffer
, ServiceName
->Length
);
1084 if (NT_SUCCESS(Status
))
1086 RtlInitUnicodeString(&KeyName
, L
"Legacy");
1089 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
1090 if (NT_SUCCESS(Status
))
1092 RtlInitUnicodeString(&KeyName
, L
"Class");
1094 RtlInitUnicodeString(&ClassName
, L
"LegacyDriver");
1095 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassName
.Buffer
, ClassName
.Length
);
1097 if (NT_SUCCESS(Status
))
1099 RtlInitUnicodeString(&KeyName
, L
"ClassGUID");
1101 RtlInitUnicodeString(&ClassGUID
, L
"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
1102 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassGUID
.Buffer
, ClassGUID
.Length
);
1108 ZwClose(InstanceHandle
);
1109 ExFreePool(FullServiceName
.Buffer
);
1111 if (!NT_SUCCESS(Status
))
1117 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
1118 IopDeviceNodeSetFlag(Node
, DNF_PROCESSED
);
1119 IopDeviceNodeSetFlag(Node
, DNF_ADDED
);
1120 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
1123 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
1125 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
1129 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1130 Node
->Parent
= ParentNode
;
1131 Node
->Sibling
= NULL
;
1132 if (ParentNode
->LastChild
== NULL
)
1134 ParentNode
->Child
= Node
;
1135 ParentNode
->LastChild
= Node
;
1139 ParentNode
->LastChild
->Sibling
= Node
;
1140 ParentNode
->LastChild
= Node
;
1142 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1143 Node
->Level
= ParentNode
->Level
+ 1;
1146 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1150 return STATUS_SUCCESS
;
1154 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
1157 PDEVICE_NODE PrevSibling
= NULL
;
1159 /* All children must be deleted before a parent is deleted */
1160 ASSERT(!DeviceNode
->Child
);
1162 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1164 ASSERT(DeviceNode
->PhysicalDeviceObject
);
1166 ObDereferenceObject(DeviceNode
->PhysicalDeviceObject
);
1168 /* Get previous sibling */
1169 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
1171 PrevSibling
= DeviceNode
->Parent
->Child
;
1172 while (PrevSibling
->Sibling
!= DeviceNode
)
1173 PrevSibling
= PrevSibling
->Sibling
;
1176 /* Unlink from parent if it exists */
1177 if (DeviceNode
->Parent
)
1179 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
1181 DeviceNode
->Parent
->LastChild
= PrevSibling
;
1183 PrevSibling
->Sibling
= NULL
;
1185 if (DeviceNode
->Parent
->Child
== DeviceNode
)
1186 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
1189 /* Unlink from sibling list */
1191 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
1193 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1195 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
1197 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
1199 if (DeviceNode
->ResourceList
)
1201 ExFreePool(DeviceNode
->ResourceList
);
1204 if (DeviceNode
->ResourceListTranslated
)
1206 ExFreePool(DeviceNode
->ResourceListTranslated
);
1209 if (DeviceNode
->ResourceRequirements
)
1211 ExFreePool(DeviceNode
->ResourceRequirements
);
1214 if (DeviceNode
->BootResources
)
1216 ExFreePool(DeviceNode
->BootResources
);
1219 ExFreePool(DeviceNode
);
1221 return STATUS_SUCCESS
;
1226 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject
,
1227 IN PIO_STACK_LOCATION IoStackLocation
,
1228 OUT PVOID
*Information
)
1231 PIO_STACK_LOCATION IrpStack
;
1232 IO_STATUS_BLOCK IoStatusBlock
;
1235 PDEVICE_OBJECT TopDeviceObject
;
1238 /* Call the top of the device stack */
1239 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
1241 /* Allocate an IRP */
1242 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
, FALSE
);
1243 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
1245 /* Initialize to failure */
1246 Irp
->IoStatus
.Status
= IoStatusBlock
.Status
= STATUS_NOT_SUPPORTED
;
1247 Irp
->IoStatus
.Information
= IoStatusBlock
.Information
= 0;
1249 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1250 if (IoStackLocation
->MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
)
1252 /* Copy the resource requirements list into the IOSB */
1253 Irp
->IoStatus
.Information
=
1254 IoStatusBlock
.Information
= (ULONG_PTR
)IoStackLocation
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
1257 /* Initialize the event */
1258 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1261 Irp
->UserIosb
= &IoStatusBlock
;
1262 Irp
->UserEvent
= &Event
;
1265 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1266 IoQueueThreadIrp(Irp
);
1268 /* Copy-in the stack */
1269 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1270 *IrpStack
= *IoStackLocation
;
1272 /* Call the driver */
1273 Status
= IoCallDriver(TopDeviceObject
, Irp
);
1274 if (Status
== STATUS_PENDING
)
1277 KeWaitForSingleObject(&Event
,
1282 Status
= IoStatusBlock
.Status
;
1285 /* Remove the reference */
1286 ObDereferenceObject(TopDeviceObject
);
1288 /* Return the information */
1289 *Information
= (PVOID
)IoStatusBlock
.Information
;
1295 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject
,
1296 IN OUT PIO_STATUS_BLOCK IoStatusBlock
,
1297 IN UCHAR MinorFunction
,
1298 IN PIO_STACK_LOCATION Stack OPTIONAL
)
1300 IO_STACK_LOCATION IoStackLocation
;
1302 /* Fill out the stack information */
1303 RtlZeroMemory(&IoStackLocation
, sizeof(IO_STACK_LOCATION
));
1304 IoStackLocation
.MajorFunction
= IRP_MJ_PNP
;
1305 IoStackLocation
.MinorFunction
= MinorFunction
;
1309 RtlCopyMemory(&IoStackLocation
.Parameters
,
1311 sizeof(Stack
->Parameters
));
1314 /* Do the PnP call */
1315 IoStatusBlock
->Status
= IopSynchronousCall(DeviceObject
,
1317 (PVOID
)&IoStatusBlock
->Information
);
1318 return IoStatusBlock
->Status
;
1322 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1324 PDEVICE_NODE ParentDeviceNode
;
1325 PDEVICE_NODE ChildDeviceNode
;
1328 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1329 ParentDeviceNode
= Context
->DeviceNode
;
1331 /* Call the action routine */
1332 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
1333 if (!NT_SUCCESS(Status
))
1338 /* Traversal of all children nodes */
1339 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
1340 ChildDeviceNode
!= NULL
;
1341 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
1343 /* Pass the current device node to the action routine */
1344 Context
->DeviceNode
= ChildDeviceNode
;
1346 Status
= IopTraverseDeviceTreeNode(Context
);
1347 if (!NT_SUCCESS(Status
))
1358 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1362 DPRINT("Context 0x%p\n", Context
);
1364 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
1365 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
1367 /* Start from the specified device node */
1368 Context
->DeviceNode
= Context
->FirstDeviceNode
;
1370 /* Recursively traverse the device tree */
1371 Status
= IopTraverseDeviceTreeNode(Context
);
1372 if (Status
== STATUS_UNSUCCESSFUL
)
1374 /* The action routine just wanted to terminate the traversal with status
1375 code STATUS_SUCCESS */
1376 Status
= STATUS_SUCCESS
;
1384 * IopCreateDeviceKeyPath
1386 * Creates a registry key
1390 * Name of the key to be created.
1392 * Handle to the newly created key
1395 * This method can create nested trees, so parent of RegistryPath can
1396 * be not existant, and will be created if needed.
1400 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
1401 IN ULONG CreateOptions
,
1404 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
1405 HANDLE hParent
= NULL
, hKey
;
1406 OBJECT_ATTRIBUTES ObjectAttributes
;
1407 UNICODE_STRING KeyName
;
1408 LPCWSTR Current
, Last
;
1412 /* Assume failure */
1415 /* Create a volatile device tree in 1st stage so we have a clean slate
1416 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1417 if (ExpInTextModeSetup
) CreateOptions
|= REG_OPTION_VOLATILE
;
1419 /* Open root key for device instances */
1420 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
1421 if (!NT_SUCCESS(Status
))
1423 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
1427 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
1428 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
1430 /* Go up to the end of the string */
1431 while (Current
<= Last
)
1433 if (Current
!= Last
&& *Current
!= '\\')
1435 /* Not the end of the string and not a separator */
1440 /* Prepare relative key name */
1441 Length
= (USHORT
)((ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
);
1442 KeyName
.MaximumLength
= KeyName
.Length
= Length
;
1443 DPRINT("Create '%wZ'\n", &KeyName
);
1446 InitializeObjectAttributes(&ObjectAttributes
,
1448 OBJ_CASE_INSENSITIVE
,
1451 Status
= ZwCreateKey(&hKey
,
1452 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
1459 /* Close parent key handle, we don't need it anymore */
1463 /* Key opening/creating failed? */
1464 if (!NT_SUCCESS(Status
))
1466 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
1470 /* Check if it is the end of the string */
1471 if (Current
== Last
)
1473 /* Yes, return success */
1475 return STATUS_SUCCESS
;
1478 /* Start with this new parent key */
1481 KeyName
.Buffer
= (LPWSTR
)Current
;
1484 return STATUS_UNSUCCESSFUL
;
1488 IopSetDeviceInstanceData(HANDLE InstanceKey
,
1489 PDEVICE_NODE DeviceNode
)
1491 OBJECT_ATTRIBUTES ObjectAttributes
;
1492 UNICODE_STRING KeyName
;
1497 HANDLE ControlHandle
;
1499 DPRINT("IopSetDeviceInstanceData() called\n");
1501 /* Create the 'LogConf' key */
1502 RtlInitUnicodeString(&KeyName
, L
"LogConf");
1503 InitializeObjectAttributes(&ObjectAttributes
,
1505 OBJ_CASE_INSENSITIVE
,
1508 Status
= ZwCreateKey(&LogConfKey
,
1513 REG_OPTION_VOLATILE
,
1515 if (NT_SUCCESS(Status
))
1517 /* Set 'BootConfig' value */
1518 if (DeviceNode
->BootResources
!= NULL
)
1520 ResCount
= DeviceNode
->BootResources
->Count
;
1523 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
1524 Status
= ZwSetValueKey(LogConfKey
,
1528 DeviceNode
->BootResources
,
1529 PnpDetermineResourceListSize(DeviceNode
->BootResources
));
1533 /* Set 'BasicConfigVector' value */
1534 if (DeviceNode
->ResourceRequirements
!= NULL
&&
1535 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
1537 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
1538 Status
= ZwSetValueKey(LogConfKey
,
1541 REG_RESOURCE_REQUIREMENTS_LIST
,
1542 DeviceNode
->ResourceRequirements
,
1543 DeviceNode
->ResourceRequirements
->ListSize
);
1546 ZwClose(LogConfKey
);
1549 /* Set the 'ConfigFlags' value */
1550 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1551 Status
= ZwQueryValueKey(InstanceKey
,
1553 KeyValueBasicInformation
,
1557 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1559 /* Write the default value */
1560 ULONG DefaultConfigFlags
= 0;
1561 Status
= ZwSetValueKey(InstanceKey
,
1565 &DefaultConfigFlags
,
1566 sizeof(DefaultConfigFlags
));
1569 /* Create the 'Control' key */
1570 RtlInitUnicodeString(&KeyName
, L
"Control");
1571 InitializeObjectAttributes(&ObjectAttributes
,
1573 OBJ_CASE_INSENSITIVE
,
1576 Status
= ZwCreateKey(&ControlHandle
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
1578 if (NT_SUCCESS(Status
))
1579 ZwClose(ControlHandle
);
1581 DPRINT("IopSetDeviceInstanceData() done\n");
1587 * IopGetParentIdPrefix
1589 * Retrieve (or create) a string which identifies a device.
1593 * Pointer to device node.
1595 * Pointer to the string where is returned the parent node identifier
1598 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1599 * valid and its Buffer field is NULL-terminated. The caller needs to
1600 * to free the string with RtlFreeUnicodeString when it is no longer
1605 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1606 PUNICODE_STRING ParentIdPrefix
)
1608 ULONG KeyNameBufferLength
;
1609 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1610 UNICODE_STRING KeyName
= {0, 0, NULL
};
1611 UNICODE_STRING KeyValue
;
1612 UNICODE_STRING ValueName
;
1617 /* HACK: As long as some devices have a NULL device
1618 * instance path, the following test is required :(
1620 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1622 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1623 &DeviceNode
->InstancePath
);
1624 return STATUS_UNSUCCESSFUL
;
1627 /* 1. Try to retrieve ParentIdPrefix from registry */
1628 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1629 ParentIdPrefixInformation
= ExAllocatePool(PagedPool
, KeyNameBufferLength
+ sizeof(WCHAR
));
1630 if (!ParentIdPrefixInformation
)
1632 return STATUS_INSUFFICIENT_RESOURCES
;
1635 KeyName
.Buffer
= ExAllocatePool(PagedPool
, (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
);
1636 if (!KeyName
.Buffer
)
1638 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1642 KeyName
.MaximumLength
= (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
;
1644 RtlAppendUnicodeToString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1645 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1647 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1648 if (!NT_SUCCESS(Status
))
1650 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1651 Status
= ZwQueryValueKey(
1653 KeyValuePartialInformation
, ParentIdPrefixInformation
,
1654 KeyNameBufferLength
, &KeyNameBufferLength
);
1655 if (NT_SUCCESS(Status
))
1657 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1658 Status
= STATUS_UNSUCCESSFUL
;
1661 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1662 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1666 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1668 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1669 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1673 /* 2. Create the ParentIdPrefix value */
1674 crc32
= RtlComputeCrc32(0,
1675 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1676 DeviceNode
->Parent
->InstancePath
.Length
);
1678 swprintf((PWSTR
)ParentIdPrefixInformation
->Data
, L
"%lx&%lx", DeviceNode
->Parent
->Level
, crc32
);
1679 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
->Data
);
1681 /* 3. Try to write the ParentIdPrefix to registry */
1682 Status
= ZwSetValueKey(hKey
,
1686 (PVOID
)KeyValue
.Buffer
,
1687 ((ULONG
)wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
1690 if (NT_SUCCESS(Status
))
1692 /* Duplicate the string to return it */
1693 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &KeyValue
, ParentIdPrefix
);
1695 ExFreePool(ParentIdPrefixInformation
);
1696 RtlFreeUnicodeString(&KeyName
);
1703 IopQueryHardwareIds(PDEVICE_NODE DeviceNode
,
1706 IO_STACK_LOCATION Stack
;
1707 IO_STATUS_BLOCK IoStatusBlock
;
1709 UNICODE_STRING ValueName
;
1711 ULONG Length
, TotalLength
;
1713 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1715 RtlZeroMemory(&Stack
, sizeof(Stack
));
1716 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
1717 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1721 if (NT_SUCCESS(Status
))
1724 * FIXME: Check for valid characters, if there is invalid characters
1728 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1729 DPRINT("Hardware IDs:\n");
1732 DPRINT(" %S\n", Ptr
);
1733 Length
= (ULONG
)wcslen(Ptr
) + 1;
1736 TotalLength
+= Length
;
1738 DPRINT("TotalLength: %hu\n", TotalLength
);
1741 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
1742 Status
= ZwSetValueKey(InstanceKey
,
1746 (PVOID
)IoStatusBlock
.Information
,
1747 (TotalLength
+ 1) * sizeof(WCHAR
));
1748 if (!NT_SUCCESS(Status
))
1750 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1755 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1762 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode
,
1765 IO_STACK_LOCATION Stack
;
1766 IO_STATUS_BLOCK IoStatusBlock
;
1768 UNICODE_STRING ValueName
;
1770 ULONG Length
, TotalLength
;
1772 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1774 RtlZeroMemory(&Stack
, sizeof(Stack
));
1775 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1776 Status
= IopInitiatePnpIrp(
1777 DeviceNode
->PhysicalDeviceObject
,
1781 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1784 * FIXME: Check for valid characters, if there is invalid characters
1788 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1789 DPRINT("Compatible IDs:\n");
1792 DPRINT(" %S\n", Ptr
);
1793 Length
= (ULONG
)wcslen(Ptr
) + 1;
1796 TotalLength
+= Length
;
1798 DPRINT("TotalLength: %hu\n", TotalLength
);
1801 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
1802 Status
= ZwSetValueKey(InstanceKey
,
1806 (PVOID
)IoStatusBlock
.Information
,
1807 (TotalLength
+ 1) * sizeof(WCHAR
));
1808 if (!NT_SUCCESS(Status
))
1810 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
1815 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1823 * IopActionInterrogateDeviceStack
1825 * Retrieve information for all (direct) child nodes of a parent node.
1829 * Pointer to device node.
1831 * Pointer to parent node to retrieve child node information for.
1834 * Any errors that occur are logged instead so that all child services have a chance
1835 * of being interrogated.
1839 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
1842 IO_STATUS_BLOCK IoStatusBlock
;
1843 PDEVICE_NODE ParentDeviceNode
;
1844 WCHAR InstancePath
[MAX_PATH
];
1845 IO_STACK_LOCATION Stack
;
1847 ULONG RequiredLength
;
1849 HANDLE InstanceKey
= NULL
;
1850 UNICODE_STRING ValueName
;
1851 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
1852 DEVICE_CAPABILITIES DeviceCapabilities
;
1854 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
1855 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
1857 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1860 * We are called for the parent too, but we don't need to do special
1861 * handling for this node
1864 if (DeviceNode
== ParentDeviceNode
)
1866 DPRINT("Success\n");
1867 return STATUS_SUCCESS
;
1871 * Make sure this device node is a direct child of the parent device node
1872 * that is given as an argument
1875 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1877 DPRINT("Skipping 2+ level child\n");
1878 return STATUS_SUCCESS
;
1881 /* Skip processing if it was already completed before */
1882 if (DeviceNode
->Flags
& DNF_PROCESSED
)
1885 return STATUS_SUCCESS
;
1889 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
1890 if (!NT_SUCCESS(Status
))
1892 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
1897 * FIXME: For critical errors, cleanup and disable device, but always
1898 * return STATUS_SUCCESS.
1901 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1903 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
1904 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1908 if (NT_SUCCESS(Status
))
1910 /* Copy the device id string */
1911 wcscpy(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1914 * FIXME: Check for valid characters, if there is invalid characters
1920 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1922 /* We have to return success otherwise we abort the traverse operation */
1923 return STATUS_SUCCESS
;
1926 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1928 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
1929 if (!NT_SUCCESS(Status
))
1931 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
1933 /* We have to return success otherwise we abort the traverse operation */
1934 return STATUS_SUCCESS
;
1937 /* This bit is only check after enumeration */
1938 if (DeviceCapabilities
.HardwareDisabled
)
1940 /* FIXME: Cleanup device */
1941 DeviceNode
->Flags
|= DNF_DISABLED
;
1942 return STATUS_SUCCESS
;
1945 DeviceNode
->Flags
&= ~DNF_DISABLED
;
1947 if (!DeviceCapabilities
.UniqueID
)
1949 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1950 DPRINT("Instance ID is not unique\n");
1951 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
1952 if (!NT_SUCCESS(Status
))
1954 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
1956 /* We have to return success otherwise we abort the traverse operation */
1957 return STATUS_SUCCESS
;
1961 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1963 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
1964 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1968 if (NT_SUCCESS(Status
))
1970 /* Append the instance id string */
1971 wcscat(InstancePath
, L
"\\");
1972 if (ParentIdPrefix
.Length
> 0)
1974 /* Add information from parent bus device to InstancePath */
1975 wcscat(InstancePath
, ParentIdPrefix
.Buffer
);
1976 if (IoStatusBlock
.Information
&& *(PWSTR
)IoStatusBlock
.Information
)
1977 wcscat(InstancePath
, L
"&");
1979 if (IoStatusBlock
.Information
)
1980 wcscat(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1983 * FIXME: Check for valid characters, if there is invalid characters
1989 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1991 RtlFreeUnicodeString(&ParentIdPrefix
);
1993 if (!RtlCreateUnicodeString(&DeviceNode
->InstancePath
, InstancePath
))
1995 DPRINT("No resources\n");
1996 /* FIXME: Cleanup and disable device */
1999 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
2002 * Create registry key for the instance id, if it doesn't exist yet
2004 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
2005 if (!NT_SUCCESS(Status
))
2007 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2009 /* We have to return success otherwise we abort the traverse operation */
2010 return STATUS_SUCCESS
;
2013 IopQueryHardwareIds(DeviceNode
, InstanceKey
);
2015 IopQueryCompatibleIds(DeviceNode
, InstanceKey
);
2017 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2019 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2020 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2021 Status
= IopInitiatePnpIrp(
2022 DeviceNode
->PhysicalDeviceObject
,
2024 IRP_MN_QUERY_DEVICE_TEXT
,
2026 /* This key is mandatory, so even if the Irp fails, we still write it */
2027 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2028 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2030 if (NT_SUCCESS(Status
) &&
2031 IoStatusBlock
.Information
&&
2032 (*(PWSTR
)IoStatusBlock
.Information
!= 0))
2034 /* This key is overriden when a driver is installed. Don't write the
2035 * new description if another one already exists */
2036 Status
= ZwSetValueKey(InstanceKey
,
2040 (PVOID
)IoStatusBlock
.Information
,
2041 ((ULONG
)wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2045 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2046 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2048 Status
= ZwSetValueKey(InstanceKey
,
2053 DeviceDesc
.MaximumLength
);
2055 if (!NT_SUCCESS(Status
))
2057 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2063 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2065 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2066 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2067 Status
= IopInitiatePnpIrp(
2068 DeviceNode
->PhysicalDeviceObject
,
2070 IRP_MN_QUERY_DEVICE_TEXT
,
2072 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2074 DPRINT("LocationInformation: %S\n", (PWSTR
)IoStatusBlock
.Information
);
2075 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2076 Status
= ZwSetValueKey(InstanceKey
,
2080 (PVOID
)IoStatusBlock
.Information
,
2081 ((ULONG
)wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2082 if (!NT_SUCCESS(Status
))
2084 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2089 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2092 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2094 Status
= IopInitiatePnpIrp(
2095 DeviceNode
->PhysicalDeviceObject
,
2097 IRP_MN_QUERY_BUS_INFORMATION
,
2099 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2101 PPNP_BUS_INFORMATION BusInformation
=
2102 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2104 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2105 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2106 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2107 ExFreePool(BusInformation
);
2111 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2113 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2114 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2115 DeviceNode
->ChildBusTypeIndex
= -1;
2118 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2120 Status
= IopInitiatePnpIrp(
2121 DeviceNode
->PhysicalDeviceObject
,
2123 IRP_MN_QUERY_RESOURCES
,
2125 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2127 DeviceNode
->BootResources
=
2128 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2129 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
2133 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2134 DeviceNode
->BootResources
= NULL
;
2137 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2139 Status
= IopInitiatePnpIrp(
2140 DeviceNode
->PhysicalDeviceObject
,
2142 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2144 if (NT_SUCCESS(Status
))
2146 DeviceNode
->ResourceRequirements
=
2147 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2151 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2152 DeviceNode
->ResourceRequirements
= NULL
;
2155 if (InstanceKey
!= NULL
)
2157 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2160 ZwClose(InstanceKey
);
2162 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2164 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2166 /* Report the device to the user-mode pnp manager */
2167 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2168 &DeviceNode
->InstancePath
);
2171 return STATUS_SUCCESS
;
2176 IopHandleDeviceRemoval(
2177 IN PDEVICE_NODE DeviceNode
,
2178 IN PDEVICE_RELATIONS DeviceRelations
)
2180 PDEVICE_NODE Child
= DeviceNode
->Child
, NextChild
;
2184 if (DeviceNode
== IopRootDeviceNode
)
2187 while (Child
!= NULL
)
2189 NextChild
= Child
->Sibling
;
2192 for (i
= 0; DeviceRelations
&& i
< DeviceRelations
->Count
; i
++)
2194 if (IopGetDeviceNode(DeviceRelations
->Objects
[i
]) == Child
)
2201 if (!Found
&& !(Child
->Flags
& DNF_WILL_BE_REMOVED
))
2203 /* Send removal IRPs to all of its children */
2204 IopPrepareDeviceForRemoval(Child
->PhysicalDeviceObject
, TRUE
);
2206 /* Send the surprise removal IRP */
2207 IopSendSurpriseRemoval(Child
->PhysicalDeviceObject
);
2209 /* Tell the user-mode PnP manager that a device was removed */
2210 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
2211 &Child
->InstancePath
);
2213 /* Send the remove device IRP */
2214 IopSendRemoveDevice(Child
->PhysicalDeviceObject
);
2223 IN PDEVICE_OBJECT DeviceObject
)
2225 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2226 DEVICETREE_TRAVERSE_CONTEXT Context
;
2227 PDEVICE_RELATIONS DeviceRelations
;
2228 PDEVICE_OBJECT ChildDeviceObject
;
2229 IO_STATUS_BLOCK IoStatusBlock
;
2230 PDEVICE_NODE ChildDeviceNode
;
2231 IO_STACK_LOCATION Stack
;
2235 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2237 if (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
)
2239 DeviceNode
->Flags
&= ~DNF_NEED_ENUMERATION_ONLY
;
2241 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2242 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2243 &DeviceNode
->InstancePath
);
2246 DeviceNode
->Flags
&= ~DNF_NEED_TO_ENUM
;
2248 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2250 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2252 Status
= IopInitiatePnpIrp(
2255 IRP_MN_QUERY_DEVICE_RELATIONS
,
2257 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2259 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2263 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2266 * Send removal IRPs for devices that have disappeared
2267 * NOTE: This code handles the case where no relations are specified
2269 IopHandleDeviceRemoval(DeviceNode
, DeviceRelations
);
2271 /* Now we bail if nothing was returned */
2272 if (!DeviceRelations
)
2274 /* We're all done */
2275 DPRINT("No PDOs\n");
2276 return STATUS_SUCCESS
;
2279 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2282 * Create device nodes for all discovered devices
2284 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2286 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2287 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2289 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2290 if (!ChildDeviceNode
)
2292 /* One doesn't exist, create it */
2293 Status
= IopCreateDeviceNode(
2298 if (NT_SUCCESS(Status
))
2300 /* Mark the node as enumerated */
2301 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2303 /* Mark the DO as bus enumerated */
2304 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2308 /* Ignore this DO */
2309 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2310 ObDereferenceObject(ChildDeviceObject
);
2315 /* Mark it as enumerated */
2316 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2317 ObDereferenceObject(ChildDeviceObject
);
2320 ExFreePool(DeviceRelations
);
2323 * Retrieve information about all discovered children from the bus driver
2325 IopInitDeviceTreeTraverseContext(
2328 IopActionInterrogateDeviceStack
,
2331 Status
= IopTraverseDeviceTree(&Context
);
2332 if (!NT_SUCCESS(Status
))
2334 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2339 * Retrieve configuration from the registry for discovered children
2341 IopInitDeviceTreeTraverseContext(
2344 IopActionConfigureChildServices
,
2347 Status
= IopTraverseDeviceTree(&Context
);
2348 if (!NT_SUCCESS(Status
))
2350 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2355 * Initialize services for discovered children.
2357 Status
= IopInitializePnpServices(DeviceNode
);
2358 if (!NT_SUCCESS(Status
))
2360 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2364 DPRINT("IopEnumerateDevice() finished\n");
2365 return STATUS_SUCCESS
;
2370 * IopActionConfigureChildServices
2372 * Retrieve configuration for all (direct) child nodes of a parent node.
2376 * Pointer to device node.
2378 * Pointer to parent node to retrieve child node configuration for.
2381 * Any errors that occur are logged instead so that all child services have a chance of beeing
2386 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2389 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2390 PDEVICE_NODE ParentDeviceNode
;
2391 PUNICODE_STRING Service
;
2392 UNICODE_STRING ClassGUID
;
2394 DEVICE_CAPABILITIES DeviceCaps
;
2396 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2398 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2401 * We are called for the parent too, but we don't need to do special
2402 * handling for this node
2404 if (DeviceNode
== ParentDeviceNode
)
2406 DPRINT("Success\n");
2407 return STATUS_SUCCESS
;
2411 * Make sure this device node is a direct child of the parent device node
2412 * that is given as an argument
2415 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2417 DPRINT("Skipping 2+ level child\n");
2418 return STATUS_SUCCESS
;
2421 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2423 DPRINT1("Child not ready to be configured\n");
2424 return STATUS_SUCCESS
;
2427 if (!(DeviceNode
->Flags
& (DNF_DISABLED
| DNF_STARTED
| DNF_ADDED
)))
2429 WCHAR RegKeyBuffer
[MAX_PATH
];
2430 UNICODE_STRING RegKey
;
2432 /* Install the service for this if it's in the CDDB */
2433 IopInstallCriticalDevice(DeviceNode
);
2436 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2437 RegKey
.Buffer
= RegKeyBuffer
;
2440 * Retrieve configuration from Enum key
2443 Service
= &DeviceNode
->ServiceName
;
2445 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2446 RtlInitUnicodeString(Service
, NULL
);
2447 RtlInitUnicodeString(&ClassGUID
, NULL
);
2449 QueryTable
[0].Name
= L
"Service";
2450 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2451 QueryTable
[0].EntryContext
= Service
;
2453 QueryTable
[1].Name
= L
"ClassGUID";
2454 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2455 QueryTable
[1].EntryContext
= &ClassGUID
;
2456 QueryTable
[1].DefaultType
= REG_SZ
;
2457 QueryTable
[1].DefaultData
= L
"";
2458 QueryTable
[1].DefaultLength
= 0;
2460 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2461 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2463 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2464 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2466 if (!NT_SUCCESS(Status
))
2468 /* FIXME: Log the error */
2469 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2470 &DeviceNode
->InstancePath
, Status
);
2471 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2472 return STATUS_SUCCESS
;
2475 if (Service
->Buffer
== NULL
)
2477 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2478 DeviceCaps
.RawDeviceOK
)
2480 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2482 DeviceNode
->ServiceName
.Length
= 0;
2483 DeviceNode
->ServiceName
.MaximumLength
= 0;
2484 DeviceNode
->ServiceName
.Buffer
= NULL
;
2486 else if (ClassGUID
.Length
!= 0)
2488 /* Device has a ClassGUID value, but no Service value.
2489 * Suppose it is using the NULL driver, so state the
2490 * device is started */
2491 DPRINT("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2492 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2496 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2498 return STATUS_SUCCESS
;
2501 DPRINT("Got Service %S\n", Service
->Buffer
);
2504 return STATUS_SUCCESS
;
2508 * IopActionInitChildServices
2510 * Initialize the service for all (direct) child nodes of a parent node
2514 * Pointer to device node.
2516 * Pointer to parent node to initialize child node services for.
2519 * If the driver image for a service is not loaded and initialized
2520 * it is done here too. Any errors that occur are logged instead so
2521 * that all child services have a chance of being initialized.
2525 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2528 PDEVICE_NODE ParentDeviceNode
;
2530 BOOLEAN BootDrivers
= !PnpSystemInit
;
2532 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2534 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2537 * We are called for the parent too, but we don't need to do special
2538 * handling for this node
2540 if (DeviceNode
== ParentDeviceNode
)
2542 DPRINT("Success\n");
2543 return STATUS_SUCCESS
;
2547 * We don't want to check for a direct child because
2548 * this function is called during boot to reinitialize
2549 * devices with drivers that couldn't load yet due to
2550 * stage 0 limitations (ie can't load from disk yet).
2553 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2555 DPRINT1("Child not ready to be added\n");
2556 return STATUS_SUCCESS
;
2559 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
) ||
2560 IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) ||
2561 IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2562 return STATUS_SUCCESS
;
2564 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
2566 /* We don't need to worry about loading the driver because we're
2567 * being driven in raw mode so our parent must be loaded to get here */
2568 Status
= IopInitializeDevice(DeviceNode
, NULL
);
2569 if (NT_SUCCESS(Status
))
2571 Status
= IopStartDevice(DeviceNode
);
2572 if (!NT_SUCCESS(Status
))
2574 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2575 &DeviceNode
->InstancePath
, Status
);
2581 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2582 PDRIVER_OBJECT DriverObject
;
2584 /* Get existing DriverObject pointer (in case the driver has
2585 already been loaded and initialized) */
2586 Status
= IopGetDriverObject(
2588 &DeviceNode
->ServiceName
,
2591 if (!NT_SUCCESS(Status
))
2593 /* Driver is not initialized, try to load it */
2594 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2596 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2598 /* Initialize the driver */
2599 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2600 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2604 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2605 &DeviceNode
->ServiceName
, Status
);
2609 /* Driver is loaded and initialized at this point */
2610 if (NT_SUCCESS(Status
))
2612 /* Initialize the device, including all filters */
2613 Status
= PipCallDriverAddDevice(DeviceNode
, FALSE
, DriverObject
);
2615 /* Remove the extra reference */
2616 ObDereferenceObject(DriverObject
);
2621 * Don't disable when trying to load only boot drivers
2625 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2626 IopDeviceNodeSetFlag(DeviceNode
, DNF_START_FAILED
);
2627 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2628 DPRINT1("Initialization of service %S failed (Status %x)\n",
2629 DeviceNode
->ServiceName
.Buffer
, Status
);
2634 return STATUS_SUCCESS
;
2638 * IopInitializePnpServices
2640 * Initialize services for discovered children
2644 * Top device node to start initializing services.
2650 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2652 DEVICETREE_TRAVERSE_CONTEXT Context
;
2654 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2656 IopInitDeviceTreeTraverseContext(
2659 IopActionInitChildServices
,
2662 return IopTraverseDeviceTree(&Context
);
2665 static NTSTATUS INIT_FUNCTION
2666 IopEnumerateDetectedDevices(
2668 IN PUNICODE_STRING RelativePath OPTIONAL
,
2670 IN BOOLEAN EnumerateSubKeys
,
2671 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2672 IN ULONG ParentBootResourcesLength
)
2674 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2675 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2676 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2677 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2678 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2679 OBJECT_ATTRIBUTES ObjectAttributes
;
2680 HANDLE hDevicesKey
= NULL
;
2681 HANDLE hDeviceKey
= NULL
;
2682 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2683 UNICODE_STRING Level2NameU
;
2684 WCHAR Level2Name
[5];
2685 ULONG IndexDevice
= 0;
2687 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2688 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2689 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2690 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2691 UNICODE_STRING DeviceName
, ValueName
;
2693 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2694 ULONG BootResourcesLength
;
2697 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2698 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2699 static ULONG DeviceIndexSerial
= 0;
2700 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2701 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2702 static ULONG DeviceIndexKeyboard
= 0;
2703 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2704 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2705 static ULONG DeviceIndexMouse
= 0;
2706 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
2707 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
2708 static ULONG DeviceIndexParallel
= 0;
2709 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
2710 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
2711 static ULONG DeviceIndexFloppy
= 0;
2712 UNICODE_STRING HardwareIdKey
;
2713 PUNICODE_STRING pHardwareId
;
2714 ULONG DeviceIndex
= 0;
2715 PUCHAR CmResourceList
;
2720 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
2721 if (!NT_SUCCESS(Status
))
2723 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2728 hDevicesKey
= hBaseKey
;
2730 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2731 if (!pDeviceInformation
)
2733 DPRINT("ExAllocatePool() failed\n");
2734 Status
= STATUS_NO_MEMORY
;
2738 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2739 if (!pValueInformation
)
2741 DPRINT("ExAllocatePool() failed\n");
2742 Status
= STATUS_NO_MEMORY
;
2748 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2749 if (Status
== STATUS_NO_MORE_ENTRIES
)
2751 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2753 ExFreePool(pDeviceInformation
);
2754 DeviceInfoLength
= RequiredSize
;
2755 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2756 if (!pDeviceInformation
)
2758 DPRINT("ExAllocatePool() failed\n");
2759 Status
= STATUS_NO_MEMORY
;
2762 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2764 if (!NT_SUCCESS(Status
))
2766 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2771 /* Open device key */
2772 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2773 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2775 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
2776 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
2777 if (!NT_SUCCESS(Status
))
2779 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2783 /* Read boot resources, and add then to parent ones */
2784 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2785 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2787 ExFreePool(pValueInformation
);
2788 ValueInfoLength
= RequiredSize
;
2789 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2790 if (!pValueInformation
)
2792 DPRINT("ExAllocatePool() failed\n");
2793 ZwDeleteKey(hLevel2Key
);
2794 Status
= STATUS_NO_MEMORY
;
2797 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2799 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
2801 BootResources
= ParentBootResources
;
2802 BootResourcesLength
= ParentBootResourcesLength
;
2804 else if (!NT_SUCCESS(Status
))
2806 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2809 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
2811 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
2816 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
2818 /* Concatenate current resources and parent ones */
2819 if (ParentBootResourcesLength
== 0)
2820 BootResourcesLength
= pValueInformation
->DataLength
;
2822 BootResourcesLength
= ParentBootResourcesLength
2823 + pValueInformation
->DataLength
2825 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
2828 DPRINT("ExAllocatePool() failed\n");
2831 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
2833 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2835 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
2837 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2839 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
2840 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2841 ParentBootResourcesLength
- Header
);
2842 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2846 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
2848 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
2849 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2850 ParentBootResourcesLength
- Header
);
2852 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
2853 pValueInformation
->Data
+ Header
,
2854 pValueInformation
->DataLength
- Header
);
2855 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2859 if (EnumerateSubKeys
)
2864 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2865 if (Status
== STATUS_NO_MORE_ENTRIES
)
2867 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2869 ExFreePool(pDeviceInformation
);
2870 DeviceInfoLength
= RequiredSize
;
2871 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2872 if (!pDeviceInformation
)
2874 DPRINT("ExAllocatePool() failed\n");
2875 Status
= STATUS_NO_MEMORY
;
2878 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2880 if (!NT_SUCCESS(Status
))
2882 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2886 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2887 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2889 Status
= IopEnumerateDetectedDevices(
2895 BootResourcesLength
);
2896 if (!NT_SUCCESS(Status
))
2901 /* Read identifier */
2902 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2903 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2905 ExFreePool(pValueInformation
);
2906 ValueInfoLength
= RequiredSize
;
2907 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2908 if (!pValueInformation
)
2910 DPRINT("ExAllocatePool() failed\n");
2911 Status
= STATUS_NO_MEMORY
;
2914 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2916 if (!NT_SUCCESS(Status
))
2918 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
2920 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2923 ValueName
.Length
= ValueName
.MaximumLength
= 0;
2925 else if (pValueInformation
->Type
!= REG_SZ
)
2927 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
2932 /* Assign hardware id to this device */
2933 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
2934 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
2935 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
2936 ValueName
.Length
-= sizeof(WCHAR
);
2939 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
2941 pHardwareId
= &HardwareIdSerial
;
2942 DeviceIndex
= DeviceIndexSerial
++;
2944 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
2946 pHardwareId
= &HardwareIdKeyboard
;
2947 DeviceIndex
= DeviceIndexKeyboard
++;
2949 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
2951 pHardwareId
= &HardwareIdMouse
;
2952 DeviceIndex
= DeviceIndexMouse
++;
2954 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
2956 pHardwareId
= &HardwareIdParallel
;
2957 DeviceIndex
= DeviceIndexParallel
++;
2959 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
2961 pHardwareId
= &HardwareIdFloppy
;
2962 DeviceIndex
= DeviceIndexFloppy
++;
2966 /* Unknown key path */
2967 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
2971 /* Prepare hardware id key (hardware id value without final \0) */
2972 HardwareIdKey
= *pHardwareId
;
2973 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
2975 /* Add the detected device to Root key */
2976 InitializeObjectAttributes(&ObjectAttributes
, &HardwareIdKey
, OBJ_KERNEL_HANDLE
, hRootKey
, NULL
);
2977 Status
= ZwCreateKey(
2983 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
2985 if (!NT_SUCCESS(Status
))
2987 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
2990 swprintf(Level2Name
, L
"%04lu", DeviceIndex
);
2991 RtlInitUnicodeString(&Level2NameU
, Level2Name
);
2992 InitializeObjectAttributes(&ObjectAttributes
, &Level2NameU
, OBJ_KERNEL_HANDLE
, hLevel1Key
, NULL
);
2993 Status
= ZwCreateKey(
2995 KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
,
2999 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
3001 ZwClose(hLevel1Key
);
3002 if (!NT_SUCCESS(Status
))
3004 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3007 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName
, DeviceIndex
, &HardwareIdKey
);
3008 Status
= ZwSetValueKey(hLevel2Key
, &HardwareIDU
, 0, REG_MULTI_SZ
, pHardwareId
->Buffer
, pHardwareId
->MaximumLength
);
3009 if (!NT_SUCCESS(Status
))
3011 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3012 ZwDeleteKey(hLevel2Key
);
3015 /* Create 'LogConf' subkey */
3016 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
, hLevel2Key
, NULL
);
3017 Status
= ZwCreateKey(
3023 REG_OPTION_VOLATILE
,
3025 if (!NT_SUCCESS(Status
))
3027 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3028 ZwDeleteKey(hLevel2Key
);
3031 if (BootResourcesLength
>= sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3033 CmResourceList
= ExAllocatePool(PagedPool
, BootResourcesLength
+ sizeof(ULONG
));
3034 if (!CmResourceList
)
3037 ZwDeleteKey(hLevel2Key
);
3041 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3043 RtlCopyMemory(CmResourceList
,
3047 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3048 RtlCopyMemory(CmResourceList
+ sizeof(ULONG
),
3050 BootResourcesLength
);
3052 /* Save boot resources to 'LogConf\BootConfig' */
3053 Status
= ZwSetValueKey(hLogConf
, &BootConfigU
, 0, REG_RESOURCE_LIST
, CmResourceList
, BootResourcesLength
+ sizeof(ULONG
));
3054 if (!NT_SUCCESS(Status
))
3056 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3058 ZwDeleteKey(hLevel2Key
);
3065 if (BootResources
&& BootResources
!= ParentBootResources
)
3067 ExFreePool(BootResources
);
3068 BootResources
= NULL
;
3072 ZwClose(hLevel2Key
);
3077 ZwClose(hDeviceKey
);
3082 Status
= STATUS_SUCCESS
;
3085 if (hDevicesKey
&& hDevicesKey
!= hBaseKey
)
3086 ZwClose(hDevicesKey
);
3088 ZwClose(hDeviceKey
);
3089 if (pDeviceInformation
)
3090 ExFreePool(pDeviceInformation
);
3091 if (pValueInformation
)
3092 ExFreePool(pValueInformation
);
3096 static BOOLEAN INIT_FUNCTION
3097 IopIsFirmwareMapperDisabled(VOID
)
3099 UNICODE_STRING KeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3100 UNICODE_STRING KeyNameU
= RTL_CONSTANT_STRING(L
"DisableFirmwareMapper");
3101 OBJECT_ATTRIBUTES ObjectAttributes
;
3103 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
;
3104 ULONG DesiredLength
, Length
;
3108 InitializeObjectAttributes(&ObjectAttributes
, &KeyPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3109 Status
= ZwOpenKey(&hPnpKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
3110 if (NT_SUCCESS(Status
))
3112 Status
= ZwQueryValueKey(hPnpKey
,
3114 KeyValuePartialInformation
,
3118 if ((Status
== STATUS_BUFFER_TOO_SMALL
) ||
3119 (Status
== STATUS_BUFFER_OVERFLOW
))
3121 Length
= DesiredLength
;
3122 KeyInformation
= ExAllocatePool(PagedPool
, Length
);
3125 Status
= ZwQueryValueKey(hPnpKey
,
3127 KeyValuePartialInformation
,
3131 if (NT_SUCCESS(Status
) && KeyInformation
->DataLength
== sizeof(ULONG
))
3133 KeyValue
= (ULONG
)(*KeyInformation
->Data
);
3137 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU
, &KeyNameU
);
3140 ExFreePool(KeyInformation
);
3144 DPRINT1("Failed to allocate memory for registry query\n");
3149 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU
, &KeyNameU
, Status
);
3156 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU
, Status
);
3159 DPRINT1("Firmware mapper is %s\n", KeyValue
!= 0 ? "disabled" : "enabled");
3161 return (KeyValue
!= 0) ? TRUE
: FALSE
;
3167 IopUpdateRootKey(VOID
)
3169 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3170 UNICODE_STRING RootPathU
= RTL_CONSTANT_STRING(L
"Root");
3171 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3172 OBJECT_ATTRIBUTES ObjectAttributes
;
3173 HANDLE hEnum
, hRoot
;
3176 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3177 Status
= ZwCreateKey(&hEnum
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
3178 if (!NT_SUCCESS(Status
))
3180 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3184 InitializeObjectAttributes(&ObjectAttributes
, &RootPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
3185 Status
= ZwCreateKey(&hRoot
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
3187 if (!NT_SUCCESS(Status
))
3189 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3193 if (!IopIsFirmwareMapperDisabled())
3195 Status
= IopOpenRegistryKeyEx(&hEnum
, NULL
, &MultiKeyPathU
, KEY_ENUMERATE_SUB_KEYS
);
3196 if (!NT_SUCCESS(Status
))
3198 /* Nothing to do, don't return with an error status */
3199 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3201 return STATUS_SUCCESS
;
3203 Status
= IopEnumerateDetectedDevices(
3214 /* Enumeration is disabled */
3215 Status
= STATUS_SUCCESS
;
3225 IopOpenRegistryKeyEx(PHANDLE KeyHandle
,
3227 PUNICODE_STRING Name
,
3228 ACCESS_MASK DesiredAccess
)
3230 OBJECT_ATTRIBUTES ObjectAttributes
;
3237 InitializeObjectAttributes(&ObjectAttributes
,
3239 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3243 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
3250 IopCreateRegistryKeyEx(OUT PHANDLE Handle
,
3251 IN HANDLE RootHandle OPTIONAL
,
3252 IN PUNICODE_STRING KeyName
,
3253 IN ACCESS_MASK DesiredAccess
,
3254 IN ULONG CreateOptions
,
3255 OUT PULONG Disposition OPTIONAL
)
3257 OBJECT_ATTRIBUTES ObjectAttributes
;
3258 ULONG KeyDisposition
, RootHandleIndex
= 0, i
= 1, NestedCloseLevel
= 0;
3260 HANDLE HandleArray
[2];
3261 BOOLEAN Recursing
= TRUE
;
3263 UNICODE_STRING KeyString
;
3264 NTSTATUS Status
= STATUS_SUCCESS
;
3267 /* P1 is start, pp is end */
3268 p1
= KeyName
->Buffer
;
3269 pp
= (PVOID
)((ULONG_PTR
)p1
+ KeyName
->Length
);
3271 /* Create the target key */
3272 InitializeObjectAttributes(&ObjectAttributes
,
3274 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3277 Status
= ZwCreateKey(&HandleArray
[i
],
3285 /* Now we check if this failed */
3286 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) && (RootHandle
))
3288 /* Target key failed, so we'll need to create its parent. Setup array */
3289 HandleArray
[0] = NULL
;
3290 HandleArray
[1] = RootHandle
;
3292 /* Keep recursing for each missing parent */
3295 /* And if we're deep enough, close the last handle */
3296 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3298 /* We're setup to ping-pong between the two handle array entries */
3299 RootHandleIndex
= i
;
3302 /* Clear the one we're attempting to open now */
3303 HandleArray
[i
] = NULL
;
3305 /* Process the parent key name */
3306 for (p
= p1
; ((p
< pp
) && (*p
!= OBJ_NAME_PATH_SEPARATOR
)); p
++);
3307 Length
= (USHORT
)(p
- p1
) * sizeof(WCHAR
);
3309 /* Is there a parent name? */
3312 /* Build the unicode string for it */
3313 KeyString
.Buffer
= p1
;
3314 KeyString
.Length
= KeyString
.MaximumLength
= Length
;
3316 /* Now try opening the parent */
3317 InitializeObjectAttributes(&ObjectAttributes
,
3319 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3320 HandleArray
[RootHandleIndex
],
3322 Status
= ZwCreateKey(&HandleArray
[i
],
3329 if (NT_SUCCESS(Status
))
3331 /* It worked, we have one more handle */
3336 /* Parent key creation failed, abandon loop */
3343 /* We don't have a parent name, probably corrupted key name */
3344 Status
= STATUS_INVALID_PARAMETER
;
3349 /* Now see if there's more parents to create */
3351 if ((p
== pp
) || (p1
== pp
))
3353 /* We're done, hopefully successfully, so stop */
3358 /* Outer loop check for handle nesting that requires closing the top handle */
3359 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3362 /* Check if we broke out of the loop due to success */
3363 if (NT_SUCCESS(Status
))
3365 /* Return the target handle (we closed all the parent ones) and disposition */
3366 *Handle
= HandleArray
[i
];
3367 if (Disposition
) *Disposition
= KeyDisposition
;
3370 /* Return the success state */
3376 IopGetRegistryValue(IN HANDLE Handle
,
3378 OUT PKEY_VALUE_FULL_INFORMATION
*Information
)
3380 UNICODE_STRING ValueString
;
3382 PKEY_VALUE_FULL_INFORMATION FullInformation
;
3386 RtlInitUnicodeString(&ValueString
, ValueName
);
3388 Status
= ZwQueryValueKey(Handle
,
3390 KeyValueFullInformation
,
3394 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
3395 (Status
!= STATUS_BUFFER_TOO_SMALL
))
3400 FullInformation
= ExAllocatePool(NonPagedPool
, Size
);
3401 if (!FullInformation
) return STATUS_INSUFFICIENT_RESOURCES
;
3403 Status
= ZwQueryValueKey(Handle
,
3405 KeyValueFullInformation
,
3409 if (!NT_SUCCESS(Status
))
3411 ExFreePool(FullInformation
);
3415 *Information
= FullInformation
;
3416 return STATUS_SUCCESS
;
3419 RTL_GENERIC_COMPARE_RESULTS
3421 PiCompareInstancePath(IN PRTL_AVL_TABLE Table
,
3422 IN PVOID FirstStruct
,
3423 IN PVOID SecondStruct
)
3431 // The allocation function is called by the generic table package whenever
3432 // it needs to allocate memory for the table.
3437 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3447 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3456 PpInitializeDeviceReferenceTable(VOID
)
3458 /* Setup the guarded mutex and AVL table */
3459 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock
);
3460 RtlInitializeGenericTableAvl(
3461 &PpDeviceReferenceTable
,
3462 (PRTL_AVL_COMPARE_ROUTINE
)PiCompareInstancePath
,
3463 (PRTL_AVL_ALLOCATE_ROUTINE
)PiAllocateGenericTableEntry
,
3464 (PRTL_AVL_FREE_ROUTINE
)PiFreeGenericTableEntry
,
3472 /* Initialize the resource when accessing device registry data */
3473 ExInitializeResourceLite(&PpRegistryDeviceResource
);
3475 /* Setup the device reference AVL table */
3476 PpInitializeDeviceReferenceTable();
3484 /* Check the initialization phase */
3485 switch (ExpInitializationPhase
)
3490 return PiInitPhase0();
3496 //return PiInitPhase1();
3500 /* Don't know any other phase! Bugcheck! */
3501 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL
);
3506 LONG IopNumberDeviceNodes
;
3510 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3512 PDEVICE_NODE DeviceNode
;
3516 DeviceNode
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), 'donD');
3517 if (!DeviceNode
) return DeviceNode
;
3520 InterlockedIncrement(&IopNumberDeviceNodes
);
3523 RtlZeroMemory(DeviceNode
, sizeof(DEVICE_NODE
));
3524 DeviceNode
->InterfaceType
= InterfaceTypeUndefined
;
3525 DeviceNode
->BusNumber
= -1;
3526 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
3527 DeviceNode
->ChildBusNumber
= -1;
3528 DeviceNode
->ChildBusTypeIndex
= -1;
3529 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3530 InitializeListHead(&DeviceNode
->DeviceArbiterList
);
3531 InitializeListHead(&DeviceNode
->DeviceTranslatorList
);
3532 InitializeListHead(&DeviceNode
->TargetDeviceNotify
);
3533 InitializeListHead(&DeviceNode
->DockInfo
.ListEntry
);
3534 InitializeListHead(&DeviceNode
->PendedSetInterfaceState
);
3536 /* Check if there is a PDO */
3537 if (PhysicalDeviceObject
)
3539 /* Link it and remove the init flag */
3540 DeviceNode
->PhysicalDeviceObject
= PhysicalDeviceObject
;
3541 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= DeviceNode
;
3542 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
3545 /* Return the node */
3549 /* PUBLIC FUNCTIONS **********************************************************/
3553 PnpBusTypeGuidGet(IN USHORT Index
,
3554 IN LPGUID BusTypeGuid
)
3556 NTSTATUS Status
= STATUS_SUCCESS
;
3558 /* Acquire the lock */
3559 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
3562 if (Index
< PnpBusTypeGuidList
->GuidCount
)
3565 RtlCopyMemory(BusTypeGuid
, &PnpBusTypeGuidList
->Guids
[Index
], sizeof(GUID
));
3570 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
3573 /* Release lock and return status */
3574 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
3580 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject
,
3581 IN PHANDLE DeviceInstanceHandle
,
3582 IN ACCESS_MASK DesiredAccess
)
3586 PDEVICE_NODE DeviceNode
;
3587 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3590 /* Open the enum key */
3591 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
3595 if (!NT_SUCCESS(Status
)) return Status
;
3597 /* Make sure we have an instance path */
3598 DeviceNode
= IopGetDeviceNode(DeviceObject
);
3599 if ((DeviceNode
) && (DeviceNode
->InstancePath
.Length
))
3601 /* Get the instance key */
3602 Status
= IopOpenRegistryKeyEx(DeviceInstanceHandle
,
3604 &DeviceNode
->InstancePath
,
3610 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3613 /* Close the handle and return status */
3620 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList
)
3622 ULONG FinalSize
, PartialSize
, EntrySize
, i
, j
;
3623 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
3624 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
3626 /* If we don't have one, that's easy */
3627 if (!ResourceList
) return 0;
3629 /* Start with the minimum size possible */
3630 FinalSize
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
3632 /* Loop each full descriptor */
3633 FullDescriptor
= ResourceList
->List
;
3634 for (i
= 0; i
< ResourceList
->Count
; i
++)
3636 /* Start with the minimum size possible */
3637 PartialSize
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
) +
3638 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST
, PartialDescriptors
);
3640 /* Loop each partial descriptor */
3641 PartialDescriptor
= FullDescriptor
->PartialResourceList
.PartialDescriptors
;
3642 for (j
= 0; j
< FullDescriptor
->PartialResourceList
.Count
; j
++)
3644 /* Start with the minimum size possible */
3645 EntrySize
= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
3647 /* Check if there is extra data */
3648 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
3651 EntrySize
+= PartialDescriptor
->u
.DeviceSpecificData
.DataSize
;
3654 /* The size of partial descriptors is bigger */
3655 PartialSize
+= EntrySize
;
3657 /* Go to the next partial descriptor */
3658 PartialDescriptor
= (PVOID
)((ULONG_PTR
)PartialDescriptor
+ EntrySize
);
3661 /* The size of full descriptors is bigger */
3662 FinalSize
+= PartialSize
;
3664 /* Go to the next full descriptor */
3665 FullDescriptor
= (PVOID
)((ULONG_PTR
)FullDescriptor
+ PartialSize
);
3668 /* Return the final size */
3674 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject
,
3679 IN PULONG BufferLength
)
3682 HANDLE KeyHandle
, SubHandle
;
3683 UNICODE_STRING KeyString
;
3684 PKEY_VALUE_FULL_INFORMATION KeyValueInfo
= NULL
;
3688 /* Find the instance key */
3689 Status
= PnpDeviceObjectToDeviceInstance(DeviceObject
, &KeyHandle
, KEY_READ
);
3690 if (NT_SUCCESS(Status
))
3692 /* Check for name given by caller */
3696 RtlInitUnicodeString(&KeyString
, KeyName
);
3697 Status
= IopOpenRegistryKeyEx(&SubHandle
,
3701 if (NT_SUCCESS(Status
))
3703 /* And use this handle instead */
3705 KeyHandle
= SubHandle
;
3709 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3710 if (NT_SUCCESS(Status
))
3712 /* Now get the size of the property */
3713 Status
= IopGetRegistryValue(KeyHandle
,
3722 /* Fail if any of the registry operations failed */
3723 if (!NT_SUCCESS(Status
)) return Status
;
3725 /* Check how much data we have to copy */
3726 Length
= KeyValueInfo
->DataLength
;
3727 if (*BufferLength
>= Length
)
3729 /* Check for a match in the value type */
3730 if (KeyValueInfo
->Type
== ValueType
)
3733 RtlCopyMemory(Buffer
,
3734 (PVOID
)((ULONG_PTR
)KeyValueInfo
+
3735 KeyValueInfo
->DataOffset
),
3740 /* Invalid registry property type, fail */
3741 Status
= STATUS_INVALID_PARAMETER_2
;
3746 /* Buffer is too small to hold data */
3747 Status
= STATUS_BUFFER_TOO_SMALL
;
3750 /* Return the required buffer length, free the buffer, and return status */
3751 *BufferLength
= Length
;
3752 ExFreePool(KeyValueInfo
);
3756 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3757 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3758 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED; while(TRUE); break;}
3765 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
3766 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
3767 IN ULONG BufferLength
,
3768 OUT PVOID PropertyBuffer
,
3769 OUT PULONG ResultLength
)
3771 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
3772 DEVICE_CAPABILITIES DeviceCaps
;
3773 ULONG ReturnLength
= 0, Length
= 0, ValueType
;
3774 PWCHAR ValueName
= NULL
, EnumeratorNameEnd
, DeviceInstanceName
;
3776 NTSTATUS Status
= STATUS_BUFFER_TOO_SMALL
;
3778 POBJECT_NAME_INFORMATION ObjectNameInfo
= NULL
;
3779 BOOLEAN NullTerminate
= FALSE
;
3781 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject
, DeviceProperty
);
3783 /* Assume failure */
3786 /* Only PDOs can call this */
3787 if (!DeviceNode
) return STATUS_INVALID_DEVICE_REQUEST
;
3789 /* Handle all properties */
3790 switch (DeviceProperty
)
3792 case DevicePropertyBusTypeGuid
:
3794 /* Get the GUID from the internal cache */
3795 Status
= PnpBusTypeGuidGet(DeviceNode
->ChildBusTypeIndex
, &BusTypeGuid
);
3796 if (!NT_SUCCESS(Status
)) return Status
;
3798 /* This is the format of the returned data */
3799 PIP_RETURN_DATA(sizeof(GUID
), &BusTypeGuid
);
3801 case DevicePropertyLegacyBusType
:
3803 /* Validate correct interface type */
3804 if (DeviceNode
->ChildInterfaceType
== InterfaceTypeUndefined
)
3805 return STATUS_OBJECT_NAME_NOT_FOUND
;
3807 /* This is the format of the returned data */
3808 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE
), &DeviceNode
->ChildInterfaceType
);
3810 case DevicePropertyBusNumber
:
3812 /* Validate correct bus number */
3813 if ((DeviceNode
->ChildBusNumber
& 0x80000000) == 0x80000000)
3814 return STATUS_OBJECT_NAME_NOT_FOUND
;
3816 /* This is the format of the returned data */
3817 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceNode
->ChildBusNumber
);
3819 case DevicePropertyEnumeratorName
:
3821 /* Get the instance path */
3822 DeviceInstanceName
= DeviceNode
->InstancePath
.Buffer
;
3825 ASSERT((BufferLength
& 1) == 0);
3826 ASSERT(DeviceInstanceName
!= NULL
);
3828 /* Get the name from the path */
3829 EnumeratorNameEnd
= wcschr(DeviceInstanceName
, OBJ_NAME_PATH_SEPARATOR
);
3830 ASSERT(EnumeratorNameEnd
);
3832 /* This string needs to be NULL-terminated */
3833 NullTerminate
= TRUE
;
3835 /* This is the format of the returned data */
3836 PIP_RETURN_DATA((ULONG
)(EnumeratorNameEnd
- DeviceInstanceName
) * sizeof(WCHAR
),
3837 DeviceInstanceName
);
3839 case DevicePropertyAddress
:
3841 /* Query the device caps */
3842 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
);
3843 if (!NT_SUCCESS(Status
) || (DeviceCaps
.Address
== MAXULONG
))
3844 return STATUS_OBJECT_NAME_NOT_FOUND
;
3846 /* This is the format of the returned data */
3847 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceCaps
.Address
);
3849 case DevicePropertyBootConfigurationTranslated
:
3851 /* Validate we have resources */
3852 if (!DeviceNode
->BootResources
)
3853 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3855 /* No resources will still fake success, but with 0 bytes */
3857 return STATUS_SUCCESS
;
3860 /* This is the format of the returned data */
3861 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode
->BootResources
), // FIXFIX: Should use BootResourcesTranslated
3862 DeviceNode
->BootResources
); // FIXFIX: Should use BootResourcesTranslated
3864 case DevicePropertyPhysicalDeviceObjectName
:
3866 /* Sanity check for Unicode-sized string */
3867 ASSERT((BufferLength
& 1) == 0);
3869 /* Allocate name buffer */
3870 Length
= BufferLength
+ sizeof(OBJECT_NAME_INFORMATION
);
3871 ObjectNameInfo
= ExAllocatePool(PagedPool
, Length
);
3872 if (!ObjectNameInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
3874 /* Query the PDO name */
3875 Status
= ObQueryNameString(DeviceObject
,
3879 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
3881 /* It's up to the caller to try again */
3882 Status
= STATUS_BUFFER_TOO_SMALL
;
3885 /* This string needs to be NULL-terminated */
3886 NullTerminate
= TRUE
;
3888 /* Return if successful */
3889 if (NT_SUCCESS(Status
)) PIP_RETURN_DATA(ObjectNameInfo
->Name
.Length
,
3890 ObjectNameInfo
->Name
.Buffer
);
3892 /* Let the caller know how big the name is */
3893 *ResultLength
-= sizeof(OBJECT_NAME_INFORMATION
);
3896 /* Handle the registry-based properties */
3897 case DevicePropertyUINumber
:
3898 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER
, REG_DWORD
);
3899 case DevicePropertyLocationInformation
:
3900 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION
, REG_SZ
);
3901 case DevicePropertyDeviceDescription
:
3902 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC
, REG_SZ
);
3903 case DevicePropertyHardwareID
:
3904 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID
, REG_MULTI_SZ
);
3905 case DevicePropertyCompatibleIDs
:
3906 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS
, REG_MULTI_SZ
);
3907 case DevicePropertyBootConfiguration
:
3908 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG
, REG_RESOURCE_LIST
);
3909 case DevicePropertyClassName
:
3910 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS
, REG_SZ
);
3911 case DevicePropertyClassGuid
:
3912 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID
, REG_SZ
);
3913 case DevicePropertyDriverKeyName
:
3914 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER
, REG_SZ
);
3915 case DevicePropertyManufacturer
:
3916 PIP_REGISTRY_DATA(REGSTR_VAL_MFG
, REG_SZ
);
3917 case DevicePropertyFriendlyName
:
3918 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME
, REG_SZ
);
3919 case DevicePropertyContainerID
:
3920 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3921 PIP_UNIMPLEMENTED();
3922 case DevicePropertyRemovalPolicy
:
3923 PIP_UNIMPLEMENTED();
3924 case DevicePropertyInstallState
:
3925 PIP_UNIMPLEMENTED();
3926 case DevicePropertyResourceRequirements
:
3927 PIP_UNIMPLEMENTED();
3928 case DevicePropertyAllocatedResources
:
3929 PIP_UNIMPLEMENTED();
3931 return STATUS_INVALID_PARAMETER_2
;
3934 /* Having a registry value name implies registry data */
3937 /* We know up-front how much data to expect */
3938 *ResultLength
= BufferLength
;
3940 /* Go get the data, use the LogConf subkey if necessary */
3941 Status
= PiGetDeviceRegistryProperty(DeviceObject
,
3945 DevicePropertyBootConfiguration
) ?
3950 else if (NT_SUCCESS(Status
))
3952 /* We know up-front how much data to expect, check the caller's buffer */
3953 *ResultLength
= ReturnLength
+ (NullTerminate
? sizeof(UNICODE_NULL
) : 0);
3954 if (*ResultLength
<= BufferLength
)
3956 /* Buffer is all good, copy the data */
3957 RtlCopyMemory(PropertyBuffer
, Data
, ReturnLength
);
3959 /* Check if we need to NULL-terminate the string */
3962 /* Terminate the string */
3963 ((PWCHAR
)PropertyBuffer
)[ReturnLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3966 /* This is the success path */
3967 Status
= STATUS_SUCCESS
;
3972 Status
= STATUS_BUFFER_TOO_SMALL
;
3976 /* Free any allocation we may have made, and return the status code */
3977 if (ObjectNameInfo
) ExFreePool(ObjectNameInfo
);
3986 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3988 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
3989 IO_STACK_LOCATION Stack
;
3992 IO_STATUS_BLOCK IoStatusBlock
;
3994 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
3995 Stack
.MajorFunction
= IRP_MJ_PNP
;
3996 Stack
.MinorFunction
= IRP_MN_QUERY_PNP_DEVICE_STATE
;
3998 Status
= IopSynchronousCall(PhysicalDeviceObject
, &Stack
, (PVOID
*)&PnPFlags
);
3999 if (!NT_SUCCESS(Status
))
4001 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status
);
4005 if (PnPFlags
& PNP_DEVICE_NOT_DISABLEABLE
)
4006 DeviceNode
->UserFlags
|= DNUF_NOT_DISABLEABLE
;
4008 DeviceNode
->UserFlags
&= ~DNUF_NOT_DISABLEABLE
;
4010 if (PnPFlags
& PNP_DEVICE_DONT_DISPLAY_IN_UI
)
4011 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
4013 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
4015 if ((PnPFlags
& PNP_DEVICE_REMOVED
) ||
4016 ((PnPFlags
& PNP_DEVICE_FAILED
) && !(PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)))
4018 /* Surprise removal */
4020 IopSendSurpriseRemoval(PhysicalDeviceObject
);
4022 /* Tell the user-mode PnP manager that a device was removed */
4023 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
4024 &DeviceNode
->InstancePath
);
4026 IopSendRemoveDevice(PhysicalDeviceObject
);
4028 else if ((PnPFlags
& PNP_DEVICE_FAILED
) && (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
))
4030 /* Stop for resource rebalance */
4032 Status
= IopStopDevice(DeviceNode
);
4033 if (!NT_SUCCESS(Status
))
4035 DPRINT1("Failed to stop device for rebalancing\n");
4037 /* Stop failed so don't rebalance */
4038 PnPFlags
&= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
;
4042 /* Resource rebalance */
4043 if (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)
4045 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4047 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4049 IRP_MN_QUERY_RESOURCES
,
4051 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
4053 DeviceNode
->BootResources
=
4054 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
4055 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
4059 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
4060 DeviceNode
->BootResources
= NULL
;
4063 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4065 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4067 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
4069 if (NT_SUCCESS(Status
))
4071 DeviceNode
->ResourceRequirements
=
4072 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
4076 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
4077 DeviceNode
->ResourceRequirements
= NULL
;
4080 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4081 if (IopStartDevice(DeviceNode
) != STATUS_SUCCESS
)
4083 DPRINT1("Restart after resource rebalance failed\n");
4085 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
4086 DeviceNode
->Flags
|= DNF_START_FAILED
;
4088 IopRemoveDevice(DeviceNode
);
4094 * @name IoOpenDeviceRegistryKey
4096 * Open a registry key unique for a specified driver or device instance.
4098 * @param DeviceObject Device to get the registry key for.
4099 * @param DevInstKeyType Type of the key to return.
4100 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4101 * @param DevInstRegKey Handle to the opened registry key on
4102 * successful return.
4110 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject
,
4111 IN ULONG DevInstKeyType
,
4112 IN ACCESS_MASK DesiredAccess
,
4113 OUT PHANDLE DevInstRegKey
)
4115 static WCHAR RootKeyName
[] =
4116 L
"\\Registry\\Machine\\System\\CurrentControlSet\\";
4117 static WCHAR ProfileKeyName
[] =
4118 L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4119 static WCHAR ClassKeyName
[] = L
"Control\\Class\\";
4120 static WCHAR EnumKeyName
[] = L
"Enum\\";
4121 static WCHAR DeviceParametersKeyName
[] = L
"Device Parameters";
4122 ULONG KeyNameLength
;
4123 LPWSTR KeyNameBuffer
;
4124 UNICODE_STRING KeyName
;
4125 ULONG DriverKeyLength
;
4126 OBJECT_ATTRIBUTES ObjectAttributes
;
4127 PDEVICE_NODE DeviceNode
= NULL
;
4130 DPRINT("IoOpenDeviceRegistryKey() called\n");
4132 if ((DevInstKeyType
& (PLUGPLAY_REGKEY_DEVICE
| PLUGPLAY_REGKEY_DRIVER
)) == 0)
4134 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4135 return STATUS_INVALID_PARAMETER
;
4138 if (!IopIsValidPhysicalDeviceObject(DeviceObject
))
4139 return STATUS_INVALID_DEVICE_REQUEST
;
4140 DeviceNode
= IopGetDeviceNode(DeviceObject
);
4143 * Calculate the length of the base key name. This is the full
4144 * name for driver key or the name excluding "Device Parameters"
4145 * subkey for device key.
4148 KeyNameLength
= sizeof(RootKeyName
);
4149 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4150 KeyNameLength
+= sizeof(ProfileKeyName
) - sizeof(UNICODE_NULL
);
4151 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4153 KeyNameLength
+= sizeof(ClassKeyName
) - sizeof(UNICODE_NULL
);
4154 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4155 0, NULL
, &DriverKeyLength
);
4156 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
4158 KeyNameLength
+= DriverKeyLength
;
4162 KeyNameLength
+= sizeof(EnumKeyName
) - sizeof(UNICODE_NULL
) +
4163 DeviceNode
->InstancePath
.Length
;
4167 * Now allocate the buffer for the key name...
4170 KeyNameBuffer
= ExAllocatePool(PagedPool
, KeyNameLength
);
4171 if (KeyNameBuffer
== NULL
)
4172 return STATUS_INSUFFICIENT_RESOURCES
;
4175 KeyName
.MaximumLength
= (USHORT
)KeyNameLength
;
4176 KeyName
.Buffer
= KeyNameBuffer
;
4179 * ...and build the key name.
4182 KeyName
.Length
+= sizeof(RootKeyName
) - sizeof(UNICODE_NULL
);
4183 RtlCopyMemory(KeyNameBuffer
, RootKeyName
, KeyName
.Length
);
4185 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4186 RtlAppendUnicodeToString(&KeyName
, ProfileKeyName
);
4188 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4190 RtlAppendUnicodeToString(&KeyName
, ClassKeyName
);
4191 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4192 DriverKeyLength
, KeyNameBuffer
+
4193 (KeyName
.Length
/ sizeof(WCHAR
)),
4195 if (!NT_SUCCESS(Status
))
4197 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status
);
4198 ExFreePool(KeyNameBuffer
);
4201 KeyName
.Length
+= (USHORT
)DriverKeyLength
- sizeof(UNICODE_NULL
);
4205 RtlAppendUnicodeToString(&KeyName
, EnumKeyName
);
4206 Status
= RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->InstancePath
);
4207 if (DeviceNode
->InstancePath
.Length
== 0)
4209 ExFreePool(KeyNameBuffer
);
4215 * Open the base key.
4217 Status
= IopOpenRegistryKeyEx(DevInstRegKey
, NULL
, &KeyName
, DesiredAccess
);
4218 if (!NT_SUCCESS(Status
))
4220 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName
, Status
);
4221 ExFreePool(KeyNameBuffer
);
4224 ExFreePool(KeyNameBuffer
);
4227 * For driver key we're done now.
4230 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4234 * Let's go further. For device key we must open "Device Parameters"
4235 * subkey and create it if it doesn't exist yet.
4238 RtlInitUnicodeString(&KeyName
, DeviceParametersKeyName
);
4239 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
,
4240 OBJ_CASE_INSENSITIVE
, *DevInstRegKey
, NULL
);
4241 Status
= ZwCreateKey(DevInstRegKey
, DesiredAccess
, &ObjectAttributes
,
4242 0, NULL
, ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0, NULL
);
4243 ZwClose(ObjectAttributes
.RootDirectory
);
4250 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
, BOOLEAN Force
)
4252 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
, FailedRemoveDevice
;
4256 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4257 ChildDeviceNode
= ParentDeviceNode
->Child
;
4258 while (ChildDeviceNode
!= NULL
)
4260 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4261 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4263 Status
= IopPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
, Force
);
4264 if (!NT_SUCCESS(Status
))
4266 FailedRemoveDevice
= ChildDeviceNode
;
4270 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4271 ChildDeviceNode
= NextDeviceNode
;
4273 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4275 return STATUS_SUCCESS
;
4278 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4279 ChildDeviceNode
= ParentDeviceNode
->Child
;
4280 while (ChildDeviceNode
!= NULL
)
4282 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4283 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4285 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4287 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4288 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4289 if (ChildDeviceNode
== FailedRemoveDevice
)
4292 ChildDeviceNode
= NextDeviceNode
;
4294 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4296 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4303 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4305 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4308 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4309 ChildDeviceNode
= ParentDeviceNode
->Child
;
4310 while (ChildDeviceNode
!= NULL
)
4312 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4313 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4315 IopSendRemoveDevice(ChildDeviceNode
->PhysicalDeviceObject
);
4317 ChildDeviceNode
= NextDeviceNode
;
4319 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4321 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4326 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4328 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4331 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4332 ChildDeviceNode
= ParentDeviceNode
->Child
;
4333 while (ChildDeviceNode
!= NULL
)
4335 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4336 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4338 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4340 ChildDeviceNode
= NextDeviceNode
;
4342 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4344 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4349 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
, BOOLEAN Force
)
4351 /* This function DOES NOT dereference the device objects on SUCCESS
4352 * but it DOES dereference device objects on FAILURE */
4357 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4359 Status
= IopPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
], Force
);
4360 if (!NT_SUCCESS(Status
))
4367 return STATUS_SUCCESS
;
4370 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4371 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4372 for (i
= 0; i
<= j
; i
++)
4374 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4375 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4376 DeviceRelations
->Objects
[i
] = NULL
;
4378 for (; i
< DeviceRelations
->Count
; i
++)
4380 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4381 DeviceRelations
->Objects
[i
] = NULL
;
4383 ExFreePool(DeviceRelations
);
4390 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4392 /* This function DOES dereference the device objects in all cases */
4396 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4398 IopSendRemoveDevice(DeviceRelations
->Objects
[i
]);
4399 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4400 DeviceRelations
->Objects
[i
] = NULL
;
4403 ExFreePool(DeviceRelations
);
4408 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4410 /* This function DOES dereference the device objects in all cases */
4414 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4416 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4417 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4418 DeviceRelations
->Objects
[i
] = NULL
;
4421 ExFreePool(DeviceRelations
);
4425 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
)
4427 IO_STACK_LOCATION Stack
;
4428 IO_STATUS_BLOCK IoStatusBlock
;
4429 PDEVICE_RELATIONS DeviceRelations
;
4432 IopCancelRemoveDevice(DeviceObject
);
4434 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4436 Status
= IopInitiatePnpIrp(DeviceObject
,
4438 IRP_MN_QUERY_DEVICE_RELATIONS
,
4440 if (!NT_SUCCESS(Status
))
4442 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4443 DeviceRelations
= NULL
;
4447 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4450 if (DeviceRelations
)
4451 IopCancelRemoveDeviceRelations(DeviceRelations
);
4455 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
)
4457 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
4458 IO_STACK_LOCATION Stack
;
4459 IO_STATUS_BLOCK IoStatusBlock
;
4460 PDEVICE_RELATIONS DeviceRelations
;
4463 if ((DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
) && !Force
)
4465 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode
->InstancePath
);
4466 return STATUS_UNSUCCESSFUL
;
4469 if (!Force
&& IopQueryRemoveDevice(DeviceObject
) != STATUS_SUCCESS
)
4471 DPRINT1("Removal vetoed by failing the query remove request\n");
4473 IopCancelRemoveDevice(DeviceObject
);
4475 return STATUS_UNSUCCESSFUL
;
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
)
4496 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, Force
);
4497 if (!NT_SUCCESS(Status
))
4501 Status
= IopQueryRemoveChildDevices(DeviceNode
, Force
);
4502 if (!NT_SUCCESS(Status
))
4504 if (DeviceRelations
)
4505 IopCancelRemoveDeviceRelations(DeviceRelations
);
4509 DeviceNode
->Flags
|= DNF_WILL_BE_REMOVED
;
4510 if (DeviceRelations
)
4511 IopSendRemoveDeviceRelations(DeviceRelations
);
4512 IopSendRemoveChildDevices(DeviceNode
);
4514 return STATUS_SUCCESS
;
4518 IopRemoveDevice(PDEVICE_NODE DeviceNode
)
4522 DPRINT("Removing device: %wZ\n", &DeviceNode
->InstancePath
);
4524 Status
= IopPrepareDeviceForRemoval(DeviceNode
->PhysicalDeviceObject
, FALSE
);
4525 if (NT_SUCCESS(Status
))
4527 IopSendRemoveDevice(DeviceNode
->PhysicalDeviceObject
);
4528 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL
,
4529 &DeviceNode
->InstancePath
);
4530 return STATUS_SUCCESS
;
4541 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject
)
4543 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
4544 PDEVICE_RELATIONS DeviceRelations
;
4545 IO_STATUS_BLOCK IoStatusBlock
;
4546 IO_STACK_LOCATION Stack
;
4547 DEVICE_CAPABILITIES Capabilities
;
4550 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT
,
4551 &DeviceNode
->InstancePath
);
4553 if (IopQueryDeviceCapabilities(DeviceNode
, &Capabilities
) != STATUS_SUCCESS
)
4558 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
4560 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4562 IRP_MN_QUERY_DEVICE_RELATIONS
,
4564 if (!NT_SUCCESS(Status
))
4566 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4567 DeviceRelations
= NULL
;
4571 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4574 if (DeviceRelations
)
4576 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, FALSE
);
4577 if (!NT_SUCCESS(Status
))
4581 Status
= IopQueryRemoveChildDevices(DeviceNode
, FALSE
);
4582 if (!NT_SUCCESS(Status
))
4584 if (DeviceRelations
)
4585 IopCancelRemoveDeviceRelations(DeviceRelations
);
4589 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject
, FALSE
) != STATUS_SUCCESS
)
4591 if (DeviceRelations
)
4592 IopCancelRemoveDeviceRelations(DeviceRelations
);
4593 IopCancelRemoveChildDevices(DeviceNode
);
4597 if (DeviceRelations
)
4598 IopSendRemoveDeviceRelations(DeviceRelations
);
4599 IopSendRemoveChildDevices(DeviceNode
);
4601 if (Capabilities
.EjectSupported
)
4603 if (IopSendEject(PhysicalDeviceObject
) != STATUS_SUCCESS
)
4610 DeviceNode
->Flags
|= DNF_DISABLED
;
4613 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT
,
4614 &DeviceNode
->InstancePath
);
4619 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED
,
4620 &DeviceNode
->InstancePath
);
4628 IoInvalidateDeviceRelations(
4629 IN PDEVICE_OBJECT DeviceObject
,
4630 IN DEVICE_RELATION_TYPE Type
)
4632 PIO_WORKITEM WorkItem
;
4633 PINVALIDATE_DEVICE_RELATION_DATA Data
;
4635 Data
= ExAllocatePool(NonPagedPool
, sizeof(INVALIDATE_DEVICE_RELATION_DATA
));
4638 WorkItem
= IoAllocateWorkItem(DeviceObject
);
4645 ObReferenceObject(DeviceObject
);
4646 Data
->DeviceObject
= DeviceObject
;
4648 Data
->WorkItem
= WorkItem
;
4652 IopAsynchronousInvalidateDeviceRelations
,
4662 IoSynchronousInvalidateDeviceRelations(
4663 IN PDEVICE_OBJECT DeviceObject
,
4664 IN DEVICE_RELATION_TYPE Type
)
4671 /* Enumerate the device */
4672 return IopEnumerateDevice(DeviceObject
);
4673 case PowerRelations
:
4674 /* Not handled yet */
4675 return STATUS_NOT_IMPLEMENTED
;
4676 case TargetDeviceRelation
:
4678 return STATUS_SUCCESS
;
4680 /* Ejection relations are not supported */
4681 return STATUS_NOT_SUPPORTED
;
4690 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType
,
4692 IN PHYSICAL_ADDRESS BusAddress
,
4693 IN OUT PULONG AddressSpace
,
4694 OUT PPHYSICAL_ADDRESS TranslatedAddress
)
4696 /* FIXME: Notify the resource arbiter */
4698 return HalTranslateBusAddress(InterfaceType
,