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 OUT PDEVICE_OBJECT
*PhysicalDeviceObject
,
134 OUT OPTIONAL PUNICODE_STRING FullInstancePath
)
136 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
137 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension
;
138 WCHAR DevicePath
[MAX_PATH
+ 1];
139 WCHAR InstancePath
[5];
140 PPNPROOT_DEVICE Device
= NULL
;
142 UNICODE_STRING PathSep
= RTL_CONSTANT_STRING(L
"\\");
144 UNICODE_STRING EnumKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM
);
145 HANDLE EnumHandle
, DeviceKeyHandle
= INVALID_HANDLE_VALUE
;
146 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
147 OBJECT_ATTRIBUTES ObjectAttributes
;
149 DeviceExtension
= PnpRootDeviceObject
->DeviceExtension
;
150 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
152 DPRINT("Creating a PnP root device for service '%wZ'\n", ServiceName
);
154 _snwprintf(DevicePath
, sizeof(DevicePath
) / sizeof(WCHAR
), L
"%s\\%wZ", REGSTR_KEY_ROOTENUM
, ServiceName
);
156 /* Initialize a PNPROOT_DEVICE structure */
157 Device
= ExAllocatePoolWithTag(PagedPool
, sizeof(PNPROOT_DEVICE
), TAG_PNP_ROOT
);
160 DPRINT("ExAllocatePoolWithTag() failed\n");
161 Status
= STATUS_NO_MEMORY
;
164 RtlZeroMemory(Device
, sizeof(PNPROOT_DEVICE
));
165 if (!RtlCreateUnicodeString(&Device
->DeviceID
, DevicePath
))
167 Status
= STATUS_NO_MEMORY
;
171 Status
= IopOpenRegistryKeyEx(&EnumHandle
, NULL
, &EnumKeyName
, KEY_READ
);
172 if (NT_SUCCESS(Status
))
174 InitializeObjectAttributes(&ObjectAttributes
, &Device
->DeviceID
, OBJ_CASE_INSENSITIVE
, EnumHandle
, NULL
);
175 Status
= ZwCreateKey(&DeviceKeyHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
179 if (!NT_SUCCESS(Status
))
181 DPRINT1("Failed to open registry key\n");
186 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
187 QueryTable
[0].Name
= L
"NextInstance";
188 QueryTable
[0].EntryContext
= &NextInstance
;
189 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
191 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
192 (PWSTR
)DeviceKeyHandle
,
196 if (!NT_SUCCESS(Status
))
198 for (NextInstance
= 0; NextInstance
<= 9999; NextInstance
++)
200 _snwprintf(InstancePath
, sizeof(InstancePath
) / sizeof(WCHAR
), L
"%04lu", NextInstance
);
201 Status
= LocateChildDevice(DeviceExtension
, DevicePath
, InstancePath
, &Device
);
202 if (Status
== STATUS_NO_SUCH_DEVICE
)
206 if (NextInstance
> 9999)
208 DPRINT1("Too many legacy devices reported for service '%wZ'\n", ServiceName
);
209 Status
= STATUS_INSUFFICIENT_RESOURCES
;
214 _snwprintf(InstancePath
, sizeof(InstancePath
) / sizeof(WCHAR
), L
"%04lu", NextInstance
);
215 Status
= LocateChildDevice(DeviceExtension
, DevicePath
, InstancePath
, &Device
);
216 if (Status
!= STATUS_NO_SUCH_DEVICE
|| NextInstance
> 9999)
218 DPRINT1("NextInstance value is corrupt! (%d)\n", NextInstance
);
219 RtlDeleteRegistryValue(RTL_REGISTRY_HANDLE
,
220 (PWSTR
)DeviceKeyHandle
,
226 Status
= RtlWriteRegistryValue(RTL_REGISTRY_HANDLE
,
227 (PWSTR
)DeviceKeyHandle
,
231 sizeof(NextInstance
));
232 if (!NT_SUCCESS(Status
))
234 DPRINT1("Failed to write new NextInstance value! (0x%x)\n", Status
);
238 if (!RtlCreateUnicodeString(&Device
->InstanceID
, InstancePath
))
240 Status
= STATUS_NO_MEMORY
;
244 if (FullInstancePath
)
246 FullInstancePath
->MaximumLength
= Device
->DeviceID
.Length
+ PathSep
.Length
+ Device
->InstanceID
.Length
;
247 FullInstancePath
->Length
= 0;
248 FullInstancePath
->Buffer
= ExAllocatePool(PagedPool
, FullInstancePath
->MaximumLength
);
249 if (!FullInstancePath
->Buffer
)
251 Status
= STATUS_NO_MEMORY
;
255 RtlAppendUnicodeStringToString(FullInstancePath
, &Device
->DeviceID
);
256 RtlAppendUnicodeStringToString(FullInstancePath
, &PathSep
);
257 RtlAppendUnicodeStringToString(FullInstancePath
, &Device
->InstanceID
);
260 /* Initialize a device object */
261 Status
= IoCreateDevice(
262 PnpRootDeviceObject
->DriverObject
,
263 sizeof(PNPROOT_PDO_DEVICE_EXTENSION
),
265 FILE_DEVICE_CONTROLLER
,
266 FILE_AUTOGENERATED_DEVICE_NAME
,
269 if (!NT_SUCCESS(Status
))
271 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
272 Status
= STATUS_NO_MEMORY
;
276 PdoDeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
277 RtlZeroMemory(PdoDeviceExtension
, sizeof(PNPROOT_PDO_DEVICE_EXTENSION
));
278 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
279 PdoDeviceExtension
->DeviceInfo
= Device
;
281 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
282 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
285 &DeviceExtension
->DeviceListHead
,
287 DeviceExtension
->DeviceListCount
++;
289 *PhysicalDeviceObject
= Device
->Pdo
;
290 DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject
, &Device
->DeviceID
, &Device
->InstanceID
);
292 Status
= STATUS_SUCCESS
;
295 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
299 IoDeleteDevice(Device
->Pdo
);
300 RtlFreeUnicodeString(&Device
->DeviceID
);
301 RtlFreeUnicodeString(&Device
->InstanceID
);
302 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
304 if (DeviceKeyHandle
!= INVALID_HANDLE_VALUE
)
305 ZwClose(DeviceKeyHandle
);
309 static NTSTATUS NTAPI
314 IN ULONG ValueLength
,
316 IN PVOID EntryContext
)
318 PUNICODE_STRING Destination
= (PUNICODE_STRING
)EntryContext
;
319 UNICODE_STRING Source
;
321 if (ValueType
!= REG_SZ
|| ValueLength
== 0 || ValueLength
% sizeof(WCHAR
) != 0)
322 return STATUS_SUCCESS
;
324 Source
.MaximumLength
= Source
.Length
= ValueLength
;
325 Source
.Buffer
= ValueData
;
326 if (Source
.Length
> 0 && Source
.Buffer
[Source
.Length
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
)
327 Source
.Length
-= sizeof(WCHAR
);
328 return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &Source
, Destination
);
331 static NTSTATUS NTAPI
332 QueryBinaryValueCallback(
336 IN ULONG ValueLength
,
338 IN PVOID EntryContext
)
340 PBUFFER Buffer
= (PBUFFER
)EntryContext
;
343 if (ValueLength
== 0)
345 *Buffer
->Data
= NULL
;
346 return STATUS_SUCCESS
;
349 BinaryValue
= ExAllocatePoolWithTag(PagedPool
, ValueLength
, TAG_PNP_ROOT
);
350 if (BinaryValue
== NULL
)
351 return STATUS_NO_MEMORY
;
352 RtlCopyMemory(BinaryValue
, ValueData
, ValueLength
);
353 *Buffer
->Data
= BinaryValue
;
354 if (Buffer
->Length
) *Buffer
->Length
= ValueLength
;
355 return STATUS_SUCCESS
;
360 IN PDEVICE_OBJECT DeviceObject
)
362 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
363 PKEY_BASIC_INFORMATION KeyInfo
= NULL
, SubKeyInfo
= NULL
;
364 UNICODE_STRING LegacyU
= RTL_CONSTANT_STRING(L
"LEGACY_");
365 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L
"\\" REGSTR_KEY_ROOTENUM
);
366 UNICODE_STRING SubKeyName
;
367 WCHAR DevicePath
[MAX_PATH
+ 1];
368 RTL_QUERY_REGISTRY_TABLE QueryTable
[5];
369 PPNPROOT_DEVICE Device
= NULL
;
370 HANDLE KeyHandle
= INVALID_HANDLE_VALUE
;
371 HANDLE SubKeyHandle
= INVALID_HANDLE_VALUE
;
372 HANDLE DeviceKeyHandle
= INVALID_HANDLE_VALUE
;
375 ULONG Index1
, Index2
;
376 BUFFER Buffer1
, Buffer2
;
377 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
379 DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject
);
381 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
382 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
384 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + (MAX_PATH
+ 1) * sizeof(WCHAR
);
385 KeyInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_PNP_ROOT
);
388 DPRINT("ExAllocatePoolWithTag() failed\n");
389 Status
= STATUS_NO_MEMORY
;
392 SubKeyInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_PNP_ROOT
);
395 DPRINT("ExAllocatePoolWithTag() failed\n");
396 Status
= STATUS_NO_MEMORY
;
400 Status
= IopOpenRegistryKeyEx(&KeyHandle
, NULL
, &KeyName
, KEY_ENUMERATE_SUB_KEYS
);
401 if (!NT_SUCCESS(Status
))
403 DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName
, Status
);
407 /* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as
408 * KeyHandle. We'll first do a first enumeration to have first level keys,
409 * and an inner one to have the real devices list.
414 Status
= ZwEnumerateKey(
421 if (Status
== STATUS_NO_MORE_ENTRIES
)
423 Status
= STATUS_SUCCESS
;
426 else if (!NT_SUCCESS(Status
))
428 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
432 /* Terminate the string */
433 KeyInfo
->Name
[KeyInfo
->NameLength
/ sizeof(WCHAR
)] = 0;
435 /* Check if it is a legacy driver */
436 RtlInitUnicodeString(&SubKeyName
, KeyInfo
->Name
);
437 if (RtlPrefixUnicodeString(&LegacyU
, &SubKeyName
, FALSE
))
439 DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName
);
445 Status
= IopOpenRegistryKeyEx(&SubKeyHandle
, KeyHandle
, &SubKeyName
, KEY_ENUMERATE_SUB_KEYS
);
446 if (!NT_SUCCESS(Status
))
448 DPRINT("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status
);
452 /* Enumerate the sub-keys */
456 Status
= ZwEnumerateKey(
463 if (Status
== STATUS_NO_MORE_ENTRIES
)
465 else if (!NT_SUCCESS(Status
))
467 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
471 /* Terminate the string */
472 SubKeyInfo
->Name
[SubKeyInfo
->NameLength
/ sizeof(WCHAR
)] = 0;
476 sizeof(DevicePath
) / sizeof(WCHAR
),
477 L
"%s\\%s", REGSTR_KEY_ROOTENUM
, KeyInfo
->Name
);
478 DPRINT("Found device %S\\%s!\n", DevicePath
, SubKeyInfo
->Name
);
479 if (LocateChildDevice(DeviceExtension
, DevicePath
, SubKeyInfo
->Name
, &Device
) == STATUS_NO_SUCH_DEVICE
)
481 /* Create a PPNPROOT_DEVICE object, and add if in the list of known devices */
482 Device
= (PPNPROOT_DEVICE
)ExAllocatePoolWithTag(PagedPool
, sizeof(PNPROOT_DEVICE
), TAG_PNP_ROOT
);
485 DPRINT("ExAllocatePoolWithTag() failed\n");
486 Status
= STATUS_NO_MEMORY
;
489 RtlZeroMemory(Device
, sizeof(PNPROOT_DEVICE
));
491 /* Fill device ID and instance ID */
492 if (!RtlCreateUnicodeString(&Device
->DeviceID
, DevicePath
))
494 DPRINT("RtlCreateUnicodeString() failed\n");
495 Status
= STATUS_NO_MEMORY
;
499 if (!RtlCreateUnicodeString(&Device
->InstanceID
, SubKeyInfo
->Name
))
501 DPRINT("RtlCreateUnicodeString() failed\n");
502 Status
= STATUS_NO_MEMORY
;
506 /* Open registry key to fill other informations */
507 Status
= IopOpenRegistryKeyEx(&DeviceKeyHandle
, SubKeyHandle
, &Device
->InstanceID
, KEY_READ
);
508 if (!NT_SUCCESS(Status
))
510 DPRINT("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status
);
514 /* Fill other informations */
515 Buffer1
.Data
= (PVOID
*)&Device
->ResourceRequirementsList
;
516 Buffer1
.Length
= NULL
;
517 Buffer2
.Data
= (PVOID
*)&Device
->ResourceList
;
518 Buffer2
.Length
= &Device
->ResourceListSize
;
519 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
520 QueryTable
[0].QueryRoutine
= QueryStringCallback
;
521 QueryTable
[0].Name
= L
"DeviceDesc";
522 QueryTable
[0].EntryContext
= &Device
->DeviceDescription
;
523 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_SUBKEY
;
524 QueryTable
[1].Name
= L
"LogConf";
525 QueryTable
[2].QueryRoutine
= QueryBinaryValueCallback
;
526 QueryTable
[2].Name
= L
"BasicConfigVector";
527 QueryTable
[2].EntryContext
= &Buffer1
;
528 QueryTable
[3].QueryRoutine
= QueryBinaryValueCallback
;
529 QueryTable
[3].Name
= L
"BootConfig";
530 QueryTable
[3].EntryContext
= &Buffer2
;
532 Status
= RtlQueryRegistryValues(
534 (PCWSTR
)DeviceKeyHandle
,
538 if (!NT_SUCCESS(Status
))
540 DPRINT("RtlQueryRegistryValues() failed with status 0x%08lx\n", Status
);
544 ZwClose(DeviceKeyHandle
);
545 DeviceKeyHandle
= INVALID_HANDLE_VALUE
;
547 /* Insert the newly created device into the list */
549 &DeviceExtension
->DeviceListHead
,
551 DeviceExtension
->DeviceListCount
++;
558 ZwClose(SubKeyHandle
);
559 SubKeyHandle
= INVALID_HANDLE_VALUE
;
566 /* We have a device that has not been added to device list. We need to clean it up */
568 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
570 if (DeviceKeyHandle
!= INVALID_HANDLE_VALUE
)
571 ZwClose(DeviceKeyHandle
);
572 if (SubKeyHandle
!= INVALID_HANDLE_VALUE
)
573 ZwClose(SubKeyHandle
);
574 if (KeyHandle
!= INVALID_HANDLE_VALUE
)
577 ExFreePoolWithTag(KeyInfo
, TAG_PNP_ROOT
);
579 ExFreePoolWithTag(SubKeyInfo
, TAG_PNP_ROOT
);
580 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
584 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
586 * DeviceObject = Pointer to functional device object of the root bus driver
587 * Irp = Pointer to IRP that should be handled
592 PnpRootQueryDeviceRelations(
593 IN PDEVICE_OBJECT DeviceObject
,
596 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension
;
597 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
598 PDEVICE_RELATIONS Relations
= NULL
, OtherRelations
= (PDEVICE_RELATIONS
)Irp
->IoStatus
.Information
;
599 PPNPROOT_DEVICE Device
= NULL
;
602 PLIST_ENTRY NextEntry
;
604 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject
, Irp
);
606 Status
= EnumerateDevices(DeviceObject
);
607 if (!NT_SUCCESS(Status
))
609 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status
);
613 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
615 Size
= FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) + sizeof(PDEVICE_OBJECT
) * DeviceExtension
->DeviceListCount
;
618 /* Another bus driver has already created a DEVICE_RELATIONS
619 * structure so we must merge this structure with our own */
621 Size
+= sizeof(PDEVICE_OBJECT
) * OtherRelations
->Count
;
623 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
626 DPRINT("ExAllocatePoolWithTag() failed\n");
627 Status
= STATUS_NO_MEMORY
;
630 RtlZeroMemory(Relations
, Size
);
633 Relations
->Count
= OtherRelations
->Count
;
634 RtlCopyMemory(Relations
->Objects
, OtherRelations
->Objects
, sizeof(PDEVICE_OBJECT
) * OtherRelations
->Count
);
637 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
640 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
641 NextEntry
!= &DeviceExtension
->DeviceListHead
;
642 NextEntry
= NextEntry
->Flink
)
645 Device
= CONTAINING_RECORD(NextEntry
, PNPROOT_DEVICE
, ListEntry
);
649 /* Create a physical device object for the
650 * device as it does not already have one */
651 Status
= IoCreateDevice(
652 DeviceObject
->DriverObject
,
653 sizeof(PNPROOT_PDO_DEVICE_EXTENSION
),
655 FILE_DEVICE_CONTROLLER
,
656 FILE_AUTOGENERATED_DEVICE_NAME
,
659 if (!NT_SUCCESS(Status
))
661 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
665 PdoDeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
666 RtlZeroMemory(PdoDeviceExtension
, sizeof(PNPROOT_PDO_DEVICE_EXTENSION
));
667 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
668 PdoDeviceExtension
->DeviceInfo
= Device
;
670 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
671 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
674 /* Reference the physical device object. The PnP manager
675 will dereference it again when it is no longer needed */
676 ObReferenceObject(Device
->Pdo
);
678 Relations
->Objects
[Relations
->Count
++] = Device
->Pdo
;
680 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
682 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
685 if (!NT_SUCCESS(Status
))
688 ExFreePool(OtherRelations
);
690 ExFreePool(Relations
);
691 if (Device
&& Device
->Pdo
)
693 IoDeleteDevice(Device
->Pdo
);
702 * FUNCTION: Handle Plug and Play IRPs for the root bus device object
704 * DeviceObject = Pointer to functional device object of the root bus driver
705 * Irp = Pointer to IRP that should be handled
710 PnpRootFdoPnpControl(
711 IN PDEVICE_OBJECT DeviceObject
,
714 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
715 PIO_STACK_LOCATION IrpSp
;
718 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
719 Status
= Irp
->IoStatus
.Status
;
720 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
722 switch (IrpSp
->MinorFunction
)
724 case IRP_MN_QUERY_DEVICE_RELATIONS
:
725 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
726 Status
= PnpRootQueryDeviceRelations(DeviceObject
, Irp
);
729 case IRP_MN_START_DEVICE
:
730 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
731 if (!IoForwardIrpSynchronously(DeviceExtension
->Ldo
, Irp
))
732 Status
= STATUS_UNSUCCESSFUL
;
735 Status
= Irp
->IoStatus
.Status
;
736 if (NT_SUCCESS(Status
))
737 DeviceExtension
->State
= dsStarted
;
740 Irp
->IoStatus
.Status
= Status
;
741 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
744 case IRP_MN_STOP_DEVICE
:
745 DPRINT("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
746 /* Root device cannot be stopped */
747 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
748 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
752 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp
->MinorFunction
);
756 if (Status
!= STATUS_PENDING
)
758 Irp
->IoStatus
.Status
= Status
;
759 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
766 PdoQueryDeviceRelations(
767 IN PDEVICE_OBJECT DeviceObject
,
769 IN PIO_STACK_LOCATION IrpSp
)
771 PDEVICE_RELATIONS Relations
;
772 NTSTATUS Status
= Irp
->IoStatus
.Status
;
774 if (IrpSp
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
777 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
778 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
781 DPRINT("ExAllocatePoolWithTag() failed\n");
782 Status
= STATUS_NO_MEMORY
;
786 ObReferenceObject(DeviceObject
);
787 Relations
->Count
= 1;
788 Relations
->Objects
[0] = DeviceObject
;
789 Status
= STATUS_SUCCESS
;
790 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
797 PdoQueryCapabilities(
798 IN PDEVICE_OBJECT DeviceObject
,
800 IN PIO_STACK_LOCATION IrpSp
)
802 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
803 PDEVICE_CAPABILITIES DeviceCapabilities
;
805 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
806 DeviceCapabilities
= IrpSp
->Parameters
.DeviceCapabilities
.Capabilities
;
808 if (DeviceCapabilities
->Version
!= 1)
809 return STATUS_REVISION_MISMATCH
;
811 DeviceCapabilities
->UniqueID
= TRUE
;
812 /* FIXME: Fill other fields */
814 return STATUS_SUCCESS
;
819 IN PDEVICE_OBJECT DeviceObject
,
821 IN PIO_STACK_LOCATION IrpSp
)
823 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
824 PCM_RESOURCE_LIST ResourceList
;
826 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
828 if (DeviceExtension
->DeviceInfo
->ResourceList
)
830 /* Copy existing resource requirement list */
831 ResourceList
= ExAllocatePool(
833 DeviceExtension
->DeviceInfo
->ResourceListSize
);
835 return STATUS_NO_MEMORY
;
839 DeviceExtension
->DeviceInfo
->ResourceList
,
840 DeviceExtension
->DeviceInfo
->ResourceListSize
);
842 Irp
->IoStatus
.Information
= (ULONG_PTR
)ResourceList
;
844 return STATUS_SUCCESS
;
848 /* No resources so just return without changing the status */
849 return Irp
->IoStatus
.Status
;
854 PdoQueryResourceRequirements(
855 IN PDEVICE_OBJECT DeviceObject
,
857 IN PIO_STACK_LOCATION IrpSp
)
859 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
860 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList
;
862 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
864 if (DeviceExtension
->DeviceInfo
->ResourceRequirementsList
)
866 /* Copy existing resource requirement list */
867 ResourceList
= ExAllocatePool(PagedPool
, DeviceExtension
->DeviceInfo
->ResourceRequirementsList
->ListSize
);
869 return STATUS_NO_MEMORY
;
873 DeviceExtension
->DeviceInfo
->ResourceRequirementsList
,
874 DeviceExtension
->DeviceInfo
->ResourceRequirementsList
->ListSize
);
876 Irp
->IoStatus
.Information
= (ULONG_PTR
)ResourceList
;
878 return STATUS_SUCCESS
;
882 /* No resource requirements so just return without changing the status */
883 return Irp
->IoStatus
.Status
;
889 IN PDEVICE_OBJECT DeviceObject
,
891 IN PIO_STACK_LOCATION IrpSp
)
893 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
894 DEVICE_TEXT_TYPE DeviceTextType
;
895 NTSTATUS Status
= Irp
->IoStatus
.Status
;
897 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
898 DeviceTextType
= IrpSp
->Parameters
.QueryDeviceText
.DeviceTextType
;
900 switch (DeviceTextType
)
902 case DeviceTextDescription
:
904 UNICODE_STRING String
;
905 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
907 Status
= RtlDuplicateUnicodeString(
908 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
909 &DeviceExtension
->DeviceInfo
->DeviceDescription
,
911 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
915 case DeviceTextLocationInformation
:
917 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
918 Status
= STATUS_NOT_SUPPORTED
;
924 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType
);
933 IN PDEVICE_OBJECT DeviceObject
,
935 IN PIO_STACK_LOCATION IrpSp
)
937 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
938 BUS_QUERY_ID_TYPE IdType
;
939 NTSTATUS Status
= Irp
->IoStatus
.Status
;
941 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
942 IdType
= IrpSp
->Parameters
.QueryId
.IdType
;
946 case BusQueryDeviceID
:
948 UNICODE_STRING String
;
949 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
951 Status
= RtlDuplicateUnicodeString(
952 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
953 &DeviceExtension
->DeviceInfo
->DeviceID
,
955 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
959 case BusQueryHardwareIDs
:
960 case BusQueryCompatibleIDs
:
962 /* Optional, do nothing */
966 case BusQueryInstanceID
:
968 UNICODE_STRING String
;
969 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
971 Status
= RtlDuplicateUnicodeString(
972 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
973 &DeviceExtension
->DeviceInfo
->InstanceID
,
975 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
981 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType
);
989 PdoQueryBusInformation(
990 IN PDEVICE_OBJECT DeviceObject
,
992 IN PIO_STACK_LOCATION IrpSp
)
994 PPNP_BUS_INFORMATION BusInfo
;
997 BusInfo
= (PPNP_BUS_INFORMATION
)ExAllocatePoolWithTag(PagedPool
, sizeof(PNP_BUS_INFORMATION
), TAG_PNP_ROOT
);
999 Status
= STATUS_NO_MEMORY
;
1003 &BusInfo
->BusTypeGuid
,
1004 &GUID_BUS_TYPE_INTERNAL
,
1005 sizeof(BusInfo
->BusTypeGuid
));
1006 BusInfo
->LegacyBusType
= PNPBus
;
1007 /* We're the only root bus enumerator on the computer */
1008 BusInfo
->BusNumber
= 0;
1009 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInfo
;
1010 Status
= STATUS_SUCCESS
;
1017 * FUNCTION: Handle Plug and Play IRPs for the child device
1019 * DeviceObject = Pointer to physical device object of the child device
1020 * Irp = Pointer to IRP that should be handled
1025 PnpRootPdoPnpControl(
1026 IN PDEVICE_OBJECT DeviceObject
,
1029 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
1030 PIO_STACK_LOCATION IrpSp
;
1033 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1034 Status
= Irp
->IoStatus
.Status
;
1035 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1037 switch (IrpSp
->MinorFunction
)
1039 case IRP_MN_START_DEVICE
: /* 0x00 */
1040 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1041 Status
= STATUS_SUCCESS
;
1044 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* 0x07 */
1045 Status
= PdoQueryDeviceRelations(DeviceObject
, Irp
, IrpSp
);
1048 case IRP_MN_QUERY_CAPABILITIES
: /* 0x09 */
1049 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
1050 Status
= PdoQueryCapabilities(DeviceObject
, Irp
, IrpSp
);
1053 case IRP_MN_QUERY_RESOURCES
: /* 0x0a */
1054 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
1055 Status
= PdoQueryResources(DeviceObject
, Irp
, IrpSp
);
1058 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
: /* 0x0b */
1059 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1060 Status
= PdoQueryResourceRequirements(DeviceObject
, Irp
, IrpSp
);
1063 case IRP_MN_QUERY_DEVICE_TEXT
: /* 0x0c */
1064 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1065 Status
= PdoQueryDeviceText(DeviceObject
, Irp
, IrpSp
);
1068 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* 0x0d */
1069 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1072 case IRP_MN_QUERY_ID
: /* 0x13 */
1073 Status
= PdoQueryId(DeviceObject
, Irp
, IrpSp
);
1076 case IRP_MN_QUERY_BUS_INFORMATION
: /* 0x15 */
1077 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
1078 Status
= PdoQueryBusInformation(DeviceObject
, Irp
, IrpSp
);
1082 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp
->MinorFunction
);
1083 Status
= STATUS_NOT_IMPLEMENTED
;
1087 if (Status
!= STATUS_PENDING
)
1089 Irp
->IoStatus
.Status
= Status
;
1090 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1097 * FUNCTION: Handle Plug and Play IRPs
1099 * DeviceObject = Pointer to PDO or FDO
1100 * Irp = Pointer to IRP that should be handled
1104 static NTSTATUS NTAPI
1106 IN PDEVICE_OBJECT DeviceObject
,
1109 PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension
;
1112 DeviceExtension
= (PPNPROOT_COMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1114 if (DeviceExtension
->IsFDO
)
1115 Status
= PnpRootFdoPnpControl(DeviceObject
, Irp
);
1117 Status
= PnpRootPdoPnpControl(DeviceObject
, Irp
);
1125 IN PDRIVER_OBJECT DriverObject
,
1126 IN PDEVICE_OBJECT PhysicalDeviceObject
)
1128 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
1131 DPRINT("PnpRootAddDevice(DriverObject %p, Pdo %p)\n", DriverObject
, PhysicalDeviceObject
);
1133 if (!PhysicalDeviceObject
)
1135 DPRINT("PhysicalDeviceObject 0x%p\n", PhysicalDeviceObject
);
1136 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1137 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1140 Status
= IoCreateDevice(
1142 sizeof(PNPROOT_FDO_DEVICE_EXTENSION
),
1144 FILE_DEVICE_BUS_EXTENDER
,
1145 FILE_DEVICE_SECURE_OPEN
,
1147 &PnpRootDeviceObject
);
1148 if (!NT_SUCCESS(Status
))
1150 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
1151 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1153 DPRINT("Created FDO %p\n", PnpRootDeviceObject
);
1155 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)PnpRootDeviceObject
->DeviceExtension
;
1156 RtlZeroMemory(DeviceExtension
, sizeof(PNPROOT_FDO_DEVICE_EXTENSION
));
1158 DeviceExtension
->Common
.IsFDO
= TRUE
;
1159 DeviceExtension
->State
= dsStopped
;
1160 InitializeListHead(&DeviceExtension
->DeviceListHead
);
1161 DeviceExtension
->DeviceListCount
= 0;
1162 KeInitializeGuardedMutex(&DeviceExtension
->DeviceListLock
);
1164 Status
= IoAttachDeviceToDeviceStackSafe(
1165 PnpRootDeviceObject
,
1166 PhysicalDeviceObject
,
1167 &DeviceExtension
->Ldo
);
1168 if (!NT_SUCCESS(Status
))
1170 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
1171 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1174 PnpRootDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1176 DPRINT("Done AddDevice()\n");
1178 return STATUS_SUCCESS
;
1183 IN PDRIVER_OBJECT DriverObject
,
1184 IN PUNICODE_STRING RegistryPath
)
1186 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject
, RegistryPath
);
1188 IopRootDriverObject
= DriverObject
;
1190 DriverObject
->DriverExtension
->AddDevice
= PnpRootAddDevice
;
1192 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = PnpRootPnpControl
;
1193 //DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
1195 return STATUS_SUCCESS
;