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
);
54 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
);
58 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject
)
60 return ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
64 IopFixupDeviceId(PWCHAR String
)
66 SIZE_T Length
= wcslen(String
), i
;
68 for (i
= 0; i
< Length
; i
++)
70 if (String
[i
] == L
'\\')
77 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode
)
80 HANDLE CriticalDeviceKey
, InstanceKey
;
81 OBJECT_ATTRIBUTES ObjectAttributes
;
82 UNICODE_STRING CriticalDeviceKeyU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
83 UNICODE_STRING CompatibleIdU
= RTL_CONSTANT_STRING(L
"CompatibleIDs");
84 UNICODE_STRING HardwareIdU
= RTL_CONSTANT_STRING(L
"HardwareID");
85 UNICODE_STRING ServiceU
= RTL_CONSTANT_STRING(L
"Service");
86 UNICODE_STRING ClassGuidU
= RTL_CONSTANT_STRING(L
"ClassGUID");
87 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
88 ULONG HidLength
= 0, CidLength
= 0, BufferLength
;
89 PWCHAR IdBuffer
, OriginalIdBuffer
;
91 /* Open the device instance key */
92 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
93 if (Status
!= STATUS_SUCCESS
)
96 Status
= ZwQueryValueKey(InstanceKey
,
98 KeyValuePartialInformation
,
102 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
104 ZwClose(InstanceKey
);
108 Status
= ZwQueryValueKey(InstanceKey
,
110 KeyValuePartialInformation
,
114 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
119 BufferLength
= HidLength
+ CidLength
;
120 BufferLength
-= (((CidLength
!= 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
));
122 /* Allocate a buffer to hold data from both */
123 OriginalIdBuffer
= IdBuffer
= ExAllocatePool(PagedPool
, BufferLength
);
126 ZwClose(InstanceKey
);
130 /* Compute the buffer size */
131 if (HidLength
> CidLength
)
132 BufferLength
= HidLength
;
134 BufferLength
= CidLength
;
136 PartialInfo
= ExAllocatePool(PagedPool
, BufferLength
);
139 ZwClose(InstanceKey
);
140 ExFreePool(OriginalIdBuffer
);
144 Status
= ZwQueryValueKey(InstanceKey
,
146 KeyValuePartialInformation
,
150 if (Status
!= STATUS_SUCCESS
)
152 ExFreePool(PartialInfo
);
153 ExFreePool(OriginalIdBuffer
);
154 ZwClose(InstanceKey
);
158 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
159 HidLength
= PartialInfo
->DataLength
- ((CidLength
!= 0) ? sizeof(WCHAR
) : 0);
160 RtlCopyMemory(IdBuffer
, PartialInfo
->Data
, HidLength
);
164 Status
= ZwQueryValueKey(InstanceKey
,
166 KeyValuePartialInformation
,
170 if (Status
!= STATUS_SUCCESS
)
172 ExFreePool(PartialInfo
);
173 ExFreePool(OriginalIdBuffer
);
174 ZwClose(InstanceKey
);
179 CidLength
= PartialInfo
->DataLength
;
180 RtlCopyMemory(((PUCHAR
)IdBuffer
) + HidLength
, PartialInfo
->Data
, CidLength
);
183 /* Free our temp buffer */
184 ExFreePool(PartialInfo
);
186 InitializeObjectAttributes(&ObjectAttributes
,
188 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
191 Status
= ZwOpenKey(&CriticalDeviceKey
,
192 KEY_ENUMERATE_SUB_KEYS
,
194 if (!NT_SUCCESS(Status
))
196 /* The critical device database doesn't exist because
197 * we're probably in 1st stage setup, but it's ok */
198 ExFreePool(OriginalIdBuffer
);
199 ZwClose(InstanceKey
);
205 USHORT StringLength
= (USHORT
)wcslen(IdBuffer
) + 1, Index
;
207 IopFixupDeviceId(IdBuffer
);
209 /* Look through all subkeys for a match */
210 for (Index
= 0; TRUE
; Index
++)
213 PKEY_BASIC_INFORMATION BasicInfo
;
215 Status
= ZwEnumerateKey(CriticalDeviceKey
,
221 if (Status
== STATUS_NO_MORE_ENTRIES
)
223 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
225 UNICODE_STRING ChildIdNameU
, RegKeyNameU
;
227 BasicInfo
= ExAllocatePool(PagedPool
, NeededLength
);
231 ExFreePool(OriginalIdBuffer
);
232 ZwClose(CriticalDeviceKey
);
233 ZwClose(InstanceKey
);
237 Status
= ZwEnumerateKey(CriticalDeviceKey
,
243 if (Status
!= STATUS_SUCCESS
)
245 /* This shouldn't happen */
246 ExFreePool(BasicInfo
);
250 ChildIdNameU
.Buffer
= IdBuffer
;
251 ChildIdNameU
.MaximumLength
= ChildIdNameU
.Length
= (StringLength
- 1) * sizeof(WCHAR
);
252 RegKeyNameU
.Buffer
= BasicInfo
->Name
;
253 RegKeyNameU
.MaximumLength
= RegKeyNameU
.Length
= (USHORT
)BasicInfo
->NameLength
;
255 if (RtlEqualUnicodeString(&ChildIdNameU
, &RegKeyNameU
, TRUE
))
257 HANDLE ChildKeyHandle
;
259 InitializeObjectAttributes(&ObjectAttributes
,
261 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
265 Status
= ZwOpenKey(&ChildKeyHandle
,
268 if (Status
!= STATUS_SUCCESS
)
270 ExFreePool(BasicInfo
);
274 /* Check if there's already a driver installed */
275 Status
= ZwQueryValueKey(InstanceKey
,
277 KeyValuePartialInformation
,
281 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
283 ExFreePool(BasicInfo
);
287 Status
= ZwQueryValueKey(ChildKeyHandle
,
289 KeyValuePartialInformation
,
293 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
295 ExFreePool(BasicInfo
);
299 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
302 ExFreePool(OriginalIdBuffer
);
303 ExFreePool(BasicInfo
);
304 ZwClose(InstanceKey
);
305 ZwClose(ChildKeyHandle
);
306 ZwClose(CriticalDeviceKey
);
310 /* Read ClassGUID entry in the CDDB */
311 Status
= ZwQueryValueKey(ChildKeyHandle
,
313 KeyValuePartialInformation
,
317 if (Status
!= STATUS_SUCCESS
)
319 ExFreePool(BasicInfo
);
323 /* Write it to the ENUM key */
324 Status
= ZwSetValueKey(InstanceKey
,
329 PartialInfo
->DataLength
);
330 if (Status
!= STATUS_SUCCESS
)
332 ExFreePool(BasicInfo
);
333 ExFreePool(PartialInfo
);
334 ZwClose(ChildKeyHandle
);
338 Status
= ZwQueryValueKey(ChildKeyHandle
,
340 KeyValuePartialInformation
,
344 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
346 ExFreePool(PartialInfo
);
347 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
350 ExFreePool(OriginalIdBuffer
);
351 ExFreePool(BasicInfo
);
352 ZwClose(InstanceKey
);
353 ZwClose(ChildKeyHandle
);
354 ZwClose(CriticalDeviceKey
);
358 /* Read the service entry from the CDDB */
359 Status
= ZwQueryValueKey(ChildKeyHandle
,
361 KeyValuePartialInformation
,
365 if (Status
!= STATUS_SUCCESS
)
367 ExFreePool(BasicInfo
);
368 ExFreePool(PartialInfo
);
369 ZwClose(ChildKeyHandle
);
373 /* Write it to the ENUM key */
374 Status
= ZwSetValueKey(InstanceKey
,
379 PartialInfo
->DataLength
);
380 if (Status
!= STATUS_SUCCESS
)
382 ExFreePool(BasicInfo
);
383 ExFreePool(PartialInfo
);
384 ZwClose(ChildKeyHandle
);
388 DPRINT1("Installed service '%S' for critical device '%wZ'\n", PartialInfo
->Data
, &ChildIdNameU
);
392 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU
);
395 ExFreePool(OriginalIdBuffer
);
396 ExFreePool(PartialInfo
);
397 ExFreePool(BasicInfo
);
398 ZwClose(InstanceKey
);
399 ZwClose(ChildKeyHandle
);
400 ZwClose(CriticalDeviceKey
);
406 ExFreePool(BasicInfo
);
410 /* Umm, not sure what happened here */
415 /* Advance to the next ID */
416 IdBuffer
+= StringLength
;
419 ExFreePool(OriginalIdBuffer
);
420 ZwClose(InstanceKey
);
421 ZwClose(CriticalDeviceKey
);
426 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
427 PDRIVER_OBJECT DriverObject
)
434 /* Special case for bus driven devices */
435 DeviceNode
->Flags
|= DNF_ADDED
;
436 return STATUS_SUCCESS
;
439 if (!DriverObject
->DriverExtension
->AddDevice
)
441 DeviceNode
->Flags
|= DNF_LEGACY_DRIVER
;
444 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
446 DeviceNode
->Flags
|= DNF_ADDED
+ DNF_STARTED
;
447 return STATUS_SUCCESS
;
450 /* This is a Plug and Play driver */
451 DPRINT("Plug and Play driver found\n");
452 ASSERT(DeviceNode
->PhysicalDeviceObject
);
454 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
455 &DriverObject
->DriverName
,
456 &DeviceNode
->InstancePath
);
457 Status
= DriverObject
->DriverExtension
->AddDevice(
458 DriverObject
, DeviceNode
->PhysicalDeviceObject
);
459 if (!NT_SUCCESS(Status
))
461 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
462 &DriverObject
->DriverName
,
463 &DeviceNode
->InstancePath
,
465 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
466 DeviceNode
->Problem
= CM_PROB_FAILED_ADD
;
470 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
472 /* Check if we have a ACPI device (needed for power management) */
473 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
475 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
477 /* There can be only one system power device */
478 if (!SystemPowerDeviceNodeCreated
)
480 PopSystemPowerDeviceNode
= DeviceNode
;
481 ObReferenceObject(PopSystemPowerDeviceNode
->PhysicalDeviceObject
);
482 SystemPowerDeviceNodeCreated
= TRUE
;
486 ObDereferenceObject(Fdo
);
488 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
490 return STATUS_SUCCESS
;
496 IopSendEject(IN PDEVICE_OBJECT DeviceObject
)
498 IO_STACK_LOCATION Stack
;
501 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
502 Stack
.MajorFunction
= IRP_MJ_PNP
;
503 Stack
.MinorFunction
= IRP_MN_EJECT
;
505 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
511 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject
)
513 IO_STACK_LOCATION Stack
;
516 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
517 Stack
.MajorFunction
= IRP_MJ_PNP
;
518 Stack
.MinorFunction
= IRP_MN_SURPRISE_REMOVAL
;
520 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
521 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
527 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
529 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
530 IO_STACK_LOCATION Stack
;
536 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING
,
537 &DeviceNode
->InstancePath
);
539 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
540 Stack
.MajorFunction
= IRP_MJ_PNP
;
541 Stack
.MinorFunction
= IRP_MN_QUERY_REMOVE_DEVICE
;
543 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
545 IopNotifyPlugPlayNotification(DeviceObject
,
546 EventCategoryTargetDeviceChange
,
547 &GUID_TARGET_DEVICE_QUERY_REMOVE
,
551 if (!NT_SUCCESS(Status
))
553 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode
->InstancePath
);
554 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED
,
555 &DeviceNode
->InstancePath
);
564 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject
)
566 IO_STACK_LOCATION Stack
;
569 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
570 Stack
.MajorFunction
= IRP_MJ_PNP
;
571 Stack
.MinorFunction
= IRP_MN_QUERY_STOP_DEVICE
;
573 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
579 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
581 IO_STACK_LOCATION Stack
;
583 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
585 /* Drop all our state for this device in case it isn't really going away */
586 DeviceNode
->Flags
&= DNF_ENUMERATED
| DNF_PROCESSED
;
588 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
589 Stack
.MajorFunction
= IRP_MJ_PNP
;
590 Stack
.MinorFunction
= IRP_MN_REMOVE_DEVICE
;
592 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
593 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
595 IopNotifyPlugPlayNotification(DeviceObject
,
596 EventCategoryTargetDeviceChange
,
597 &GUID_TARGET_DEVICE_REMOVE_COMPLETE
,
600 ObDereferenceObject(DeviceObject
);
606 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
608 IO_STACK_LOCATION Stack
;
611 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
612 Stack
.MajorFunction
= IRP_MJ_PNP
;
613 Stack
.MinorFunction
= IRP_MN_CANCEL_REMOVE_DEVICE
;
615 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
616 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
618 IopNotifyPlugPlayNotification(DeviceObject
,
619 EventCategoryTargetDeviceChange
,
620 &GUID_TARGET_DEVICE_REMOVE_CANCELLED
,
628 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject
)
630 IO_STACK_LOCATION Stack
;
633 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
634 Stack
.MajorFunction
= IRP_MJ_PNP
;
635 Stack
.MinorFunction
= IRP_MN_STOP_DEVICE
;
637 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
638 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
643 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject
)
645 IO_STACK_LOCATION Stack
;
646 PDEVICE_NODE DeviceNode
;
649 DEVICE_CAPABILITIES DeviceCapabilities
;
651 /* Get the device node */
652 DeviceNode
= IopGetDeviceNode(DeviceObject
);
654 ASSERT(!(DeviceNode
->Flags
& DNF_DISABLED
));
656 /* Build the I/O stack location */
657 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
658 Stack
.MajorFunction
= IRP_MJ_PNP
;
659 Stack
.MinorFunction
= IRP_MN_START_DEVICE
;
661 Stack
.Parameters
.StartDevice
.AllocatedResources
=
662 DeviceNode
->ResourceList
;
663 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
=
664 DeviceNode
->ResourceListTranslated
;
667 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
668 if (!NT_SUCCESS(Status
))
670 /* Send an IRP_MN_REMOVE_DEVICE request */
671 IopRemoveDevice(DeviceNode
);
673 /* Set the appropriate flag */
674 DeviceNode
->Flags
|= DNF_START_FAILED
;
675 DeviceNode
->Problem
= CM_PROB_FAILED_START
;
677 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode
->InstancePath
, Status
);
681 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
683 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
684 if (!NT_SUCCESS(Status
))
686 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
689 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
690 IoInvalidateDeviceState(DeviceObject
);
692 /* Otherwise, mark us as started */
693 DeviceNode
->Flags
|= DNF_STARTED
;
694 DeviceNode
->Flags
&= ~DNF_STOPPED
;
696 /* We now need enumeration */
697 DeviceNode
->Flags
|= DNF_NEED_ENUMERATION_ONLY
;
702 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode
)
704 PDEVICE_OBJECT DeviceObject
;
709 ASSERT((DeviceNode
->Flags
& DNF_ADDED
));
710 ASSERT((DeviceNode
->Flags
& (DNF_RESOURCE_ASSIGNED
|
711 DNF_RESOURCE_REPORTED
|
712 DNF_NO_RESOURCE_REQUIRED
)));
714 /* Get the device object */
715 DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
717 /* Check if we're not started yet */
718 if (!(DeviceNode
->Flags
& DNF_STARTED
))
721 IopStartDevice2(DeviceObject
);
724 /* Do we need to query IDs? This happens in the case of manual reporting */
726 if (DeviceNode
->Flags
& DNF_NEED_QUERY_IDS
)
728 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
729 /* And that case shouldn't happen yet */
734 /* Make sure we're started, and check if we need enumeration */
735 if ((DeviceNode
->Flags
& DNF_STARTED
) &&
736 (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
))
739 IoSynchronousInvalidateDeviceRelations(DeviceObject
, BusRelations
);
740 Status
= STATUS_SUCCESS
;
745 Status
= STATUS_SUCCESS
;
754 PDEVICE_NODE DeviceNode
)
758 DPRINT("Stopping device: %wZ\n", &DeviceNode
->InstancePath
);
760 Status
= IopQueryStopDevice(DeviceNode
->PhysicalDeviceObject
);
761 if (NT_SUCCESS(Status
))
763 IopSendStopDevice(DeviceNode
->PhysicalDeviceObject
);
765 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
766 DeviceNode
->Flags
|= DNF_STOPPED
;
768 return STATUS_SUCCESS
;
776 PDEVICE_NODE DeviceNode
)
779 HANDLE InstanceHandle
= INVALID_HANDLE_VALUE
, ControlHandle
= INVALID_HANDLE_VALUE
;
780 UNICODE_STRING KeyName
;
781 OBJECT_ATTRIBUTES ObjectAttributes
;
783 if (DeviceNode
->Flags
& DNF_DISABLED
)
784 return STATUS_SUCCESS
;
786 Status
= IopAssignDeviceResources(DeviceNode
);
787 if (!NT_SUCCESS(Status
))
791 IopStartAndEnumerateDevice(DeviceNode
);
793 /* FIX: Should be done in new device instance code */
794 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceHandle
);
795 if (!NT_SUCCESS(Status
))
798 /* FIX: Should be done in IoXxxPrepareDriverLoading */
800 RtlInitUnicodeString(&KeyName
, L
"Control");
801 InitializeObjectAttributes(&ObjectAttributes
,
803 OBJ_CASE_INSENSITIVE
,
806 Status
= ZwCreateKey(&ControlHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
807 if (!NT_SUCCESS(Status
))
810 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
811 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, DeviceNode
->ServiceName
.Buffer
, DeviceNode
->ServiceName
.Length
);
815 if (ControlHandle
!= INVALID_HANDLE_VALUE
)
816 ZwClose(ControlHandle
);
818 if (InstanceHandle
!= INVALID_HANDLE_VALUE
)
819 ZwClose(InstanceHandle
);
826 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
827 PDEVICE_CAPABILITIES DeviceCaps
)
829 IO_STATUS_BLOCK StatusBlock
;
830 IO_STACK_LOCATION Stack
;
833 UNICODE_STRING ValueName
;
835 /* Set up the Header */
836 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
837 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
838 DeviceCaps
->Version
= 1;
839 DeviceCaps
->Address
= -1;
840 DeviceCaps
->UINumber
= -1;
842 /* Set up the Stack */
843 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
844 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
847 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
849 IRP_MN_QUERY_CAPABILITIES
,
851 if (!NT_SUCCESS(Status
))
853 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%x\n", Status
);
857 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCaps
->Version
+ sizeof(DeviceCaps
->Version
));
859 if (DeviceCaps
->NoDisplayInUI
)
860 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
862 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
864 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
865 if (NT_SUCCESS(Status
))
867 /* Set 'Capabilities' value */
868 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
869 Status
= ZwSetValueKey(InstanceKey
,
873 (PVOID
)&DeviceNode
->CapabilityFlags
,
876 /* Set 'UINumber' value */
877 if (DeviceCaps
->UINumber
!= MAXULONG
)
879 RtlInitUnicodeString(&ValueName
, L
"UINumber");
880 Status
= ZwSetValueKey(InstanceKey
,
884 &DeviceCaps
->UINumber
,
893 IopAsynchronousInvalidateDeviceRelations(
894 IN PDEVICE_OBJECT DeviceObject
,
895 IN PVOID InvalidateContext
)
897 PINVALIDATE_DEVICE_RELATION_DATA Data
= InvalidateContext
;
899 IoSynchronousInvalidateDeviceRelations(
903 ObDereferenceObject(Data
->DeviceObject
);
904 IoFreeWorkItem(Data
->WorkItem
);
909 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
913 if (PopSystemPowerDeviceNode
)
915 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
916 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
917 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
919 return STATUS_SUCCESS
;
922 return STATUS_UNSUCCESSFUL
;
927 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
929 USHORT i
= 0, FoundIndex
= 0xFFFF;
933 /* Acquire the lock */
934 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
936 /* Loop all entries */
937 while (i
< PnpBusTypeGuidList
->GuidCount
)
939 /* Try to find a match */
940 if (RtlCompareMemory(BusTypeGuid
,
941 &PnpBusTypeGuidList
->Guids
[i
],
942 sizeof(GUID
)) == sizeof(GUID
))
951 /* Check if we have to grow the list */
952 if (PnpBusTypeGuidList
->GuidCount
)
954 /* Calculate the new size */
955 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
956 (sizeof(GUID
) * PnpBusTypeGuidList
->GuidCount
);
958 /* Allocate the new copy */
959 NewList
= ExAllocatePool(PagedPool
, NewSize
);
963 ExFreePool(PnpBusTypeGuidList
);
967 /* Now copy them, decrease the size too */
968 NewSize
-= sizeof(GUID
);
969 RtlCopyMemory(NewList
, PnpBusTypeGuidList
, NewSize
);
971 /* Free the old list */
972 ExFreePool(PnpBusTypeGuidList
);
974 /* Use the new buffer */
975 PnpBusTypeGuidList
= NewList
;
978 /* Copy the new GUID */
979 RtlCopyMemory(&PnpBusTypeGuidList
->Guids
[PnpBusTypeGuidList
->GuidCount
],
983 /* The new entry is the index */
984 FoundIndex
= (USHORT
)PnpBusTypeGuidList
->GuidCount
;
985 PnpBusTypeGuidList
->GuidCount
++;
988 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
994 * Creates a device node
997 * ParentNode = Pointer to parent device node
998 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
999 * to have the root device node create one
1000 * (eg. for legacy drivers)
1001 * DeviceNode = Pointer to storage for created device node
1007 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
1008 PDEVICE_OBJECT PhysicalDeviceObject
,
1009 PUNICODE_STRING ServiceName
,
1010 PDEVICE_NODE
*DeviceNode
)
1015 UNICODE_STRING FullServiceName
;
1016 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
1017 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
1018 UNICODE_STRING KeyName
, ClassName
;
1019 PUNICODE_STRING ServiceName1
;
1021 UNICODE_STRING ClassGUID
;
1022 HANDLE InstanceHandle
;
1024 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1025 ParentNode
, PhysicalDeviceObject
, ServiceName
);
1027 Node
= (PDEVICE_NODE
)ExAllocatePool(NonPagedPool
, sizeof(DEVICE_NODE
));
1030 return STATUS_INSUFFICIENT_RESOURCES
;
1033 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
1036 ServiceName1
= &UnknownDeviceName
;
1038 ServiceName1
= ServiceName
;
1040 if (!PhysicalDeviceObject
)
1042 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName1
->Length
;
1043 FullServiceName
.Length
= 0;
1044 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
1045 if (!FullServiceName
.Buffer
)
1048 return STATUS_INSUFFICIENT_RESOURCES
;
1051 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
1052 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName1
);
1054 Status
= PnpRootCreateDevice(&FullServiceName
, NULL
, &PhysicalDeviceObject
, &Node
->InstancePath
);
1055 if (!NT_SUCCESS(Status
))
1057 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
1062 /* Create the device key for legacy drivers */
1063 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, REG_OPTION_VOLATILE
, &InstanceHandle
);
1064 if (!NT_SUCCESS(Status
))
1066 ZwClose(InstanceHandle
);
1068 ExFreePool(FullServiceName
.Buffer
);
1072 Node
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, ServiceName1
->Length
);
1073 if (!Node
->ServiceName
.Buffer
)
1075 ZwClose(InstanceHandle
);
1077 ExFreePool(FullServiceName
.Buffer
);
1081 Node
->ServiceName
.MaximumLength
= ServiceName1
->Length
;
1082 Node
->ServiceName
.Length
= 0;
1084 RtlAppendUnicodeStringToString(&Node
->ServiceName
, ServiceName1
);
1088 RtlInitUnicodeString(&KeyName
, L
"Service");
1089 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName
->Buffer
, ServiceName
->Length
);
1092 if (NT_SUCCESS(Status
))
1094 RtlInitUnicodeString(&KeyName
, L
"Legacy");
1097 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
1098 if (NT_SUCCESS(Status
))
1100 RtlInitUnicodeString(&KeyName
, L
"Class");
1102 RtlInitUnicodeString(&ClassName
, L
"LegacyDriver\0");
1103 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassName
.Buffer
, ClassName
.Length
+ sizeof(UNICODE_NULL
));
1104 if (NT_SUCCESS(Status
))
1106 RtlInitUnicodeString(&KeyName
, L
"ClassGUID");
1108 RtlInitUnicodeString(&ClassGUID
, L
"{8ECC055D-047F-11D1-A537-0000F8753ED1}\0");
1109 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassGUID
.Buffer
, ClassGUID
.Length
+ sizeof(UNICODE_NULL
));
1110 if (NT_SUCCESS(Status
))
1112 RtlInitUnicodeString(&KeyName
, L
"DeviceDesc");
1114 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName1
->Buffer
, ServiceName1
->Length
+ sizeof(UNICODE_NULL
));
1120 ZwClose(InstanceHandle
);
1121 ExFreePool(FullServiceName
.Buffer
);
1123 if (!NT_SUCCESS(Status
))
1129 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
1130 IopDeviceNodeSetFlag(Node
, DNF_PROCESSED
);
1131 IopDeviceNodeSetFlag(Node
, DNF_ADDED
);
1132 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
1135 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
1137 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
1141 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1142 Node
->Parent
= ParentNode
;
1143 Node
->Sibling
= NULL
;
1144 if (ParentNode
->LastChild
== NULL
)
1146 ParentNode
->Child
= Node
;
1147 ParentNode
->LastChild
= Node
;
1151 ParentNode
->LastChild
->Sibling
= Node
;
1152 ParentNode
->LastChild
= Node
;
1154 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1155 Node
->Level
= ParentNode
->Level
+ 1;
1158 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1162 return STATUS_SUCCESS
;
1166 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
1169 PDEVICE_NODE PrevSibling
= NULL
;
1171 /* All children must be deleted before a parent is deleted */
1172 ASSERT(!DeviceNode
->Child
);
1173 ASSERT(DeviceNode
->PhysicalDeviceObject
);
1175 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1177 /* Get previous sibling */
1178 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
1180 PrevSibling
= DeviceNode
->Parent
->Child
;
1181 while (PrevSibling
->Sibling
!= DeviceNode
)
1182 PrevSibling
= PrevSibling
->Sibling
;
1185 /* Unlink from parent if it exists */
1186 if (DeviceNode
->Parent
)
1188 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
1190 DeviceNode
->Parent
->LastChild
= PrevSibling
;
1192 PrevSibling
->Sibling
= NULL
;
1194 if (DeviceNode
->Parent
->Child
== DeviceNode
)
1195 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
1198 /* Unlink from sibling list */
1200 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
1202 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1204 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
1206 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
1208 if (DeviceNode
->ResourceList
)
1210 ExFreePool(DeviceNode
->ResourceList
);
1213 if (DeviceNode
->ResourceListTranslated
)
1215 ExFreePool(DeviceNode
->ResourceListTranslated
);
1218 if (DeviceNode
->ResourceRequirements
)
1220 ExFreePool(DeviceNode
->ResourceRequirements
);
1223 if (DeviceNode
->BootResources
)
1225 ExFreePool(DeviceNode
->BootResources
);
1228 ExFreePool(DeviceNode
);
1230 return STATUS_SUCCESS
;
1235 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject
,
1236 IN PIO_STACK_LOCATION IoStackLocation
,
1237 OUT PVOID
*Information
)
1240 PIO_STACK_LOCATION IrpStack
;
1241 IO_STATUS_BLOCK IoStatusBlock
;
1244 PDEVICE_OBJECT TopDeviceObject
;
1247 /* Call the top of the device stack */
1248 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
1250 /* Allocate an IRP */
1251 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
, FALSE
);
1252 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
1254 /* Initialize to failure */
1255 Irp
->IoStatus
.Status
= IoStatusBlock
.Status
= STATUS_NOT_SUPPORTED
;
1256 Irp
->IoStatus
.Information
= IoStatusBlock
.Information
= 0;
1258 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1259 if (IoStackLocation
->MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
)
1261 /* Copy the resource requirements list into the IOSB */
1262 Irp
->IoStatus
.Information
=
1263 IoStatusBlock
.Information
= (ULONG_PTR
)IoStackLocation
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
1266 /* Initialize the event */
1267 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1270 Irp
->UserIosb
= &IoStatusBlock
;
1271 Irp
->UserEvent
= &Event
;
1274 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1275 IoQueueThreadIrp(Irp
);
1277 /* Copy-in the stack */
1278 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1279 *IrpStack
= *IoStackLocation
;
1281 /* Call the driver */
1282 Status
= IoCallDriver(TopDeviceObject
, Irp
);
1283 if (Status
== STATUS_PENDING
)
1286 KeWaitForSingleObject(&Event
,
1291 Status
= IoStatusBlock
.Status
;
1294 /* Remove the reference */
1295 ObDereferenceObject(TopDeviceObject
);
1297 /* Return the information */
1298 *Information
= (PVOID
)IoStatusBlock
.Information
;
1304 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject
,
1305 IN OUT PIO_STATUS_BLOCK IoStatusBlock
,
1306 IN UCHAR MinorFunction
,
1307 IN PIO_STACK_LOCATION Stack OPTIONAL
)
1309 IO_STACK_LOCATION IoStackLocation
;
1311 /* Fill out the stack information */
1312 RtlZeroMemory(&IoStackLocation
, sizeof(IO_STACK_LOCATION
));
1313 IoStackLocation
.MajorFunction
= IRP_MJ_PNP
;
1314 IoStackLocation
.MinorFunction
= MinorFunction
;
1318 RtlCopyMemory(&IoStackLocation
.Parameters
,
1320 sizeof(Stack
->Parameters
));
1323 /* Do the PnP call */
1324 IoStatusBlock
->Status
= IopSynchronousCall(DeviceObject
,
1326 (PVOID
)&IoStatusBlock
->Information
);
1327 return IoStatusBlock
->Status
;
1331 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1333 PDEVICE_NODE ParentDeviceNode
;
1334 PDEVICE_NODE ChildDeviceNode
;
1337 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1338 ParentDeviceNode
= Context
->DeviceNode
;
1340 /* Call the action routine */
1341 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
1342 if (!NT_SUCCESS(Status
))
1347 /* Traversal of all children nodes */
1348 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
1349 ChildDeviceNode
!= NULL
;
1350 ChildDeviceNode
= ChildDeviceNode
->Sibling
)
1352 /* Pass the current device node to the action routine */
1353 Context
->DeviceNode
= ChildDeviceNode
;
1355 Status
= IopTraverseDeviceTreeNode(Context
);
1356 if (!NT_SUCCESS(Status
))
1367 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1371 DPRINT("Context 0x%p\n", Context
);
1373 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
1374 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
1376 /* Start from the specified device node */
1377 Context
->DeviceNode
= Context
->FirstDeviceNode
;
1379 /* Recursively traverse the device tree */
1380 Status
= IopTraverseDeviceTreeNode(Context
);
1381 if (Status
== STATUS_UNSUCCESSFUL
)
1383 /* The action routine just wanted to terminate the traversal with status
1384 code STATUS_SUCCESS */
1385 Status
= STATUS_SUCCESS
;
1393 * IopCreateDeviceKeyPath
1395 * Creates a registry key
1399 * Name of the key to be created.
1401 * Handle to the newly created key
1404 * This method can create nested trees, so parent of RegistryPath can
1405 * be not existant, and will be created if needed.
1409 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
1410 IN ULONG CreateOptions
,
1413 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
1414 HANDLE hParent
= NULL
, hKey
;
1415 OBJECT_ATTRIBUTES ObjectAttributes
;
1416 UNICODE_STRING KeyName
;
1417 LPCWSTR Current
, Last
;
1421 /* Assume failure */
1424 /* Create a volatile device tree in 1st stage so we have a clean slate
1425 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1426 if (ExpInTextModeSetup
) CreateOptions
|= REG_OPTION_VOLATILE
;
1428 /* Open root key for device instances */
1429 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
1430 if (!NT_SUCCESS(Status
))
1432 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
1436 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
1437 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
1439 /* Go up to the end of the string */
1440 while (Current
<= Last
)
1442 if (Current
!= Last
&& *Current
!= '\\')
1444 /* Not the end of the string and not a separator */
1449 /* Prepare relative key name */
1450 Length
= (USHORT
)((ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
);
1451 KeyName
.MaximumLength
= KeyName
.Length
= Length
;
1452 DPRINT("Create '%wZ'\n", &KeyName
);
1455 InitializeObjectAttributes(&ObjectAttributes
,
1457 OBJ_CASE_INSENSITIVE
,
1460 Status
= ZwCreateKey(&hKey
,
1461 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
1468 /* Close parent key handle, we don't need it anymore */
1472 /* Key opening/creating failed? */
1473 if (!NT_SUCCESS(Status
))
1475 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
1479 /* Check if it is the end of the string */
1480 if (Current
== Last
)
1482 /* Yes, return success */
1484 return STATUS_SUCCESS
;
1487 /* Start with this new parent key */
1490 KeyName
.Buffer
= (LPWSTR
)Current
;
1493 return STATUS_UNSUCCESSFUL
;
1497 IopSetDeviceInstanceData(HANDLE InstanceKey
,
1498 PDEVICE_NODE DeviceNode
)
1500 OBJECT_ATTRIBUTES ObjectAttributes
;
1501 UNICODE_STRING KeyName
;
1506 HANDLE ControlHandle
;
1508 DPRINT("IopSetDeviceInstanceData() called\n");
1510 /* Create the 'LogConf' key */
1511 RtlInitUnicodeString(&KeyName
, L
"LogConf");
1512 InitializeObjectAttributes(&ObjectAttributes
,
1514 OBJ_CASE_INSENSITIVE
,
1517 Status
= ZwCreateKey(&LogConfKey
,
1522 REG_OPTION_VOLATILE
,
1524 if (NT_SUCCESS(Status
))
1526 /* Set 'BootConfig' value */
1527 if (DeviceNode
->BootResources
!= NULL
)
1529 ResCount
= DeviceNode
->BootResources
->Count
;
1532 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
1533 Status
= ZwSetValueKey(LogConfKey
,
1537 DeviceNode
->BootResources
,
1538 PnpDetermineResourceListSize(DeviceNode
->BootResources
));
1542 /* Set 'BasicConfigVector' value */
1543 if (DeviceNode
->ResourceRequirements
!= NULL
&&
1544 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
1546 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
1547 Status
= ZwSetValueKey(LogConfKey
,
1550 REG_RESOURCE_REQUIREMENTS_LIST
,
1551 DeviceNode
->ResourceRequirements
,
1552 DeviceNode
->ResourceRequirements
->ListSize
);
1555 ZwClose(LogConfKey
);
1558 /* Set the 'ConfigFlags' value */
1559 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1560 Status
= ZwQueryValueKey(InstanceKey
,
1562 KeyValueBasicInformation
,
1566 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1568 /* Write the default value */
1569 ULONG DefaultConfigFlags
= 0;
1570 Status
= ZwSetValueKey(InstanceKey
,
1574 &DefaultConfigFlags
,
1575 sizeof(DefaultConfigFlags
));
1578 /* Create the 'Control' key */
1579 RtlInitUnicodeString(&KeyName
, L
"Control");
1580 InitializeObjectAttributes(&ObjectAttributes
,
1582 OBJ_CASE_INSENSITIVE
,
1585 Status
= ZwCreateKey(&ControlHandle
, 0, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
1587 if (NT_SUCCESS(Status
))
1588 ZwClose(ControlHandle
);
1590 DPRINT("IopSetDeviceInstanceData() done\n");
1596 * IopGetParentIdPrefix
1598 * Retrieve (or create) a string which identifies a device.
1602 * Pointer to device node.
1604 * Pointer to the string where is returned the parent node identifier
1607 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1608 * valid and its Buffer field is NULL-terminated. The caller needs to
1609 * to free the string with RtlFreeUnicodeString when it is no longer
1614 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1615 PUNICODE_STRING ParentIdPrefix
)
1617 ULONG KeyNameBufferLength
;
1618 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1619 UNICODE_STRING KeyName
= {0, 0, NULL
};
1620 UNICODE_STRING KeyValue
;
1621 UNICODE_STRING ValueName
;
1626 /* HACK: As long as some devices have a NULL device
1627 * instance path, the following test is required :(
1629 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1631 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1632 &DeviceNode
->InstancePath
);
1633 return STATUS_UNSUCCESSFUL
;
1636 /* 1. Try to retrieve ParentIdPrefix from registry */
1637 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]) + MAX_PATH
* sizeof(WCHAR
);
1638 ParentIdPrefixInformation
= ExAllocatePool(PagedPool
, KeyNameBufferLength
+ sizeof(WCHAR
));
1639 if (!ParentIdPrefixInformation
)
1641 return STATUS_INSUFFICIENT_RESOURCES
;
1644 KeyName
.Buffer
= ExAllocatePool(PagedPool
, (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
);
1645 if (!KeyName
.Buffer
)
1647 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1651 KeyName
.MaximumLength
= (49 * sizeof(WCHAR
)) + DeviceNode
->Parent
->InstancePath
.Length
;
1653 RtlAppendUnicodeToString(&KeyName
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1654 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1656 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1657 if (!NT_SUCCESS(Status
))
1659 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1660 Status
= ZwQueryValueKey(
1662 KeyValuePartialInformation
, ParentIdPrefixInformation
,
1663 KeyNameBufferLength
, &KeyNameBufferLength
);
1664 if (NT_SUCCESS(Status
))
1666 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1667 Status
= STATUS_UNSUCCESSFUL
;
1670 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1671 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1675 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1677 KeyValue
.Length
= KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1678 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1682 /* 2. Create the ParentIdPrefix value */
1683 crc32
= RtlComputeCrc32(0,
1684 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1685 DeviceNode
->Parent
->InstancePath
.Length
);
1687 swprintf((PWSTR
)ParentIdPrefixInformation
->Data
, L
"%lx&%lx", DeviceNode
->Parent
->Level
, crc32
);
1688 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
->Data
);
1690 /* 3. Try to write the ParentIdPrefix to registry */
1691 Status
= ZwSetValueKey(hKey
,
1695 (PVOID
)KeyValue
.Buffer
,
1696 ((ULONG
)wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
1699 if (NT_SUCCESS(Status
))
1701 /* Duplicate the string to return it */
1702 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &KeyValue
, ParentIdPrefix
);
1704 ExFreePool(ParentIdPrefixInformation
);
1705 RtlFreeUnicodeString(&KeyName
);
1712 IopQueryHardwareIds(PDEVICE_NODE DeviceNode
,
1715 IO_STACK_LOCATION Stack
;
1716 IO_STATUS_BLOCK IoStatusBlock
;
1718 UNICODE_STRING ValueName
;
1720 ULONG Length
, TotalLength
;
1722 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1724 RtlZeroMemory(&Stack
, sizeof(Stack
));
1725 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
1726 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1730 if (NT_SUCCESS(Status
))
1733 * FIXME: Check for valid characters, if there is invalid characters
1737 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1738 DPRINT("Hardware IDs:\n");
1741 DPRINT(" %S\n", Ptr
);
1742 Length
= (ULONG
)wcslen(Ptr
) + 1;
1745 TotalLength
+= Length
;
1747 DPRINT("TotalLength: %hu\n", TotalLength
);
1750 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
1751 Status
= ZwSetValueKey(InstanceKey
,
1755 (PVOID
)IoStatusBlock
.Information
,
1756 (TotalLength
+ 1) * sizeof(WCHAR
));
1757 if (!NT_SUCCESS(Status
))
1759 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
1764 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1771 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode
,
1774 IO_STACK_LOCATION Stack
;
1775 IO_STATUS_BLOCK IoStatusBlock
;
1777 UNICODE_STRING ValueName
;
1779 ULONG Length
, TotalLength
;
1781 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1783 RtlZeroMemory(&Stack
, sizeof(Stack
));
1784 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
1785 Status
= IopInitiatePnpIrp(
1786 DeviceNode
->PhysicalDeviceObject
,
1790 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
1793 * FIXME: Check for valid characters, if there is invalid characters
1797 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
1798 DPRINT("Compatible IDs:\n");
1801 DPRINT(" %S\n", Ptr
);
1802 Length
= (ULONG
)wcslen(Ptr
) + 1;
1805 TotalLength
+= Length
;
1807 DPRINT("TotalLength: %hu\n", TotalLength
);
1810 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
1811 Status
= ZwSetValueKey(InstanceKey
,
1815 (PVOID
)IoStatusBlock
.Information
,
1816 (TotalLength
+ 1) * sizeof(WCHAR
));
1817 if (!NT_SUCCESS(Status
))
1819 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
1824 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1832 * IopActionInterrogateDeviceStack
1834 * Retrieve information for all (direct) child nodes of a parent node.
1838 * Pointer to device node.
1840 * Pointer to parent node to retrieve child node information for.
1843 * Any errors that occur are logged instead so that all child services have a chance
1844 * of being interrogated.
1848 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
1851 IO_STATUS_BLOCK IoStatusBlock
;
1852 PDEVICE_NODE ParentDeviceNode
;
1853 WCHAR InstancePath
[MAX_PATH
];
1854 IO_STACK_LOCATION Stack
;
1856 ULONG RequiredLength
;
1858 HANDLE InstanceKey
= NULL
;
1859 UNICODE_STRING ValueName
;
1860 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
1861 UNICODE_STRING InstancePathU
;
1862 DEVICE_CAPABILITIES DeviceCapabilities
;
1863 PDEVICE_OBJECT OldDeviceObject
;
1865 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
1866 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
1868 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
1871 * We are called for the parent too, but we don't need to do special
1872 * handling for this node
1875 if (DeviceNode
== ParentDeviceNode
)
1877 DPRINT("Success\n");
1878 return STATUS_SUCCESS
;
1882 * Make sure this device node is a direct child of the parent device node
1883 * that is given as an argument
1886 if (DeviceNode
->Parent
!= ParentDeviceNode
)
1888 DPRINT("Skipping 2+ level child\n");
1889 return STATUS_SUCCESS
;
1892 /* Skip processing if it was already completed before */
1893 if (DeviceNode
->Flags
& DNF_PROCESSED
)
1896 return STATUS_SUCCESS
;
1900 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
1901 if (!NT_SUCCESS(Status
))
1903 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
1908 * FIXME: For critical errors, cleanup and disable device, but always
1909 * return STATUS_SUCCESS.
1912 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1914 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
1915 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1919 if (NT_SUCCESS(Status
))
1921 /* Copy the device id string */
1922 wcscpy(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1925 * FIXME: Check for valid characters, if there is invalid characters
1931 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
1933 /* We have to return success otherwise we abort the traverse operation */
1934 return STATUS_SUCCESS
;
1937 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1939 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
1940 if (!NT_SUCCESS(Status
))
1942 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
1944 /* We have to return success otherwise we abort the traverse operation */
1945 return STATUS_SUCCESS
;
1948 /* This bit is only check after enumeration */
1949 if (DeviceCapabilities
.HardwareDisabled
)
1951 /* FIXME: Cleanup device */
1952 DeviceNode
->Flags
|= DNF_DISABLED
;
1953 return STATUS_SUCCESS
;
1956 DeviceNode
->Flags
&= ~DNF_DISABLED
;
1958 if (!DeviceCapabilities
.UniqueID
)
1960 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1961 DPRINT("Instance ID is not unique\n");
1962 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
1963 if (!NT_SUCCESS(Status
))
1965 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
1967 /* We have to return success otherwise we abort the traverse operation */
1968 return STATUS_SUCCESS
;
1972 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1974 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
1975 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1979 if (NT_SUCCESS(Status
))
1981 /* Append the instance id string */
1982 wcscat(InstancePath
, L
"\\");
1983 if (ParentIdPrefix
.Length
> 0)
1985 /* Add information from parent bus device to InstancePath */
1986 wcscat(InstancePath
, ParentIdPrefix
.Buffer
);
1987 if (IoStatusBlock
.Information
&& *(PWSTR
)IoStatusBlock
.Information
)
1988 wcscat(InstancePath
, L
"&");
1990 if (IoStatusBlock
.Information
)
1991 wcscat(InstancePath
, (PWSTR
)IoStatusBlock
.Information
);
1994 * FIXME: Check for valid characters, if there is invalid characters
2000 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2002 RtlFreeUnicodeString(&ParentIdPrefix
);
2004 if (!RtlCreateUnicodeString(&InstancePathU
, InstancePath
))
2006 DPRINT("No resources\n");
2007 /* FIXME: Cleanup and disable device */
2010 /* Verify that this is not a duplicate */
2011 OldDeviceObject
= IopGetDeviceObjectFromDeviceInstance(&InstancePathU
);
2012 if (OldDeviceObject
!= NULL
)
2014 PDEVICE_NODE OldDeviceNode
= IopGetDeviceNode(OldDeviceObject
);
2016 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU
);
2017 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode
->Parent
->InstancePath
);
2018 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode
->Parent
->InstancePath
);
2020 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR
,
2022 (ULONG_PTR
)DeviceNode
->PhysicalDeviceObject
,
2023 (ULONG_PTR
)OldDeviceObject
,
2027 DeviceNode
->InstancePath
= InstancePathU
;
2029 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
2032 * Create registry key for the instance id, if it doesn't exist yet
2034 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, 0, &InstanceKey
);
2035 if (!NT_SUCCESS(Status
))
2037 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2039 /* We have to return success otherwise we abort the traverse operation */
2040 return STATUS_SUCCESS
;
2043 IopQueryHardwareIds(DeviceNode
, InstanceKey
);
2045 IopQueryCompatibleIds(DeviceNode
, InstanceKey
);
2047 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2049 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2050 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2051 Status
= IopInitiatePnpIrp(
2052 DeviceNode
->PhysicalDeviceObject
,
2054 IRP_MN_QUERY_DEVICE_TEXT
,
2056 /* This key is mandatory, so even if the Irp fails, we still write it */
2057 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2058 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2060 if (NT_SUCCESS(Status
) &&
2061 IoStatusBlock
.Information
&&
2062 (*(PWSTR
)IoStatusBlock
.Information
!= 0))
2064 /* This key is overriden when a driver is installed. Don't write the
2065 * new description if another one already exists */
2066 Status
= ZwSetValueKey(InstanceKey
,
2070 (PVOID
)IoStatusBlock
.Information
,
2071 ((ULONG
)wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2075 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2076 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2078 Status
= ZwSetValueKey(InstanceKey
,
2083 DeviceDesc
.MaximumLength
);
2085 if (!NT_SUCCESS(Status
))
2087 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2093 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2095 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2096 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2097 Status
= IopInitiatePnpIrp(
2098 DeviceNode
->PhysicalDeviceObject
,
2100 IRP_MN_QUERY_DEVICE_TEXT
,
2102 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2104 DPRINT("LocationInformation: %S\n", (PWSTR
)IoStatusBlock
.Information
);
2105 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2106 Status
= ZwSetValueKey(InstanceKey
,
2110 (PVOID
)IoStatusBlock
.Information
,
2111 ((ULONG
)wcslen((PWSTR
)IoStatusBlock
.Information
) + 1) * sizeof(WCHAR
));
2112 if (!NT_SUCCESS(Status
))
2114 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2119 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2122 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2124 Status
= IopInitiatePnpIrp(
2125 DeviceNode
->PhysicalDeviceObject
,
2127 IRP_MN_QUERY_BUS_INFORMATION
,
2129 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2131 PPNP_BUS_INFORMATION BusInformation
=
2132 (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2134 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2135 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2136 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2137 ExFreePool(BusInformation
);
2141 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2143 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2144 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2145 DeviceNode
->ChildBusTypeIndex
= -1;
2148 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2150 Status
= IopInitiatePnpIrp(
2151 DeviceNode
->PhysicalDeviceObject
,
2153 IRP_MN_QUERY_RESOURCES
,
2155 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2157 DeviceNode
->BootResources
=
2158 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2159 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
2163 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2164 DeviceNode
->BootResources
= NULL
;
2167 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2169 Status
= IopInitiatePnpIrp(
2170 DeviceNode
->PhysicalDeviceObject
,
2172 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2174 if (NT_SUCCESS(Status
))
2176 DeviceNode
->ResourceRequirements
=
2177 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2181 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2182 DeviceNode
->ResourceRequirements
= NULL
;
2185 if (InstanceKey
!= NULL
)
2187 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2190 ZwClose(InstanceKey
);
2192 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2194 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2196 /* Report the device to the user-mode pnp manager */
2197 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2198 &DeviceNode
->InstancePath
);
2201 return STATUS_SUCCESS
;
2206 IopHandleDeviceRemoval(
2207 IN PDEVICE_NODE DeviceNode
,
2208 IN PDEVICE_RELATIONS DeviceRelations
)
2210 PDEVICE_NODE Child
= DeviceNode
->Child
, NextChild
;
2214 if (DeviceNode
== IopRootDeviceNode
)
2217 while (Child
!= NULL
)
2219 NextChild
= Child
->Sibling
;
2222 for (i
= 0; DeviceRelations
&& i
< DeviceRelations
->Count
; i
++)
2224 if (IopGetDeviceNode(DeviceRelations
->Objects
[i
]) == Child
)
2231 if (!Found
&& !(Child
->Flags
& DNF_WILL_BE_REMOVED
))
2233 /* Send removal IRPs to all of its children */
2234 IopPrepareDeviceForRemoval(Child
->PhysicalDeviceObject
, TRUE
);
2236 /* Send the surprise removal IRP */
2237 IopSendSurpriseRemoval(Child
->PhysicalDeviceObject
);
2239 /* Tell the user-mode PnP manager that a device was removed */
2240 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
2241 &Child
->InstancePath
);
2243 /* Send the remove device IRP */
2244 IopSendRemoveDevice(Child
->PhysicalDeviceObject
);
2253 IN PDEVICE_OBJECT DeviceObject
)
2255 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2256 DEVICETREE_TRAVERSE_CONTEXT Context
;
2257 PDEVICE_RELATIONS DeviceRelations
;
2258 PDEVICE_OBJECT ChildDeviceObject
;
2259 IO_STATUS_BLOCK IoStatusBlock
;
2260 PDEVICE_NODE ChildDeviceNode
;
2261 IO_STACK_LOCATION Stack
;
2265 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2267 if (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
)
2269 DeviceNode
->Flags
&= ~DNF_NEED_ENUMERATION_ONLY
;
2271 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2272 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2273 &DeviceNode
->InstancePath
);
2276 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2278 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2280 Status
= IopInitiatePnpIrp(
2283 IRP_MN_QUERY_DEVICE_RELATIONS
,
2285 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2287 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2291 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2294 * Send removal IRPs for devices that have disappeared
2295 * NOTE: This code handles the case where no relations are specified
2297 IopHandleDeviceRemoval(DeviceNode
, DeviceRelations
);
2299 /* Now we bail if nothing was returned */
2300 if (!DeviceRelations
)
2302 /* We're all done */
2303 DPRINT("No PDOs\n");
2304 return STATUS_SUCCESS
;
2307 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2310 * Create device nodes for all discovered devices
2312 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2314 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2315 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2317 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2318 if (!ChildDeviceNode
)
2320 /* One doesn't exist, create it */
2321 Status
= IopCreateDeviceNode(
2326 if (NT_SUCCESS(Status
))
2328 /* Mark the node as enumerated */
2329 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2331 /* Mark the DO as bus enumerated */
2332 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2336 /* Ignore this DO */
2337 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2338 ObDereferenceObject(ChildDeviceObject
);
2343 /* Mark it as enumerated */
2344 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2345 ObDereferenceObject(ChildDeviceObject
);
2348 ExFreePool(DeviceRelations
);
2351 * Retrieve information about all discovered children from the bus driver
2353 IopInitDeviceTreeTraverseContext(
2356 IopActionInterrogateDeviceStack
,
2359 Status
= IopTraverseDeviceTree(&Context
);
2360 if (!NT_SUCCESS(Status
))
2362 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2367 * Retrieve configuration from the registry for discovered children
2369 IopInitDeviceTreeTraverseContext(
2372 IopActionConfigureChildServices
,
2375 Status
= IopTraverseDeviceTree(&Context
);
2376 if (!NT_SUCCESS(Status
))
2378 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2383 * Initialize services for discovered children.
2385 Status
= IopInitializePnpServices(DeviceNode
);
2386 if (!NT_SUCCESS(Status
))
2388 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2392 DPRINT("IopEnumerateDevice() finished\n");
2393 return STATUS_SUCCESS
;
2398 * IopActionConfigureChildServices
2400 * Retrieve configuration for all (direct) child nodes of a parent node.
2404 * Pointer to device node.
2406 * Pointer to parent node to retrieve child node configuration for.
2409 * Any errors that occur are logged instead so that all child services have a chance of beeing
2414 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2417 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2418 PDEVICE_NODE ParentDeviceNode
;
2419 PUNICODE_STRING Service
;
2420 UNICODE_STRING ClassGUID
;
2422 DEVICE_CAPABILITIES DeviceCaps
;
2424 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2426 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2429 * We are called for the parent too, but we don't need to do special
2430 * handling for this node
2432 if (DeviceNode
== ParentDeviceNode
)
2434 DPRINT("Success\n");
2435 return STATUS_SUCCESS
;
2439 * Make sure this device node is a direct child of the parent device node
2440 * that is given as an argument
2443 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2445 DPRINT("Skipping 2+ level child\n");
2446 return STATUS_SUCCESS
;
2449 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2451 DPRINT1("Child not ready to be configured\n");
2452 return STATUS_SUCCESS
;
2455 if (!(DeviceNode
->Flags
& (DNF_DISABLED
| DNF_STARTED
| DNF_ADDED
)))
2457 WCHAR RegKeyBuffer
[MAX_PATH
];
2458 UNICODE_STRING RegKey
;
2460 /* Install the service for this if it's in the CDDB */
2461 IopInstallCriticalDevice(DeviceNode
);
2464 RegKey
.MaximumLength
= sizeof(RegKeyBuffer
);
2465 RegKey
.Buffer
= RegKeyBuffer
;
2468 * Retrieve configuration from Enum key
2471 Service
= &DeviceNode
->ServiceName
;
2473 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2474 RtlInitUnicodeString(Service
, NULL
);
2475 RtlInitUnicodeString(&ClassGUID
, NULL
);
2477 QueryTable
[0].Name
= L
"Service";
2478 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2479 QueryTable
[0].EntryContext
= Service
;
2481 QueryTable
[1].Name
= L
"ClassGUID";
2482 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2483 QueryTable
[1].EntryContext
= &ClassGUID
;
2484 QueryTable
[1].DefaultType
= REG_SZ
;
2485 QueryTable
[1].DefaultData
= L
"";
2486 QueryTable
[1].DefaultLength
= 0;
2488 RtlAppendUnicodeToString(&RegKey
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2489 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2491 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2492 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2494 if (!NT_SUCCESS(Status
))
2496 /* FIXME: Log the error */
2497 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2498 &DeviceNode
->InstancePath
, Status
);
2499 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2500 return STATUS_SUCCESS
;
2503 if (Service
->Buffer
== NULL
)
2505 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2506 DeviceCaps
.RawDeviceOK
)
2508 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2510 DeviceNode
->ServiceName
.Length
= 0;
2511 DeviceNode
->ServiceName
.MaximumLength
= 0;
2512 DeviceNode
->ServiceName
.Buffer
= NULL
;
2514 else if (ClassGUID
.Length
!= 0)
2516 /* Device has a ClassGUID value, but no Service value.
2517 * Suppose it is using the NULL driver, so state the
2518 * device is started */
2519 DPRINT("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2520 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2524 DeviceNode
->Problem
= CM_PROB_FAILED_INSTALL
;
2525 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2527 return STATUS_SUCCESS
;
2530 DPRINT("Got Service %S\n", Service
->Buffer
);
2533 return STATUS_SUCCESS
;
2537 * IopActionInitChildServices
2539 * Initialize the service for all (direct) child nodes of a parent node
2543 * Pointer to device node.
2545 * Pointer to parent node to initialize child node services for.
2548 * If the driver image for a service is not loaded and initialized
2549 * it is done here too. Any errors that occur are logged instead so
2550 * that all child services have a chance of being initialized.
2554 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2557 PDEVICE_NODE ParentDeviceNode
;
2559 BOOLEAN BootDrivers
= !PnpSystemInit
;
2561 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2563 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2566 * We are called for the parent too, but we don't need to do special
2567 * handling for this node
2569 if (DeviceNode
== ParentDeviceNode
)
2571 DPRINT("Success\n");
2572 return STATUS_SUCCESS
;
2576 * We don't want to check for a direct child because
2577 * this function is called during boot to reinitialize
2578 * devices with drivers that couldn't load yet due to
2579 * stage 0 limitations (ie can't load from disk yet).
2582 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2584 DPRINT1("Child not ready to be added\n");
2585 return STATUS_SUCCESS
;
2588 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
) ||
2589 IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) ||
2590 IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
2591 return STATUS_SUCCESS
;
2593 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
2595 /* We don't need to worry about loading the driver because we're
2596 * being driven in raw mode so our parent must be loaded to get here */
2597 Status
= IopInitializeDevice(DeviceNode
, NULL
);
2598 if (NT_SUCCESS(Status
))
2600 Status
= IopStartDevice(DeviceNode
);
2601 if (!NT_SUCCESS(Status
))
2603 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2604 &DeviceNode
->InstancePath
, Status
);
2610 PLDR_DATA_TABLE_ENTRY ModuleObject
;
2611 PDRIVER_OBJECT DriverObject
;
2613 /* Get existing DriverObject pointer (in case the driver has
2614 already been loaded and initialized) */
2615 Status
= IopGetDriverObject(
2617 &DeviceNode
->ServiceName
,
2620 if (!NT_SUCCESS(Status
))
2622 /* Driver is not initialized, try to load it */
2623 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
2625 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
2627 /* Initialize the driver */
2628 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
2629 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
2630 if (!NT_SUCCESS(Status
)) DeviceNode
->Problem
= CM_PROB_FAILED_DRIVER_ENTRY
;
2632 else if (Status
== STATUS_DRIVER_UNABLE_TO_LOAD
)
2634 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode
->ServiceName
);
2635 DeviceNode
->Problem
= CM_PROB_DISABLED_SERVICE
;
2639 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2640 &DeviceNode
->ServiceName
, Status
);
2641 if (!BootDrivers
) DeviceNode
->Problem
= CM_PROB_DRIVER_FAILED_LOAD
;
2645 /* Driver is loaded and initialized at this point */
2646 if (NT_SUCCESS(Status
))
2648 /* Initialize the device, including all filters */
2649 Status
= PipCallDriverAddDevice(DeviceNode
, FALSE
, DriverObject
);
2651 /* Remove the extra reference */
2652 ObDereferenceObject(DriverObject
);
2657 * Don't disable when trying to load only boot drivers
2661 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2666 return STATUS_SUCCESS
;
2670 * IopInitializePnpServices
2672 * Initialize services for discovered children
2676 * Top device node to start initializing services.
2682 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
2684 DEVICETREE_TRAVERSE_CONTEXT Context
;
2686 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
2688 IopInitDeviceTreeTraverseContext(
2691 IopActionInitChildServices
,
2694 return IopTraverseDeviceTree(&Context
);
2697 static NTSTATUS INIT_FUNCTION
2698 IopEnumerateDetectedDevices(
2700 IN PUNICODE_STRING RelativePath OPTIONAL
,
2702 IN BOOLEAN EnumerateSubKeys
,
2703 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
2704 IN ULONG ParentBootResourcesLength
)
2706 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
2707 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
2708 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
2709 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
2710 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
2711 OBJECT_ATTRIBUTES ObjectAttributes
;
2712 HANDLE hDevicesKey
= NULL
;
2713 HANDLE hDeviceKey
= NULL
;
2714 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
2715 UNICODE_STRING Level2NameU
;
2716 WCHAR Level2Name
[5];
2717 ULONG IndexDevice
= 0;
2719 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
2720 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
2721 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
2722 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
2723 UNICODE_STRING DeviceName
, ValueName
;
2725 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
2726 ULONG BootResourcesLength
;
2729 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
2730 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
2731 static ULONG DeviceIndexSerial
= 0;
2732 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
2733 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
2734 static ULONG DeviceIndexKeyboard
= 0;
2735 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
2736 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
2737 static ULONG DeviceIndexMouse
= 0;
2738 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
2739 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
2740 static ULONG DeviceIndexParallel
= 0;
2741 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
2742 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
2743 static ULONG DeviceIndexFloppy
= 0;
2744 UNICODE_STRING HardwareIdKey
;
2745 PUNICODE_STRING pHardwareId
;
2746 ULONG DeviceIndex
= 0;
2747 PUCHAR CmResourceList
;
2752 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
2753 if (!NT_SUCCESS(Status
))
2755 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2760 hDevicesKey
= hBaseKey
;
2762 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2763 if (!pDeviceInformation
)
2765 DPRINT("ExAllocatePool() failed\n");
2766 Status
= STATUS_NO_MEMORY
;
2770 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2771 if (!pValueInformation
)
2773 DPRINT("ExAllocatePool() failed\n");
2774 Status
= STATUS_NO_MEMORY
;
2780 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2781 if (Status
== STATUS_NO_MORE_ENTRIES
)
2783 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2785 ExFreePool(pDeviceInformation
);
2786 DeviceInfoLength
= RequiredSize
;
2787 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2788 if (!pDeviceInformation
)
2790 DPRINT("ExAllocatePool() failed\n");
2791 Status
= STATUS_NO_MEMORY
;
2794 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2796 if (!NT_SUCCESS(Status
))
2798 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2803 /* Open device key */
2804 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2805 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2807 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
2808 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
2809 if (!NT_SUCCESS(Status
))
2811 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
2815 /* Read boot resources, and add then to parent ones */
2816 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2817 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2819 ExFreePool(pValueInformation
);
2820 ValueInfoLength
= RequiredSize
;
2821 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2822 if (!pValueInformation
)
2824 DPRINT("ExAllocatePool() failed\n");
2825 ZwDeleteKey(hLevel2Key
);
2826 Status
= STATUS_NO_MEMORY
;
2829 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2831 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
2833 BootResources
= ParentBootResources
;
2834 BootResourcesLength
= ParentBootResourcesLength
;
2836 else if (!NT_SUCCESS(Status
))
2838 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2841 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
2843 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
2848 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
2850 /* Concatenate current resources and parent ones */
2851 if (ParentBootResourcesLength
== 0)
2852 BootResourcesLength
= pValueInformation
->DataLength
;
2854 BootResourcesLength
= ParentBootResourcesLength
2855 + pValueInformation
->DataLength
2857 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
2860 DPRINT("ExAllocatePool() failed\n");
2863 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
2865 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2867 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
2869 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
2871 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
2872 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2873 ParentBootResourcesLength
- Header
);
2874 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2878 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
2880 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
2881 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
2882 ParentBootResourcesLength
- Header
);
2884 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
2885 pValueInformation
->Data
+ Header
,
2886 pValueInformation
->DataLength
- Header
);
2887 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
2891 if (EnumerateSubKeys
)
2896 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2897 if (Status
== STATUS_NO_MORE_ENTRIES
)
2899 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2901 ExFreePool(pDeviceInformation
);
2902 DeviceInfoLength
= RequiredSize
;
2903 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
2904 if (!pDeviceInformation
)
2906 DPRINT("ExAllocatePool() failed\n");
2907 Status
= STATUS_NO_MEMORY
;
2910 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
2912 if (!NT_SUCCESS(Status
))
2914 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
2918 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
2919 DeviceName
.Buffer
= pDeviceInformation
->Name
;
2921 Status
= IopEnumerateDetectedDevices(
2927 BootResourcesLength
);
2928 if (!NT_SUCCESS(Status
))
2933 /* Read identifier */
2934 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2935 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
2937 ExFreePool(pValueInformation
);
2938 ValueInfoLength
= RequiredSize
;
2939 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
2940 if (!pValueInformation
)
2942 DPRINT("ExAllocatePool() failed\n");
2943 Status
= STATUS_NO_MEMORY
;
2946 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
2948 if (!NT_SUCCESS(Status
))
2950 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
2952 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
2955 ValueName
.Length
= ValueName
.MaximumLength
= 0;
2957 else if (pValueInformation
->Type
!= REG_SZ
)
2959 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
2964 /* Assign hardware id to this device */
2965 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
2966 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
2967 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
2968 ValueName
.Length
-= sizeof(WCHAR
);
2971 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
2973 pHardwareId
= &HardwareIdSerial
;
2974 DeviceIndex
= DeviceIndexSerial
++;
2976 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
2978 pHardwareId
= &HardwareIdKeyboard
;
2979 DeviceIndex
= DeviceIndexKeyboard
++;
2981 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
2983 pHardwareId
= &HardwareIdMouse
;
2984 DeviceIndex
= DeviceIndexMouse
++;
2986 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
2988 pHardwareId
= &HardwareIdParallel
;
2989 DeviceIndex
= DeviceIndexParallel
++;
2991 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
2993 pHardwareId
= &HardwareIdFloppy
;
2994 DeviceIndex
= DeviceIndexFloppy
++;
2998 /* Unknown key path */
2999 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
3003 /* Prepare hardware id key (hardware id value without final \0) */
3004 HardwareIdKey
= *pHardwareId
;
3005 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
3007 /* Add the detected device to Root key */
3008 InitializeObjectAttributes(&ObjectAttributes
, &HardwareIdKey
, OBJ_KERNEL_HANDLE
, hRootKey
, NULL
);
3009 Status
= ZwCreateKey(
3015 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
3017 if (!NT_SUCCESS(Status
))
3019 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3022 swprintf(Level2Name
, L
"%04lu", DeviceIndex
);
3023 RtlInitUnicodeString(&Level2NameU
, Level2Name
);
3024 InitializeObjectAttributes(&ObjectAttributes
, &Level2NameU
, OBJ_KERNEL_HANDLE
, hLevel1Key
, NULL
);
3025 Status
= ZwCreateKey(
3027 KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
,
3031 ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0,
3033 ZwClose(hLevel1Key
);
3034 if (!NT_SUCCESS(Status
))
3036 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3039 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName
, DeviceIndex
, &HardwareIdKey
);
3040 Status
= ZwSetValueKey(hLevel2Key
, &HardwareIDU
, 0, REG_MULTI_SZ
, pHardwareId
->Buffer
, pHardwareId
->MaximumLength
);
3041 if (!NT_SUCCESS(Status
))
3043 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3044 ZwDeleteKey(hLevel2Key
);
3047 /* Create 'LogConf' subkey */
3048 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
, hLevel2Key
, NULL
);
3049 Status
= ZwCreateKey(
3055 REG_OPTION_VOLATILE
,
3057 if (!NT_SUCCESS(Status
))
3059 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3060 ZwDeleteKey(hLevel2Key
);
3063 if (BootResourcesLength
>= sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3065 CmResourceList
= ExAllocatePool(PagedPool
, BootResourcesLength
+ sizeof(ULONG
));
3066 if (!CmResourceList
)
3069 ZwDeleteKey(hLevel2Key
);
3073 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3075 RtlCopyMemory(CmResourceList
,
3079 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3080 RtlCopyMemory(CmResourceList
+ sizeof(ULONG
),
3082 BootResourcesLength
);
3084 /* Save boot resources to 'LogConf\BootConfig' */
3085 Status
= ZwSetValueKey(hLogConf
, &BootConfigU
, 0, REG_RESOURCE_LIST
, CmResourceList
, BootResourcesLength
+ sizeof(ULONG
));
3086 if (!NT_SUCCESS(Status
))
3088 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3090 ZwDeleteKey(hLevel2Key
);
3097 if (BootResources
&& BootResources
!= ParentBootResources
)
3099 ExFreePool(BootResources
);
3100 BootResources
= NULL
;
3104 ZwClose(hLevel2Key
);
3109 ZwClose(hDeviceKey
);
3114 Status
= STATUS_SUCCESS
;
3117 if (hDevicesKey
&& hDevicesKey
!= hBaseKey
)
3118 ZwClose(hDevicesKey
);
3120 ZwClose(hDeviceKey
);
3121 if (pDeviceInformation
)
3122 ExFreePool(pDeviceInformation
);
3123 if (pValueInformation
)
3124 ExFreePool(pValueInformation
);
3128 static BOOLEAN INIT_FUNCTION
3129 IopIsFirmwareMapperDisabled(VOID
)
3131 UNICODE_STRING KeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3132 UNICODE_STRING KeyNameU
= RTL_CONSTANT_STRING(L
"DisableFirmwareMapper");
3133 OBJECT_ATTRIBUTES ObjectAttributes
;
3135 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
;
3136 ULONG DesiredLength
, Length
;
3140 InitializeObjectAttributes(&ObjectAttributes
, &KeyPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3141 Status
= ZwOpenKey(&hPnpKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
3142 if (NT_SUCCESS(Status
))
3144 Status
= ZwQueryValueKey(hPnpKey
,
3146 KeyValuePartialInformation
,
3150 if ((Status
== STATUS_BUFFER_TOO_SMALL
) ||
3151 (Status
== STATUS_BUFFER_OVERFLOW
))
3153 Length
= DesiredLength
;
3154 KeyInformation
= ExAllocatePool(PagedPool
, Length
);
3157 Status
= ZwQueryValueKey(hPnpKey
,
3159 KeyValuePartialInformation
,
3163 if (NT_SUCCESS(Status
) && KeyInformation
->DataLength
== sizeof(ULONG
))
3165 KeyValue
= (ULONG
)(*KeyInformation
->Data
);
3169 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU
, &KeyNameU
);
3172 ExFreePool(KeyInformation
);
3176 DPRINT1("Failed to allocate memory for registry query\n");
3181 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU
, &KeyNameU
, Status
);
3188 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU
, Status
);
3191 DPRINT1("Firmware mapper is %s\n", KeyValue
!= 0 ? "disabled" : "enabled");
3193 return (KeyValue
!= 0) ? TRUE
: FALSE
;
3199 IopUpdateRootKey(VOID
)
3201 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3202 UNICODE_STRING RootPathU
= RTL_CONSTANT_STRING(L
"Root");
3203 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3204 OBJECT_ATTRIBUTES ObjectAttributes
;
3205 HANDLE hEnum
, hRoot
;
3208 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3209 Status
= ZwCreateKey(&hEnum
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
3210 if (!NT_SUCCESS(Status
))
3212 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3216 InitializeObjectAttributes(&ObjectAttributes
, &RootPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
3217 Status
= ZwCreateKey(&hRoot
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, 0, NULL
);
3219 if (!NT_SUCCESS(Status
))
3221 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3225 if (!IopIsFirmwareMapperDisabled())
3227 Status
= IopOpenRegistryKeyEx(&hEnum
, NULL
, &MultiKeyPathU
, KEY_ENUMERATE_SUB_KEYS
);
3228 if (!NT_SUCCESS(Status
))
3230 /* Nothing to do, don't return with an error status */
3231 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3233 return STATUS_SUCCESS
;
3235 Status
= IopEnumerateDetectedDevices(
3246 /* Enumeration is disabled */
3247 Status
= STATUS_SUCCESS
;
3257 IopOpenRegistryKeyEx(PHANDLE KeyHandle
,
3259 PUNICODE_STRING Name
,
3260 ACCESS_MASK DesiredAccess
)
3262 OBJECT_ATTRIBUTES ObjectAttributes
;
3269 InitializeObjectAttributes(&ObjectAttributes
,
3271 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3275 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
3282 IopCreateRegistryKeyEx(OUT PHANDLE Handle
,
3283 IN HANDLE RootHandle OPTIONAL
,
3284 IN PUNICODE_STRING KeyName
,
3285 IN ACCESS_MASK DesiredAccess
,
3286 IN ULONG CreateOptions
,
3287 OUT PULONG Disposition OPTIONAL
)
3289 OBJECT_ATTRIBUTES ObjectAttributes
;
3290 ULONG KeyDisposition
, RootHandleIndex
= 0, i
= 1, NestedCloseLevel
= 0;
3292 HANDLE HandleArray
[2];
3293 BOOLEAN Recursing
= TRUE
;
3295 UNICODE_STRING KeyString
;
3296 NTSTATUS Status
= STATUS_SUCCESS
;
3299 /* P1 is start, pp is end */
3300 p1
= KeyName
->Buffer
;
3301 pp
= (PVOID
)((ULONG_PTR
)p1
+ KeyName
->Length
);
3303 /* Create the target key */
3304 InitializeObjectAttributes(&ObjectAttributes
,
3306 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3309 Status
= ZwCreateKey(&HandleArray
[i
],
3317 /* Now we check if this failed */
3318 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) && (RootHandle
))
3320 /* Target key failed, so we'll need to create its parent. Setup array */
3321 HandleArray
[0] = NULL
;
3322 HandleArray
[1] = RootHandle
;
3324 /* Keep recursing for each missing parent */
3327 /* And if we're deep enough, close the last handle */
3328 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3330 /* We're setup to ping-pong between the two handle array entries */
3331 RootHandleIndex
= i
;
3334 /* Clear the one we're attempting to open now */
3335 HandleArray
[i
] = NULL
;
3337 /* Process the parent key name */
3338 for (p
= p1
; ((p
< pp
) && (*p
!= OBJ_NAME_PATH_SEPARATOR
)); p
++);
3339 Length
= (USHORT
)(p
- p1
) * sizeof(WCHAR
);
3341 /* Is there a parent name? */
3344 /* Build the unicode string for it */
3345 KeyString
.Buffer
= p1
;
3346 KeyString
.Length
= KeyString
.MaximumLength
= Length
;
3348 /* Now try opening the parent */
3349 InitializeObjectAttributes(&ObjectAttributes
,
3351 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3352 HandleArray
[RootHandleIndex
],
3354 Status
= ZwCreateKey(&HandleArray
[i
],
3361 if (NT_SUCCESS(Status
))
3363 /* It worked, we have one more handle */
3368 /* Parent key creation failed, abandon loop */
3375 /* We don't have a parent name, probably corrupted key name */
3376 Status
= STATUS_INVALID_PARAMETER
;
3381 /* Now see if there's more parents to create */
3383 if ((p
== pp
) || (p1
== pp
))
3385 /* We're done, hopefully successfully, so stop */
3390 /* Outer loop check for handle nesting that requires closing the top handle */
3391 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3394 /* Check if we broke out of the loop due to success */
3395 if (NT_SUCCESS(Status
))
3397 /* Return the target handle (we closed all the parent ones) and disposition */
3398 *Handle
= HandleArray
[i
];
3399 if (Disposition
) *Disposition
= KeyDisposition
;
3402 /* Return the success state */
3408 IopGetRegistryValue(IN HANDLE Handle
,
3410 OUT PKEY_VALUE_FULL_INFORMATION
*Information
)
3412 UNICODE_STRING ValueString
;
3414 PKEY_VALUE_FULL_INFORMATION FullInformation
;
3418 RtlInitUnicodeString(&ValueString
, ValueName
);
3420 Status
= ZwQueryValueKey(Handle
,
3422 KeyValueFullInformation
,
3426 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
3427 (Status
!= STATUS_BUFFER_TOO_SMALL
))
3432 FullInformation
= ExAllocatePool(NonPagedPool
, Size
);
3433 if (!FullInformation
) return STATUS_INSUFFICIENT_RESOURCES
;
3435 Status
= ZwQueryValueKey(Handle
,
3437 KeyValueFullInformation
,
3441 if (!NT_SUCCESS(Status
))
3443 ExFreePool(FullInformation
);
3447 *Information
= FullInformation
;
3448 return STATUS_SUCCESS
;
3451 RTL_GENERIC_COMPARE_RESULTS
3453 PiCompareInstancePath(IN PRTL_AVL_TABLE Table
,
3454 IN PVOID FirstStruct
,
3455 IN PVOID SecondStruct
)
3463 // The allocation function is called by the generic table package whenever
3464 // it needs to allocate memory for the table.
3469 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3479 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3488 PpInitializeDeviceReferenceTable(VOID
)
3490 /* Setup the guarded mutex and AVL table */
3491 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock
);
3492 RtlInitializeGenericTableAvl(
3493 &PpDeviceReferenceTable
,
3494 (PRTL_AVL_COMPARE_ROUTINE
)PiCompareInstancePath
,
3495 (PRTL_AVL_ALLOCATE_ROUTINE
)PiAllocateGenericTableEntry
,
3496 (PRTL_AVL_FREE_ROUTINE
)PiFreeGenericTableEntry
,
3504 /* Initialize the resource when accessing device registry data */
3505 ExInitializeResourceLite(&PpRegistryDeviceResource
);
3507 /* Setup the device reference AVL table */
3508 PpInitializeDeviceReferenceTable();
3516 /* Check the initialization phase */
3517 switch (ExpInitializationPhase
)
3522 return PiInitPhase0();
3528 //return PiInitPhase1();
3532 /* Don't know any other phase! Bugcheck! */
3533 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL
);
3538 LONG IopNumberDeviceNodes
;
3542 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3544 PDEVICE_NODE DeviceNode
;
3548 DeviceNode
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), 'donD');
3549 if (!DeviceNode
) return DeviceNode
;
3552 InterlockedIncrement(&IopNumberDeviceNodes
);
3555 RtlZeroMemory(DeviceNode
, sizeof(DEVICE_NODE
));
3556 DeviceNode
->InterfaceType
= InterfaceTypeUndefined
;
3557 DeviceNode
->BusNumber
= -1;
3558 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
3559 DeviceNode
->ChildBusNumber
= -1;
3560 DeviceNode
->ChildBusTypeIndex
= -1;
3561 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3562 InitializeListHead(&DeviceNode
->DeviceArbiterList
);
3563 InitializeListHead(&DeviceNode
->DeviceTranslatorList
);
3564 InitializeListHead(&DeviceNode
->TargetDeviceNotify
);
3565 InitializeListHead(&DeviceNode
->DockInfo
.ListEntry
);
3566 InitializeListHead(&DeviceNode
->PendedSetInterfaceState
);
3568 /* Check if there is a PDO */
3569 if (PhysicalDeviceObject
)
3571 /* Link it and remove the init flag */
3572 DeviceNode
->PhysicalDeviceObject
= PhysicalDeviceObject
;
3573 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= DeviceNode
;
3574 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
3577 /* Return the node */
3581 /* PUBLIC FUNCTIONS **********************************************************/
3585 PnpBusTypeGuidGet(IN USHORT Index
,
3586 IN LPGUID BusTypeGuid
)
3588 NTSTATUS Status
= STATUS_SUCCESS
;
3590 /* Acquire the lock */
3591 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
3594 if (Index
< PnpBusTypeGuidList
->GuidCount
)
3597 RtlCopyMemory(BusTypeGuid
, &PnpBusTypeGuidList
->Guids
[Index
], sizeof(GUID
));
3602 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
3605 /* Release lock and return status */
3606 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
3612 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject
,
3613 IN PHANDLE DeviceInstanceHandle
,
3614 IN ACCESS_MASK DesiredAccess
)
3618 PDEVICE_NODE DeviceNode
;
3619 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3622 /* Open the enum key */
3623 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
3627 if (!NT_SUCCESS(Status
)) return Status
;
3629 /* Make sure we have an instance path */
3630 DeviceNode
= IopGetDeviceNode(DeviceObject
);
3631 if ((DeviceNode
) && (DeviceNode
->InstancePath
.Length
))
3633 /* Get the instance key */
3634 Status
= IopOpenRegistryKeyEx(DeviceInstanceHandle
,
3636 &DeviceNode
->InstancePath
,
3642 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3645 /* Close the handle and return status */
3652 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList
)
3654 ULONG FinalSize
, PartialSize
, EntrySize
, i
, j
;
3655 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
3656 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
3658 /* If we don't have one, that's easy */
3659 if (!ResourceList
) return 0;
3661 /* Start with the minimum size possible */
3662 FinalSize
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
3664 /* Loop each full descriptor */
3665 FullDescriptor
= ResourceList
->List
;
3666 for (i
= 0; i
< ResourceList
->Count
; i
++)
3668 /* Start with the minimum size possible */
3669 PartialSize
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
) +
3670 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST
, PartialDescriptors
);
3672 /* Loop each partial descriptor */
3673 PartialDescriptor
= FullDescriptor
->PartialResourceList
.PartialDescriptors
;
3674 for (j
= 0; j
< FullDescriptor
->PartialResourceList
.Count
; j
++)
3676 /* Start with the minimum size possible */
3677 EntrySize
= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
3679 /* Check if there is extra data */
3680 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
3683 EntrySize
+= PartialDescriptor
->u
.DeviceSpecificData
.DataSize
;
3686 /* The size of partial descriptors is bigger */
3687 PartialSize
+= EntrySize
;
3689 /* Go to the next partial descriptor */
3690 PartialDescriptor
= (PVOID
)((ULONG_PTR
)PartialDescriptor
+ EntrySize
);
3693 /* The size of full descriptors is bigger */
3694 FinalSize
+= PartialSize
;
3696 /* Go to the next full descriptor */
3697 FullDescriptor
= (PVOID
)((ULONG_PTR
)FullDescriptor
+ PartialSize
);
3700 /* Return the final size */
3706 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject
,
3711 IN PULONG BufferLength
)
3714 HANDLE KeyHandle
, SubHandle
;
3715 UNICODE_STRING KeyString
;
3716 PKEY_VALUE_FULL_INFORMATION KeyValueInfo
= NULL
;
3720 /* Find the instance key */
3721 Status
= PnpDeviceObjectToDeviceInstance(DeviceObject
, &KeyHandle
, KEY_READ
);
3722 if (NT_SUCCESS(Status
))
3724 /* Check for name given by caller */
3728 RtlInitUnicodeString(&KeyString
, KeyName
);
3729 Status
= IopOpenRegistryKeyEx(&SubHandle
,
3733 if (NT_SUCCESS(Status
))
3735 /* And use this handle instead */
3737 KeyHandle
= SubHandle
;
3741 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3742 if (NT_SUCCESS(Status
))
3744 /* Now get the size of the property */
3745 Status
= IopGetRegistryValue(KeyHandle
,
3754 /* Fail if any of the registry operations failed */
3755 if (!NT_SUCCESS(Status
)) return Status
;
3757 /* Check how much data we have to copy */
3758 Length
= KeyValueInfo
->DataLength
;
3759 if (*BufferLength
>= Length
)
3761 /* Check for a match in the value type */
3762 if (KeyValueInfo
->Type
== ValueType
)
3765 RtlCopyMemory(Buffer
,
3766 (PVOID
)((ULONG_PTR
)KeyValueInfo
+
3767 KeyValueInfo
->DataOffset
),
3772 /* Invalid registry property type, fail */
3773 Status
= STATUS_INVALID_PARAMETER_2
;
3778 /* Buffer is too small to hold data */
3779 Status
= STATUS_BUFFER_TOO_SMALL
;
3782 /* Return the required buffer length, free the buffer, and return status */
3783 *BufferLength
= Length
;
3784 ExFreePool(KeyValueInfo
);
3788 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3789 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3790 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
3797 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
3798 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
3799 IN ULONG BufferLength
,
3800 OUT PVOID PropertyBuffer
,
3801 OUT PULONG ResultLength
)
3803 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
3804 DEVICE_CAPABILITIES DeviceCaps
;
3805 ULONG ReturnLength
= 0, Length
= 0, ValueType
;
3806 PWCHAR ValueName
= NULL
, EnumeratorNameEnd
, DeviceInstanceName
;
3808 NTSTATUS Status
= STATUS_BUFFER_TOO_SMALL
;
3810 POBJECT_NAME_INFORMATION ObjectNameInfo
= NULL
;
3811 BOOLEAN NullTerminate
= FALSE
;
3813 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject
, DeviceProperty
);
3815 /* Assume failure */
3818 /* Only PDOs can call this */
3819 if (!DeviceNode
) return STATUS_INVALID_DEVICE_REQUEST
;
3821 /* Handle all properties */
3822 switch (DeviceProperty
)
3824 case DevicePropertyBusTypeGuid
:
3826 /* Get the GUID from the internal cache */
3827 Status
= PnpBusTypeGuidGet(DeviceNode
->ChildBusTypeIndex
, &BusTypeGuid
);
3828 if (!NT_SUCCESS(Status
)) return Status
;
3830 /* This is the format of the returned data */
3831 PIP_RETURN_DATA(sizeof(GUID
), &BusTypeGuid
);
3833 case DevicePropertyLegacyBusType
:
3835 /* Validate correct interface type */
3836 if (DeviceNode
->ChildInterfaceType
== InterfaceTypeUndefined
)
3837 return STATUS_OBJECT_NAME_NOT_FOUND
;
3839 /* This is the format of the returned data */
3840 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE
), &DeviceNode
->ChildInterfaceType
);
3842 case DevicePropertyBusNumber
:
3844 /* Validate correct bus number */
3845 if ((DeviceNode
->ChildBusNumber
& 0x80000000) == 0x80000000)
3846 return STATUS_OBJECT_NAME_NOT_FOUND
;
3848 /* This is the format of the returned data */
3849 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceNode
->ChildBusNumber
);
3851 case DevicePropertyEnumeratorName
:
3853 /* Get the instance path */
3854 DeviceInstanceName
= DeviceNode
->InstancePath
.Buffer
;
3857 ASSERT((BufferLength
& 1) == 0);
3858 ASSERT(DeviceInstanceName
!= NULL
);
3860 /* Get the name from the path */
3861 EnumeratorNameEnd
= wcschr(DeviceInstanceName
, OBJ_NAME_PATH_SEPARATOR
);
3862 ASSERT(EnumeratorNameEnd
);
3864 /* This string needs to be NULL-terminated */
3865 NullTerminate
= TRUE
;
3867 /* This is the format of the returned data */
3868 PIP_RETURN_DATA((ULONG
)(EnumeratorNameEnd
- DeviceInstanceName
) * sizeof(WCHAR
),
3869 DeviceInstanceName
);
3871 case DevicePropertyAddress
:
3873 /* Query the device caps */
3874 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
);
3875 if (!NT_SUCCESS(Status
) || (DeviceCaps
.Address
== MAXULONG
))
3876 return STATUS_OBJECT_NAME_NOT_FOUND
;
3878 /* This is the format of the returned data */
3879 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceCaps
.Address
);
3881 case DevicePropertyBootConfigurationTranslated
:
3883 /* Validate we have resources */
3884 if (!DeviceNode
->BootResources
)
3885 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3887 /* No resources will still fake success, but with 0 bytes */
3889 return STATUS_SUCCESS
;
3892 /* This is the format of the returned data */
3893 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode
->BootResources
), // FIXFIX: Should use BootResourcesTranslated
3894 DeviceNode
->BootResources
); // FIXFIX: Should use BootResourcesTranslated
3896 case DevicePropertyPhysicalDeviceObjectName
:
3898 /* Sanity check for Unicode-sized string */
3899 ASSERT((BufferLength
& 1) == 0);
3901 /* Allocate name buffer */
3902 Length
= BufferLength
+ sizeof(OBJECT_NAME_INFORMATION
);
3903 ObjectNameInfo
= ExAllocatePool(PagedPool
, Length
);
3904 if (!ObjectNameInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
3906 /* Query the PDO name */
3907 Status
= ObQueryNameString(DeviceObject
,
3911 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
3913 /* It's up to the caller to try again */
3914 Status
= STATUS_BUFFER_TOO_SMALL
;
3917 /* This string needs to be NULL-terminated */
3918 NullTerminate
= TRUE
;
3920 /* Return if successful */
3921 if (NT_SUCCESS(Status
)) PIP_RETURN_DATA(ObjectNameInfo
->Name
.Length
,
3922 ObjectNameInfo
->Name
.Buffer
);
3924 /* Let the caller know how big the name is */
3925 *ResultLength
-= sizeof(OBJECT_NAME_INFORMATION
);
3928 /* Handle the registry-based properties */
3929 case DevicePropertyUINumber
:
3930 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER
, REG_DWORD
);
3931 case DevicePropertyLocationInformation
:
3932 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION
, REG_SZ
);
3933 case DevicePropertyDeviceDescription
:
3934 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC
, REG_SZ
);
3935 case DevicePropertyHardwareID
:
3936 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID
, REG_MULTI_SZ
);
3937 case DevicePropertyCompatibleIDs
:
3938 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS
, REG_MULTI_SZ
);
3939 case DevicePropertyBootConfiguration
:
3940 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG
, REG_RESOURCE_LIST
);
3941 case DevicePropertyClassName
:
3942 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS
, REG_SZ
);
3943 case DevicePropertyClassGuid
:
3944 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID
, REG_SZ
);
3945 case DevicePropertyDriverKeyName
:
3946 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER
, REG_SZ
);
3947 case DevicePropertyManufacturer
:
3948 PIP_REGISTRY_DATA(REGSTR_VAL_MFG
, REG_SZ
);
3949 case DevicePropertyFriendlyName
:
3950 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME
, REG_SZ
);
3951 case DevicePropertyContainerID
:
3952 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3953 PIP_UNIMPLEMENTED();
3954 case DevicePropertyRemovalPolicy
:
3955 PIP_UNIMPLEMENTED();
3956 case DevicePropertyInstallState
:
3957 PIP_UNIMPLEMENTED();
3958 case DevicePropertyResourceRequirements
:
3959 PIP_UNIMPLEMENTED();
3960 case DevicePropertyAllocatedResources
:
3961 PIP_UNIMPLEMENTED();
3963 return STATUS_INVALID_PARAMETER_2
;
3966 /* Having a registry value name implies registry data */
3969 /* We know up-front how much data to expect */
3970 *ResultLength
= BufferLength
;
3972 /* Go get the data, use the LogConf subkey if necessary */
3973 Status
= PiGetDeviceRegistryProperty(DeviceObject
,
3977 DevicePropertyBootConfiguration
) ?
3982 else if (NT_SUCCESS(Status
))
3984 /* We know up-front how much data to expect, check the caller's buffer */
3985 *ResultLength
= ReturnLength
+ (NullTerminate
? sizeof(UNICODE_NULL
) : 0);
3986 if (*ResultLength
<= BufferLength
)
3988 /* Buffer is all good, copy the data */
3989 RtlCopyMemory(PropertyBuffer
, Data
, ReturnLength
);
3991 /* Check if we need to NULL-terminate the string */
3994 /* Terminate the string */
3995 ((PWCHAR
)PropertyBuffer
)[ReturnLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
3998 /* This is the success path */
3999 Status
= STATUS_SUCCESS
;
4004 Status
= STATUS_BUFFER_TOO_SMALL
;
4008 /* Free any allocation we may have made, and return the status code */
4009 if (ObjectNameInfo
) ExFreePool(ObjectNameInfo
);
4018 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject
)
4020 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
4021 IO_STACK_LOCATION Stack
;
4024 IO_STATUS_BLOCK IoStatusBlock
;
4026 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
4027 Stack
.MajorFunction
= IRP_MJ_PNP
;
4028 Stack
.MinorFunction
= IRP_MN_QUERY_PNP_DEVICE_STATE
;
4030 Status
= IopSynchronousCall(PhysicalDeviceObject
, &Stack
, (PVOID
*)&PnPFlags
);
4031 if (!NT_SUCCESS(Status
))
4033 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status
);
4037 if (PnPFlags
& PNP_DEVICE_NOT_DISABLEABLE
)
4038 DeviceNode
->UserFlags
|= DNUF_NOT_DISABLEABLE
;
4040 DeviceNode
->UserFlags
&= ~DNUF_NOT_DISABLEABLE
;
4042 if (PnPFlags
& PNP_DEVICE_DONT_DISPLAY_IN_UI
)
4043 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
4045 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
4047 if ((PnPFlags
& PNP_DEVICE_REMOVED
) ||
4048 ((PnPFlags
& PNP_DEVICE_FAILED
) && !(PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)))
4050 /* Flag it if it's failed */
4051 if (PnPFlags
& PNP_DEVICE_FAILED
) DeviceNode
->Problem
= CM_PROB_FAILED_POST_START
;
4053 /* Send removal IRPs to all of its children */
4054 IopPrepareDeviceForRemoval(PhysicalDeviceObject
, TRUE
);
4056 /* Send surprise removal */
4057 IopSendSurpriseRemoval(PhysicalDeviceObject
);
4059 /* Tell the user-mode PnP manager that a device was removed */
4060 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
4061 &DeviceNode
->InstancePath
);
4063 IopSendRemoveDevice(PhysicalDeviceObject
);
4065 else if ((PnPFlags
& PNP_DEVICE_FAILED
) && (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
))
4067 /* Stop for resource rebalance */
4068 Status
= IopStopDevice(DeviceNode
);
4069 if (!NT_SUCCESS(Status
))
4071 DPRINT1("Failed to stop device for rebalancing\n");
4073 /* Stop failed so don't rebalance */
4074 PnPFlags
&= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
;
4078 /* Resource rebalance */
4079 if (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)
4081 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4083 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4085 IRP_MN_QUERY_RESOURCES
,
4087 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
4089 DeviceNode
->BootResources
=
4090 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
4091 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
4095 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
4096 DeviceNode
->BootResources
= NULL
;
4099 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4101 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4103 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
4105 if (NT_SUCCESS(Status
))
4107 DeviceNode
->ResourceRequirements
=
4108 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
4112 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
4113 DeviceNode
->ResourceRequirements
= NULL
;
4116 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4117 if (IopStartDevice(DeviceNode
) != STATUS_SUCCESS
)
4119 DPRINT1("Restart after resource rebalance failed\n");
4121 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
4122 DeviceNode
->Flags
|= DNF_START_FAILED
;
4124 IopRemoveDevice(DeviceNode
);
4130 * @name IoOpenDeviceRegistryKey
4132 * Open a registry key unique for a specified driver or device instance.
4134 * @param DeviceObject Device to get the registry key for.
4135 * @param DevInstKeyType Type of the key to return.
4136 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4137 * @param DevInstRegKey Handle to the opened registry key on
4138 * successful return.
4146 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject
,
4147 IN ULONG DevInstKeyType
,
4148 IN ACCESS_MASK DesiredAccess
,
4149 OUT PHANDLE DevInstRegKey
)
4151 static WCHAR RootKeyName
[] =
4152 L
"\\Registry\\Machine\\System\\CurrentControlSet\\";
4153 static WCHAR ProfileKeyName
[] =
4154 L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4155 static WCHAR ClassKeyName
[] = L
"Control\\Class\\";
4156 static WCHAR EnumKeyName
[] = L
"Enum\\";
4157 static WCHAR DeviceParametersKeyName
[] = L
"Device Parameters";
4158 ULONG KeyNameLength
;
4159 LPWSTR KeyNameBuffer
;
4160 UNICODE_STRING KeyName
;
4161 ULONG DriverKeyLength
;
4162 OBJECT_ATTRIBUTES ObjectAttributes
;
4163 PDEVICE_NODE DeviceNode
= NULL
;
4166 DPRINT("IoOpenDeviceRegistryKey() called\n");
4168 if ((DevInstKeyType
& (PLUGPLAY_REGKEY_DEVICE
| PLUGPLAY_REGKEY_DRIVER
)) == 0)
4170 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4171 return STATUS_INVALID_PARAMETER
;
4174 if (!IopIsValidPhysicalDeviceObject(DeviceObject
))
4175 return STATUS_INVALID_DEVICE_REQUEST
;
4176 DeviceNode
= IopGetDeviceNode(DeviceObject
);
4179 * Calculate the length of the base key name. This is the full
4180 * name for driver key or the name excluding "Device Parameters"
4181 * subkey for device key.
4184 KeyNameLength
= sizeof(RootKeyName
);
4185 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4186 KeyNameLength
+= sizeof(ProfileKeyName
) - sizeof(UNICODE_NULL
);
4187 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4189 KeyNameLength
+= sizeof(ClassKeyName
) - sizeof(UNICODE_NULL
);
4190 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4191 0, NULL
, &DriverKeyLength
);
4192 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
4194 KeyNameLength
+= DriverKeyLength
;
4198 KeyNameLength
+= sizeof(EnumKeyName
) - sizeof(UNICODE_NULL
) +
4199 DeviceNode
->InstancePath
.Length
;
4203 * Now allocate the buffer for the key name...
4206 KeyNameBuffer
= ExAllocatePool(PagedPool
, KeyNameLength
);
4207 if (KeyNameBuffer
== NULL
)
4208 return STATUS_INSUFFICIENT_RESOURCES
;
4211 KeyName
.MaximumLength
= (USHORT
)KeyNameLength
;
4212 KeyName
.Buffer
= KeyNameBuffer
;
4215 * ...and build the key name.
4218 KeyName
.Length
+= sizeof(RootKeyName
) - sizeof(UNICODE_NULL
);
4219 RtlCopyMemory(KeyNameBuffer
, RootKeyName
, KeyName
.Length
);
4221 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4222 RtlAppendUnicodeToString(&KeyName
, ProfileKeyName
);
4224 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4226 RtlAppendUnicodeToString(&KeyName
, ClassKeyName
);
4227 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4228 DriverKeyLength
, KeyNameBuffer
+
4229 (KeyName
.Length
/ sizeof(WCHAR
)),
4231 if (!NT_SUCCESS(Status
))
4233 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status
);
4234 ExFreePool(KeyNameBuffer
);
4237 KeyName
.Length
+= (USHORT
)DriverKeyLength
- sizeof(UNICODE_NULL
);
4241 RtlAppendUnicodeToString(&KeyName
, EnumKeyName
);
4242 Status
= RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->InstancePath
);
4243 if (DeviceNode
->InstancePath
.Length
== 0)
4245 ExFreePool(KeyNameBuffer
);
4251 * Open the base key.
4253 Status
= IopOpenRegistryKeyEx(DevInstRegKey
, NULL
, &KeyName
, DesiredAccess
);
4254 if (!NT_SUCCESS(Status
))
4256 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName
, Status
);
4257 ExFreePool(KeyNameBuffer
);
4260 ExFreePool(KeyNameBuffer
);
4263 * For driver key we're done now.
4266 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4270 * Let's go further. For device key we must open "Device Parameters"
4271 * subkey and create it if it doesn't exist yet.
4274 RtlInitUnicodeString(&KeyName
, DeviceParametersKeyName
);
4275 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
,
4276 OBJ_CASE_INSENSITIVE
, *DevInstRegKey
, NULL
);
4277 Status
= ZwCreateKey(DevInstRegKey
, DesiredAccess
, &ObjectAttributes
,
4278 0, NULL
, ExpInTextModeSetup
? REG_OPTION_VOLATILE
: 0, NULL
);
4279 ZwClose(ObjectAttributes
.RootDirectory
);
4286 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
, BOOLEAN Force
)
4288 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
, FailedRemoveDevice
;
4292 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4293 ChildDeviceNode
= ParentDeviceNode
->Child
;
4294 while (ChildDeviceNode
!= NULL
)
4296 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4297 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4299 Status
= IopPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
, Force
);
4300 if (!NT_SUCCESS(Status
))
4302 FailedRemoveDevice
= ChildDeviceNode
;
4306 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4307 ChildDeviceNode
= NextDeviceNode
;
4309 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4311 return STATUS_SUCCESS
;
4314 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4315 ChildDeviceNode
= ParentDeviceNode
->Child
;
4316 while (ChildDeviceNode
!= NULL
)
4318 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4319 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4321 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4323 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4324 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4325 if (ChildDeviceNode
== FailedRemoveDevice
)
4328 ChildDeviceNode
= NextDeviceNode
;
4330 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4332 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4339 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4341 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4344 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4345 ChildDeviceNode
= ParentDeviceNode
->Child
;
4346 while (ChildDeviceNode
!= NULL
)
4348 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4349 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4351 IopSendRemoveDevice(ChildDeviceNode
->PhysicalDeviceObject
);
4353 ChildDeviceNode
= NextDeviceNode
;
4355 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4357 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4362 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4364 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4367 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4368 ChildDeviceNode
= ParentDeviceNode
->Child
;
4369 while (ChildDeviceNode
!= NULL
)
4371 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4372 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4374 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4376 ChildDeviceNode
= NextDeviceNode
;
4378 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4380 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4385 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
, BOOLEAN Force
)
4387 /* This function DOES NOT dereference the device objects on SUCCESS
4388 * but it DOES dereference device objects on FAILURE */
4393 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4395 Status
= IopPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
], Force
);
4396 if (!NT_SUCCESS(Status
))
4403 return STATUS_SUCCESS
;
4406 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4407 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4408 for (i
= 0; i
<= j
; i
++)
4410 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4411 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4412 DeviceRelations
->Objects
[i
] = NULL
;
4414 for (; i
< DeviceRelations
->Count
; i
++)
4416 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4417 DeviceRelations
->Objects
[i
] = NULL
;
4419 ExFreePool(DeviceRelations
);
4426 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4428 /* This function DOES dereference the device objects in all cases */
4432 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4434 IopSendRemoveDevice(DeviceRelations
->Objects
[i
]);
4435 DeviceRelations
->Objects
[i
] = NULL
;
4438 ExFreePool(DeviceRelations
);
4443 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4445 /* This function DOES dereference the device objects in all cases */
4449 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4451 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4452 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4453 DeviceRelations
->Objects
[i
] = NULL
;
4456 ExFreePool(DeviceRelations
);
4460 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
)
4462 IO_STACK_LOCATION Stack
;
4463 IO_STATUS_BLOCK IoStatusBlock
;
4464 PDEVICE_RELATIONS DeviceRelations
;
4467 IopCancelRemoveDevice(DeviceObject
);
4469 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4471 Status
= IopInitiatePnpIrp(DeviceObject
,
4473 IRP_MN_QUERY_DEVICE_RELATIONS
,
4475 if (!NT_SUCCESS(Status
))
4477 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4478 DeviceRelations
= NULL
;
4482 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4485 if (DeviceRelations
)
4486 IopCancelRemoveDeviceRelations(DeviceRelations
);
4490 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
)
4492 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
4493 IO_STACK_LOCATION Stack
;
4494 IO_STATUS_BLOCK IoStatusBlock
;
4495 PDEVICE_RELATIONS DeviceRelations
;
4498 if ((DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
) && !Force
)
4500 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode
->InstancePath
);
4501 return STATUS_UNSUCCESSFUL
;
4504 if (!Force
&& IopQueryRemoveDevice(DeviceObject
) != STATUS_SUCCESS
)
4506 DPRINT1("Removal vetoed by failing the query remove request\n");
4508 IopCancelRemoveDevice(DeviceObject
);
4510 return STATUS_UNSUCCESSFUL
;
4513 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4515 Status
= IopInitiatePnpIrp(DeviceObject
,
4517 IRP_MN_QUERY_DEVICE_RELATIONS
,
4519 if (!NT_SUCCESS(Status
))
4521 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4522 DeviceRelations
= NULL
;
4526 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4529 if (DeviceRelations
)
4531 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, Force
);
4532 if (!NT_SUCCESS(Status
))
4536 Status
= IopQueryRemoveChildDevices(DeviceNode
, Force
);
4537 if (!NT_SUCCESS(Status
))
4539 if (DeviceRelations
)
4540 IopCancelRemoveDeviceRelations(DeviceRelations
);
4544 if (DeviceRelations
)
4545 IopSendRemoveDeviceRelations(DeviceRelations
);
4546 IopSendRemoveChildDevices(DeviceNode
);
4548 return STATUS_SUCCESS
;
4552 IopRemoveDevice(PDEVICE_NODE DeviceNode
)
4556 DPRINT("Removing device: %wZ\n", &DeviceNode
->InstancePath
);
4558 Status
= IopPrepareDeviceForRemoval(DeviceNode
->PhysicalDeviceObject
, FALSE
);
4559 if (NT_SUCCESS(Status
))
4561 IopSendRemoveDevice(DeviceNode
->PhysicalDeviceObject
);
4562 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL
,
4563 &DeviceNode
->InstancePath
);
4564 return STATUS_SUCCESS
;
4575 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject
)
4577 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
4578 PDEVICE_RELATIONS DeviceRelations
;
4579 IO_STATUS_BLOCK IoStatusBlock
;
4580 IO_STACK_LOCATION Stack
;
4581 DEVICE_CAPABILITIES Capabilities
;
4584 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT
,
4585 &DeviceNode
->InstancePath
);
4587 if (IopQueryDeviceCapabilities(DeviceNode
, &Capabilities
) != STATUS_SUCCESS
)
4592 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
4594 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4596 IRP_MN_QUERY_DEVICE_RELATIONS
,
4598 if (!NT_SUCCESS(Status
))
4600 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4601 DeviceRelations
= NULL
;
4605 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4608 if (DeviceRelations
)
4610 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, FALSE
);
4611 if (!NT_SUCCESS(Status
))
4615 Status
= IopQueryRemoveChildDevices(DeviceNode
, FALSE
);
4616 if (!NT_SUCCESS(Status
))
4618 if (DeviceRelations
)
4619 IopCancelRemoveDeviceRelations(DeviceRelations
);
4623 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject
, FALSE
) != STATUS_SUCCESS
)
4625 if (DeviceRelations
)
4626 IopCancelRemoveDeviceRelations(DeviceRelations
);
4627 IopCancelRemoveChildDevices(DeviceNode
);
4631 if (DeviceRelations
)
4632 IopSendRemoveDeviceRelations(DeviceRelations
);
4633 IopSendRemoveChildDevices(DeviceNode
);
4635 DeviceNode
->Problem
= CM_PROB_HELD_FOR_EJECT
;
4636 if (Capabilities
.EjectSupported
)
4638 if (IopSendEject(PhysicalDeviceObject
) != STATUS_SUCCESS
)
4645 DeviceNode
->Flags
|= DNF_DISABLED
;
4648 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT
,
4649 &DeviceNode
->InstancePath
);
4654 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED
,
4655 &DeviceNode
->InstancePath
);
4663 IoInvalidateDeviceRelations(
4664 IN PDEVICE_OBJECT DeviceObject
,
4665 IN DEVICE_RELATION_TYPE Type
)
4667 PIO_WORKITEM WorkItem
;
4668 PINVALIDATE_DEVICE_RELATION_DATA Data
;
4670 Data
= ExAllocatePool(NonPagedPool
, sizeof(INVALIDATE_DEVICE_RELATION_DATA
));
4673 WorkItem
= IoAllocateWorkItem(DeviceObject
);
4680 ObReferenceObject(DeviceObject
);
4681 Data
->DeviceObject
= DeviceObject
;
4683 Data
->WorkItem
= WorkItem
;
4687 IopAsynchronousInvalidateDeviceRelations
,
4697 IoSynchronousInvalidateDeviceRelations(
4698 IN PDEVICE_OBJECT DeviceObject
,
4699 IN DEVICE_RELATION_TYPE Type
)
4706 /* Enumerate the device */
4707 return IopEnumerateDevice(DeviceObject
);
4708 case PowerRelations
:
4709 /* Not handled yet */
4710 return STATUS_NOT_IMPLEMENTED
;
4711 case TargetDeviceRelation
:
4713 return STATUS_SUCCESS
;
4715 /* Ejection relations are not supported */
4716 return STATUS_NOT_SUPPORTED
;
4725 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType
,
4727 IN PHYSICAL_ADDRESS BusAddress
,
4728 IN OUT PULONG AddressSpace
,
4729 OUT PPHYSICAL_ADDRESS TranslatedAddress
)
4731 /* FIXME: Notify the resource arbiter */
4733 return HalTranslateBusAddress(InterfaceType
,