2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnproot.c
5 * PURPOSE: PnP manager root device
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Herv? Poussineau (hpoussin@reactos.org)
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 #define ENUM_NAME_ROOT L"Root"
20 /* DATA **********************************************************************/
22 typedef struct _PNPROOT_DEVICE
24 // Entry on device list
26 // Physical Device Object of device
29 UNICODE_STRING DeviceID
;
31 UNICODE_STRING InstanceID
;
33 UNICODE_STRING DeviceDescription
;
34 // Resource requirement list
35 PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirementsList
;
36 // Associated resource list
37 PCM_RESOURCE_LIST ResourceList
;
38 ULONG ResourceListSize
;
39 } PNPROOT_DEVICE
, *PPNPROOT_DEVICE
;
48 } PNPROOT_DEVICE_STATE
;
50 typedef struct _PNPROOT_COMMON_DEVICE_EXTENSION
52 // Wether this device extension is for an FDO or PDO
54 } PNPROOT_COMMON_DEVICE_EXTENSION
, *PPNPROOT_COMMON_DEVICE_EXTENSION
;
56 /* Physical Device Object device extension for a child device */
57 typedef struct _PNPROOT_PDO_DEVICE_EXTENSION
60 PNPROOT_COMMON_DEVICE_EXTENSION Common
;
61 // Informations about the device
62 PPNPROOT_DEVICE DeviceInfo
;
63 } PNPROOT_PDO_DEVICE_EXTENSION
, *PPNPROOT_PDO_DEVICE_EXTENSION
;
65 /* Physical Device Object device extension for the Root bus device object */
66 typedef struct _PNPROOT_FDO_DEVICE_EXTENSION
69 PNPROOT_COMMON_DEVICE_EXTENSION Common
;
70 // Lower device object
72 // Current state of the driver
73 PNPROOT_DEVICE_STATE State
;
74 // Namespace device list
75 LIST_ENTRY DeviceListHead
;
76 // Number of (not removed) devices in device list
77 ULONG DeviceListCount
;
78 // Lock for namespace device list
79 KGUARDED_MUTEX DeviceListLock
;
80 } PNPROOT_FDO_DEVICE_EXTENSION
, *PPNPROOT_FDO_DEVICE_EXTENSION
;
82 typedef struct _BUFFER
88 static PDEVICE_OBJECT PnpRootDeviceObject
= NULL
;
90 /* FUNCTIONS *****************************************************************/
94 IN PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
,
97 OUT PPNPROOT_DEVICE
* ChildDevice
)
99 PPNPROOT_DEVICE Device
;
100 UNICODE_STRING DeviceIdU
, InstanceIdU
;
101 PLIST_ENTRY NextEntry
;
103 /* Initialize the strings to compare */
104 RtlInitUnicodeString(&DeviceIdU
, DeviceId
);
105 RtlInitUnicodeString(&InstanceIdU
, InstanceId
);
108 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
109 NextEntry
!= &DeviceExtension
->DeviceListHead
;
110 NextEntry
= NextEntry
->Flink
)
113 Device
= CONTAINING_RECORD(NextEntry
, PNPROOT_DEVICE
, ListEntry
);
115 /* See if the strings match */
116 if (RtlEqualUnicodeString(&DeviceIdU
, &Device
->DeviceID
, TRUE
) &&
117 RtlEqualUnicodeString(&InstanceIdU
, &Device
->InstanceID
, TRUE
))
119 /* They do, so set the pointer and return success */
120 *ChildDevice
= Device
;
121 return STATUS_SUCCESS
;
125 /* No device found */
126 return STATUS_NO_SUCH_DEVICE
;
129 /* Creates a new PnP device for a legacy driver */
132 IN PUNICODE_STRING ServiceName
,
133 IN OPTIONAL PDRIVER_OBJECT DriverObject
,
134 OUT PDEVICE_OBJECT
*PhysicalDeviceObject
,
135 OUT OPTIONAL PUNICODE_STRING FullInstancePath
)
137 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
138 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension
;
139 WCHAR DevicePath
[MAX_PATH
+ 1];
140 WCHAR InstancePath
[5];
141 PPNPROOT_DEVICE Device
= NULL
;
143 UNICODE_STRING PathSep
= RTL_CONSTANT_STRING(L
"\\");
145 UNICODE_STRING EnumKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM
);
146 HANDLE EnumHandle
, DeviceKeyHandle
= INVALID_HANDLE_VALUE
, InstanceKeyHandle
;
147 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
148 OBJECT_ATTRIBUTES ObjectAttributes
;
150 DeviceExtension
= PnpRootDeviceObject
->DeviceExtension
;
151 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
153 DPRINT("Creating a PnP root device for service '%wZ'\n", ServiceName
);
155 _snwprintf(DevicePath
, sizeof(DevicePath
) / sizeof(WCHAR
), L
"%s\\%wZ", REGSTR_KEY_ROOTENUM
, ServiceName
);
157 /* Initialize a PNPROOT_DEVICE structure */
158 Device
= ExAllocatePoolWithTag(PagedPool
, sizeof(PNPROOT_DEVICE
), TAG_PNP_ROOT
);
161 DPRINT("ExAllocatePoolWithTag() failed\n");
162 Status
= STATUS_NO_MEMORY
;
165 RtlZeroMemory(Device
, sizeof(PNPROOT_DEVICE
));
166 if (!RtlCreateUnicodeString(&Device
->DeviceID
, DevicePath
))
168 Status
= STATUS_NO_MEMORY
;
172 Status
= IopOpenRegistryKeyEx(&EnumHandle
, NULL
, &EnumKeyName
, KEY_READ
);
173 if (NT_SUCCESS(Status
))
175 InitializeObjectAttributes(&ObjectAttributes
, &Device
->DeviceID
, OBJ_CASE_INSENSITIVE
, EnumHandle
, NULL
);
176 Status
= ZwCreateKey(&DeviceKeyHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
180 if (!NT_SUCCESS(Status
))
182 DPRINT1("Failed to open registry key\n");
187 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
188 QueryTable
[0].Name
= L
"NextInstance";
189 QueryTable
[0].EntryContext
= &NextInstance
;
190 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
192 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
193 (PWSTR
)DeviceKeyHandle
,
197 if (!NT_SUCCESS(Status
))
199 for (NextInstance
= 0; NextInstance
<= 9999; NextInstance
++)
201 _snwprintf(InstancePath
, sizeof(InstancePath
) / sizeof(WCHAR
), L
"%04lu", NextInstance
);
202 Status
= LocateChildDevice(DeviceExtension
, DevicePath
, InstancePath
, &Device
);
203 if (Status
== STATUS_NO_SUCH_DEVICE
)
207 if (NextInstance
> 9999)
209 DPRINT1("Too many legacy devices reported for service '%wZ'\n", ServiceName
);
210 Status
= STATUS_INSUFFICIENT_RESOURCES
;
215 _snwprintf(InstancePath
, sizeof(InstancePath
) / sizeof(WCHAR
), L
"%04lu", NextInstance
);
216 Status
= LocateChildDevice(DeviceExtension
, DevicePath
, InstancePath
, &Device
);
217 if (Status
!= STATUS_NO_SUCH_DEVICE
|| NextInstance
> 9999)
219 DPRINT1("NextInstance value is corrupt! (%d)\n", NextInstance
);
220 RtlDeleteRegistryValue(RTL_REGISTRY_HANDLE
,
221 (PWSTR
)DeviceKeyHandle
,
227 Status
= RtlWriteRegistryValue(RTL_REGISTRY_HANDLE
,
228 (PWSTR
)DeviceKeyHandle
,
232 sizeof(NextInstance
));
233 if (!NT_SUCCESS(Status
))
235 DPRINT1("Failed to write new NextInstance value! (0x%x)\n", Status
);
239 if (!RtlCreateUnicodeString(&Device
->InstanceID
, InstancePath
))
241 Status
= STATUS_NO_MEMORY
;
245 /* Finish creating the instance path in the registry */
246 InitializeObjectAttributes(&ObjectAttributes
, &Device
->InstanceID
, OBJ_CASE_INSENSITIVE
, DeviceKeyHandle
, NULL
);
247 Status
= ZwCreateKey(&InstanceKeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
248 if (NT_SUCCESS(Status
))
250 DPRINT1("Failed to create instance path (0x%x)\n", Status
);
254 /* Just close the handle */
255 ZwClose(InstanceKeyHandle
);
257 if (FullInstancePath
)
259 FullInstancePath
->MaximumLength
= Device
->DeviceID
.Length
+ PathSep
.Length
+ Device
->InstanceID
.Length
;
260 FullInstancePath
->Length
= 0;
261 FullInstancePath
->Buffer
= ExAllocatePool(PagedPool
, FullInstancePath
->MaximumLength
);
262 if (!FullInstancePath
->Buffer
)
264 Status
= STATUS_NO_MEMORY
;
268 RtlAppendUnicodeStringToString(FullInstancePath
, &Device
->DeviceID
);
269 RtlAppendUnicodeStringToString(FullInstancePath
, &PathSep
);
270 RtlAppendUnicodeStringToString(FullInstancePath
, &Device
->InstanceID
);
273 /* Initialize a device object */
274 Status
= IoCreateDevice(
275 DriverObject
? DriverObject
: PnpRootDeviceObject
->DriverObject
,
276 sizeof(PNPROOT_PDO_DEVICE_EXTENSION
),
278 FILE_DEVICE_CONTROLLER
,
279 FILE_AUTOGENERATED_DEVICE_NAME
,
282 if (!NT_SUCCESS(Status
))
284 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
285 Status
= STATUS_NO_MEMORY
;
289 PdoDeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
290 RtlZeroMemory(PdoDeviceExtension
, sizeof(PNPROOT_PDO_DEVICE_EXTENSION
));
291 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
292 PdoDeviceExtension
->DeviceInfo
= Device
;
294 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
295 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
298 &DeviceExtension
->DeviceListHead
,
300 DeviceExtension
->DeviceListCount
++;
302 *PhysicalDeviceObject
= Device
->Pdo
;
303 DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject
, &Device
->DeviceID
, &Device
->InstanceID
);
305 Status
= STATUS_SUCCESS
;
308 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
312 IoDeleteDevice(Device
->Pdo
);
313 RtlFreeUnicodeString(&Device
->DeviceID
);
314 RtlFreeUnicodeString(&Device
->InstanceID
);
315 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
317 if (DeviceKeyHandle
!= INVALID_HANDLE_VALUE
)
318 ZwClose(DeviceKeyHandle
);
322 static NTSTATUS NTAPI
327 IN ULONG ValueLength
,
329 IN PVOID EntryContext
)
331 PUNICODE_STRING Destination
= (PUNICODE_STRING
)EntryContext
;
332 UNICODE_STRING Source
;
334 if (ValueType
!= REG_SZ
|| ValueLength
== 0 || ValueLength
% sizeof(WCHAR
) != 0)
336 Destination
->Length
= 0;
337 Destination
->MaximumLength
= 0;
338 Destination
->Buffer
= NULL
;
339 return STATUS_SUCCESS
;
342 Source
.MaximumLength
= Source
.Length
= (USHORT
)ValueLength
;
343 Source
.Buffer
= ValueData
;
345 return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &Source
, Destination
);
348 static NTSTATUS NTAPI
349 QueryBinaryValueCallback(
353 IN ULONG ValueLength
,
355 IN PVOID EntryContext
)
357 PBUFFER Buffer
= (PBUFFER
)EntryContext
;
360 if (ValueLength
== 0)
362 *Buffer
->Data
= NULL
;
363 return STATUS_SUCCESS
;
366 BinaryValue
= ExAllocatePoolWithTag(PagedPool
, ValueLength
, TAG_PNP_ROOT
);
367 if (BinaryValue
== NULL
)
368 return STATUS_NO_MEMORY
;
369 RtlCopyMemory(BinaryValue
, ValueData
, ValueLength
);
370 *Buffer
->Data
= BinaryValue
;
371 if (Buffer
->Length
) *Buffer
->Length
= ValueLength
;
372 return STATUS_SUCCESS
;
377 IN PDEVICE_OBJECT DeviceObject
)
379 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
380 PKEY_BASIC_INFORMATION KeyInfo
= NULL
, SubKeyInfo
= NULL
;
381 UNICODE_STRING LegacyU
= RTL_CONSTANT_STRING(L
"LEGACY_");
382 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L
"\\" REGSTR_KEY_ROOTENUM
);
383 UNICODE_STRING SubKeyName
;
384 WCHAR DevicePath
[MAX_PATH
+ 1];
385 RTL_QUERY_REGISTRY_TABLE QueryTable
[4];
386 PPNPROOT_DEVICE Device
= NULL
;
387 HANDLE KeyHandle
= INVALID_HANDLE_VALUE
;
388 HANDLE SubKeyHandle
= INVALID_HANDLE_VALUE
;
389 HANDLE DeviceKeyHandle
= INVALID_HANDLE_VALUE
;
392 ULONG Index1
, Index2
;
393 BUFFER Buffer1
, Buffer2
;
394 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
396 DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject
);
398 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
399 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
401 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + (MAX_PATH
+ 1) * sizeof(WCHAR
);
402 KeyInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_PNP_ROOT
);
405 DPRINT("ExAllocatePoolWithTag() failed\n");
406 Status
= STATUS_NO_MEMORY
;
409 SubKeyInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_PNP_ROOT
);
412 DPRINT("ExAllocatePoolWithTag() failed\n");
413 Status
= STATUS_NO_MEMORY
;
417 Status
= IopOpenRegistryKeyEx(&KeyHandle
, NULL
, &KeyName
, KEY_ENUMERATE_SUB_KEYS
);
418 if (!NT_SUCCESS(Status
))
420 DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName
, Status
);
424 /* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as
425 * KeyHandle. We'll first do a first enumeration to have first level keys,
426 * and an inner one to have the real devices list.
431 Status
= ZwEnumerateKey(
438 if (Status
== STATUS_NO_MORE_ENTRIES
)
440 Status
= STATUS_SUCCESS
;
443 else if (!NT_SUCCESS(Status
))
445 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
449 /* Terminate the string */
450 KeyInfo
->Name
[KeyInfo
->NameLength
/ sizeof(WCHAR
)] = 0;
452 /* Check if it is a legacy driver */
453 RtlInitUnicodeString(&SubKeyName
, KeyInfo
->Name
);
454 if (RtlPrefixUnicodeString(&LegacyU
, &SubKeyName
, FALSE
))
456 DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName
);
462 Status
= IopOpenRegistryKeyEx(&SubKeyHandle
, KeyHandle
, &SubKeyName
, KEY_ENUMERATE_SUB_KEYS
);
463 if (!NT_SUCCESS(Status
))
465 DPRINT("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status
);
469 /* Enumerate the sub-keys */
473 Status
= ZwEnumerateKey(
480 if (Status
== STATUS_NO_MORE_ENTRIES
)
482 else if (!NT_SUCCESS(Status
))
484 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
488 /* Terminate the string */
489 SubKeyInfo
->Name
[SubKeyInfo
->NameLength
/ sizeof(WCHAR
)] = 0;
493 sizeof(DevicePath
) / sizeof(WCHAR
),
494 L
"%s\\%s", REGSTR_KEY_ROOTENUM
, KeyInfo
->Name
);
495 DPRINT("Found device %S\\%s!\n", DevicePath
, SubKeyInfo
->Name
);
496 if (LocateChildDevice(DeviceExtension
, DevicePath
, SubKeyInfo
->Name
, &Device
) == STATUS_NO_SUCH_DEVICE
)
498 /* Create a PPNPROOT_DEVICE object, and add if in the list of known devices */
499 Device
= (PPNPROOT_DEVICE
)ExAllocatePoolWithTag(PagedPool
, sizeof(PNPROOT_DEVICE
), TAG_PNP_ROOT
);
502 DPRINT("ExAllocatePoolWithTag() failed\n");
503 Status
= STATUS_NO_MEMORY
;
506 RtlZeroMemory(Device
, sizeof(PNPROOT_DEVICE
));
508 /* Fill device ID and instance ID */
509 if (!RtlCreateUnicodeString(&Device
->DeviceID
, DevicePath
))
511 DPRINT1("RtlCreateUnicodeString() failed\n");
512 Status
= STATUS_NO_MEMORY
;
516 if (!RtlCreateUnicodeString(&Device
->InstanceID
, SubKeyInfo
->Name
))
518 DPRINT1("RtlCreateUnicodeString() failed\n");
519 Status
= STATUS_NO_MEMORY
;
523 /* Open registry key to fill other informations */
524 Status
= IopOpenRegistryKeyEx(&DeviceKeyHandle
, SubKeyHandle
, &Device
->InstanceID
, KEY_READ
);
525 if (!NT_SUCCESS(Status
))
527 DPRINT1("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status
);
531 /* Fill information from the device instance key */
532 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
533 QueryTable
[0].QueryRoutine
= QueryStringCallback
;
534 QueryTable
[0].Name
= L
"DeviceDesc";
535 QueryTable
[0].EntryContext
= &Device
->DeviceDescription
;
537 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
538 (PCWSTR
)DeviceKeyHandle
,
543 /* Fill information from the LogConf subkey */
544 Buffer1
.Data
= (PVOID
*)&Device
->ResourceRequirementsList
;
545 Buffer1
.Length
= NULL
;
546 Buffer2
.Data
= (PVOID
*)&Device
->ResourceList
;
547 Buffer2
.Length
= &Device
->ResourceListSize
;
548 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
549 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_SUBKEY
;
550 QueryTable
[0].Name
= L
"LogConf";
551 QueryTable
[1].QueryRoutine
= QueryBinaryValueCallback
;
552 QueryTable
[1].Name
= L
"BasicConfigVector";
553 QueryTable
[1].EntryContext
= &Buffer1
;
554 QueryTable
[2].QueryRoutine
= QueryBinaryValueCallback
;
555 QueryTable
[2].Name
= L
"BootConfig";
556 QueryTable
[2].EntryContext
= &Buffer2
;
558 if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
559 (PCWSTR
)DeviceKeyHandle
,
564 /* Non-fatal error */
565 DPRINT1("Failed to read the LogConf key for %S\\%S\n", DevicePath
, SubKeyInfo
->Name
);
568 ZwClose(DeviceKeyHandle
);
569 DeviceKeyHandle
= INVALID_HANDLE_VALUE
;
571 /* Insert the newly created device into the list */
573 &DeviceExtension
->DeviceListHead
,
575 DeviceExtension
->DeviceListCount
++;
582 ZwClose(SubKeyHandle
);
583 SubKeyHandle
= INVALID_HANDLE_VALUE
;
590 /* We have a device that has not been added to device list. We need to clean it up */
592 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
594 if (DeviceKeyHandle
!= INVALID_HANDLE_VALUE
)
595 ZwClose(DeviceKeyHandle
);
596 if (SubKeyHandle
!= INVALID_HANDLE_VALUE
)
597 ZwClose(SubKeyHandle
);
598 if (KeyHandle
!= INVALID_HANDLE_VALUE
)
601 ExFreePoolWithTag(KeyInfo
, TAG_PNP_ROOT
);
603 ExFreePoolWithTag(SubKeyInfo
, TAG_PNP_ROOT
);
604 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
608 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
610 * DeviceObject = Pointer to functional device object of the root bus driver
611 * Irp = Pointer to IRP that should be handled
616 PnpRootQueryDeviceRelations(
617 IN PDEVICE_OBJECT DeviceObject
,
620 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension
;
621 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
622 PDEVICE_RELATIONS Relations
= NULL
, OtherRelations
= (PDEVICE_RELATIONS
)Irp
->IoStatus
.Information
;
623 PPNPROOT_DEVICE Device
= NULL
;
626 PLIST_ENTRY NextEntry
;
628 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject
, Irp
);
630 Status
= EnumerateDevices(DeviceObject
);
631 if (!NT_SUCCESS(Status
))
633 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status
);
637 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
639 Size
= FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) + sizeof(PDEVICE_OBJECT
) * DeviceExtension
->DeviceListCount
;
642 /* Another bus driver has already created a DEVICE_RELATIONS
643 * structure so we must merge this structure with our own */
645 Size
+= sizeof(PDEVICE_OBJECT
) * OtherRelations
->Count
;
647 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
650 DPRINT("ExAllocatePoolWithTag() failed\n");
651 Status
= STATUS_NO_MEMORY
;
654 RtlZeroMemory(Relations
, Size
);
657 Relations
->Count
= OtherRelations
->Count
;
658 RtlCopyMemory(Relations
->Objects
, OtherRelations
->Objects
, sizeof(PDEVICE_OBJECT
) * OtherRelations
->Count
);
661 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
664 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
665 NextEntry
!= &DeviceExtension
->DeviceListHead
;
666 NextEntry
= NextEntry
->Flink
)
669 Device
= CONTAINING_RECORD(NextEntry
, PNPROOT_DEVICE
, ListEntry
);
673 /* Create a physical device object for the
674 * device as it does not already have one */
675 Status
= IoCreateDevice(
676 DeviceObject
->DriverObject
,
677 sizeof(PNPROOT_PDO_DEVICE_EXTENSION
),
679 FILE_DEVICE_CONTROLLER
,
680 FILE_AUTOGENERATED_DEVICE_NAME
,
683 if (!NT_SUCCESS(Status
))
685 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
689 PdoDeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
690 RtlZeroMemory(PdoDeviceExtension
, sizeof(PNPROOT_PDO_DEVICE_EXTENSION
));
691 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
692 PdoDeviceExtension
->DeviceInfo
= Device
;
694 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
695 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
698 /* Reference the physical device object. The PnP manager
699 will dereference it again when it is no longer needed */
700 ObReferenceObject(Device
->Pdo
);
702 Relations
->Objects
[Relations
->Count
++] = Device
->Pdo
;
704 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
706 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
709 if (!NT_SUCCESS(Status
))
712 ExFreePool(OtherRelations
);
714 ExFreePool(Relations
);
715 if (Device
&& Device
->Pdo
)
717 IoDeleteDevice(Device
->Pdo
);
726 * FUNCTION: Handle Plug and Play IRPs for the root bus device object
728 * DeviceObject = Pointer to functional device object of the root bus driver
729 * Irp = Pointer to IRP that should be handled
734 PnpRootFdoPnpControl(
735 IN PDEVICE_OBJECT DeviceObject
,
738 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
739 PIO_STACK_LOCATION IrpSp
;
742 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
743 Status
= Irp
->IoStatus
.Status
;
744 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
746 switch (IrpSp
->MinorFunction
)
748 case IRP_MN_QUERY_DEVICE_RELATIONS
:
749 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
750 Status
= PnpRootQueryDeviceRelations(DeviceObject
, Irp
);
753 case IRP_MN_START_DEVICE
:
754 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
755 if (!IoForwardIrpSynchronously(DeviceExtension
->Ldo
, Irp
))
756 Status
= STATUS_UNSUCCESSFUL
;
759 Status
= Irp
->IoStatus
.Status
;
760 if (NT_SUCCESS(Status
))
761 DeviceExtension
->State
= dsStarted
;
764 Irp
->IoStatus
.Status
= Status
;
765 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
768 case IRP_MN_STOP_DEVICE
:
769 DPRINT("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
770 /* Root device cannot be stopped */
771 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
772 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
776 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp
->MinorFunction
);
780 if (Status
!= STATUS_PENDING
)
782 Irp
->IoStatus
.Status
= Status
;
783 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
790 PdoQueryDeviceRelations(
791 IN PDEVICE_OBJECT DeviceObject
,
793 IN PIO_STACK_LOCATION IrpSp
)
795 PDEVICE_RELATIONS Relations
;
796 NTSTATUS Status
= Irp
->IoStatus
.Status
;
798 if (IrpSp
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
801 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
802 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
805 DPRINT("ExAllocatePoolWithTag() failed\n");
806 Status
= STATUS_NO_MEMORY
;
810 ObReferenceObject(DeviceObject
);
811 Relations
->Count
= 1;
812 Relations
->Objects
[0] = DeviceObject
;
813 Status
= STATUS_SUCCESS
;
814 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
821 PdoQueryCapabilities(
822 IN PDEVICE_OBJECT DeviceObject
,
824 IN PIO_STACK_LOCATION IrpSp
)
826 PDEVICE_CAPABILITIES DeviceCapabilities
;
828 DeviceCapabilities
= IrpSp
->Parameters
.DeviceCapabilities
.Capabilities
;
830 if (DeviceCapabilities
->Version
!= 1)
831 return STATUS_REVISION_MISMATCH
;
833 DeviceCapabilities
->UniqueID
= TRUE
;
834 /* FIXME: Fill other fields */
836 return STATUS_SUCCESS
;
841 IN PDEVICE_OBJECT DeviceObject
,
843 IN PIO_STACK_LOCATION IrpSp
)
845 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
846 PCM_RESOURCE_LIST ResourceList
;
848 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
850 if (DeviceExtension
->DeviceInfo
->ResourceList
)
852 /* Copy existing resource requirement list */
853 ResourceList
= ExAllocatePool(
855 DeviceExtension
->DeviceInfo
->ResourceListSize
);
857 return STATUS_NO_MEMORY
;
861 DeviceExtension
->DeviceInfo
->ResourceList
,
862 DeviceExtension
->DeviceInfo
->ResourceListSize
);
864 Irp
->IoStatus
.Information
= (ULONG_PTR
)ResourceList
;
866 return STATUS_SUCCESS
;
870 /* No resources so just return without changing the status */
871 return Irp
->IoStatus
.Status
;
876 PdoQueryResourceRequirements(
877 IN PDEVICE_OBJECT DeviceObject
,
879 IN PIO_STACK_LOCATION IrpSp
)
881 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
882 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList
;
884 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
886 if (DeviceExtension
->DeviceInfo
->ResourceRequirementsList
)
888 /* Copy existing resource requirement list */
889 ResourceList
= ExAllocatePool(PagedPool
, DeviceExtension
->DeviceInfo
->ResourceRequirementsList
->ListSize
);
891 return STATUS_NO_MEMORY
;
895 DeviceExtension
->DeviceInfo
->ResourceRequirementsList
,
896 DeviceExtension
->DeviceInfo
->ResourceRequirementsList
->ListSize
);
898 Irp
->IoStatus
.Information
= (ULONG_PTR
)ResourceList
;
900 return STATUS_SUCCESS
;
904 /* No resource requirements so just return without changing the status */
905 return Irp
->IoStatus
.Status
;
911 IN PDEVICE_OBJECT DeviceObject
,
913 IN PIO_STACK_LOCATION IrpSp
)
915 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
916 DEVICE_TEXT_TYPE DeviceTextType
;
917 NTSTATUS Status
= Irp
->IoStatus
.Status
;
919 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
920 DeviceTextType
= IrpSp
->Parameters
.QueryDeviceText
.DeviceTextType
;
922 switch (DeviceTextType
)
924 case DeviceTextDescription
:
926 UNICODE_STRING String
;
927 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
929 if (DeviceExtension
->DeviceInfo
->DeviceDescription
.Buffer
!= NULL
)
931 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
932 &DeviceExtension
->DeviceInfo
->DeviceDescription
,
934 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
939 case DeviceTextLocationInformation
:
941 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
947 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType
);
956 IN PDEVICE_OBJECT DeviceObject
,
958 IN PIO_STACK_LOCATION IrpSp
)
960 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
961 BUS_QUERY_ID_TYPE IdType
;
962 NTSTATUS Status
= Irp
->IoStatus
.Status
;
964 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
965 IdType
= IrpSp
->Parameters
.QueryId
.IdType
;
969 case BusQueryDeviceID
:
971 UNICODE_STRING String
;
972 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
974 Status
= RtlDuplicateUnicodeString(
975 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
976 &DeviceExtension
->DeviceInfo
->DeviceID
,
978 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
982 case BusQueryHardwareIDs
:
983 case BusQueryCompatibleIDs
:
985 /* Optional, do nothing */
989 case BusQueryInstanceID
:
991 UNICODE_STRING String
;
992 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
994 Status
= RtlDuplicateUnicodeString(
995 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
996 &DeviceExtension
->DeviceInfo
->InstanceID
,
998 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
1004 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType
);
1012 PdoQueryBusInformation(
1013 IN PDEVICE_OBJECT DeviceObject
,
1015 IN PIO_STACK_LOCATION IrpSp
)
1017 PPNP_BUS_INFORMATION BusInfo
;
1020 BusInfo
= (PPNP_BUS_INFORMATION
)ExAllocatePoolWithTag(PagedPool
, sizeof(PNP_BUS_INFORMATION
), TAG_PNP_ROOT
);
1022 Status
= STATUS_NO_MEMORY
;
1026 &BusInfo
->BusTypeGuid
,
1027 &GUID_BUS_TYPE_INTERNAL
,
1028 sizeof(BusInfo
->BusTypeGuid
));
1029 BusInfo
->LegacyBusType
= PNPBus
;
1030 /* We're the only root bus enumerator on the computer */
1031 BusInfo
->BusNumber
= 0;
1032 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInfo
;
1033 Status
= STATUS_SUCCESS
;
1040 * FUNCTION: Handle Plug and Play IRPs for the child device
1042 * DeviceObject = Pointer to physical device object of the child device
1043 * Irp = Pointer to IRP that should be handled
1048 PnpRootPdoPnpControl(
1049 IN PDEVICE_OBJECT DeviceObject
,
1052 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
1053 PPNPROOT_FDO_DEVICE_EXTENSION FdoDeviceExtension
;
1054 PIO_STACK_LOCATION IrpSp
;
1057 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1058 FdoDeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)PnpRootDeviceObject
->DeviceExtension
;
1059 Status
= Irp
->IoStatus
.Status
;
1060 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1062 switch (IrpSp
->MinorFunction
)
1064 case IRP_MN_START_DEVICE
: /* 0x00 */
1065 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1066 Status
= STATUS_SUCCESS
;
1069 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* 0x07 */
1070 Status
= PdoQueryDeviceRelations(DeviceObject
, Irp
, IrpSp
);
1073 case IRP_MN_QUERY_CAPABILITIES
: /* 0x09 */
1074 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
1075 Status
= PdoQueryCapabilities(DeviceObject
, Irp
, IrpSp
);
1078 case IRP_MN_QUERY_RESOURCES
: /* 0x0a */
1079 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
1080 Status
= PdoQueryResources(DeviceObject
, Irp
, IrpSp
);
1083 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
: /* 0x0b */
1084 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1085 Status
= PdoQueryResourceRequirements(DeviceObject
, Irp
, IrpSp
);
1088 case IRP_MN_QUERY_DEVICE_TEXT
: /* 0x0c */
1089 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1090 Status
= PdoQueryDeviceText(DeviceObject
, Irp
, IrpSp
);
1093 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* 0x0d */
1094 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1097 case IRP_MN_REMOVE_DEVICE
:
1098 /* Remove the device from the device list and decrement the device count*/
1099 KeAcquireGuardedMutex(&FdoDeviceExtension
->DeviceListLock
);
1100 RemoveEntryList(&DeviceExtension
->DeviceInfo
->ListEntry
);
1101 FdoDeviceExtension
->DeviceListCount
--;
1102 KeReleaseGuardedMutex(&FdoDeviceExtension
->DeviceListLock
);
1104 /* Free some strings we created */
1105 RtlFreeUnicodeString(&DeviceExtension
->DeviceInfo
->DeviceDescription
);
1106 RtlFreeUnicodeString(&DeviceExtension
->DeviceInfo
->DeviceID
);
1107 RtlFreeUnicodeString(&DeviceExtension
->DeviceInfo
->InstanceID
);
1109 /* Free the resource requirements list */
1110 if (DeviceExtension
->DeviceInfo
->ResourceRequirementsList
!= NULL
)
1111 ExFreePool(DeviceExtension
->DeviceInfo
->ResourceRequirementsList
);
1113 /* Free the boot resources list */
1114 if (DeviceExtension
->DeviceInfo
->ResourceList
!= NULL
)
1115 ExFreePool(DeviceExtension
->DeviceInfo
->ResourceList
);
1117 /* Free the device info */
1118 ExFreePool(DeviceExtension
->DeviceInfo
);
1120 /* Finally, delete the device object */
1121 IoDeleteDevice(DeviceObject
);
1123 /* Return success */
1124 Status
= STATUS_SUCCESS
;
1127 case IRP_MN_QUERY_ID
: /* 0x13 */
1128 Status
= PdoQueryId(DeviceObject
, Irp
, IrpSp
);
1131 case IRP_MN_QUERY_BUS_INFORMATION
: /* 0x15 */
1132 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
1133 Status
= PdoQueryBusInformation(DeviceObject
, Irp
, IrpSp
);
1137 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp
->MinorFunction
);
1141 if (Status
!= STATUS_PENDING
)
1143 Irp
->IoStatus
.Status
= Status
;
1144 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1151 * FUNCTION: Handle Plug and Play IRPs
1153 * DeviceObject = Pointer to PDO or FDO
1154 * Irp = Pointer to IRP that should be handled
1158 static NTSTATUS NTAPI
1160 IN PDEVICE_OBJECT DeviceObject
,
1163 PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension
;
1166 DeviceExtension
= (PPNPROOT_COMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1168 if (DeviceExtension
->IsFDO
)
1169 Status
= PnpRootFdoPnpControl(DeviceObject
, Irp
);
1171 Status
= PnpRootPdoPnpControl(DeviceObject
, Irp
);
1179 IN PDRIVER_OBJECT DriverObject
,
1180 IN PDEVICE_OBJECT PhysicalDeviceObject
)
1182 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
1185 DPRINT("PnpRootAddDevice(DriverObject %p, Pdo %p)\n", DriverObject
, PhysicalDeviceObject
);
1187 if (!PhysicalDeviceObject
)
1189 DPRINT("PhysicalDeviceObject 0x%p\n", PhysicalDeviceObject
);
1190 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1191 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1194 Status
= IoCreateDevice(
1196 sizeof(PNPROOT_FDO_DEVICE_EXTENSION
),
1198 FILE_DEVICE_BUS_EXTENDER
,
1199 FILE_DEVICE_SECURE_OPEN
,
1201 &PnpRootDeviceObject
);
1202 if (!NT_SUCCESS(Status
))
1204 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
1205 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1207 DPRINT("Created FDO %p\n", PnpRootDeviceObject
);
1209 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)PnpRootDeviceObject
->DeviceExtension
;
1210 RtlZeroMemory(DeviceExtension
, sizeof(PNPROOT_FDO_DEVICE_EXTENSION
));
1212 DeviceExtension
->Common
.IsFDO
= TRUE
;
1213 DeviceExtension
->State
= dsStopped
;
1214 InitializeListHead(&DeviceExtension
->DeviceListHead
);
1215 DeviceExtension
->DeviceListCount
= 0;
1216 KeInitializeGuardedMutex(&DeviceExtension
->DeviceListLock
);
1218 Status
= IoAttachDeviceToDeviceStackSafe(
1219 PnpRootDeviceObject
,
1220 PhysicalDeviceObject
,
1221 &DeviceExtension
->Ldo
);
1222 if (!NT_SUCCESS(Status
))
1224 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
1225 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1228 PnpRootDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1230 DPRINT("Done AddDevice()\n");
1232 return STATUS_SUCCESS
;
1237 IN PDRIVER_OBJECT DriverObject
,
1238 IN PUNICODE_STRING RegistryPath
)
1240 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject
, RegistryPath
);
1242 IopRootDriverObject
= DriverObject
;
1244 DriverObject
->DriverExtension
->AddDevice
= PnpRootAddDevice
;
1246 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = PnpRootPnpControl
;
1247 //DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
1249 return STATUS_SUCCESS
;