2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 PDEVICE_NODE IopRootDeviceNode
;
19 KSPIN_LOCK IopDeviceTreeLock
;
20 ERESOURCE PpRegistryDeviceResource
;
21 KGUARDED_MUTEX PpDeviceReferenceTableLock
;
22 RTL_AVL_TABLE PpDeviceReferenceTable
;
24 extern ERESOURCE IopDriverLoadResource
;
25 extern ULONG ExpInitializationPhase
;
26 extern BOOLEAN PnpSystemInit
;
28 #define MAX_DEVICE_ID_LEN 200
29 #define MAX_SEPARATORS_INSTANCEID 0
30 #define MAX_SEPARATORS_DEVICEID 1
32 /* DATA **********************************************************************/
34 PDRIVER_OBJECT IopRootDriverObject
;
35 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList
= NULL
;
36 LIST_ENTRY IopDeviceActionRequestList
;
37 WORK_QUEUE_ITEM IopDeviceActionWorkItem
;
38 BOOLEAN IopDeviceActionInProgress
;
39 KSPIN_LOCK IopDeviceActionLock
;
41 typedef struct _DEVICE_ACTION_DATA
43 LIST_ENTRY RequestListEntry
;
44 PDEVICE_OBJECT DeviceObject
;
45 DEVICE_RELATION_TYPE Type
;
46 } DEVICE_ACTION_DATA
, *PDEVICE_ACTION_DATA
;
48 /* FUNCTIONS *****************************************************************/
51 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
52 IN ULONG CreateOptions
,
56 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
);
59 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
);
62 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
);
66 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject
)
68 return ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
72 IopFixupDeviceId(PWCHAR String
)
74 SIZE_T Length
= wcslen(String
), i
;
76 for (i
= 0; i
< Length
; i
++)
78 if (String
[i
] == L
'\\')
85 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode
)
88 HANDLE CriticalDeviceKey
, InstanceKey
;
89 OBJECT_ATTRIBUTES ObjectAttributes
;
90 UNICODE_STRING CriticalDeviceKeyU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
91 UNICODE_STRING CompatibleIdU
= RTL_CONSTANT_STRING(L
"CompatibleIDs");
92 UNICODE_STRING HardwareIdU
= RTL_CONSTANT_STRING(L
"HardwareID");
93 UNICODE_STRING ServiceU
= RTL_CONSTANT_STRING(L
"Service");
94 UNICODE_STRING ClassGuidU
= RTL_CONSTANT_STRING(L
"ClassGUID");
95 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
96 ULONG HidLength
= 0, CidLength
= 0, BufferLength
;
97 PWCHAR IdBuffer
, OriginalIdBuffer
;
99 /* Open the device instance key */
100 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceKey
);
101 if (Status
!= STATUS_SUCCESS
)
104 Status
= ZwQueryValueKey(InstanceKey
,
106 KeyValuePartialInformation
,
110 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
112 ZwClose(InstanceKey
);
116 Status
= ZwQueryValueKey(InstanceKey
,
118 KeyValuePartialInformation
,
122 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
127 BufferLength
= HidLength
+ CidLength
;
128 BufferLength
-= (((CidLength
!= 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
));
130 /* Allocate a buffer to hold data from both */
131 OriginalIdBuffer
= IdBuffer
= ExAllocatePool(PagedPool
, BufferLength
);
134 ZwClose(InstanceKey
);
138 /* Compute the buffer size */
139 if (HidLength
> CidLength
)
140 BufferLength
= HidLength
;
142 BufferLength
= CidLength
;
144 PartialInfo
= ExAllocatePool(PagedPool
, BufferLength
);
147 ZwClose(InstanceKey
);
148 ExFreePool(OriginalIdBuffer
);
152 Status
= ZwQueryValueKey(InstanceKey
,
154 KeyValuePartialInformation
,
158 if (Status
!= STATUS_SUCCESS
)
160 ExFreePool(PartialInfo
);
161 ExFreePool(OriginalIdBuffer
);
162 ZwClose(InstanceKey
);
166 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
167 HidLength
= PartialInfo
->DataLength
- ((CidLength
!= 0) ? sizeof(WCHAR
) : 0);
168 RtlCopyMemory(IdBuffer
, PartialInfo
->Data
, HidLength
);
172 Status
= ZwQueryValueKey(InstanceKey
,
174 KeyValuePartialInformation
,
178 if (Status
!= STATUS_SUCCESS
)
180 ExFreePool(PartialInfo
);
181 ExFreePool(OriginalIdBuffer
);
182 ZwClose(InstanceKey
);
187 CidLength
= PartialInfo
->DataLength
;
188 RtlCopyMemory(((PUCHAR
)IdBuffer
) + HidLength
, PartialInfo
->Data
, CidLength
);
191 /* Free our temp buffer */
192 ExFreePool(PartialInfo
);
194 InitializeObjectAttributes(&ObjectAttributes
,
196 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
199 Status
= ZwOpenKey(&CriticalDeviceKey
,
200 KEY_ENUMERATE_SUB_KEYS
,
202 if (!NT_SUCCESS(Status
))
204 /* The critical device database doesn't exist because
205 * we're probably in 1st stage setup, but it's ok */
206 ExFreePool(OriginalIdBuffer
);
207 ZwClose(InstanceKey
);
213 USHORT StringLength
= (USHORT
)wcslen(IdBuffer
) + 1, Index
;
215 IopFixupDeviceId(IdBuffer
);
217 /* Look through all subkeys for a match */
218 for (Index
= 0; TRUE
; Index
++)
221 PKEY_BASIC_INFORMATION BasicInfo
;
223 Status
= ZwEnumerateKey(CriticalDeviceKey
,
229 if (Status
== STATUS_NO_MORE_ENTRIES
)
231 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
233 UNICODE_STRING ChildIdNameU
, RegKeyNameU
;
235 BasicInfo
= ExAllocatePool(PagedPool
, NeededLength
);
239 ExFreePool(OriginalIdBuffer
);
240 ZwClose(CriticalDeviceKey
);
241 ZwClose(InstanceKey
);
245 Status
= ZwEnumerateKey(CriticalDeviceKey
,
251 if (Status
!= STATUS_SUCCESS
)
253 /* This shouldn't happen */
254 ExFreePool(BasicInfo
);
258 ChildIdNameU
.Buffer
= IdBuffer
;
259 ChildIdNameU
.MaximumLength
= ChildIdNameU
.Length
= (StringLength
- 1) * sizeof(WCHAR
);
260 RegKeyNameU
.Buffer
= BasicInfo
->Name
;
261 RegKeyNameU
.MaximumLength
= RegKeyNameU
.Length
= (USHORT
)BasicInfo
->NameLength
;
263 if (RtlEqualUnicodeString(&ChildIdNameU
, &RegKeyNameU
, TRUE
))
265 HANDLE ChildKeyHandle
;
267 InitializeObjectAttributes(&ObjectAttributes
,
269 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
273 Status
= ZwOpenKey(&ChildKeyHandle
,
276 if (Status
!= STATUS_SUCCESS
)
278 ExFreePool(BasicInfo
);
282 /* Check if there's already a driver installed */
283 Status
= ZwQueryValueKey(InstanceKey
,
285 KeyValuePartialInformation
,
289 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
291 ExFreePool(BasicInfo
);
295 Status
= ZwQueryValueKey(ChildKeyHandle
,
297 KeyValuePartialInformation
,
301 if (Status
!= STATUS_BUFFER_OVERFLOW
&& Status
!= STATUS_BUFFER_TOO_SMALL
)
303 ExFreePool(BasicInfo
);
307 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
310 ExFreePool(OriginalIdBuffer
);
311 ExFreePool(BasicInfo
);
312 ZwClose(InstanceKey
);
313 ZwClose(ChildKeyHandle
);
314 ZwClose(CriticalDeviceKey
);
318 /* Read ClassGUID entry in the CDDB */
319 Status
= ZwQueryValueKey(ChildKeyHandle
,
321 KeyValuePartialInformation
,
325 if (Status
!= STATUS_SUCCESS
)
327 ExFreePool(BasicInfo
);
331 /* Write it to the ENUM key */
332 Status
= ZwSetValueKey(InstanceKey
,
337 PartialInfo
->DataLength
);
338 if (Status
!= STATUS_SUCCESS
)
340 ExFreePool(BasicInfo
);
341 ExFreePool(PartialInfo
);
342 ZwClose(ChildKeyHandle
);
346 Status
= ZwQueryValueKey(ChildKeyHandle
,
348 KeyValuePartialInformation
,
352 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
354 ExFreePool(PartialInfo
);
355 PartialInfo
= ExAllocatePool(PagedPool
, NeededLength
);
358 ExFreePool(OriginalIdBuffer
);
359 ExFreePool(BasicInfo
);
360 ZwClose(InstanceKey
);
361 ZwClose(ChildKeyHandle
);
362 ZwClose(CriticalDeviceKey
);
366 /* Read the service entry from the CDDB */
367 Status
= ZwQueryValueKey(ChildKeyHandle
,
369 KeyValuePartialInformation
,
373 if (Status
!= STATUS_SUCCESS
)
375 ExFreePool(BasicInfo
);
376 ExFreePool(PartialInfo
);
377 ZwClose(ChildKeyHandle
);
381 /* Write it to the ENUM key */
382 Status
= ZwSetValueKey(InstanceKey
,
387 PartialInfo
->DataLength
);
388 if (Status
!= STATUS_SUCCESS
)
390 ExFreePool(BasicInfo
);
391 ExFreePool(PartialInfo
);
392 ZwClose(ChildKeyHandle
);
396 DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo
->Data
, &ChildIdNameU
);
400 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU
);
403 ExFreePool(OriginalIdBuffer
);
404 ExFreePool(PartialInfo
);
405 ExFreePool(BasicInfo
);
406 ZwClose(InstanceKey
);
407 ZwClose(ChildKeyHandle
);
408 ZwClose(CriticalDeviceKey
);
414 ExFreePool(BasicInfo
);
418 /* Umm, not sure what happened here */
423 /* Advance to the next ID */
424 IdBuffer
+= StringLength
;
427 ExFreePool(OriginalIdBuffer
);
428 ZwClose(InstanceKey
);
429 ZwClose(CriticalDeviceKey
);
434 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
435 PDRIVER_OBJECT DriverObject
)
442 /* Special case for bus driven devices */
443 DeviceNode
->Flags
|= DNF_ADDED
;
444 return STATUS_SUCCESS
;
447 if (!DriverObject
->DriverExtension
->AddDevice
)
449 DeviceNode
->Flags
|= DNF_LEGACY_DRIVER
;
452 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
454 DeviceNode
->Flags
|= (DNF_ADDED
| DNF_STARTED
);
455 return STATUS_SUCCESS
;
458 /* This is a Plug and Play driver */
459 DPRINT("Plug and Play driver found\n");
460 ASSERT(DeviceNode
->PhysicalDeviceObject
);
462 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
463 &DriverObject
->DriverName
,
464 &DeviceNode
->InstancePath
);
465 Status
= DriverObject
->DriverExtension
->AddDevice(DriverObject
,
466 DeviceNode
->PhysicalDeviceObject
);
467 if (!NT_SUCCESS(Status
))
469 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
470 &DriverObject
->DriverName
,
471 &DeviceNode
->InstancePath
,
473 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
474 DeviceNode
->Problem
= CM_PROB_FAILED_ADD
;
478 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
480 /* Check if we have a ACPI device (needed for power management) */
481 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
483 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
485 /* There can be only one system power device */
486 if (!SystemPowerDeviceNodeCreated
)
488 PopSystemPowerDeviceNode
= DeviceNode
;
489 ObReferenceObject(PopSystemPowerDeviceNode
->PhysicalDeviceObject
);
490 SystemPowerDeviceNodeCreated
= TRUE
;
494 ObDereferenceObject(Fdo
);
496 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
498 return STATUS_SUCCESS
;
504 IopSendEject(IN PDEVICE_OBJECT DeviceObject
)
506 IO_STACK_LOCATION Stack
;
509 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
510 Stack
.MajorFunction
= IRP_MJ_PNP
;
511 Stack
.MinorFunction
= IRP_MN_EJECT
;
513 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
519 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject
)
521 IO_STACK_LOCATION Stack
;
524 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
525 Stack
.MajorFunction
= IRP_MJ_PNP
;
526 Stack
.MinorFunction
= IRP_MN_SURPRISE_REMOVAL
;
528 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
529 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
535 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
537 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
538 IO_STACK_LOCATION Stack
;
544 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING
,
545 &DeviceNode
->InstancePath
);
547 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
548 Stack
.MajorFunction
= IRP_MJ_PNP
;
549 Stack
.MinorFunction
= IRP_MN_QUERY_REMOVE_DEVICE
;
551 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
553 IopNotifyPlugPlayNotification(DeviceObject
,
554 EventCategoryTargetDeviceChange
,
555 &GUID_TARGET_DEVICE_QUERY_REMOVE
,
559 if (!NT_SUCCESS(Status
))
561 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode
->InstancePath
);
562 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED
,
563 &DeviceNode
->InstancePath
);
572 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject
)
574 IO_STACK_LOCATION Stack
;
577 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
578 Stack
.MajorFunction
= IRP_MJ_PNP
;
579 Stack
.MinorFunction
= IRP_MN_QUERY_STOP_DEVICE
;
581 return IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
587 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
589 IO_STACK_LOCATION Stack
;
591 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
593 /* Drop all our state for this device in case it isn't really going away */
594 DeviceNode
->Flags
&= DNF_ENUMERATED
| DNF_PROCESSED
;
596 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
597 Stack
.MajorFunction
= IRP_MJ_PNP
;
598 Stack
.MinorFunction
= IRP_MN_REMOVE_DEVICE
;
600 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
601 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
603 IopNotifyPlugPlayNotification(DeviceObject
,
604 EventCategoryTargetDeviceChange
,
605 &GUID_TARGET_DEVICE_REMOVE_COMPLETE
,
608 ObDereferenceObject(DeviceObject
);
614 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject
)
616 IO_STACK_LOCATION Stack
;
619 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
620 Stack
.MajorFunction
= IRP_MJ_PNP
;
621 Stack
.MinorFunction
= IRP_MN_CANCEL_REMOVE_DEVICE
;
623 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
624 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
626 IopNotifyPlugPlayNotification(DeviceObject
,
627 EventCategoryTargetDeviceChange
,
628 &GUID_TARGET_DEVICE_REMOVE_CANCELLED
,
636 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject
)
638 IO_STACK_LOCATION Stack
;
641 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
642 Stack
.MajorFunction
= IRP_MJ_PNP
;
643 Stack
.MinorFunction
= IRP_MN_STOP_DEVICE
;
645 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
646 IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
651 IopSetServiceEnumData(PDEVICE_NODE DeviceNode
)
653 UNICODE_STRING ServicesKeyPath
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
654 UNICODE_STRING ServiceKeyName
;
655 UNICODE_STRING EnumKeyName
;
656 UNICODE_STRING ValueName
;
657 PKEY_VALUE_FULL_INFORMATION KeyValueInformation
;
658 HANDLE ServiceKey
= NULL
, ServiceEnumKey
= NULL
;
660 ULONG Count
= 0, NextInstance
= 0;
661 WCHAR ValueBuffer
[6];
662 NTSTATUS Status
= STATUS_SUCCESS
;
664 DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode
);
665 DPRINT("Instance: %wZ\n", &DeviceNode
->InstancePath
);
666 DPRINT("Service: %wZ\n", &DeviceNode
->ServiceName
);
668 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
670 DPRINT1("No service!\n");
671 return STATUS_SUCCESS
;
674 ServiceKeyName
.MaximumLength
= ServicesKeyPath
.Length
+ DeviceNode
->ServiceName
.Length
+ sizeof(UNICODE_NULL
);
675 ServiceKeyName
.Length
= 0;
676 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, ServiceKeyName
.MaximumLength
);
677 if (ServiceKeyName
.Buffer
== NULL
)
679 DPRINT1("No ServiceKeyName.Buffer!\n");
680 return STATUS_INSUFFICIENT_RESOURCES
;
683 RtlAppendUnicodeStringToString(&ServiceKeyName
, &ServicesKeyPath
);
684 RtlAppendUnicodeStringToString(&ServiceKeyName
, &DeviceNode
->ServiceName
);
686 DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName
);
688 Status
= IopOpenRegistryKeyEx(&ServiceKey
, NULL
, &ServiceKeyName
, KEY_CREATE_SUB_KEY
);
689 if (!NT_SUCCESS(Status
))
694 RtlInitUnicodeString(&EnumKeyName
, L
"Enum");
695 Status
= IopCreateRegistryKeyEx(&ServiceEnumKey
,
701 if (NT_SUCCESS(Status
))
703 if (Disposition
== REG_OPENED_EXISTING_KEY
)
705 /* Read the NextInstance value */
706 Status
= IopGetRegistryValue(ServiceEnumKey
,
708 &KeyValueInformation
);
709 if (!NT_SUCCESS(Status
))
712 if ((KeyValueInformation
->Type
== REG_DWORD
) &&
713 (KeyValueInformation
->DataLength
))
716 Count
= *(PULONG
)((ULONG_PTR
)KeyValueInformation
+
717 KeyValueInformation
->DataOffset
);
720 ExFreePool(KeyValueInformation
);
721 KeyValueInformation
= NULL
;
723 /* Read the NextInstance value */
724 Status
= IopGetRegistryValue(ServiceEnumKey
,
726 &KeyValueInformation
);
727 if (!NT_SUCCESS(Status
))
730 if ((KeyValueInformation
->Type
== REG_DWORD
) &&
731 (KeyValueInformation
->DataLength
))
733 NextInstance
= *(PULONG
)((ULONG_PTR
)KeyValueInformation
+
734 KeyValueInformation
->DataOffset
);
737 ExFreePool(KeyValueInformation
);
738 KeyValueInformation
= NULL
;
741 /* Set the instance path */
742 swprintf(ValueBuffer
, L
"%lu", NextInstance
);
743 RtlInitUnicodeString(&ValueName
, ValueBuffer
);
744 Status
= ZwSetValueKey(ServiceEnumKey
,
748 DeviceNode
->InstancePath
.Buffer
,
749 DeviceNode
->InstancePath
.MaximumLength
);
750 if (!NT_SUCCESS(Status
))
753 /* Increment Count and NextInstance */
757 /* Set the new Count value */
758 RtlInitUnicodeString(&ValueName
, L
"Count");
759 Status
= ZwSetValueKey(ServiceEnumKey
,
765 if (!NT_SUCCESS(Status
))
768 /* Set the new NextInstance value */
769 RtlInitUnicodeString(&ValueName
, L
"NextInstance");
770 Status
= ZwSetValueKey(ServiceEnumKey
,
775 sizeof(NextInstance
));
779 if (ServiceEnumKey
!= NULL
)
780 ZwClose(ServiceEnumKey
);
782 if (ServiceKey
!= NULL
)
785 ExFreePool(ServiceKeyName
.Buffer
);
792 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject
)
794 IO_STACK_LOCATION Stack
;
795 PDEVICE_NODE DeviceNode
;
798 DEVICE_CAPABILITIES DeviceCapabilities
;
800 /* Get the device node */
801 DeviceNode
= IopGetDeviceNode(DeviceObject
);
803 ASSERT(!(DeviceNode
->Flags
& DNF_DISABLED
));
805 /* Build the I/O stack location */
806 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
807 Stack
.MajorFunction
= IRP_MJ_PNP
;
808 Stack
.MinorFunction
= IRP_MN_START_DEVICE
;
810 Stack
.Parameters
.StartDevice
.AllocatedResources
=
811 DeviceNode
->ResourceList
;
812 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
=
813 DeviceNode
->ResourceListTranslated
;
816 Status
= IopSynchronousCall(DeviceObject
, &Stack
, &Dummy
);
817 if (!NT_SUCCESS(Status
))
819 /* Send an IRP_MN_REMOVE_DEVICE request */
820 IopRemoveDevice(DeviceNode
);
822 /* Set the appropriate flag */
823 DeviceNode
->Flags
|= DNF_START_FAILED
;
824 DeviceNode
->Problem
= CM_PROB_FAILED_START
;
826 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode
->InstancePath
, Status
);
830 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
832 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
833 if (!NT_SUCCESS(Status
))
835 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
838 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
839 IoInvalidateDeviceState(DeviceObject
);
841 /* Otherwise, mark us as started */
842 DeviceNode
->Flags
|= DNF_STARTED
;
843 DeviceNode
->Flags
&= ~DNF_STOPPED
;
845 /* We now need enumeration */
846 DeviceNode
->Flags
|= DNF_NEED_ENUMERATION_ONLY
;
851 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode
)
853 PDEVICE_OBJECT DeviceObject
;
858 ASSERT((DeviceNode
->Flags
& DNF_ADDED
));
859 ASSERT((DeviceNode
->Flags
& (DNF_RESOURCE_ASSIGNED
|
860 DNF_RESOURCE_REPORTED
|
861 DNF_NO_RESOURCE_REQUIRED
)));
863 /* Get the device object */
864 DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
866 /* Check if we're not started yet */
867 if (!(DeviceNode
->Flags
& DNF_STARTED
))
870 IopStartDevice2(DeviceObject
);
873 /* Do we need to query IDs? This happens in the case of manual reporting */
875 if (DeviceNode
->Flags
& DNF_NEED_QUERY_IDS
)
877 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
878 /* And that case shouldn't happen yet */
883 IopSetServiceEnumData(DeviceNode
);
885 /* Make sure we're started, and check if we need enumeration */
886 if ((DeviceNode
->Flags
& DNF_STARTED
) &&
887 (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
))
890 IoSynchronousInvalidateDeviceRelations(DeviceObject
, BusRelations
);
891 Status
= STATUS_SUCCESS
;
896 Status
= STATUS_SUCCESS
;
905 PDEVICE_NODE DeviceNode
)
909 DPRINT("Stopping device: %wZ\n", &DeviceNode
->InstancePath
);
911 Status
= IopQueryStopDevice(DeviceNode
->PhysicalDeviceObject
);
912 if (NT_SUCCESS(Status
))
914 IopSendStopDevice(DeviceNode
->PhysicalDeviceObject
);
916 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
917 DeviceNode
->Flags
|= DNF_STOPPED
;
919 return STATUS_SUCCESS
;
927 PDEVICE_NODE DeviceNode
)
930 HANDLE InstanceHandle
= NULL
, ControlHandle
= NULL
;
931 UNICODE_STRING KeyName
, ValueString
;
932 OBJECT_ATTRIBUTES ObjectAttributes
;
934 if (DeviceNode
->Flags
& DNF_DISABLED
)
935 return STATUS_SUCCESS
;
937 Status
= IopAssignDeviceResources(DeviceNode
);
938 if (!NT_SUCCESS(Status
))
942 IopStartAndEnumerateDevice(DeviceNode
);
944 /* FIX: Should be done in new device instance code */
945 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceHandle
);
946 if (!NT_SUCCESS(Status
))
949 /* FIX: Should be done in IoXxxPrepareDriverLoading */
951 RtlInitUnicodeString(&KeyName
, L
"Control");
952 InitializeObjectAttributes(&ObjectAttributes
,
954 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
957 Status
= ZwCreateKey(&ControlHandle
,
964 if (!NT_SUCCESS(Status
))
967 RtlInitUnicodeString(&KeyName
, L
"ActiveService");
968 ValueString
= DeviceNode
->ServiceName
;
969 if (!ValueString
.Buffer
)
970 RtlInitUnicodeString(&ValueString
, L
"");
971 Status
= ZwSetValueKey(ControlHandle
, &KeyName
, 0, REG_SZ
, ValueString
.Buffer
, ValueString
.Length
+ sizeof(UNICODE_NULL
));
975 if (ControlHandle
!= NULL
)
976 ZwClose(ControlHandle
);
978 if (InstanceHandle
!= NULL
)
979 ZwClose(InstanceHandle
);
986 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode
,
987 PDEVICE_CAPABILITIES DeviceCaps
)
989 IO_STATUS_BLOCK StatusBlock
;
990 IO_STACK_LOCATION Stack
;
993 UNICODE_STRING ValueName
;
995 /* Set up the Header */
996 RtlZeroMemory(DeviceCaps
, sizeof(DEVICE_CAPABILITIES
));
997 DeviceCaps
->Size
= sizeof(DEVICE_CAPABILITIES
);
998 DeviceCaps
->Version
= 1;
999 DeviceCaps
->Address
= -1;
1000 DeviceCaps
->UINumber
= -1;
1002 /* Set up the Stack */
1003 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
1004 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= DeviceCaps
;
1007 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
1009 IRP_MN_QUERY_CAPABILITIES
,
1011 if (!NT_SUCCESS(Status
))
1013 if (Status
!= STATUS_NOT_SUPPORTED
)
1015 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status
);
1020 DeviceNode
->CapabilityFlags
= *(PULONG
)((ULONG_PTR
)&DeviceCaps
->Version
+ sizeof(DeviceCaps
->Version
));
1022 if (DeviceCaps
->NoDisplayInUI
)
1023 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
1025 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
1027 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceKey
);
1028 if (NT_SUCCESS(Status
))
1030 /* Set 'Capabilities' value */
1031 RtlInitUnicodeString(&ValueName
, L
"Capabilities");
1032 Status
= ZwSetValueKey(InstanceKey
,
1036 &DeviceNode
->CapabilityFlags
,
1039 /* Set 'UINumber' value */
1040 if (DeviceCaps
->UINumber
!= MAXULONG
)
1042 RtlInitUnicodeString(&ValueName
, L
"UINumber");
1043 Status
= ZwSetValueKey(InstanceKey
,
1047 &DeviceCaps
->UINumber
,
1051 ZwClose(InstanceKey
);
1060 IopDeviceActionWorker(
1063 PLIST_ENTRY ListEntry
;
1064 PDEVICE_ACTION_DATA Data
;
1067 KeAcquireSpinLock(&IopDeviceActionLock
, &OldIrql
);
1068 while (!IsListEmpty(&IopDeviceActionRequestList
))
1070 ListEntry
= RemoveHeadList(&IopDeviceActionRequestList
);
1071 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
1072 Data
= CONTAINING_RECORD(ListEntry
,
1076 IoSynchronousInvalidateDeviceRelations(Data
->DeviceObject
,
1079 ObDereferenceObject(Data
->DeviceObject
);
1080 ExFreePoolWithTag(Data
, TAG_IO
);
1081 KeAcquireSpinLock(&IopDeviceActionLock
, &OldIrql
);
1083 IopDeviceActionInProgress
= FALSE
;
1084 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
1088 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT
*DeviceObject
)
1092 if (PopSystemPowerDeviceNode
)
1094 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1095 *DeviceObject
= PopSystemPowerDeviceNode
->PhysicalDeviceObject
;
1096 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1098 return STATUS_SUCCESS
;
1101 return STATUS_UNSUCCESSFUL
;
1106 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid
)
1108 USHORT i
= 0, FoundIndex
= 0xFFFF;
1112 /* Acquire the lock */
1113 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
1115 /* Loop all entries */
1116 while (i
< PnpBusTypeGuidList
->GuidCount
)
1118 /* Try to find a match */
1119 if (RtlCompareMemory(BusTypeGuid
,
1120 &PnpBusTypeGuidList
->Guids
[i
],
1121 sizeof(GUID
)) == sizeof(GUID
))
1130 /* Check if we have to grow the list */
1131 if (PnpBusTypeGuidList
->GuidCount
)
1133 /* Calculate the new size */
1134 NewSize
= sizeof(IO_BUS_TYPE_GUID_LIST
) +
1135 (sizeof(GUID
) * PnpBusTypeGuidList
->GuidCount
);
1137 /* Allocate the new copy */
1138 NewList
= ExAllocatePool(PagedPool
, NewSize
);
1143 ExFreePool(PnpBusTypeGuidList
);
1147 /* Now copy them, decrease the size too */
1148 NewSize
-= sizeof(GUID
);
1149 RtlCopyMemory(NewList
, PnpBusTypeGuidList
, NewSize
);
1151 /* Free the old list */
1152 ExFreePool(PnpBusTypeGuidList
);
1154 /* Use the new buffer */
1155 PnpBusTypeGuidList
= NewList
;
1158 /* Copy the new GUID */
1159 RtlCopyMemory(&PnpBusTypeGuidList
->Guids
[PnpBusTypeGuidList
->GuidCount
],
1163 /* The new entry is the index */
1164 FoundIndex
= (USHORT
)PnpBusTypeGuidList
->GuidCount
;
1165 PnpBusTypeGuidList
->GuidCount
++;
1168 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
1174 * Creates a device node
1177 * ParentNode = Pointer to parent device node
1178 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
1179 * to have the root device node create one
1180 * (eg. for legacy drivers)
1181 * DeviceNode = Pointer to storage for created device node
1187 IopCreateDeviceNode(PDEVICE_NODE ParentNode
,
1188 PDEVICE_OBJECT PhysicalDeviceObject
,
1189 PUNICODE_STRING ServiceName
,
1190 PDEVICE_NODE
*DeviceNode
)
1195 UNICODE_STRING FullServiceName
;
1196 UNICODE_STRING LegacyPrefix
= RTL_CONSTANT_STRING(L
"LEGACY_");
1197 UNICODE_STRING UnknownDeviceName
= RTL_CONSTANT_STRING(L
"UNKNOWN");
1198 UNICODE_STRING KeyName
, ClassName
;
1199 PUNICODE_STRING ServiceName1
;
1201 UNICODE_STRING ClassGUID
;
1202 HANDLE InstanceHandle
;
1204 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1205 ParentNode
, PhysicalDeviceObject
, ServiceName
);
1207 Node
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), TAG_IO_DEVNODE
);
1210 return STATUS_INSUFFICIENT_RESOURCES
;
1213 RtlZeroMemory(Node
, sizeof(DEVICE_NODE
));
1216 ServiceName1
= &UnknownDeviceName
;
1218 ServiceName1
= ServiceName
;
1220 if (!PhysicalDeviceObject
)
1222 FullServiceName
.MaximumLength
= LegacyPrefix
.Length
+ ServiceName1
->Length
+ sizeof(UNICODE_NULL
);
1223 FullServiceName
.Length
= 0;
1224 FullServiceName
.Buffer
= ExAllocatePool(PagedPool
, FullServiceName
.MaximumLength
);
1225 if (!FullServiceName
.Buffer
)
1227 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1228 return STATUS_INSUFFICIENT_RESOURCES
;
1231 RtlAppendUnicodeStringToString(&FullServiceName
, &LegacyPrefix
);
1232 RtlAppendUnicodeStringToString(&FullServiceName
, ServiceName1
);
1233 RtlUpcaseUnicodeString(&FullServiceName
, &FullServiceName
, FALSE
);
1235 Status
= PnpRootCreateDevice(&FullServiceName
, NULL
, &PhysicalDeviceObject
, &Node
->InstancePath
);
1236 if (!NT_SUCCESS(Status
))
1238 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status
);
1239 ExFreePool(FullServiceName
.Buffer
);
1240 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1244 /* Create the device key for legacy drivers */
1245 Status
= IopCreateDeviceKeyPath(&Node
->InstancePath
, REG_OPTION_VOLATILE
, &InstanceHandle
);
1246 if (!NT_SUCCESS(Status
))
1248 ExFreePool(FullServiceName
.Buffer
);
1249 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1253 Node
->ServiceName
.MaximumLength
= ServiceName1
->Length
+ sizeof(UNICODE_NULL
);
1254 Node
->ServiceName
.Length
= 0;
1255 Node
->ServiceName
.Buffer
= ExAllocatePool(PagedPool
, Node
->ServiceName
.MaximumLength
);
1256 if (!Node
->ServiceName
.Buffer
)
1258 ZwClose(InstanceHandle
);
1259 ExFreePool(FullServiceName
.Buffer
);
1260 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1264 RtlCopyUnicodeString(&Node
->ServiceName
, ServiceName1
);
1268 RtlInitUnicodeString(&KeyName
, L
"Service");
1269 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName
->Buffer
, ServiceName
->Length
+ sizeof(UNICODE_NULL
));
1272 if (NT_SUCCESS(Status
))
1274 RtlInitUnicodeString(&KeyName
, L
"Legacy");
1276 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
1278 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1280 ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_DWORD
, &LegacyValue
, sizeof(LegacyValue
));
1282 if (NT_SUCCESS(Status
))
1284 RtlInitUnicodeString(&KeyName
, L
"Class");
1285 RtlInitUnicodeString(&ClassName
, L
"LegacyDriver");
1286 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassName
.Buffer
, ClassName
.Length
+ sizeof(UNICODE_NULL
));
1287 if (NT_SUCCESS(Status
))
1289 RtlInitUnicodeString(&KeyName
, L
"ClassGUID");
1290 RtlInitUnicodeString(&ClassGUID
, L
"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
1291 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ClassGUID
.Buffer
, ClassGUID
.Length
+ sizeof(UNICODE_NULL
));
1292 if (NT_SUCCESS(Status
))
1294 // FIXME: Retrieve the real "description" by looking at the "DisplayName" string
1295 // of the corresponding CurrentControlSet\Services\xxx entry for this driver.
1296 RtlInitUnicodeString(&KeyName
, L
"DeviceDesc");
1297 Status
= ZwSetValueKey(InstanceHandle
, &KeyName
, 0, REG_SZ
, ServiceName1
->Buffer
, ServiceName1
->Length
+ sizeof(UNICODE_NULL
));
1303 ZwClose(InstanceHandle
);
1304 ExFreePool(FullServiceName
.Buffer
);
1306 if (!NT_SUCCESS(Status
))
1308 ExFreePool(Node
->ServiceName
.Buffer
);
1309 ExFreePoolWithTag(Node
, TAG_IO_DEVNODE
);
1313 IopDeviceNodeSetFlag(Node
, DNF_LEGACY_DRIVER
);
1314 IopDeviceNodeSetFlag(Node
, DNF_PROCESSED
);
1315 IopDeviceNodeSetFlag(Node
, DNF_ADDED
);
1316 IopDeviceNodeSetFlag(Node
, DNF_STARTED
);
1319 Node
->PhysicalDeviceObject
= PhysicalDeviceObject
;
1321 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= Node
;
1325 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1326 Node
->Parent
= ParentNode
;
1327 Node
->Sibling
= NULL
;
1328 if (ParentNode
->LastChild
== NULL
)
1330 ParentNode
->Child
= Node
;
1331 ParentNode
->LastChild
= Node
;
1335 ParentNode
->LastChild
->Sibling
= Node
;
1336 ParentNode
->LastChild
= Node
;
1338 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1339 Node
->Level
= ParentNode
->Level
+ 1;
1342 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1346 return STATUS_SUCCESS
;
1350 IopFreeDeviceNode(PDEVICE_NODE DeviceNode
)
1353 PDEVICE_NODE PrevSibling
= NULL
;
1355 /* All children must be deleted before a parent is deleted */
1356 ASSERT(!DeviceNode
->Child
);
1357 ASSERT(DeviceNode
->PhysicalDeviceObject
);
1359 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
1361 /* Get previous sibling */
1362 if (DeviceNode
->Parent
&& DeviceNode
->Parent
->Child
!= DeviceNode
)
1364 PrevSibling
= DeviceNode
->Parent
->Child
;
1365 while (PrevSibling
->Sibling
!= DeviceNode
)
1366 PrevSibling
= PrevSibling
->Sibling
;
1369 /* Unlink from parent if it exists */
1370 if (DeviceNode
->Parent
)
1372 if (DeviceNode
->Parent
->LastChild
== DeviceNode
)
1374 DeviceNode
->Parent
->LastChild
= PrevSibling
;
1376 PrevSibling
->Sibling
= NULL
;
1378 if (DeviceNode
->Parent
->Child
== DeviceNode
)
1379 DeviceNode
->Parent
->Child
= DeviceNode
->Sibling
;
1382 /* Unlink from sibling list */
1384 PrevSibling
->Sibling
= DeviceNode
->Sibling
;
1386 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
1388 RtlFreeUnicodeString(&DeviceNode
->InstancePath
);
1390 RtlFreeUnicodeString(&DeviceNode
->ServiceName
);
1392 if (DeviceNode
->ResourceList
)
1394 ExFreePool(DeviceNode
->ResourceList
);
1397 if (DeviceNode
->ResourceListTranslated
)
1399 ExFreePool(DeviceNode
->ResourceListTranslated
);
1402 if (DeviceNode
->ResourceRequirements
)
1404 ExFreePool(DeviceNode
->ResourceRequirements
);
1407 if (DeviceNode
->BootResources
)
1409 ExFreePool(DeviceNode
->BootResources
);
1412 ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceNode
->PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= NULL
;
1413 ExFreePoolWithTag(DeviceNode
, TAG_IO_DEVNODE
);
1415 return STATUS_SUCCESS
;
1420 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject
,
1421 IN PIO_STACK_LOCATION IoStackLocation
,
1422 OUT PVOID
*Information
)
1425 PIO_STACK_LOCATION IrpStack
;
1426 IO_STATUS_BLOCK IoStatusBlock
;
1429 PDEVICE_OBJECT TopDeviceObject
;
1432 /* Call the top of the device stack */
1433 TopDeviceObject
= IoGetAttachedDeviceReference(DeviceObject
);
1435 /* Allocate an IRP */
1436 Irp
= IoAllocateIrp(TopDeviceObject
->StackSize
, FALSE
);
1437 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
1439 /* Initialize to failure */
1440 Irp
->IoStatus
.Status
= IoStatusBlock
.Status
= STATUS_NOT_SUPPORTED
;
1441 Irp
->IoStatus
.Information
= IoStatusBlock
.Information
= 0;
1443 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1444 if ((IoStackLocation
->MajorFunction
== IRP_MJ_PNP
) &&
1445 (IoStackLocation
->MinorFunction
== IRP_MN_FILTER_RESOURCE_REQUIREMENTS
))
1447 /* Copy the resource requirements list into the IOSB */
1448 Irp
->IoStatus
.Information
=
1449 IoStatusBlock
.Information
= (ULONG_PTR
)IoStackLocation
->Parameters
.FilterResourceRequirements
.IoResourceRequirementList
;
1452 /* Initialize the event */
1453 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1456 Irp
->UserIosb
= &IoStatusBlock
;
1457 Irp
->UserEvent
= &Event
;
1460 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1461 IoQueueThreadIrp(Irp
);
1463 /* Copy-in the stack */
1464 IrpStack
= IoGetNextIrpStackLocation(Irp
);
1465 *IrpStack
= *IoStackLocation
;
1467 /* Call the driver */
1468 Status
= IoCallDriver(TopDeviceObject
, Irp
);
1469 if (Status
== STATUS_PENDING
)
1472 KeWaitForSingleObject(&Event
,
1477 Status
= IoStatusBlock
.Status
;
1480 /* Remove the reference */
1481 ObDereferenceObject(TopDeviceObject
);
1483 /* Return the information */
1484 *Information
= (PVOID
)IoStatusBlock
.Information
;
1490 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject
,
1491 IN OUT PIO_STATUS_BLOCK IoStatusBlock
,
1492 IN UCHAR MinorFunction
,
1493 IN PIO_STACK_LOCATION Stack OPTIONAL
)
1495 IO_STACK_LOCATION IoStackLocation
;
1497 /* Fill out the stack information */
1498 RtlZeroMemory(&IoStackLocation
, sizeof(IO_STACK_LOCATION
));
1499 IoStackLocation
.MajorFunction
= IRP_MJ_PNP
;
1500 IoStackLocation
.MinorFunction
= MinorFunction
;
1504 RtlCopyMemory(&IoStackLocation
.Parameters
,
1506 sizeof(Stack
->Parameters
));
1509 /* Do the PnP call */
1510 IoStatusBlock
->Status
= IopSynchronousCall(DeviceObject
,
1512 (PVOID
)&IoStatusBlock
->Information
);
1513 return IoStatusBlock
->Status
;
1517 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1519 PDEVICE_NODE ParentDeviceNode
;
1520 PDEVICE_NODE ChildDeviceNode
;
1521 PDEVICE_NODE NextDeviceNode
;
1524 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1525 ParentDeviceNode
= Context
->DeviceNode
;
1527 /* HACK: Keep a reference to the PDO so we can keep traversing the tree
1528 * if the device is deleted. In a perfect world, children would have to be
1529 * deleted before their parents, and we'd restart the traversal after
1530 * deleting a device node. */
1531 ObReferenceObject(ParentDeviceNode
->PhysicalDeviceObject
);
1533 /* Call the action routine */
1534 Status
= (Context
->Action
)(ParentDeviceNode
, Context
->Context
);
1535 if (!NT_SUCCESS(Status
))
1537 ObDereferenceObject(ParentDeviceNode
->PhysicalDeviceObject
);
1541 /* Traversal of all children nodes */
1542 for (ChildDeviceNode
= ParentDeviceNode
->Child
;
1543 ChildDeviceNode
!= NULL
;
1544 ChildDeviceNode
= NextDeviceNode
)
1546 /* HACK: We need this reference to ensure we can get Sibling below. */
1547 ObReferenceObject(ChildDeviceNode
->PhysicalDeviceObject
);
1549 /* Pass the current device node to the action routine */
1550 Context
->DeviceNode
= ChildDeviceNode
;
1552 Status
= IopTraverseDeviceTreeNode(Context
);
1553 if (!NT_SUCCESS(Status
))
1555 ObDereferenceObject(ChildDeviceNode
->PhysicalDeviceObject
);
1556 ObDereferenceObject(ParentDeviceNode
->PhysicalDeviceObject
);
1560 NextDeviceNode
= ChildDeviceNode
->Sibling
;
1561 ObDereferenceObject(ChildDeviceNode
->PhysicalDeviceObject
);
1564 ObDereferenceObject(ParentDeviceNode
->PhysicalDeviceObject
);
1570 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context
)
1574 DPRINT("Context 0x%p\n", Context
);
1576 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
1577 Context
->DeviceNode
, Context
->FirstDeviceNode
, Context
->Action
, Context
->Context
);
1579 /* Start from the specified device node */
1580 Context
->DeviceNode
= Context
->FirstDeviceNode
;
1582 /* Recursively traverse the device tree */
1583 Status
= IopTraverseDeviceTreeNode(Context
);
1584 if (Status
== STATUS_UNSUCCESSFUL
)
1586 /* The action routine just wanted to terminate the traversal with status
1587 code STATUS_SUCCESS */
1588 Status
= STATUS_SUCCESS
;
1596 * IopCreateDeviceKeyPath
1598 * Creates a registry key
1602 * Name of the key to be created.
1604 * Handle to the newly created key
1607 * This method can create nested trees, so parent of RegistryPath can
1608 * be not existant, and will be created if needed.
1612 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath
,
1613 IN ULONG CreateOptions
,
1616 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(ENUM_ROOT
);
1617 HANDLE hParent
= NULL
, hKey
;
1618 OBJECT_ATTRIBUTES ObjectAttributes
;
1619 UNICODE_STRING KeyName
;
1620 PCWSTR Current
, Last
;
1624 /* Assume failure */
1627 /* Open root key for device instances */
1628 Status
= IopOpenRegistryKeyEx(&hParent
, NULL
, &EnumU
, KEY_CREATE_SUB_KEY
);
1629 if (!NT_SUCCESS(Status
))
1631 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU
, Status
);
1635 Current
= KeyName
.Buffer
= RegistryPath
->Buffer
;
1636 Last
= &RegistryPath
->Buffer
[RegistryPath
->Length
/ sizeof(WCHAR
)];
1638 /* Go up to the end of the string */
1639 while (Current
<= Last
)
1641 if (Current
!= Last
&& *Current
!= L
'\\')
1643 /* Not the end of the string and not a separator */
1648 /* Prepare relative key name */
1649 Length
= (USHORT
)((ULONG_PTR
)Current
- (ULONG_PTR
)KeyName
.Buffer
);
1650 KeyName
.MaximumLength
= KeyName
.Length
= Length
;
1651 DPRINT("Create '%wZ'\n", &KeyName
);
1654 InitializeObjectAttributes(&ObjectAttributes
,
1656 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1659 Status
= ZwCreateKey(&hKey
,
1660 Current
== Last
? KEY_ALL_ACCESS
: KEY_CREATE_SUB_KEY
,
1667 /* Close parent key handle, we don't need it anymore */
1671 /* Key opening/creating failed? */
1672 if (!NT_SUCCESS(Status
))
1674 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName
, Status
);
1678 /* Check if it is the end of the string */
1679 if (Current
== Last
)
1681 /* Yes, return success */
1683 return STATUS_SUCCESS
;
1686 /* Start with this new parent key */
1689 KeyName
.Buffer
= (PWSTR
)Current
;
1692 return STATUS_UNSUCCESSFUL
;
1696 IopSetDeviceInstanceData(HANDLE InstanceKey
,
1697 PDEVICE_NODE DeviceNode
)
1699 OBJECT_ATTRIBUTES ObjectAttributes
;
1700 UNICODE_STRING KeyName
;
1701 HANDLE LogConfKey
, ControlKey
, DeviceParamsKey
;
1706 DPRINT("IopSetDeviceInstanceData() called\n");
1708 /* Create the 'LogConf' key */
1709 RtlInitUnicodeString(&KeyName
, L
"LogConf");
1710 InitializeObjectAttributes(&ObjectAttributes
,
1712 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1715 Status
= ZwCreateKey(&LogConfKey
,
1720 // FIXME? In r53694 it was silently turned from non-volatile into this,
1721 // without any extra warning. Is this still needed??
1722 REG_OPTION_VOLATILE
,
1724 if (NT_SUCCESS(Status
))
1726 /* Set 'BootConfig' value */
1727 if (DeviceNode
->BootResources
!= NULL
)
1729 ResCount
= DeviceNode
->BootResources
->Count
;
1732 RtlInitUnicodeString(&KeyName
, L
"BootConfig");
1733 Status
= ZwSetValueKey(LogConfKey
,
1737 DeviceNode
->BootResources
,
1738 PnpDetermineResourceListSize(DeviceNode
->BootResources
));
1742 /* Set 'BasicConfigVector' value */
1743 if (DeviceNode
->ResourceRequirements
!= NULL
&&
1744 DeviceNode
->ResourceRequirements
->ListSize
!= 0)
1746 RtlInitUnicodeString(&KeyName
, L
"BasicConfigVector");
1747 Status
= ZwSetValueKey(LogConfKey
,
1750 REG_RESOURCE_REQUIREMENTS_LIST
,
1751 DeviceNode
->ResourceRequirements
,
1752 DeviceNode
->ResourceRequirements
->ListSize
);
1755 ZwClose(LogConfKey
);
1758 /* Set the 'ConfigFlags' value */
1759 RtlInitUnicodeString(&KeyName
, L
"ConfigFlags");
1760 Status
= ZwQueryValueKey(InstanceKey
,
1762 KeyValueBasicInformation
,
1766 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
1768 /* Write the default value */
1769 ULONG DefaultConfigFlags
= 0;
1770 Status
= ZwSetValueKey(InstanceKey
,
1774 &DefaultConfigFlags
,
1775 sizeof(DefaultConfigFlags
));
1778 /* Create the 'Control' key */
1779 RtlInitUnicodeString(&KeyName
, L
"Control");
1780 InitializeObjectAttributes(&ObjectAttributes
,
1782 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1785 Status
= ZwCreateKey(&ControlKey
,
1790 REG_OPTION_VOLATILE
,
1792 if (NT_SUCCESS(Status
))
1793 ZwClose(ControlKey
);
1795 /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
1796 if (_wcsnicmp(DeviceNode
->InstancePath
.Buffer
, L
"ACPI\\", 5) == 0)
1798 RtlInitUnicodeString(&KeyName
, L
"Device Parameters");
1799 InitializeObjectAttributes(&ObjectAttributes
,
1801 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1804 Status
= ZwCreateKey(&DeviceParamsKey
,
1809 REG_OPTION_NON_VOLATILE
,
1811 if (NT_SUCCESS(Status
))
1813 ULONG FirmwareIdentified
= 1;
1814 RtlInitUnicodeString(&KeyName
, L
"FirmwareIdentified");
1815 Status
= ZwSetValueKey(DeviceParamsKey
,
1819 &FirmwareIdentified
,
1820 sizeof(FirmwareIdentified
));
1822 ZwClose(DeviceParamsKey
);
1826 DPRINT("IopSetDeviceInstanceData() done\n");
1832 * IopGetParentIdPrefix
1834 * Retrieve (or create) a string which identifies a device.
1838 * Pointer to device node.
1840 * Pointer to the string where is returned the parent node identifier
1843 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1844 * valid and its Buffer field is NULL-terminated. The caller needs to
1845 * to free the string with RtlFreeUnicodeString when it is no longer
1850 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode
,
1851 PUNICODE_STRING ParentIdPrefix
)
1853 const UNICODE_STRING EnumKeyPath
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1854 ULONG KeyNameBufferLength
;
1855 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation
= NULL
;
1856 UNICODE_STRING KeyName
= {0, 0, NULL
};
1857 UNICODE_STRING KeyValue
;
1858 UNICODE_STRING ValueName
;
1863 /* HACK: As long as some devices have a NULL device
1864 * instance path, the following test is required :(
1866 if (DeviceNode
->Parent
->InstancePath
.Length
== 0)
1868 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1869 &DeviceNode
->InstancePath
);
1870 return STATUS_UNSUCCESSFUL
;
1873 /* 1. Try to retrieve ParentIdPrefix from registry */
1874 KeyNameBufferLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
) + sizeof(L
"12345678&12345678");
1875 ParentIdPrefixInformation
= ExAllocatePoolWithTag(PagedPool
,
1876 KeyNameBufferLength
+ sizeof(UNICODE_NULL
),
1878 if (!ParentIdPrefixInformation
)
1880 return STATUS_INSUFFICIENT_RESOURCES
;
1884 KeyName
.MaximumLength
= EnumKeyPath
.Length
+
1885 DeviceNode
->Parent
->InstancePath
.Length
+
1886 sizeof(UNICODE_NULL
);
1887 KeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1888 KeyName
.MaximumLength
,
1890 if (!KeyName
.Buffer
)
1892 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1896 RtlCopyUnicodeString(&KeyName
, &EnumKeyPath
);
1897 RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->Parent
->InstancePath
);
1899 Status
= IopOpenRegistryKeyEx(&hKey
, NULL
, &KeyName
, KEY_QUERY_VALUE
| KEY_SET_VALUE
);
1900 if (!NT_SUCCESS(Status
))
1904 RtlInitUnicodeString(&ValueName
, L
"ParentIdPrefix");
1905 Status
= ZwQueryValueKey(hKey
,
1907 KeyValuePartialInformation
,
1908 ParentIdPrefixInformation
,
1909 KeyNameBufferLength
,
1910 &KeyNameBufferLength
);
1911 if (NT_SUCCESS(Status
))
1913 if (ParentIdPrefixInformation
->Type
!= REG_SZ
)
1915 Status
= STATUS_UNSUCCESSFUL
;
1919 KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1920 KeyValue
.Length
= KeyValue
.MaximumLength
- sizeof(UNICODE_NULL
);
1921 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1922 ASSERT(KeyValue
.Buffer
[KeyValue
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
);
1926 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1928 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
1929 KeyValue
.MaximumLength
= (USHORT
)ParentIdPrefixInformation
->DataLength
;
1930 KeyValue
.Length
= KeyValue
.MaximumLength
- sizeof(UNICODE_NULL
);
1931 KeyValue
.Buffer
= (PWSTR
)ParentIdPrefixInformation
->Data
;
1932 ASSERT(KeyValue
.Buffer
[KeyValue
.Length
/ sizeof(WCHAR
)] == UNICODE_NULL
);
1936 /* 2. Create the ParentIdPrefix value */
1937 crc32
= RtlComputeCrc32(0,
1938 (PUCHAR
)DeviceNode
->Parent
->InstancePath
.Buffer
,
1939 DeviceNode
->Parent
->InstancePath
.Length
);
1941 RtlStringCbPrintfW((PWSTR
)ParentIdPrefixInformation
,
1942 KeyNameBufferLength
,
1944 DeviceNode
->Parent
->Level
,
1946 RtlInitUnicodeString(&KeyValue
, (PWSTR
)ParentIdPrefixInformation
);
1948 /* 3. Try to write the ParentIdPrefix to registry */
1949 Status
= ZwSetValueKey(hKey
,
1954 ((ULONG
)wcslen(KeyValue
.Buffer
) + 1) * sizeof(WCHAR
));
1957 if (NT_SUCCESS(Status
))
1959 /* Duplicate the string to return it */
1960 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1964 ExFreePoolWithTag(ParentIdPrefixInformation
, TAG_IO
);
1965 RtlFreeUnicodeString(&KeyName
);
1977 _In_ BUS_QUERY_ID_TYPE QueryType
)
1982 ULONG SeparatorsCount
= 0;
1983 PWCHAR PtrPrevChar
= NULL
;
1984 ULONG MaxSeparators
;
1991 case BusQueryDeviceID
:
1992 MaxSeparators
= MAX_SEPARATORS_DEVICEID
;
1995 case BusQueryInstanceID
:
1996 MaxSeparators
= MAX_SEPARATORS_INSTANCEID
;
2000 case BusQueryHardwareIDs
:
2001 case BusQueryCompatibleIDs
:
2002 MaxSeparators
= MAX_SEPARATORS_DEVICEID
;
2007 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType
);
2011 StringEnd
= Id
+ MAX_DEVICE_ID_LEN
;
2013 for (PtrChar
= Id
; PtrChar
< StringEnd
; PtrChar
++)
2017 if (Char
== UNICODE_NULL
)
2019 if (!IsMultiSz
|| (PtrPrevChar
&& PtrChar
== PtrPrevChar
+ 1))
2021 if (MaxSeparators
== SeparatorsCount
|| IsMultiSz
)
2026 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
2027 SeparatorsCount
, MaxSeparators
);
2031 StringEnd
= PtrChar
+ MAX_DEVICE_ID_LEN
+ 1;
2032 PtrPrevChar
= PtrChar
;
2033 SeparatorsCount
= 0;
2035 else if (Char
< ' ' || Char
> 0x7F || Char
== ',')
2037 DPRINT1("IopValidateID: Invalid character - %04X\n", Char
);
2040 else if (Char
== ' ')
2044 else if (Char
== '\\')
2048 if (SeparatorsCount
> MaxSeparators
)
2050 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
2051 SeparatorsCount
, MaxSeparators
);
2057 DPRINT1("IopValidateID: Not terminated ID\n");
2065 IopQueryHardwareIds(PDEVICE_NODE DeviceNode
,
2068 IO_STACK_LOCATION Stack
;
2069 IO_STATUS_BLOCK IoStatusBlock
;
2071 UNICODE_STRING ValueName
;
2073 ULONG Length
, TotalLength
;
2076 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2078 RtlZeroMemory(&Stack
, sizeof(Stack
));
2079 Stack
.Parameters
.QueryId
.IdType
= BusQueryHardwareIDs
;
2080 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2084 if (NT_SUCCESS(Status
))
2086 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryHardwareIDs
);
2090 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode
);
2095 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
2096 DPRINT("Hardware IDs:\n");
2099 DPRINT(" %S\n", Ptr
);
2100 Length
= (ULONG
)wcslen(Ptr
) + 1;
2103 TotalLength
+= Length
;
2105 DPRINT("TotalLength: %hu\n", TotalLength
);
2108 RtlInitUnicodeString(&ValueName
, L
"HardwareID");
2109 Status
= ZwSetValueKey(InstanceKey
,
2113 (PVOID
)IoStatusBlock
.Information
,
2114 (TotalLength
+ 1) * sizeof(WCHAR
));
2115 if (!NT_SUCCESS(Status
))
2117 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2122 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2129 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode
,
2132 IO_STACK_LOCATION Stack
;
2133 IO_STATUS_BLOCK IoStatusBlock
;
2135 UNICODE_STRING ValueName
;
2137 ULONG Length
, TotalLength
;
2140 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2142 RtlZeroMemory(&Stack
, sizeof(Stack
));
2143 Stack
.Parameters
.QueryId
.IdType
= BusQueryCompatibleIDs
;
2144 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2148 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2150 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryCompatibleIDs
);
2154 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode
);
2159 Ptr
= (PWSTR
)IoStatusBlock
.Information
;
2160 DPRINT("Compatible IDs:\n");
2163 DPRINT(" %S\n", Ptr
);
2164 Length
= (ULONG
)wcslen(Ptr
) + 1;
2167 TotalLength
+= Length
;
2169 DPRINT("TotalLength: %hu\n", TotalLength
);
2172 RtlInitUnicodeString(&ValueName
, L
"CompatibleIDs");
2173 Status
= ZwSetValueKey(InstanceKey
,
2177 (PVOID
)IoStatusBlock
.Information
,
2178 (TotalLength
+ 1) * sizeof(WCHAR
));
2179 if (!NT_SUCCESS(Status
))
2181 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status
);
2186 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status
);
2193 IopCreateDeviceInstancePath(
2194 _In_ PDEVICE_NODE DeviceNode
,
2195 _Out_ PUNICODE_STRING InstancePath
)
2197 IO_STATUS_BLOCK IoStatusBlock
;
2198 UNICODE_STRING DeviceId
;
2199 UNICODE_STRING InstanceId
;
2200 IO_STACK_LOCATION Stack
;
2202 UNICODE_STRING ParentIdPrefix
= { 0, 0, NULL
};
2203 DEVICE_CAPABILITIES DeviceCapabilities
;
2206 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2208 Stack
.Parameters
.QueryId
.IdType
= BusQueryDeviceID
;
2209 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2213 if (!NT_SUCCESS(Status
))
2215 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status
);
2219 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryDeviceID
);
2223 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode
);
2226 /* Save the device id string */
2227 RtlInitUnicodeString(&DeviceId
, (PWSTR
)IoStatusBlock
.Information
);
2229 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
2231 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCapabilities
);
2232 if (!NT_SUCCESS(Status
))
2234 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status
);
2235 RtlFreeUnicodeString(&DeviceId
);
2239 /* This bit is only check after enumeration */
2240 if (DeviceCapabilities
.HardwareDisabled
)
2242 /* FIXME: Cleanup device */
2243 DeviceNode
->Flags
|= DNF_DISABLED
;
2244 RtlFreeUnicodeString(&DeviceId
);
2245 return STATUS_PLUGPLAY_NO_DEVICE
;
2249 DeviceNode
->Flags
&= ~DNF_DISABLED
;
2252 if (!DeviceCapabilities
.UniqueID
)
2254 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2255 DPRINT("Instance ID is not unique\n");
2256 Status
= IopGetParentIdPrefix(DeviceNode
, &ParentIdPrefix
);
2257 if (!NT_SUCCESS(Status
))
2259 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status
);
2260 RtlFreeUnicodeString(&DeviceId
);
2265 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2267 Stack
.Parameters
.QueryId
.IdType
= BusQueryInstanceID
;
2268 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2272 if (!NT_SUCCESS(Status
))
2274 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status
);
2275 ASSERT(IoStatusBlock
.Information
== 0);
2278 if (IoStatusBlock
.Information
)
2280 IsValidID
= IopValidateID((PWCHAR
)IoStatusBlock
.Information
, BusQueryInstanceID
);
2284 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode
);
2288 RtlInitUnicodeString(&InstanceId
,
2289 (PWSTR
)IoStatusBlock
.Information
);
2291 InstancePath
->Length
= 0;
2292 InstancePath
->MaximumLength
= DeviceId
.Length
+ sizeof(WCHAR
) +
2293 ParentIdPrefix
.Length
+
2295 sizeof(UNICODE_NULL
);
2296 if (ParentIdPrefix
.Length
&& InstanceId
.Length
)
2298 InstancePath
->MaximumLength
+= sizeof(WCHAR
);
2301 InstancePath
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
2302 InstancePath
->MaximumLength
,
2304 if (!InstancePath
->Buffer
)
2306 RtlFreeUnicodeString(&InstanceId
);
2307 RtlFreeUnicodeString(&ParentIdPrefix
);
2308 RtlFreeUnicodeString(&DeviceId
);
2309 return STATUS_INSUFFICIENT_RESOURCES
;
2312 /* Start with the device id */
2313 RtlCopyUnicodeString(InstancePath
, &DeviceId
);
2314 RtlAppendUnicodeToString(InstancePath
, L
"\\");
2316 /* Add information from parent bus device to InstancePath */
2317 RtlAppendUnicodeStringToString(InstancePath
, &ParentIdPrefix
);
2318 if (ParentIdPrefix
.Length
&& InstanceId
.Length
)
2320 RtlAppendUnicodeToString(InstancePath
, L
"&");
2323 /* Finally, add the id returned by the driver stack */
2324 RtlAppendUnicodeStringToString(InstancePath
, &InstanceId
);
2327 * FIXME: Check for valid characters, if there is invalid characters
2331 RtlFreeUnicodeString(&InstanceId
);
2332 RtlFreeUnicodeString(&DeviceId
);
2333 RtlFreeUnicodeString(&ParentIdPrefix
);
2335 return STATUS_SUCCESS
;
2339 * IopActionInterrogateDeviceStack
2341 * Retrieve information for all (direct) child nodes of a parent node.
2345 * Pointer to device node.
2347 * Pointer to parent node to retrieve child node information for.
2350 * Any errors that occur are logged instead so that all child services have a chance
2351 * of being interrogated.
2355 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode
,
2358 IO_STATUS_BLOCK IoStatusBlock
;
2359 PWSTR DeviceDescription
;
2360 PWSTR LocationInformation
;
2361 PDEVICE_NODE ParentDeviceNode
;
2362 IO_STACK_LOCATION Stack
;
2364 ULONG RequiredLength
;
2366 HANDLE InstanceKey
= NULL
;
2367 UNICODE_STRING ValueName
;
2368 UNICODE_STRING InstancePathU
;
2369 PDEVICE_OBJECT OldDeviceObject
;
2371 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode
, Context
);
2372 DPRINT("PDO 0x%p\n", DeviceNode
->PhysicalDeviceObject
);
2374 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2377 * We are called for the parent too, but we don't need to do special
2378 * handling for this node
2380 if (DeviceNode
== ParentDeviceNode
)
2382 DPRINT("Success\n");
2383 return STATUS_SUCCESS
;
2387 * Make sure this device node is a direct child of the parent device node
2388 * that is given as an argument
2390 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2392 DPRINT("Skipping 2+ level child\n");
2393 return STATUS_SUCCESS
;
2396 /* Skip processing if it was already completed before */
2397 if (DeviceNode
->Flags
& DNF_PROCESSED
)
2400 return STATUS_SUCCESS
;
2404 Status
= ZwQueryDefaultLocale(FALSE
, &LocaleId
);
2405 if (!NT_SUCCESS(Status
))
2407 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status
);
2412 * FIXME: For critical errors, cleanup and disable device, but always
2413 * return STATUS_SUCCESS.
2416 Status
= IopCreateDeviceInstancePath(DeviceNode
, &InstancePathU
);
2417 if (!NT_SUCCESS(Status
))
2419 if (Status
!= STATUS_PLUGPLAY_NO_DEVICE
)
2421 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status
);
2424 /* We have to return success otherwise we abort the traverse operation */
2425 return STATUS_SUCCESS
;
2428 /* Verify that this is not a duplicate */
2429 OldDeviceObject
= IopGetDeviceObjectFromDeviceInstance(&InstancePathU
);
2430 if (OldDeviceObject
!= NULL
)
2432 PDEVICE_NODE OldDeviceNode
= IopGetDeviceNode(OldDeviceObject
);
2434 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU
);
2435 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode
->Parent
->InstancePath
);
2436 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode
->Parent
->InstancePath
);
2438 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR
,
2440 (ULONG_PTR
)DeviceNode
->PhysicalDeviceObject
,
2441 (ULONG_PTR
)OldDeviceObject
,
2445 DeviceNode
->InstancePath
= InstancePathU
;
2447 DPRINT("InstancePath is %S\n", DeviceNode
->InstancePath
.Buffer
);
2450 * Create registry key for the instance id, if it doesn't exist yet
2452 Status
= IopCreateDeviceKeyPath(&DeviceNode
->InstancePath
, REG_OPTION_NON_VOLATILE
, &InstanceKey
);
2453 if (!NT_SUCCESS(Status
))
2455 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status
);
2457 /* We have to return success otherwise we abort the traverse operation */
2458 return STATUS_SUCCESS
;
2461 IopQueryHardwareIds(DeviceNode
, InstanceKey
);
2463 IopQueryCompatibleIds(DeviceNode
, InstanceKey
);
2465 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2467 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextDescription
;
2468 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2469 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2471 IRP_MN_QUERY_DEVICE_TEXT
,
2473 DeviceDescription
= NT_SUCCESS(Status
) ? (PWSTR
)IoStatusBlock
.Information
2475 /* This key is mandatory, so even if the Irp fails, we still write it */
2476 RtlInitUnicodeString(&ValueName
, L
"DeviceDesc");
2477 if (ZwQueryValueKey(InstanceKey
, &ValueName
, KeyValueBasicInformation
, NULL
, 0, &RequiredLength
) == STATUS_OBJECT_NAME_NOT_FOUND
)
2479 if (DeviceDescription
&&
2480 *DeviceDescription
!= UNICODE_NULL
)
2482 /* This key is overriden when a driver is installed. Don't write the
2483 * new description if another one already exists */
2484 Status
= ZwSetValueKey(InstanceKey
,
2489 ((ULONG
)wcslen(DeviceDescription
) + 1) * sizeof(WCHAR
));
2493 UNICODE_STRING DeviceDesc
= RTL_CONSTANT_STRING(L
"Unknown device");
2494 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status
);
2496 Status
= ZwSetValueKey(InstanceKey
,
2501 DeviceDesc
.MaximumLength
);
2502 if (!NT_SUCCESS(Status
))
2504 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status
);
2510 if (DeviceDescription
)
2512 ExFreePoolWithTag(DeviceDescription
, 0);
2515 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2517 Stack
.Parameters
.QueryDeviceText
.DeviceTextType
= DeviceTextLocationInformation
;
2518 Stack
.Parameters
.QueryDeviceText
.LocaleId
= LocaleId
;
2519 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2521 IRP_MN_QUERY_DEVICE_TEXT
,
2523 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2525 LocationInformation
= (PWSTR
)IoStatusBlock
.Information
;
2526 DPRINT("LocationInformation: %S\n", LocationInformation
);
2527 RtlInitUnicodeString(&ValueName
, L
"LocationInformation");
2528 Status
= ZwSetValueKey(InstanceKey
,
2532 LocationInformation
,
2533 ((ULONG
)wcslen(LocationInformation
) + 1) * sizeof(WCHAR
));
2534 if (!NT_SUCCESS(Status
))
2536 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
2539 ExFreePoolWithTag(LocationInformation
, 0);
2543 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2546 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2548 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2550 IRP_MN_QUERY_BUS_INFORMATION
,
2552 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2554 PPNP_BUS_INFORMATION BusInformation
= (PPNP_BUS_INFORMATION
)IoStatusBlock
.Information
;
2556 DeviceNode
->ChildBusNumber
= BusInformation
->BusNumber
;
2557 DeviceNode
->ChildInterfaceType
= BusInformation
->LegacyBusType
;
2558 DeviceNode
->ChildBusTypeIndex
= IopGetBusTypeGuidIndex(&BusInformation
->BusTypeGuid
);
2559 ExFreePoolWithTag(BusInformation
, 0);
2563 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2565 DeviceNode
->ChildBusNumber
= 0xFFFFFFF0;
2566 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
2567 DeviceNode
->ChildBusTypeIndex
= -1;
2570 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2572 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2574 IRP_MN_QUERY_RESOURCES
,
2576 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
2578 DeviceNode
->BootResources
= (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
2579 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
2583 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
2584 DeviceNode
->BootResources
= NULL
;
2587 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2589 Status
= IopInitiatePnpIrp(DeviceNode
->PhysicalDeviceObject
,
2591 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
2593 if (NT_SUCCESS(Status
))
2595 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
2599 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
2600 DeviceNode
->ResourceRequirements
= NULL
;
2603 if (InstanceKey
!= NULL
)
2605 IopSetDeviceInstanceData(InstanceKey
, DeviceNode
);
2608 ZwClose(InstanceKey
);
2610 IopDeviceNodeSetFlag(DeviceNode
, DNF_PROCESSED
);
2612 if (!IopDeviceNodeHasFlag(DeviceNode
, DNF_LEGACY_DRIVER
))
2614 /* Report the device to the user-mode pnp manager */
2615 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED
,
2616 &DeviceNode
->InstancePath
);
2619 return STATUS_SUCCESS
;
2624 IopHandleDeviceRemoval(
2625 IN PDEVICE_NODE DeviceNode
,
2626 IN PDEVICE_RELATIONS DeviceRelations
)
2628 PDEVICE_NODE Child
= DeviceNode
->Child
, NextChild
;
2632 if (DeviceNode
== IopRootDeviceNode
)
2635 while (Child
!= NULL
)
2637 NextChild
= Child
->Sibling
;
2640 for (i
= 0; DeviceRelations
&& i
< DeviceRelations
->Count
; i
++)
2642 if (IopGetDeviceNode(DeviceRelations
->Objects
[i
]) == Child
)
2649 if (!Found
&& !(Child
->Flags
& DNF_WILL_BE_REMOVED
))
2651 /* Send removal IRPs to all of its children */
2652 IopPrepareDeviceForRemoval(Child
->PhysicalDeviceObject
, TRUE
);
2654 /* Send the surprise removal IRP */
2655 IopSendSurpriseRemoval(Child
->PhysicalDeviceObject
);
2657 /* Tell the user-mode PnP manager that a device was removed */
2658 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
2659 &Child
->InstancePath
);
2661 /* Send the remove device IRP */
2662 IopSendRemoveDevice(Child
->PhysicalDeviceObject
);
2671 IN PDEVICE_OBJECT DeviceObject
)
2673 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
2674 DEVICETREE_TRAVERSE_CONTEXT Context
;
2675 PDEVICE_RELATIONS DeviceRelations
;
2676 PDEVICE_OBJECT ChildDeviceObject
;
2677 IO_STATUS_BLOCK IoStatusBlock
;
2678 PDEVICE_NODE ChildDeviceNode
;
2679 IO_STACK_LOCATION Stack
;
2683 DPRINT("DeviceObject 0x%p\n", DeviceObject
);
2685 if (DeviceNode
->Flags
& DNF_NEED_ENUMERATION_ONLY
)
2687 DeviceNode
->Flags
&= ~DNF_NEED_ENUMERATION_ONLY
;
2689 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2690 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL
,
2691 &DeviceNode
->InstancePath
);
2694 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2696 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
2698 Status
= IopInitiatePnpIrp(
2701 IRP_MN_QUERY_DEVICE_RELATIONS
,
2703 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
2705 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
2709 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
2712 * Send removal IRPs for devices that have disappeared
2713 * NOTE: This code handles the case where no relations are specified
2715 IopHandleDeviceRemoval(DeviceNode
, DeviceRelations
);
2717 /* Now we bail if nothing was returned */
2718 if (!DeviceRelations
)
2720 /* We're all done */
2721 DPRINT("No PDOs\n");
2722 return STATUS_SUCCESS
;
2725 DPRINT("Got %u PDOs\n", DeviceRelations
->Count
);
2728 * Create device nodes for all discovered devices
2730 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
2732 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
2733 ASSERT((ChildDeviceObject
->Flags
& DO_DEVICE_INITIALIZING
) == 0);
2735 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
2736 if (!ChildDeviceNode
)
2738 /* One doesn't exist, create it */
2739 Status
= IopCreateDeviceNode(
2744 if (NT_SUCCESS(Status
))
2746 /* Mark the node as enumerated */
2747 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2749 /* Mark the DO as bus enumerated */
2750 ChildDeviceObject
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
2754 /* Ignore this DO */
2755 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status
, i
);
2756 ObDereferenceObject(ChildDeviceObject
);
2761 /* Mark it as enumerated */
2762 ChildDeviceNode
->Flags
|= DNF_ENUMERATED
;
2763 ObDereferenceObject(ChildDeviceObject
);
2766 ExFreePool(DeviceRelations
);
2769 * Retrieve information about all discovered children from the bus driver
2771 IopInitDeviceTreeTraverseContext(
2774 IopActionInterrogateDeviceStack
,
2777 Status
= IopTraverseDeviceTree(&Context
);
2778 if (!NT_SUCCESS(Status
))
2780 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2785 * Retrieve configuration from the registry for discovered children
2787 IopInitDeviceTreeTraverseContext(
2790 IopActionConfigureChildServices
,
2793 Status
= IopTraverseDeviceTree(&Context
);
2794 if (!NT_SUCCESS(Status
))
2796 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status
);
2801 * Initialize services for discovered children.
2803 Status
= IopInitializePnpServices(DeviceNode
);
2804 if (!NT_SUCCESS(Status
))
2806 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status
);
2810 DPRINT("IopEnumerateDevice() finished\n");
2811 return STATUS_SUCCESS
;
2816 * IopActionConfigureChildServices
2818 * Retrieve configuration for all (direct) child nodes of a parent node.
2822 * Pointer to device node.
2824 * Pointer to parent node to retrieve child node configuration for.
2827 * Any errors that occur are logged instead so that all child services have a chance of beeing
2832 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode
,
2835 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
2836 PDEVICE_NODE ParentDeviceNode
;
2837 PUNICODE_STRING Service
;
2838 UNICODE_STRING ClassGUID
;
2840 DEVICE_CAPABILITIES DeviceCaps
;
2842 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode
, Context
);
2844 ParentDeviceNode
= (PDEVICE_NODE
)Context
;
2847 * We are called for the parent too, but we don't need to do special
2848 * handling for this node
2850 if (DeviceNode
== ParentDeviceNode
)
2852 DPRINT("Success\n");
2853 return STATUS_SUCCESS
;
2857 * Make sure this device node is a direct child of the parent device node
2858 * that is given as an argument
2861 if (DeviceNode
->Parent
!= ParentDeviceNode
)
2863 DPRINT("Skipping 2+ level child\n");
2864 return STATUS_SUCCESS
;
2867 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
2869 DPRINT1("Child not ready to be configured\n");
2870 return STATUS_SUCCESS
;
2873 if (!(DeviceNode
->Flags
& (DNF_DISABLED
| DNF_STARTED
| DNF_ADDED
)))
2875 UNICODE_STRING RegKey
;
2877 /* Install the service for this if it's in the CDDB */
2878 IopInstallCriticalDevice(DeviceNode
);
2881 * Retrieve configuration from Enum key
2884 Service
= &DeviceNode
->ServiceName
;
2886 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2887 RtlInitUnicodeString(Service
, NULL
);
2888 RtlInitUnicodeString(&ClassGUID
, NULL
);
2890 QueryTable
[0].Name
= L
"Service";
2891 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2892 QueryTable
[0].EntryContext
= Service
;
2894 QueryTable
[1].Name
= L
"ClassGUID";
2895 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
2896 QueryTable
[1].EntryContext
= &ClassGUID
;
2897 QueryTable
[1].DefaultType
= REG_SZ
;
2898 QueryTable
[1].DefaultData
= L
"";
2899 QueryTable
[1].DefaultLength
= 0;
2902 RegKey
.MaximumLength
= sizeof(ENUM_ROOT
) + sizeof(WCHAR
) + DeviceNode
->InstancePath
.Length
;
2903 RegKey
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
2904 RegKey
.MaximumLength
,
2906 if (RegKey
.Buffer
== NULL
)
2908 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2909 return STATUS_INSUFFICIENT_RESOURCES
;
2912 RtlAppendUnicodeToString(&RegKey
, ENUM_ROOT
);
2913 RtlAppendUnicodeToString(&RegKey
, L
"\\");
2914 RtlAppendUnicodeStringToString(&RegKey
, &DeviceNode
->InstancePath
);
2916 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2917 RegKey
.Buffer
, QueryTable
, NULL
, NULL
);
2918 ExFreePoolWithTag(RegKey
.Buffer
, TAG_IO
);
2920 if (!NT_SUCCESS(Status
))
2922 /* FIXME: Log the error */
2923 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2924 &DeviceNode
->InstancePath
, Status
);
2925 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2926 return STATUS_SUCCESS
;
2929 if (Service
->Buffer
== NULL
)
2931 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
)) &&
2932 DeviceCaps
.RawDeviceOK
)
2934 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode
->InstancePath
, &ParentDeviceNode
->ServiceName
);
2935 RtlInitEmptyUnicodeString(&DeviceNode
->ServiceName
, NULL
, 0);
2937 else if (ClassGUID
.Length
!= 0)
2939 /* Device has a ClassGUID value, but no Service value.
2940 * Suppose it is using the NULL driver, so state the
2941 * device is started */
2942 DPRINT("%wZ is using NULL driver\n", &DeviceNode
->InstancePath
);
2943 IopDeviceNodeSetFlag(DeviceNode
, DNF_STARTED
);
2947 DeviceNode
->Problem
= CM_PROB_FAILED_INSTALL
;
2948 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
2950 return STATUS_SUCCESS
;
2953 DPRINT("Got Service %S\n", Service
->Buffer
);
2956 return STATUS_SUCCESS
;
2960 * IopActionInitChildServices
2962 * Initialize the service for all (direct) child nodes of a parent node
2966 * Pointer to device node.
2968 * Pointer to parent node to initialize child node services for.
2971 * If the driver image for a service is not loaded and initialized
2972 * it is done here too. Any errors that occur are logged instead so
2973 * that all child services have a chance of being initialized.
2977 IopActionInitChildServices(PDEVICE_NODE DeviceNode
,
2980 PDEVICE_NODE ParentDeviceNode
;
2982 BOOLEAN BootDrivers
= !PnpSystemInit
;
2984 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode
, Context
);
2986 ParentDeviceNode
= Context
;
2989 * We are called for the parent too, but we don't need to do special
2990 * handling for this node
2992 if (DeviceNode
== ParentDeviceNode
)
2994 DPRINT("Success\n");
2995 return STATUS_SUCCESS
;
2999 * We don't want to check for a direct child because
3000 * this function is called during boot to reinitialize
3001 * devices with drivers that couldn't load yet due to
3002 * stage 0 limitations (ie can't load from disk yet).
3005 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
3007 DPRINT1("Child not ready to be added\n");
3008 return STATUS_SUCCESS
;
3011 if (IopDeviceNodeHasFlag(DeviceNode
, DNF_STARTED
) ||
3012 IopDeviceNodeHasFlag(DeviceNode
, DNF_ADDED
) ||
3013 IopDeviceNodeHasFlag(DeviceNode
, DNF_DISABLED
))
3014 return STATUS_SUCCESS
;
3016 if (DeviceNode
->ServiceName
.Buffer
== NULL
)
3018 /* We don't need to worry about loading the driver because we're
3019 * being driven in raw mode so our parent must be loaded to get here */
3020 Status
= IopInitializeDevice(DeviceNode
, NULL
);
3021 if (NT_SUCCESS(Status
))
3023 Status
= IopStartDevice(DeviceNode
);
3024 if (!NT_SUCCESS(Status
))
3026 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
3027 &DeviceNode
->InstancePath
, Status
);
3033 PLDR_DATA_TABLE_ENTRY ModuleObject
;
3034 PDRIVER_OBJECT DriverObject
;
3036 KeEnterCriticalRegion();
3037 ExAcquireResourceExclusiveLite(&IopDriverLoadResource
, TRUE
);
3038 /* Get existing DriverObject pointer (in case the driver has
3039 already been loaded and initialized) */
3040 Status
= IopGetDriverObject(
3042 &DeviceNode
->ServiceName
,
3045 if (!NT_SUCCESS(Status
))
3047 /* Driver is not initialized, try to load it */
3048 Status
= IopLoadServiceModule(&DeviceNode
->ServiceName
, &ModuleObject
);
3050 if (NT_SUCCESS(Status
) || Status
== STATUS_IMAGE_ALREADY_LOADED
)
3052 /* Initialize the driver */
3053 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
3054 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
3055 if (!NT_SUCCESS(Status
)) DeviceNode
->Problem
= CM_PROB_FAILED_DRIVER_ENTRY
;
3057 else if (Status
== STATUS_DRIVER_UNABLE_TO_LOAD
)
3059 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode
->ServiceName
);
3060 DeviceNode
->Problem
= CM_PROB_DISABLED_SERVICE
;
3064 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
3065 &DeviceNode
->ServiceName
, Status
);
3066 if (!BootDrivers
) DeviceNode
->Problem
= CM_PROB_DRIVER_FAILED_LOAD
;
3069 ExReleaseResourceLite(&IopDriverLoadResource
);
3070 KeLeaveCriticalRegion();
3072 /* Driver is loaded and initialized at this point */
3073 if (NT_SUCCESS(Status
))
3075 /* Initialize the device, including all filters */
3076 Status
= PipCallDriverAddDevice(DeviceNode
, FALSE
, DriverObject
);
3078 /* Remove the extra reference */
3079 ObDereferenceObject(DriverObject
);
3084 * Don't disable when trying to load only boot drivers
3088 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
3093 return STATUS_SUCCESS
;
3097 * IopInitializePnpServices
3099 * Initialize services for discovered children
3103 * Top device node to start initializing services.
3109 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode
)
3111 DEVICETREE_TRAVERSE_CONTEXT Context
;
3113 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode
);
3115 IopInitDeviceTreeTraverseContext(
3118 IopActionInitChildServices
,
3121 return IopTraverseDeviceTree(&Context
);
3127 IopEnumerateDetectedDevices(
3129 IN PUNICODE_STRING RelativePath OPTIONAL
,
3131 IN BOOLEAN EnumerateSubKeys
,
3132 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources
,
3133 IN ULONG ParentBootResourcesLength
)
3135 UNICODE_STRING IdentifierU
= RTL_CONSTANT_STRING(L
"Identifier");
3136 UNICODE_STRING HardwareIDU
= RTL_CONSTANT_STRING(L
"HardwareID");
3137 UNICODE_STRING ConfigurationDataU
= RTL_CONSTANT_STRING(L
"Configuration Data");
3138 UNICODE_STRING BootConfigU
= RTL_CONSTANT_STRING(L
"BootConfig");
3139 UNICODE_STRING LogConfU
= RTL_CONSTANT_STRING(L
"LogConf");
3140 OBJECT_ATTRIBUTES ObjectAttributes
;
3141 HANDLE hDevicesKey
= NULL
;
3142 HANDLE hDeviceKey
= NULL
;
3143 HANDLE hLevel1Key
, hLevel2Key
= NULL
, hLogConf
;
3144 UNICODE_STRING Level2NameU
;
3145 WCHAR Level2Name
[5];
3146 ULONG IndexDevice
= 0;
3148 PKEY_BASIC_INFORMATION pDeviceInformation
= NULL
;
3149 ULONG DeviceInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + 50 * sizeof(WCHAR
);
3150 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation
= NULL
;
3151 ULONG ValueInfoLength
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 50 * sizeof(WCHAR
);
3152 UNICODE_STRING DeviceName
, ValueName
;
3154 PCM_FULL_RESOURCE_DESCRIPTOR BootResources
= NULL
;
3155 ULONG BootResourcesLength
;
3158 const UNICODE_STRING IdentifierSerial
= RTL_CONSTANT_STRING(L
"SerialController");
3159 UNICODE_STRING HardwareIdSerial
= RTL_CONSTANT_STRING(L
"*PNP0501\0");
3160 static ULONG DeviceIndexSerial
= 0;
3161 const UNICODE_STRING IdentifierKeyboard
= RTL_CONSTANT_STRING(L
"KeyboardController");
3162 UNICODE_STRING HardwareIdKeyboard
= RTL_CONSTANT_STRING(L
"*PNP0303\0");
3163 static ULONG DeviceIndexKeyboard
= 0;
3164 const UNICODE_STRING IdentifierMouse
= RTL_CONSTANT_STRING(L
"PointerController");
3165 UNICODE_STRING HardwareIdMouse
= RTL_CONSTANT_STRING(L
"*PNP0F13\0");
3166 static ULONG DeviceIndexMouse
= 0;
3167 const UNICODE_STRING IdentifierParallel
= RTL_CONSTANT_STRING(L
"ParallelController");
3168 UNICODE_STRING HardwareIdParallel
= RTL_CONSTANT_STRING(L
"*PNP0400\0");
3169 static ULONG DeviceIndexParallel
= 0;
3170 const UNICODE_STRING IdentifierFloppy
= RTL_CONSTANT_STRING(L
"FloppyDiskPeripheral");
3171 UNICODE_STRING HardwareIdFloppy
= RTL_CONSTANT_STRING(L
"*PNP0700\0");
3172 static ULONG DeviceIndexFloppy
= 0;
3173 UNICODE_STRING HardwareIdKey
;
3174 PUNICODE_STRING pHardwareId
;
3175 ULONG DeviceIndex
= 0;
3176 PUCHAR CmResourceList
;
3181 Status
= IopOpenRegistryKeyEx(&hDevicesKey
, hBaseKey
, RelativePath
, KEY_ENUMERATE_SUB_KEYS
);
3182 if (!NT_SUCCESS(Status
))
3184 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3189 hDevicesKey
= hBaseKey
;
3191 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3192 if (!pDeviceInformation
)
3194 DPRINT("ExAllocatePool() failed\n");
3195 Status
= STATUS_NO_MEMORY
;
3199 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3200 if (!pValueInformation
)
3202 DPRINT("ExAllocatePool() failed\n");
3203 Status
= STATUS_NO_MEMORY
;
3209 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3210 if (Status
== STATUS_NO_MORE_ENTRIES
)
3212 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3214 ExFreePool(pDeviceInformation
);
3215 DeviceInfoLength
= RequiredSize
;
3216 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3217 if (!pDeviceInformation
)
3219 DPRINT("ExAllocatePool() failed\n");
3220 Status
= STATUS_NO_MEMORY
;
3223 Status
= ZwEnumerateKey(hDevicesKey
, IndexDevice
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3225 if (!NT_SUCCESS(Status
))
3227 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3232 /* Open device key */
3233 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3234 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3236 Status
= IopOpenRegistryKeyEx(&hDeviceKey
, hDevicesKey
, &DeviceName
,
3237 KEY_QUERY_VALUE
+ (EnumerateSubKeys
? KEY_ENUMERATE_SUB_KEYS
: 0));
3238 if (!NT_SUCCESS(Status
))
3240 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3244 /* Read boot resources, and add then to parent ones */
3245 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3246 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3248 ExFreePool(pValueInformation
);
3249 ValueInfoLength
= RequiredSize
;
3250 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3251 if (!pValueInformation
)
3253 DPRINT("ExAllocatePool() failed\n");
3254 ZwDeleteKey(hLevel2Key
);
3255 Status
= STATUS_NO_MEMORY
;
3258 Status
= ZwQueryValueKey(hDeviceKey
, &ConfigurationDataU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3260 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
3262 BootResources
= ParentBootResources
;
3263 BootResourcesLength
= ParentBootResourcesLength
;
3265 else if (!NT_SUCCESS(Status
))
3267 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3270 else if (pValueInformation
->Type
!= REG_FULL_RESOURCE_DESCRIPTOR
)
3272 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_FULL_RESOURCE_DESCRIPTOR
);
3277 static const ULONG Header
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
.PartialDescriptors
);
3279 /* Concatenate current resources and parent ones */
3280 if (ParentBootResourcesLength
== 0)
3281 BootResourcesLength
= pValueInformation
->DataLength
;
3283 BootResourcesLength
= ParentBootResourcesLength
3284 + pValueInformation
->DataLength
3286 BootResources
= ExAllocatePool(PagedPool
, BootResourcesLength
);
3289 DPRINT("ExAllocatePool() failed\n");
3292 if (ParentBootResourcesLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3294 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3296 else if (ParentBootResources
->PartialResourceList
.PartialDescriptors
[ParentBootResources
->PartialResourceList
.Count
- 1].Type
== CmResourceTypeDeviceSpecific
)
3298 RtlCopyMemory(BootResources
, pValueInformation
->Data
, pValueInformation
->DataLength
);
3300 (PVOID
)((ULONG_PTR
)BootResources
+ pValueInformation
->DataLength
),
3301 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3302 ParentBootResourcesLength
- Header
);
3303 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
3307 RtlCopyMemory(BootResources
, pValueInformation
->Data
, Header
);
3309 (PVOID
)((ULONG_PTR
)BootResources
+ Header
),
3310 (PVOID
)((ULONG_PTR
)ParentBootResources
+ Header
),
3311 ParentBootResourcesLength
- Header
);
3313 (PVOID
)((ULONG_PTR
)BootResources
+ ParentBootResourcesLength
),
3314 pValueInformation
->Data
+ Header
,
3315 pValueInformation
->DataLength
- Header
);
3316 BootResources
->PartialResourceList
.Count
+= ParentBootResources
->PartialResourceList
.Count
;
3320 if (EnumerateSubKeys
)
3325 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3326 if (Status
== STATUS_NO_MORE_ENTRIES
)
3328 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3330 ExFreePool(pDeviceInformation
);
3331 DeviceInfoLength
= RequiredSize
;
3332 pDeviceInformation
= ExAllocatePool(PagedPool
, DeviceInfoLength
);
3333 if (!pDeviceInformation
)
3335 DPRINT("ExAllocatePool() failed\n");
3336 Status
= STATUS_NO_MEMORY
;
3339 Status
= ZwEnumerateKey(hDeviceKey
, IndexSubKey
, KeyBasicInformation
, pDeviceInformation
, DeviceInfoLength
, &RequiredSize
);
3341 if (!NT_SUCCESS(Status
))
3343 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
3347 DeviceName
.Length
= DeviceName
.MaximumLength
= (USHORT
)pDeviceInformation
->NameLength
;
3348 DeviceName
.Buffer
= pDeviceInformation
->Name
;
3350 Status
= IopEnumerateDetectedDevices(
3356 BootResourcesLength
);
3357 if (!NT_SUCCESS(Status
))
3362 /* Read identifier */
3363 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3364 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
3366 ExFreePool(pValueInformation
);
3367 ValueInfoLength
= RequiredSize
;
3368 pValueInformation
= ExAllocatePool(PagedPool
, ValueInfoLength
);
3369 if (!pValueInformation
)
3371 DPRINT("ExAllocatePool() failed\n");
3372 Status
= STATUS_NO_MEMORY
;
3375 Status
= ZwQueryValueKey(hDeviceKey
, &IdentifierU
, KeyValuePartialInformation
, pValueInformation
, ValueInfoLength
, &RequiredSize
);
3377 if (!NT_SUCCESS(Status
))
3379 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
3381 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status
);
3384 ValueName
.Length
= ValueName
.MaximumLength
= 0;
3386 else if (pValueInformation
->Type
!= REG_SZ
)
3388 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation
->Type
, REG_SZ
);
3393 /* Assign hardware id to this device */
3394 ValueName
.Length
= ValueName
.MaximumLength
= (USHORT
)pValueInformation
->DataLength
;
3395 ValueName
.Buffer
= (PWCHAR
)pValueInformation
->Data
;
3396 if (ValueName
.Length
>= sizeof(WCHAR
) && ValueName
.Buffer
[ValueName
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
3397 ValueName
.Length
-= sizeof(WCHAR
);
3400 if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierSerial
, FALSE
) == 0)
3402 pHardwareId
= &HardwareIdSerial
;
3403 DeviceIndex
= DeviceIndexSerial
++;
3405 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierKeyboard
, FALSE
) == 0)
3407 pHardwareId
= &HardwareIdKeyboard
;
3408 DeviceIndex
= DeviceIndexKeyboard
++;
3410 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierMouse
, FALSE
) == 0)
3412 pHardwareId
= &HardwareIdMouse
;
3413 DeviceIndex
= DeviceIndexMouse
++;
3415 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierParallel
, FALSE
) == 0)
3417 pHardwareId
= &HardwareIdParallel
;
3418 DeviceIndex
= DeviceIndexParallel
++;
3420 else if (RelativePath
&& RtlCompareUnicodeString(RelativePath
, &IdentifierFloppy
, FALSE
) == 0)
3422 pHardwareId
= &HardwareIdFloppy
;
3423 DeviceIndex
= DeviceIndexFloppy
++;
3427 /* Unknown key path */
3428 DPRINT("Unknown key path '%wZ'\n", RelativePath
);
3432 /* Prepare hardware id key (hardware id value without final \0) */
3433 HardwareIdKey
= *pHardwareId
;
3434 HardwareIdKey
.Length
-= sizeof(UNICODE_NULL
);
3436 /* Add the detected device to Root key */
3437 InitializeObjectAttributes(&ObjectAttributes
, &HardwareIdKey
, OBJ_KERNEL_HANDLE
, hRootKey
, NULL
);
3438 Status
= ZwCreateKey(
3444 REG_OPTION_NON_VOLATILE
,
3446 if (!NT_SUCCESS(Status
))
3448 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3451 swprintf(Level2Name
, L
"%04lu", DeviceIndex
);
3452 RtlInitUnicodeString(&Level2NameU
, Level2Name
);
3453 InitializeObjectAttributes(&ObjectAttributes
, &Level2NameU
, OBJ_KERNEL_HANDLE
, hLevel1Key
, NULL
);
3454 Status
= ZwCreateKey(
3456 KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
,
3460 REG_OPTION_NON_VOLATILE
,
3462 ZwClose(hLevel1Key
);
3463 if (!NT_SUCCESS(Status
))
3465 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3468 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName
, DeviceIndex
, &HardwareIdKey
);
3469 Status
= ZwSetValueKey(hLevel2Key
, &HardwareIDU
, 0, REG_MULTI_SZ
, pHardwareId
->Buffer
, pHardwareId
->MaximumLength
);
3470 if (!NT_SUCCESS(Status
))
3472 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3473 ZwDeleteKey(hLevel2Key
);
3476 /* Create 'LogConf' subkey */
3477 InitializeObjectAttributes(&ObjectAttributes
, &LogConfU
, OBJ_KERNEL_HANDLE
, hLevel2Key
, NULL
);
3478 Status
= ZwCreateKey(
3484 REG_OPTION_VOLATILE
,
3486 if (!NT_SUCCESS(Status
))
3488 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3489 ZwDeleteKey(hLevel2Key
);
3492 if (BootResourcesLength
>= sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
3494 CmResourceList
= ExAllocatePool(PagedPool
, BootResourcesLength
+ sizeof(ULONG
));
3495 if (!CmResourceList
)
3498 ZwDeleteKey(hLevel2Key
);
3502 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3504 RtlCopyMemory(CmResourceList
,
3508 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3509 RtlCopyMemory(CmResourceList
+ sizeof(ULONG
),
3511 BootResourcesLength
);
3513 /* Save boot resources to 'LogConf\BootConfig' */
3514 Status
= ZwSetValueKey(hLogConf
, &BootConfigU
, 0, REG_RESOURCE_LIST
, CmResourceList
, BootResourcesLength
+ sizeof(ULONG
));
3515 if (!NT_SUCCESS(Status
))
3517 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status
);
3519 ZwDeleteKey(hLevel2Key
);
3526 if (BootResources
&& BootResources
!= ParentBootResources
)
3528 ExFreePool(BootResources
);
3529 BootResources
= NULL
;
3533 ZwClose(hLevel2Key
);
3538 ZwClose(hDeviceKey
);
3543 Status
= STATUS_SUCCESS
;
3546 if (hDevicesKey
&& hDevicesKey
!= hBaseKey
)
3547 ZwClose(hDevicesKey
);
3549 ZwClose(hDeviceKey
);
3550 if (pDeviceInformation
)
3551 ExFreePool(pDeviceInformation
);
3552 if (pValueInformation
)
3553 ExFreePool(pValueInformation
);
3560 IopIsFirmwareMapperDisabled(VOID
)
3562 UNICODE_STRING KeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3563 UNICODE_STRING KeyNameU
= RTL_CONSTANT_STRING(L
"DisableFirmwareMapper");
3564 OBJECT_ATTRIBUTES ObjectAttributes
;
3566 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
;
3567 ULONG DesiredLength
, Length
;
3571 InitializeObjectAttributes(&ObjectAttributes
, &KeyPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3572 Status
= ZwOpenKey(&hPnpKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
3573 if (NT_SUCCESS(Status
))
3575 Status
= ZwQueryValueKey(hPnpKey
,
3577 KeyValuePartialInformation
,
3581 if ((Status
== STATUS_BUFFER_TOO_SMALL
) ||
3582 (Status
== STATUS_BUFFER_OVERFLOW
))
3584 Length
= DesiredLength
;
3585 KeyInformation
= ExAllocatePool(PagedPool
, Length
);
3588 Status
= ZwQueryValueKey(hPnpKey
,
3590 KeyValuePartialInformation
,
3594 if (NT_SUCCESS(Status
) && KeyInformation
->DataLength
== sizeof(ULONG
))
3596 KeyValue
= (ULONG
)(*KeyInformation
->Data
);
3600 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU
, &KeyNameU
);
3603 ExFreePool(KeyInformation
);
3607 DPRINT1("Failed to allocate memory for registry query\n");
3612 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU
, &KeyNameU
, Status
);
3619 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU
, Status
);
3622 DPRINT("Firmware mapper is %s\n", KeyValue
!= 0 ? "disabled" : "enabled");
3624 return (KeyValue
!= 0) ? TRUE
: FALSE
;
3630 IopUpdateRootKey(VOID
)
3632 UNICODE_STRING EnumU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3633 UNICODE_STRING RootPathU
= RTL_CONSTANT_STRING(L
"Root");
3634 UNICODE_STRING MultiKeyPathU
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3635 OBJECT_ATTRIBUTES ObjectAttributes
;
3636 HANDLE hEnum
, hRoot
;
3639 InitializeObjectAttributes(&ObjectAttributes
, &EnumU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
3640 Status
= ZwCreateKey(&hEnum
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, REG_OPTION_NON_VOLATILE
, NULL
);
3641 if (!NT_SUCCESS(Status
))
3643 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status
);
3647 InitializeObjectAttributes(&ObjectAttributes
, &RootPathU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hEnum
, NULL
);
3648 Status
= ZwCreateKey(&hRoot
, KEY_CREATE_SUB_KEY
, &ObjectAttributes
, 0, NULL
, REG_OPTION_NON_VOLATILE
, NULL
);
3650 if (!NT_SUCCESS(Status
))
3652 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3656 if (!IopIsFirmwareMapperDisabled())
3658 Status
= IopOpenRegistryKeyEx(&hEnum
, NULL
, &MultiKeyPathU
, KEY_ENUMERATE_SUB_KEYS
);
3659 if (!NT_SUCCESS(Status
))
3661 /* Nothing to do, don't return with an error status */
3662 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
3664 return STATUS_SUCCESS
;
3666 Status
= IopEnumerateDetectedDevices(
3677 /* Enumeration is disabled */
3678 Status
= STATUS_SUCCESS
;
3688 IopOpenRegistryKeyEx(PHANDLE KeyHandle
,
3690 PUNICODE_STRING Name
,
3691 ACCESS_MASK DesiredAccess
)
3693 OBJECT_ATTRIBUTES ObjectAttributes
;
3700 InitializeObjectAttributes(&ObjectAttributes
,
3702 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3706 Status
= ZwOpenKey(KeyHandle
, DesiredAccess
, &ObjectAttributes
);
3713 IopCreateRegistryKeyEx(OUT PHANDLE Handle
,
3714 IN HANDLE RootHandle OPTIONAL
,
3715 IN PUNICODE_STRING KeyName
,
3716 IN ACCESS_MASK DesiredAccess
,
3717 IN ULONG CreateOptions
,
3718 OUT PULONG Disposition OPTIONAL
)
3720 OBJECT_ATTRIBUTES ObjectAttributes
;
3721 ULONG KeyDisposition
, RootHandleIndex
= 0, i
= 1, NestedCloseLevel
= 0;
3723 HANDLE HandleArray
[2];
3724 BOOLEAN Recursing
= TRUE
;
3726 UNICODE_STRING KeyString
;
3727 NTSTATUS Status
= STATUS_SUCCESS
;
3730 /* P1 is start, pp is end */
3731 p1
= KeyName
->Buffer
;
3732 pp
= (PVOID
)((ULONG_PTR
)p1
+ KeyName
->Length
);
3734 /* Create the target key */
3735 InitializeObjectAttributes(&ObjectAttributes
,
3737 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3740 Status
= ZwCreateKey(&HandleArray
[i
],
3748 /* Now we check if this failed */
3749 if ((Status
== STATUS_OBJECT_NAME_NOT_FOUND
) && (RootHandle
))
3751 /* Target key failed, so we'll need to create its parent. Setup array */
3752 HandleArray
[0] = NULL
;
3753 HandleArray
[1] = RootHandle
;
3755 /* Keep recursing for each missing parent */
3758 /* And if we're deep enough, close the last handle */
3759 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3761 /* We're setup to ping-pong between the two handle array entries */
3762 RootHandleIndex
= i
;
3765 /* Clear the one we're attempting to open now */
3766 HandleArray
[i
] = NULL
;
3768 /* Process the parent key name */
3769 for (p
= p1
; ((p
< pp
) && (*p
!= OBJ_NAME_PATH_SEPARATOR
)); p
++);
3770 Length
= (USHORT
)(p
- p1
) * sizeof(WCHAR
);
3772 /* Is there a parent name? */
3775 /* Build the unicode string for it */
3776 KeyString
.Buffer
= p1
;
3777 KeyString
.Length
= KeyString
.MaximumLength
= Length
;
3779 /* Now try opening the parent */
3780 InitializeObjectAttributes(&ObjectAttributes
,
3782 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
3783 HandleArray
[RootHandleIndex
],
3785 Status
= ZwCreateKey(&HandleArray
[i
],
3792 if (NT_SUCCESS(Status
))
3794 /* It worked, we have one more handle */
3799 /* Parent key creation failed, abandon loop */
3806 /* We don't have a parent name, probably corrupted key name */
3807 Status
= STATUS_INVALID_PARAMETER
;
3812 /* Now see if there's more parents to create */
3814 if ((p
== pp
) || (p1
== pp
))
3816 /* We're done, hopefully successfully, so stop */
3821 /* Outer loop check for handle nesting that requires closing the top handle */
3822 if (NestedCloseLevel
> 1) ZwClose(HandleArray
[RootHandleIndex
]);
3825 /* Check if we broke out of the loop due to success */
3826 if (NT_SUCCESS(Status
))
3828 /* Return the target handle (we closed all the parent ones) and disposition */
3829 *Handle
= HandleArray
[i
];
3830 if (Disposition
) *Disposition
= KeyDisposition
;
3833 /* Return the success state */
3839 IopGetRegistryValue(IN HANDLE Handle
,
3841 OUT PKEY_VALUE_FULL_INFORMATION
*Information
)
3843 UNICODE_STRING ValueString
;
3845 PKEY_VALUE_FULL_INFORMATION FullInformation
;
3849 RtlInitUnicodeString(&ValueString
, ValueName
);
3851 Status
= ZwQueryValueKey(Handle
,
3853 KeyValueFullInformation
,
3857 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
3858 (Status
!= STATUS_BUFFER_TOO_SMALL
))
3863 FullInformation
= ExAllocatePool(NonPagedPool
, Size
);
3864 if (!FullInformation
) return STATUS_INSUFFICIENT_RESOURCES
;
3866 Status
= ZwQueryValueKey(Handle
,
3868 KeyValueFullInformation
,
3872 if (!NT_SUCCESS(Status
))
3874 ExFreePool(FullInformation
);
3878 *Information
= FullInformation
;
3879 return STATUS_SUCCESS
;
3882 RTL_GENERIC_COMPARE_RESULTS
3884 PiCompareInstancePath(IN PRTL_AVL_TABLE Table
,
3885 IN PVOID FirstStruct
,
3886 IN PVOID SecondStruct
)
3894 // The allocation function is called by the generic table package whenever
3895 // it needs to allocate memory for the table.
3900 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3910 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table
,
3919 PpInitializeDeviceReferenceTable(VOID
)
3921 /* Setup the guarded mutex and AVL table */
3922 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock
);
3923 RtlInitializeGenericTableAvl(
3924 &PpDeviceReferenceTable
,
3925 (PRTL_AVL_COMPARE_ROUTINE
)PiCompareInstancePath
,
3926 (PRTL_AVL_ALLOCATE_ROUTINE
)PiAllocateGenericTableEntry
,
3927 (PRTL_AVL_FREE_ROUTINE
)PiFreeGenericTableEntry
,
3935 /* Initialize the resource when accessing device registry data */
3936 ExInitializeResourceLite(&PpRegistryDeviceResource
);
3938 /* Setup the device reference AVL table */
3939 PpInitializeDeviceReferenceTable();
3947 /* Check the initialization phase */
3948 switch (ExpInitializationPhase
)
3953 return PiInitPhase0();
3959 //return PiInitPhase1();
3963 /* Don't know any other phase! Bugcheck! */
3964 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL
);
3969 LONG IopNumberDeviceNodes
;
3973 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject
)
3975 PDEVICE_NODE DeviceNode
;
3979 DeviceNode
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEVICE_NODE
), TAG_IO_DEVNODE
);
3980 if (!DeviceNode
) return DeviceNode
;
3983 InterlockedIncrement(&IopNumberDeviceNodes
);
3986 RtlZeroMemory(DeviceNode
, sizeof(DEVICE_NODE
));
3987 DeviceNode
->InterfaceType
= InterfaceTypeUndefined
;
3988 DeviceNode
->BusNumber
= -1;
3989 DeviceNode
->ChildInterfaceType
= InterfaceTypeUndefined
;
3990 DeviceNode
->ChildBusNumber
= -1;
3991 DeviceNode
->ChildBusTypeIndex
= -1;
3992 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3993 InitializeListHead(&DeviceNode
->DeviceArbiterList
);
3994 InitializeListHead(&DeviceNode
->DeviceTranslatorList
);
3995 InitializeListHead(&DeviceNode
->TargetDeviceNotify
);
3996 InitializeListHead(&DeviceNode
->DockInfo
.ListEntry
);
3997 InitializeListHead(&DeviceNode
->PendedSetInterfaceState
);
3999 /* Check if there is a PDO */
4000 if (PhysicalDeviceObject
)
4002 /* Link it and remove the init flag */
4003 DeviceNode
->PhysicalDeviceObject
= PhysicalDeviceObject
;
4004 ((PEXTENDED_DEVOBJ_EXTENSION
)PhysicalDeviceObject
->DeviceObjectExtension
)->DeviceNode
= DeviceNode
;
4005 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
4008 /* Return the node */
4012 /* PUBLIC FUNCTIONS **********************************************************/
4016 PnpBusTypeGuidGet(IN USHORT Index
,
4017 IN LPGUID BusTypeGuid
)
4019 NTSTATUS Status
= STATUS_SUCCESS
;
4021 /* Acquire the lock */
4022 ExAcquireFastMutex(&PnpBusTypeGuidList
->Lock
);
4025 if (Index
< PnpBusTypeGuidList
->GuidCount
)
4028 RtlCopyMemory(BusTypeGuid
, &PnpBusTypeGuidList
->Guids
[Index
], sizeof(GUID
));
4033 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
4036 /* Release lock and return status */
4037 ExReleaseFastMutex(&PnpBusTypeGuidList
->Lock
);
4043 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject
,
4044 IN PHANDLE DeviceInstanceHandle
,
4045 IN ACCESS_MASK DesiredAccess
)
4049 PDEVICE_NODE DeviceNode
;
4050 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
4053 /* Open the enum key */
4054 Status
= IopOpenRegistryKeyEx(&KeyHandle
,
4058 if (!NT_SUCCESS(Status
)) return Status
;
4060 /* Make sure we have an instance path */
4061 DeviceNode
= IopGetDeviceNode(DeviceObject
);
4062 if ((DeviceNode
) && (DeviceNode
->InstancePath
.Length
))
4064 /* Get the instance key */
4065 Status
= IopOpenRegistryKeyEx(DeviceInstanceHandle
,
4067 &DeviceNode
->InstancePath
,
4073 Status
= STATUS_INVALID_DEVICE_REQUEST
;
4076 /* Close the handle and return status */
4083 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList
)
4085 ULONG FinalSize
, PartialSize
, EntrySize
, i
, j
;
4086 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor
;
4087 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor
;
4089 /* If we don't have one, that's easy */
4090 if (!ResourceList
) return 0;
4092 /* Start with the minimum size possible */
4093 FinalSize
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
);
4095 /* Loop each full descriptor */
4096 FullDescriptor
= ResourceList
->List
;
4097 for (i
= 0; i
< ResourceList
->Count
; i
++)
4099 /* Start with the minimum size possible */
4100 PartialSize
= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR
, PartialResourceList
) +
4101 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST
, PartialDescriptors
);
4103 /* Loop each partial descriptor */
4104 PartialDescriptor
= FullDescriptor
->PartialResourceList
.PartialDescriptors
;
4105 for (j
= 0; j
< FullDescriptor
->PartialResourceList
.Count
; j
++)
4107 /* Start with the minimum size possible */
4108 EntrySize
= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
);
4110 /* Check if there is extra data */
4111 if (PartialDescriptor
->Type
== CmResourceTypeDeviceSpecific
)
4114 EntrySize
+= PartialDescriptor
->u
.DeviceSpecificData
.DataSize
;
4117 /* The size of partial descriptors is bigger */
4118 PartialSize
+= EntrySize
;
4120 /* Go to the next partial descriptor */
4121 PartialDescriptor
= (PVOID
)((ULONG_PTR
)PartialDescriptor
+ EntrySize
);
4124 /* The size of full descriptors is bigger */
4125 FinalSize
+= PartialSize
;
4127 /* Go to the next full descriptor */
4128 FullDescriptor
= (PVOID
)((ULONG_PTR
)FullDescriptor
+ PartialSize
);
4131 /* Return the final size */
4137 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject
,
4142 IN PULONG BufferLength
)
4145 HANDLE KeyHandle
, SubHandle
;
4146 UNICODE_STRING KeyString
;
4147 PKEY_VALUE_FULL_INFORMATION KeyValueInfo
= NULL
;
4151 /* Find the instance key */
4152 Status
= PnpDeviceObjectToDeviceInstance(DeviceObject
, &KeyHandle
, KEY_READ
);
4153 if (NT_SUCCESS(Status
))
4155 /* Check for name given by caller */
4159 RtlInitUnicodeString(&KeyString
, KeyName
);
4160 Status
= IopOpenRegistryKeyEx(&SubHandle
,
4164 if (NT_SUCCESS(Status
))
4166 /* And use this handle instead */
4168 KeyHandle
= SubHandle
;
4172 /* Check if sub-key handle succeeded (or no-op if no key name given) */
4173 if (NT_SUCCESS(Status
))
4175 /* Now get the size of the property */
4176 Status
= IopGetRegistryValue(KeyHandle
,
4185 /* Fail if any of the registry operations failed */
4186 if (!NT_SUCCESS(Status
)) return Status
;
4188 /* Check how much data we have to copy */
4189 Length
= KeyValueInfo
->DataLength
;
4190 if (*BufferLength
>= Length
)
4192 /* Check for a match in the value type */
4193 if (KeyValueInfo
->Type
== ValueType
)
4196 RtlCopyMemory(Buffer
,
4197 (PVOID
)((ULONG_PTR
)KeyValueInfo
+
4198 KeyValueInfo
->DataOffset
),
4203 /* Invalid registry property type, fail */
4204 Status
= STATUS_INVALID_PARAMETER_2
;
4209 /* Buffer is too small to hold data */
4210 Status
= STATUS_BUFFER_TOO_SMALL
;
4213 /* Return the required buffer length, free the buffer, and return status */
4214 *BufferLength
= Length
;
4215 ExFreePool(KeyValueInfo
);
4219 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
4220 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
4221 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
4228 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject
,
4229 IN DEVICE_REGISTRY_PROPERTY DeviceProperty
,
4230 IN ULONG BufferLength
,
4231 OUT PVOID PropertyBuffer
,
4232 OUT PULONG ResultLength
)
4234 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
4235 DEVICE_CAPABILITIES DeviceCaps
;
4236 ULONG ReturnLength
= 0, Length
= 0, ValueType
;
4237 PWCHAR ValueName
= NULL
, EnumeratorNameEnd
, DeviceInstanceName
;
4239 NTSTATUS Status
= STATUS_BUFFER_TOO_SMALL
;
4241 POBJECT_NAME_INFORMATION ObjectNameInfo
= NULL
;
4242 BOOLEAN NullTerminate
= FALSE
;
4243 DEVICE_REMOVAL_POLICY Policy
;
4245 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject
, DeviceProperty
);
4247 /* Assume failure */
4250 /* Only PDOs can call this */
4251 if (!DeviceNode
) return STATUS_INVALID_DEVICE_REQUEST
;
4253 /* Handle all properties */
4254 switch (DeviceProperty
)
4256 case DevicePropertyBusTypeGuid
:
4258 /* Get the GUID from the internal cache */
4259 Status
= PnpBusTypeGuidGet(DeviceNode
->ChildBusTypeIndex
, &BusTypeGuid
);
4260 if (!NT_SUCCESS(Status
)) return Status
;
4262 /* This is the format of the returned data */
4263 PIP_RETURN_DATA(sizeof(GUID
), &BusTypeGuid
);
4265 case DevicePropertyLegacyBusType
:
4267 /* Validate correct interface type */
4268 if (DeviceNode
->ChildInterfaceType
== InterfaceTypeUndefined
)
4269 return STATUS_OBJECT_NAME_NOT_FOUND
;
4271 /* This is the format of the returned data */
4272 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE
), &DeviceNode
->ChildInterfaceType
);
4274 case DevicePropertyBusNumber
:
4276 /* Validate correct bus number */
4277 if ((DeviceNode
->ChildBusNumber
& 0x80000000) == 0x80000000)
4278 return STATUS_OBJECT_NAME_NOT_FOUND
;
4280 /* This is the format of the returned data */
4281 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceNode
->ChildBusNumber
);
4283 case DevicePropertyEnumeratorName
:
4285 /* Get the instance path */
4286 DeviceInstanceName
= DeviceNode
->InstancePath
.Buffer
;
4289 ASSERT((BufferLength
& 1) == 0);
4290 ASSERT(DeviceInstanceName
!= NULL
);
4292 /* Get the name from the path */
4293 EnumeratorNameEnd
= wcschr(DeviceInstanceName
, OBJ_NAME_PATH_SEPARATOR
);
4294 ASSERT(EnumeratorNameEnd
);
4296 /* This string needs to be NULL-terminated */
4297 NullTerminate
= TRUE
;
4299 /* This is the format of the returned data */
4300 PIP_RETURN_DATA((ULONG
)(EnumeratorNameEnd
- DeviceInstanceName
) * sizeof(WCHAR
),
4301 DeviceInstanceName
);
4303 case DevicePropertyAddress
:
4305 /* Query the device caps */
4306 Status
= IopQueryDeviceCapabilities(DeviceNode
, &DeviceCaps
);
4307 if (!NT_SUCCESS(Status
) || (DeviceCaps
.Address
== MAXULONG
))
4308 return STATUS_OBJECT_NAME_NOT_FOUND
;
4310 /* This is the format of the returned data */
4311 PIP_RETURN_DATA(sizeof(ULONG
), &DeviceCaps
.Address
);
4313 case DevicePropertyBootConfigurationTranslated
:
4315 /* Validate we have resources */
4316 if (!DeviceNode
->BootResources
)
4317 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
4319 /* No resources will still fake success, but with 0 bytes */
4321 return STATUS_SUCCESS
;
4324 /* This is the format of the returned data */
4325 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode
->BootResources
), // FIXFIX: Should use BootResourcesTranslated
4326 DeviceNode
->BootResources
); // FIXFIX: Should use BootResourcesTranslated
4328 case DevicePropertyPhysicalDeviceObjectName
:
4330 /* Sanity check for Unicode-sized string */
4331 ASSERT((BufferLength
& 1) == 0);
4333 /* Allocate name buffer */
4334 Length
= BufferLength
+ sizeof(OBJECT_NAME_INFORMATION
);
4335 ObjectNameInfo
= ExAllocatePool(PagedPool
, Length
);
4336 if (!ObjectNameInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
4338 /* Query the PDO name */
4339 Status
= ObQueryNameString(DeviceObject
,
4343 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
4345 /* It's up to the caller to try again */
4346 Status
= STATUS_BUFFER_TOO_SMALL
;
4349 /* This string needs to be NULL-terminated */
4350 NullTerminate
= TRUE
;
4352 /* Return if successful */
4353 if (NT_SUCCESS(Status
)) PIP_RETURN_DATA(ObjectNameInfo
->Name
.Length
,
4354 ObjectNameInfo
->Name
.Buffer
);
4356 /* Let the caller know how big the name is */
4357 *ResultLength
-= sizeof(OBJECT_NAME_INFORMATION
);
4360 case DevicePropertyRemovalPolicy
:
4362 Policy
= DeviceNode
->RemovalPolicy
;
4363 PIP_RETURN_DATA(sizeof(Policy
), &Policy
);
4365 /* Handle the registry-based properties */
4366 case DevicePropertyUINumber
:
4367 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER
, REG_DWORD
);
4368 case DevicePropertyLocationInformation
:
4369 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION
, REG_SZ
);
4370 case DevicePropertyDeviceDescription
:
4371 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC
, REG_SZ
);
4372 case DevicePropertyHardwareID
:
4373 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID
, REG_MULTI_SZ
);
4374 case DevicePropertyCompatibleIDs
:
4375 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS
, REG_MULTI_SZ
);
4376 case DevicePropertyBootConfiguration
:
4377 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG
, REG_RESOURCE_LIST
);
4378 case DevicePropertyClassName
:
4379 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS
, REG_SZ
);
4380 case DevicePropertyClassGuid
:
4381 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID
, REG_SZ
);
4382 case DevicePropertyDriverKeyName
:
4383 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER
, REG_SZ
);
4384 case DevicePropertyManufacturer
:
4385 PIP_REGISTRY_DATA(REGSTR_VAL_MFG
, REG_SZ
);
4386 case DevicePropertyFriendlyName
:
4387 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME
, REG_SZ
);
4388 case DevicePropertyContainerID
:
4389 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
4390 PIP_UNIMPLEMENTED();
4392 case DevicePropertyInstallState
:
4393 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS
, REG_DWORD
);
4395 case DevicePropertyResourceRequirements
:
4396 PIP_UNIMPLEMENTED();
4397 case DevicePropertyAllocatedResources
:
4398 PIP_UNIMPLEMENTED();
4400 return STATUS_INVALID_PARAMETER_2
;
4403 /* Having a registry value name implies registry data */
4406 /* We know up-front how much data to expect */
4407 *ResultLength
= BufferLength
;
4409 /* Go get the data, use the LogConf subkey if necessary */
4410 Status
= PiGetDeviceRegistryProperty(DeviceObject
,
4414 DevicePropertyBootConfiguration
) ?
4419 else if (NT_SUCCESS(Status
))
4421 /* We know up-front how much data to expect, check the caller's buffer */
4422 *ResultLength
= ReturnLength
+ (NullTerminate
? sizeof(UNICODE_NULL
) : 0);
4423 if (*ResultLength
<= BufferLength
)
4425 /* Buffer is all good, copy the data */
4426 RtlCopyMemory(PropertyBuffer
, Data
, ReturnLength
);
4428 /* Check if we need to NULL-terminate the string */
4431 /* Terminate the string */
4432 ((PWCHAR
)PropertyBuffer
)[ReturnLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
4435 /* This is the success path */
4436 Status
= STATUS_SUCCESS
;
4441 Status
= STATUS_BUFFER_TOO_SMALL
;
4445 /* Free any allocation we may have made, and return the status code */
4446 if (ObjectNameInfo
) ExFreePool(ObjectNameInfo
);
4455 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject
)
4457 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
4458 IO_STACK_LOCATION Stack
;
4461 IO_STATUS_BLOCK IoStatusBlock
;
4463 RtlZeroMemory(&Stack
, sizeof(IO_STACK_LOCATION
));
4464 Stack
.MajorFunction
= IRP_MJ_PNP
;
4465 Stack
.MinorFunction
= IRP_MN_QUERY_PNP_DEVICE_STATE
;
4467 Status
= IopSynchronousCall(PhysicalDeviceObject
, &Stack
, (PVOID
*)&PnPFlags
);
4468 if (!NT_SUCCESS(Status
))
4470 if (Status
!= STATUS_NOT_SUPPORTED
)
4472 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status
);
4477 if (PnPFlags
& PNP_DEVICE_NOT_DISABLEABLE
)
4478 DeviceNode
->UserFlags
|= DNUF_NOT_DISABLEABLE
;
4480 DeviceNode
->UserFlags
&= ~DNUF_NOT_DISABLEABLE
;
4482 if (PnPFlags
& PNP_DEVICE_DONT_DISPLAY_IN_UI
)
4483 DeviceNode
->UserFlags
|= DNUF_DONT_SHOW_IN_UI
;
4485 DeviceNode
->UserFlags
&= ~DNUF_DONT_SHOW_IN_UI
;
4487 if ((PnPFlags
& PNP_DEVICE_REMOVED
) ||
4488 ((PnPFlags
& PNP_DEVICE_FAILED
) && !(PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)))
4490 /* Flag it if it's failed */
4491 if (PnPFlags
& PNP_DEVICE_FAILED
) DeviceNode
->Problem
= CM_PROB_FAILED_POST_START
;
4493 /* Send removal IRPs to all of its children */
4494 IopPrepareDeviceForRemoval(PhysicalDeviceObject
, TRUE
);
4496 /* Send surprise removal */
4497 IopSendSurpriseRemoval(PhysicalDeviceObject
);
4499 /* Tell the user-mode PnP manager that a device was removed */
4500 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL
,
4501 &DeviceNode
->InstancePath
);
4503 IopSendRemoveDevice(PhysicalDeviceObject
);
4505 else if ((PnPFlags
& PNP_DEVICE_FAILED
) && (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
))
4507 /* Stop for resource rebalance */
4508 Status
= IopStopDevice(DeviceNode
);
4509 if (!NT_SUCCESS(Status
))
4511 DPRINT1("Failed to stop device for rebalancing\n");
4513 /* Stop failed so don't rebalance */
4514 PnPFlags
&= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
;
4518 /* Resource rebalance */
4519 if (PnPFlags
& PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
)
4521 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4523 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4525 IRP_MN_QUERY_RESOURCES
,
4527 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
4529 DeviceNode
->BootResources
=
4530 (PCM_RESOURCE_LIST
)IoStatusBlock
.Information
;
4531 IopDeviceNodeSetFlag(DeviceNode
, DNF_HAS_BOOT_CONFIG
);
4535 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status
);
4536 DeviceNode
->BootResources
= NULL
;
4539 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4541 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
4543 IRP_MN_QUERY_RESOURCE_REQUIREMENTS
,
4545 if (NT_SUCCESS(Status
))
4547 DeviceNode
->ResourceRequirements
=
4548 (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
4552 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status
);
4553 DeviceNode
->ResourceRequirements
= NULL
;
4556 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4557 if (IopStartDevice(DeviceNode
) != STATUS_SUCCESS
)
4559 DPRINT1("Restart after resource rebalance failed\n");
4561 DeviceNode
->Flags
&= ~(DNF_STARTED
| DNF_START_REQUEST_PENDING
);
4562 DeviceNode
->Flags
|= DNF_START_FAILED
;
4564 IopRemoveDevice(DeviceNode
);
4570 * @name IoOpenDeviceRegistryKey
4572 * Open a registry key unique for a specified driver or device instance.
4574 * @param DeviceObject Device to get the registry key for.
4575 * @param DevInstKeyType Type of the key to return.
4576 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4577 * @param DevInstRegKey Handle to the opened registry key on
4578 * successful return.
4586 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject
,
4587 IN ULONG DevInstKeyType
,
4588 IN ACCESS_MASK DesiredAccess
,
4589 OUT PHANDLE DevInstRegKey
)
4591 static WCHAR RootKeyName
[] =
4592 L
"\\Registry\\Machine\\System\\CurrentControlSet\\";
4593 static WCHAR ProfileKeyName
[] =
4594 L
"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4595 static WCHAR ClassKeyName
[] = L
"Control\\Class\\";
4596 static WCHAR EnumKeyName
[] = L
"Enum\\";
4597 static WCHAR DeviceParametersKeyName
[] = L
"Device Parameters";
4598 ULONG KeyNameLength
;
4599 PWSTR KeyNameBuffer
;
4600 UNICODE_STRING KeyName
;
4601 ULONG DriverKeyLength
;
4602 OBJECT_ATTRIBUTES ObjectAttributes
;
4603 PDEVICE_NODE DeviceNode
= NULL
;
4606 DPRINT("IoOpenDeviceRegistryKey() called\n");
4608 if ((DevInstKeyType
& (PLUGPLAY_REGKEY_DEVICE
| PLUGPLAY_REGKEY_DRIVER
)) == 0)
4610 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4611 return STATUS_INVALID_PARAMETER
;
4614 if (!IopIsValidPhysicalDeviceObject(DeviceObject
))
4615 return STATUS_INVALID_DEVICE_REQUEST
;
4616 DeviceNode
= IopGetDeviceNode(DeviceObject
);
4619 * Calculate the length of the base key name. This is the full
4620 * name for driver key or the name excluding "Device Parameters"
4621 * subkey for device key.
4624 KeyNameLength
= sizeof(RootKeyName
);
4625 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4626 KeyNameLength
+= sizeof(ProfileKeyName
) - sizeof(UNICODE_NULL
);
4627 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4629 KeyNameLength
+= sizeof(ClassKeyName
) - sizeof(UNICODE_NULL
);
4630 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4631 0, NULL
, &DriverKeyLength
);
4632 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
4634 KeyNameLength
+= DriverKeyLength
;
4638 KeyNameLength
+= sizeof(EnumKeyName
) - sizeof(UNICODE_NULL
) +
4639 DeviceNode
->InstancePath
.Length
;
4643 * Now allocate the buffer for the key name...
4646 KeyNameBuffer
= ExAllocatePool(PagedPool
, KeyNameLength
);
4647 if (KeyNameBuffer
== NULL
)
4648 return STATUS_INSUFFICIENT_RESOURCES
;
4651 KeyName
.MaximumLength
= (USHORT
)KeyNameLength
;
4652 KeyName
.Buffer
= KeyNameBuffer
;
4655 * ...and build the key name.
4658 KeyName
.Length
+= sizeof(RootKeyName
) - sizeof(UNICODE_NULL
);
4659 RtlCopyMemory(KeyNameBuffer
, RootKeyName
, KeyName
.Length
);
4661 if (DevInstKeyType
& PLUGPLAY_REGKEY_CURRENT_HWPROFILE
)
4662 RtlAppendUnicodeToString(&KeyName
, ProfileKeyName
);
4664 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4666 RtlAppendUnicodeToString(&KeyName
, ClassKeyName
);
4667 Status
= IoGetDeviceProperty(DeviceObject
, DevicePropertyDriverKeyName
,
4668 DriverKeyLength
, KeyNameBuffer
+
4669 (KeyName
.Length
/ sizeof(WCHAR
)),
4671 if (!NT_SUCCESS(Status
))
4673 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status
);
4674 ExFreePool(KeyNameBuffer
);
4677 KeyName
.Length
+= (USHORT
)DriverKeyLength
- sizeof(UNICODE_NULL
);
4681 RtlAppendUnicodeToString(&KeyName
, EnumKeyName
);
4682 Status
= RtlAppendUnicodeStringToString(&KeyName
, &DeviceNode
->InstancePath
);
4683 if (DeviceNode
->InstancePath
.Length
== 0)
4685 ExFreePool(KeyNameBuffer
);
4691 * Open the base key.
4693 Status
= IopOpenRegistryKeyEx(DevInstRegKey
, NULL
, &KeyName
, DesiredAccess
);
4694 if (!NT_SUCCESS(Status
))
4696 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName
, Status
);
4697 ExFreePool(KeyNameBuffer
);
4700 ExFreePool(KeyNameBuffer
);
4703 * For driver key we're done now.
4706 if (DevInstKeyType
& PLUGPLAY_REGKEY_DRIVER
)
4710 * Let's go further. For device key we must open "Device Parameters"
4711 * subkey and create it if it doesn't exist yet.
4714 RtlInitUnicodeString(&KeyName
, DeviceParametersKeyName
);
4715 InitializeObjectAttributes(&ObjectAttributes
,
4717 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
4720 Status
= ZwCreateKey(DevInstRegKey
,
4725 REG_OPTION_NON_VOLATILE
,
4727 ZwClose(ObjectAttributes
.RootDirectory
);
4734 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
, BOOLEAN Force
)
4736 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
, FailedRemoveDevice
;
4740 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4741 ChildDeviceNode
= ParentDeviceNode
->Child
;
4742 while (ChildDeviceNode
!= NULL
)
4744 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4745 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4747 Status
= IopPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
, Force
);
4748 if (!NT_SUCCESS(Status
))
4750 FailedRemoveDevice
= ChildDeviceNode
;
4754 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4755 ChildDeviceNode
= NextDeviceNode
;
4757 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4759 return STATUS_SUCCESS
;
4762 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4763 ChildDeviceNode
= ParentDeviceNode
->Child
;
4764 while (ChildDeviceNode
!= NULL
)
4766 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4767 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4769 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4771 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4772 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4773 if (ChildDeviceNode
== FailedRemoveDevice
)
4776 ChildDeviceNode
= NextDeviceNode
;
4778 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4780 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4787 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4789 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4792 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4793 ChildDeviceNode
= ParentDeviceNode
->Child
;
4794 while (ChildDeviceNode
!= NULL
)
4796 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4797 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4799 IopSendRemoveDevice(ChildDeviceNode
->PhysicalDeviceObject
);
4801 ChildDeviceNode
= NextDeviceNode
;
4803 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4805 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4810 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode
)
4812 PDEVICE_NODE ChildDeviceNode
, NextDeviceNode
;
4815 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4816 ChildDeviceNode
= ParentDeviceNode
->Child
;
4817 while (ChildDeviceNode
!= NULL
)
4819 NextDeviceNode
= ChildDeviceNode
->Sibling
;
4820 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4822 IopCancelPrepareDeviceForRemoval(ChildDeviceNode
->PhysicalDeviceObject
);
4824 ChildDeviceNode
= NextDeviceNode
;
4826 KeAcquireSpinLock(&IopDeviceTreeLock
, &OldIrql
);
4828 KeReleaseSpinLock(&IopDeviceTreeLock
, OldIrql
);
4833 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
, BOOLEAN Force
)
4835 /* This function DOES NOT dereference the device objects on SUCCESS
4836 * but it DOES dereference device objects on FAILURE */
4841 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4843 Status
= IopPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
], Force
);
4844 if (!NT_SUCCESS(Status
))
4851 return STATUS_SUCCESS
;
4854 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4855 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4856 for (i
= 0; i
<= j
; i
++)
4858 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4859 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4860 DeviceRelations
->Objects
[i
] = NULL
;
4862 for (; i
< DeviceRelations
->Count
; i
++)
4864 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4865 DeviceRelations
->Objects
[i
] = NULL
;
4867 ExFreePool(DeviceRelations
);
4874 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4876 /* This function DOES dereference the device objects in all cases */
4880 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4882 IopSendRemoveDevice(DeviceRelations
->Objects
[i
]);
4883 DeviceRelations
->Objects
[i
] = NULL
;
4886 ExFreePool(DeviceRelations
);
4891 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations
)
4893 /* This function DOES dereference the device objects in all cases */
4897 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
4899 IopCancelPrepareDeviceForRemoval(DeviceRelations
->Objects
[i
]);
4900 ObDereferenceObject(DeviceRelations
->Objects
[i
]);
4901 DeviceRelations
->Objects
[i
] = NULL
;
4904 ExFreePool(DeviceRelations
);
4908 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject
)
4910 IO_STACK_LOCATION Stack
;
4911 IO_STATUS_BLOCK IoStatusBlock
;
4912 PDEVICE_RELATIONS DeviceRelations
;
4915 IopCancelRemoveDevice(DeviceObject
);
4917 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4919 Status
= IopInitiatePnpIrp(DeviceObject
,
4921 IRP_MN_QUERY_DEVICE_RELATIONS
,
4923 if (!NT_SUCCESS(Status
))
4925 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4926 DeviceRelations
= NULL
;
4930 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4933 if (DeviceRelations
)
4934 IopCancelRemoveDeviceRelations(DeviceRelations
);
4938 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject
, BOOLEAN Force
)
4940 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
4941 IO_STACK_LOCATION Stack
;
4942 IO_STATUS_BLOCK IoStatusBlock
;
4943 PDEVICE_RELATIONS DeviceRelations
;
4946 if ((DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
) && !Force
)
4948 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode
->InstancePath
);
4949 return STATUS_UNSUCCESSFUL
;
4952 if (!Force
&& IopQueryRemoveDevice(DeviceObject
) != STATUS_SUCCESS
)
4954 DPRINT1("Removal vetoed by failing the query remove request\n");
4956 IopCancelRemoveDevice(DeviceObject
);
4958 return STATUS_UNSUCCESSFUL
;
4961 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
4963 Status
= IopInitiatePnpIrp(DeviceObject
,
4965 IRP_MN_QUERY_DEVICE_RELATIONS
,
4967 if (!NT_SUCCESS(Status
))
4969 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
4970 DeviceRelations
= NULL
;
4974 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
4977 if (DeviceRelations
)
4979 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, Force
);
4980 if (!NT_SUCCESS(Status
))
4984 Status
= IopQueryRemoveChildDevices(DeviceNode
, Force
);
4985 if (!NT_SUCCESS(Status
))
4987 if (DeviceRelations
)
4988 IopCancelRemoveDeviceRelations(DeviceRelations
);
4992 if (DeviceRelations
)
4993 IopSendRemoveDeviceRelations(DeviceRelations
);
4994 IopSendRemoveChildDevices(DeviceNode
);
4996 return STATUS_SUCCESS
;
5000 IopRemoveDevice(PDEVICE_NODE DeviceNode
)
5004 DPRINT("Removing device: %wZ\n", &DeviceNode
->InstancePath
);
5006 Status
= IopPrepareDeviceForRemoval(DeviceNode
->PhysicalDeviceObject
, FALSE
);
5007 if (NT_SUCCESS(Status
))
5009 IopSendRemoveDevice(DeviceNode
->PhysicalDeviceObject
);
5010 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL
,
5011 &DeviceNode
->InstancePath
);
5012 return STATUS_SUCCESS
;
5023 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject
)
5025 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(PhysicalDeviceObject
);
5026 PDEVICE_RELATIONS DeviceRelations
;
5027 IO_STATUS_BLOCK IoStatusBlock
;
5028 IO_STACK_LOCATION Stack
;
5029 DEVICE_CAPABILITIES Capabilities
;
5032 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT
,
5033 &DeviceNode
->InstancePath
);
5035 if (IopQueryDeviceCapabilities(DeviceNode
, &Capabilities
) != STATUS_SUCCESS
)
5040 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
5042 Status
= IopInitiatePnpIrp(PhysicalDeviceObject
,
5044 IRP_MN_QUERY_DEVICE_RELATIONS
,
5046 if (!NT_SUCCESS(Status
))
5048 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status
);
5049 DeviceRelations
= NULL
;
5053 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
5056 if (DeviceRelations
)
5058 Status
= IopQueryRemoveDeviceRelations(DeviceRelations
, FALSE
);
5059 if (!NT_SUCCESS(Status
))
5063 Status
= IopQueryRemoveChildDevices(DeviceNode
, FALSE
);
5064 if (!NT_SUCCESS(Status
))
5066 if (DeviceRelations
)
5067 IopCancelRemoveDeviceRelations(DeviceRelations
);
5071 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject
, FALSE
) != STATUS_SUCCESS
)
5073 if (DeviceRelations
)
5074 IopCancelRemoveDeviceRelations(DeviceRelations
);
5075 IopCancelRemoveChildDevices(DeviceNode
);
5079 if (DeviceRelations
)
5080 IopSendRemoveDeviceRelations(DeviceRelations
);
5081 IopSendRemoveChildDevices(DeviceNode
);
5083 DeviceNode
->Problem
= CM_PROB_HELD_FOR_EJECT
;
5084 if (Capabilities
.EjectSupported
)
5086 if (IopSendEject(PhysicalDeviceObject
) != STATUS_SUCCESS
)
5093 DeviceNode
->Flags
|= DNF_DISABLED
;
5096 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT
,
5097 &DeviceNode
->InstancePath
);
5102 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED
,
5103 &DeviceNode
->InstancePath
);
5111 IoInvalidateDeviceRelations(
5112 IN PDEVICE_OBJECT DeviceObject
,
5113 IN DEVICE_RELATION_TYPE Type
)
5115 PDEVICE_ACTION_DATA Data
;
5118 Data
= ExAllocatePoolWithTag(NonPagedPool
,
5119 sizeof(DEVICE_ACTION_DATA
),
5124 ObReferenceObject(DeviceObject
);
5125 Data
->DeviceObject
= DeviceObject
;
5128 KeAcquireSpinLock(&IopDeviceActionLock
, &OldIrql
);
5129 InsertTailList(&IopDeviceActionRequestList
, &Data
->RequestListEntry
);
5130 if (IopDeviceActionInProgress
)
5132 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
5135 IopDeviceActionInProgress
= TRUE
;
5136 KeReleaseSpinLock(&IopDeviceActionLock
, OldIrql
);
5138 ExInitializeWorkItem(&IopDeviceActionWorkItem
,
5139 IopDeviceActionWorker
,
5141 ExQueueWorkItem(&IopDeviceActionWorkItem
,
5150 IoSynchronousInvalidateDeviceRelations(
5151 IN PDEVICE_OBJECT DeviceObject
,
5152 IN DEVICE_RELATION_TYPE Type
)
5159 /* Enumerate the device */
5160 return IopEnumerateDevice(DeviceObject
);
5161 case PowerRelations
:
5162 /* Not handled yet */
5163 return STATUS_NOT_IMPLEMENTED
;
5164 case TargetDeviceRelation
:
5166 return STATUS_SUCCESS
;
5168 /* Ejection relations are not supported */
5169 return STATUS_NOT_SUPPORTED
;
5178 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType
,
5180 IN PHYSICAL_ADDRESS BusAddress
,
5181 IN OUT PULONG AddressSpace
,
5182 OUT PPHYSICAL_ADDRESS TranslatedAddress
)
5184 /* FIXME: Notify the resource arbiter */
5186 return HalTranslateBusAddress(InterfaceType
,