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
;
130 PnpRootRegisterDevice(
131 IN PDEVICE_OBJECT DeviceObject
)
133 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
= PnpRootDeviceObject
->DeviceExtension
;
134 PPNPROOT_DEVICE Device
;
135 PDEVICE_NODE DeviceNode
;
137 UNICODE_STRING InstancePathCopy
;
139 Device
= ExAllocatePoolWithTag(PagedPool
, sizeof(PNPROOT_DEVICE
), TAG_PNP_ROOT
);
140 if (!Device
) return STATUS_NO_MEMORY
;
142 DeviceNode
= IopGetDeviceNode(DeviceObject
);
143 if (!RtlCreateUnicodeString(&InstancePathCopy
, DeviceNode
->InstancePath
.Buffer
))
145 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
146 return STATUS_NO_MEMORY
;
149 InstancePath
= wcsrchr(InstancePathCopy
.Buffer
, L
'\\');
150 ASSERT(InstancePath
);
152 if (!RtlCreateUnicodeString(&Device
->InstanceID
, InstancePath
+ 1))
154 RtlFreeUnicodeString(&InstancePathCopy
);
155 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
156 return STATUS_NO_MEMORY
;
159 InstancePath
[0] = UNICODE_NULL
;
161 if (!RtlCreateUnicodeString(&Device
->DeviceID
, InstancePathCopy
.Buffer
))
163 RtlFreeUnicodeString(&InstancePathCopy
);
164 RtlFreeUnicodeString(&Device
->InstanceID
);
165 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
166 return STATUS_NO_MEMORY
;
169 InstancePath
[0] = L
'\\';
171 Device
->Pdo
= DeviceObject
;
173 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
174 InsertTailList(&DeviceExtension
->DeviceListHead
,
176 DeviceExtension
->DeviceListCount
++;
177 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
179 RtlFreeUnicodeString(&InstancePathCopy
);
181 return STATUS_SUCCESS
;
184 /* Creates a new PnP device for a legacy driver */
187 IN PUNICODE_STRING ServiceName
,
188 IN OPTIONAL PDRIVER_OBJECT DriverObject
,
189 OUT PDEVICE_OBJECT
*PhysicalDeviceObject
,
190 OUT OPTIONAL PUNICODE_STRING FullInstancePath
)
192 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
193 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension
;
194 WCHAR DevicePath
[MAX_PATH
+ 1];
195 WCHAR InstancePath
[5];
196 PPNPROOT_DEVICE Device
= NULL
;
198 UNICODE_STRING PathSep
= RTL_CONSTANT_STRING(L
"\\");
200 UNICODE_STRING EnumKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM
);
201 HANDLE EnumHandle
, DeviceKeyHandle
= INVALID_HANDLE_VALUE
, InstanceKeyHandle
;
202 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
203 OBJECT_ATTRIBUTES ObjectAttributes
;
205 DeviceExtension
= PnpRootDeviceObject
->DeviceExtension
;
206 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
208 DPRINT("Creating a PnP root device for service '%wZ'\n", ServiceName
);
210 _snwprintf(DevicePath
, sizeof(DevicePath
) / sizeof(WCHAR
), L
"%s\\%wZ", REGSTR_KEY_ROOTENUM
, ServiceName
);
212 /* Initialize a PNPROOT_DEVICE structure */
213 Device
= ExAllocatePoolWithTag(PagedPool
, sizeof(PNPROOT_DEVICE
), TAG_PNP_ROOT
);
216 DPRINT("ExAllocatePoolWithTag() failed\n");
217 Status
= STATUS_NO_MEMORY
;
220 RtlZeroMemory(Device
, sizeof(PNPROOT_DEVICE
));
221 if (!RtlCreateUnicodeString(&Device
->DeviceID
, DevicePath
))
223 Status
= STATUS_NO_MEMORY
;
227 Status
= IopOpenRegistryKeyEx(&EnumHandle
, NULL
, &EnumKeyName
, KEY_READ
);
228 if (NT_SUCCESS(Status
))
230 InitializeObjectAttributes(&ObjectAttributes
, &Device
->DeviceID
, OBJ_CASE_INSENSITIVE
, EnumHandle
, NULL
);
231 Status
= ZwCreateKey(&DeviceKeyHandle
, KEY_SET_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
235 if (!NT_SUCCESS(Status
))
237 DPRINT1("Failed to open registry key\n");
242 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
243 QueryTable
[0].Name
= L
"NextInstance";
244 QueryTable
[0].EntryContext
= &NextInstance
;
245 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
247 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
248 (PWSTR
)DeviceKeyHandle
,
252 if (!NT_SUCCESS(Status
))
254 for (NextInstance
= 0; NextInstance
<= 9999; NextInstance
++)
256 _snwprintf(InstancePath
, sizeof(InstancePath
) / sizeof(WCHAR
), L
"%04lu", NextInstance
);
257 Status
= LocateChildDevice(DeviceExtension
, DevicePath
, InstancePath
, &Device
);
258 if (Status
== STATUS_NO_SUCH_DEVICE
)
262 if (NextInstance
> 9999)
264 DPRINT1("Too many legacy devices reported for service '%wZ'\n", ServiceName
);
265 Status
= STATUS_INSUFFICIENT_RESOURCES
;
270 _snwprintf(InstancePath
, sizeof(InstancePath
) / sizeof(WCHAR
), L
"%04lu", NextInstance
);
271 Status
= LocateChildDevice(DeviceExtension
, DevicePath
, InstancePath
, &Device
);
272 if (Status
!= STATUS_NO_SUCH_DEVICE
|| NextInstance
> 9999)
274 DPRINT1("NextInstance value is corrupt! (%d)\n", NextInstance
);
275 RtlDeleteRegistryValue(RTL_REGISTRY_HANDLE
,
276 (PWSTR
)DeviceKeyHandle
,
282 Status
= RtlWriteRegistryValue(RTL_REGISTRY_HANDLE
,
283 (PWSTR
)DeviceKeyHandle
,
287 sizeof(NextInstance
));
288 if (!NT_SUCCESS(Status
))
290 DPRINT1("Failed to write new NextInstance value! (0x%x)\n", Status
);
294 if (!RtlCreateUnicodeString(&Device
->InstanceID
, InstancePath
))
296 Status
= STATUS_NO_MEMORY
;
300 /* Finish creating the instance path in the registry */
301 InitializeObjectAttributes(&ObjectAttributes
, &Device
->InstanceID
, OBJ_CASE_INSENSITIVE
, DeviceKeyHandle
, NULL
);
302 Status
= ZwCreateKey(&InstanceKeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
, 0, NULL
, REG_OPTION_VOLATILE
, NULL
);
303 if (NT_SUCCESS(Status
))
305 DPRINT1("Failed to create instance path (0x%x)\n", Status
);
309 /* Just close the handle */
310 ZwClose(InstanceKeyHandle
);
312 if (FullInstancePath
)
314 FullInstancePath
->MaximumLength
= Device
->DeviceID
.Length
+ PathSep
.Length
+ Device
->InstanceID
.Length
;
315 FullInstancePath
->Length
= 0;
316 FullInstancePath
->Buffer
= ExAllocatePool(PagedPool
, FullInstancePath
->MaximumLength
);
317 if (!FullInstancePath
->Buffer
)
319 Status
= STATUS_NO_MEMORY
;
323 RtlAppendUnicodeStringToString(FullInstancePath
, &Device
->DeviceID
);
324 RtlAppendUnicodeStringToString(FullInstancePath
, &PathSep
);
325 RtlAppendUnicodeStringToString(FullInstancePath
, &Device
->InstanceID
);
328 /* Initialize a device object */
329 Status
= IoCreateDevice(
330 DriverObject
? DriverObject
: PnpRootDeviceObject
->DriverObject
,
331 sizeof(PNPROOT_PDO_DEVICE_EXTENSION
),
333 FILE_DEVICE_CONTROLLER
,
334 FILE_AUTOGENERATED_DEVICE_NAME
,
337 if (!NT_SUCCESS(Status
))
339 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
340 Status
= STATUS_NO_MEMORY
;
344 PdoDeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
345 RtlZeroMemory(PdoDeviceExtension
, sizeof(PNPROOT_PDO_DEVICE_EXTENSION
));
346 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
347 PdoDeviceExtension
->DeviceInfo
= Device
;
349 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
350 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
353 &DeviceExtension
->DeviceListHead
,
355 DeviceExtension
->DeviceListCount
++;
357 *PhysicalDeviceObject
= Device
->Pdo
;
358 DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject
, &Device
->DeviceID
, &Device
->InstanceID
);
360 Status
= STATUS_SUCCESS
;
363 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
367 IoDeleteDevice(Device
->Pdo
);
368 RtlFreeUnicodeString(&Device
->DeviceID
);
369 RtlFreeUnicodeString(&Device
->InstanceID
);
370 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
372 if (DeviceKeyHandle
!= INVALID_HANDLE_VALUE
)
373 ZwClose(DeviceKeyHandle
);
377 static NTSTATUS NTAPI
382 IN ULONG ValueLength
,
384 IN PVOID EntryContext
)
386 PUNICODE_STRING Destination
= (PUNICODE_STRING
)EntryContext
;
387 UNICODE_STRING Source
;
389 if (ValueType
!= REG_SZ
|| ValueLength
== 0 || ValueLength
% sizeof(WCHAR
) != 0)
391 Destination
->Length
= 0;
392 Destination
->MaximumLength
= 0;
393 Destination
->Buffer
= NULL
;
394 return STATUS_SUCCESS
;
397 Source
.MaximumLength
= Source
.Length
= (USHORT
)ValueLength
;
398 Source
.Buffer
= ValueData
;
400 return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &Source
, Destination
);
403 static NTSTATUS NTAPI
404 QueryBinaryValueCallback(
408 IN ULONG ValueLength
,
410 IN PVOID EntryContext
)
412 PBUFFER Buffer
= (PBUFFER
)EntryContext
;
415 if (ValueLength
== 0)
417 *Buffer
->Data
= NULL
;
418 return STATUS_SUCCESS
;
421 BinaryValue
= ExAllocatePoolWithTag(PagedPool
, ValueLength
, TAG_PNP_ROOT
);
422 if (BinaryValue
== NULL
)
423 return STATUS_NO_MEMORY
;
424 RtlCopyMemory(BinaryValue
, ValueData
, ValueLength
);
425 *Buffer
->Data
= BinaryValue
;
426 if (Buffer
->Length
) *Buffer
->Length
= ValueLength
;
427 return STATUS_SUCCESS
;
432 IN PDEVICE_OBJECT DeviceObject
)
434 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
435 PKEY_BASIC_INFORMATION KeyInfo
= NULL
, SubKeyInfo
= NULL
;
436 UNICODE_STRING LegacyU
= RTL_CONSTANT_STRING(L
"LEGACY_");
437 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L
"\\" REGSTR_KEY_ROOTENUM
);
438 UNICODE_STRING SubKeyName
;
439 WCHAR DevicePath
[MAX_PATH
+ 1];
440 RTL_QUERY_REGISTRY_TABLE QueryTable
[4];
441 PPNPROOT_DEVICE Device
= NULL
;
442 HANDLE KeyHandle
= INVALID_HANDLE_VALUE
;
443 HANDLE SubKeyHandle
= INVALID_HANDLE_VALUE
;
444 HANDLE DeviceKeyHandle
= INVALID_HANDLE_VALUE
;
447 ULONG Index1
, Index2
;
448 BUFFER Buffer1
, Buffer2
;
449 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
451 DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject
);
453 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
454 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
456 BufferSize
= sizeof(KEY_BASIC_INFORMATION
) + (MAX_PATH
+ 1) * sizeof(WCHAR
);
457 KeyInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_PNP_ROOT
);
460 DPRINT("ExAllocatePoolWithTag() failed\n");
461 Status
= STATUS_NO_MEMORY
;
464 SubKeyInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_PNP_ROOT
);
467 DPRINT("ExAllocatePoolWithTag() failed\n");
468 Status
= STATUS_NO_MEMORY
;
472 Status
= IopOpenRegistryKeyEx(&KeyHandle
, NULL
, &KeyName
, KEY_ENUMERATE_SUB_KEYS
);
473 if (!NT_SUCCESS(Status
))
475 DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName
, Status
);
479 /* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as
480 * KeyHandle. We'll first do a first enumeration to have first level keys,
481 * and an inner one to have the real devices list.
486 Status
= ZwEnumerateKey(
493 if (Status
== STATUS_NO_MORE_ENTRIES
)
495 Status
= STATUS_SUCCESS
;
498 else if (!NT_SUCCESS(Status
))
500 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
504 /* Terminate the string */
505 KeyInfo
->Name
[KeyInfo
->NameLength
/ sizeof(WCHAR
)] = 0;
507 /* Check if it is a legacy driver */
508 RtlInitUnicodeString(&SubKeyName
, KeyInfo
->Name
);
509 if (RtlPrefixUnicodeString(&LegacyU
, &SubKeyName
, FALSE
))
511 DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName
);
517 Status
= IopOpenRegistryKeyEx(&SubKeyHandle
, KeyHandle
, &SubKeyName
, KEY_ENUMERATE_SUB_KEYS
);
518 if (!NT_SUCCESS(Status
))
520 DPRINT("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status
);
524 /* Enumerate the sub-keys */
528 Status
= ZwEnumerateKey(
535 if (Status
== STATUS_NO_MORE_ENTRIES
)
537 else if (!NT_SUCCESS(Status
))
539 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status
);
543 /* Terminate the string */
544 SubKeyInfo
->Name
[SubKeyInfo
->NameLength
/ sizeof(WCHAR
)] = 0;
546 _snwprintf(DevicePath
, sizeof(DevicePath
) / sizeof(WCHAR
),
547 L
"%s\\%s", REGSTR_KEY_ROOTENUM
, KeyInfo
->Name
);
548 DPRINT("Found device %S\\%s!\n", DevicePath
, SubKeyInfo
->Name
);
549 if (LocateChildDevice(DeviceExtension
, DevicePath
, SubKeyInfo
->Name
, &Device
) == STATUS_NO_SUCH_DEVICE
)
551 /* Create a PPNPROOT_DEVICE object, and add if in the list of known devices */
552 Device
= (PPNPROOT_DEVICE
)ExAllocatePoolWithTag(PagedPool
, sizeof(PNPROOT_DEVICE
), TAG_PNP_ROOT
);
555 DPRINT("ExAllocatePoolWithTag() failed\n");
556 Status
= STATUS_NO_MEMORY
;
559 RtlZeroMemory(Device
, sizeof(PNPROOT_DEVICE
));
561 /* Fill device ID and instance ID */
562 if (!RtlCreateUnicodeString(&Device
->DeviceID
, DevicePath
))
564 DPRINT1("RtlCreateUnicodeString() failed\n");
565 Status
= STATUS_NO_MEMORY
;
569 if (!RtlCreateUnicodeString(&Device
->InstanceID
, SubKeyInfo
->Name
))
571 DPRINT1("RtlCreateUnicodeString() failed\n");
572 Status
= STATUS_NO_MEMORY
;
576 /* Open registry key to fill other informations */
577 Status
= IopOpenRegistryKeyEx(&DeviceKeyHandle
, SubKeyHandle
, &Device
->InstanceID
, KEY_READ
);
578 if (!NT_SUCCESS(Status
))
580 DPRINT1("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status
);
584 /* Fill information from the device instance key */
585 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
586 QueryTable
[0].QueryRoutine
= QueryStringCallback
;
587 QueryTable
[0].Name
= L
"DeviceDesc";
588 QueryTable
[0].EntryContext
= &Device
->DeviceDescription
;
590 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
591 (PCWSTR
)DeviceKeyHandle
,
596 /* Fill information from the LogConf subkey */
597 Buffer1
.Data
= (PVOID
*)&Device
->ResourceRequirementsList
;
598 Buffer1
.Length
= NULL
;
599 Buffer2
.Data
= (PVOID
*)&Device
->ResourceList
;
600 Buffer2
.Length
= &Device
->ResourceListSize
;
601 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
602 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_SUBKEY
;
603 QueryTable
[0].Name
= L
"LogConf";
604 QueryTable
[1].QueryRoutine
= QueryBinaryValueCallback
;
605 QueryTable
[1].Name
= L
"BasicConfigVector";
606 QueryTable
[1].EntryContext
= &Buffer1
;
607 QueryTable
[2].QueryRoutine
= QueryBinaryValueCallback
;
608 QueryTable
[2].Name
= L
"BootConfig";
609 QueryTable
[2].EntryContext
= &Buffer2
;
611 if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
612 (PCWSTR
)DeviceKeyHandle
,
617 /* Non-fatal error */
618 DPRINT1("Failed to read the LogConf key for %S\\%S\n", DevicePath
, SubKeyInfo
->Name
);
621 ZwClose(DeviceKeyHandle
);
622 DeviceKeyHandle
= INVALID_HANDLE_VALUE
;
624 /* Insert the newly created device into the list */
626 &DeviceExtension
->DeviceListHead
,
628 DeviceExtension
->DeviceListCount
++;
635 ZwClose(SubKeyHandle
);
636 SubKeyHandle
= INVALID_HANDLE_VALUE
;
643 /* We have a device that has not been added to device list. We need to clean it up */
645 ExFreePoolWithTag(Device
, TAG_PNP_ROOT
);
647 if (DeviceKeyHandle
!= INVALID_HANDLE_VALUE
)
648 ZwClose(DeviceKeyHandle
);
649 if (SubKeyHandle
!= INVALID_HANDLE_VALUE
)
650 ZwClose(SubKeyHandle
);
651 if (KeyHandle
!= INVALID_HANDLE_VALUE
)
654 ExFreePoolWithTag(KeyInfo
, TAG_PNP_ROOT
);
656 ExFreePoolWithTag(SubKeyInfo
, TAG_PNP_ROOT
);
657 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
661 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
663 * DeviceObject = Pointer to functional device object of the root bus driver
664 * Irp = Pointer to IRP that should be handled
669 PnpRootQueryDeviceRelations(
670 IN PDEVICE_OBJECT DeviceObject
,
673 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension
;
674 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
675 PDEVICE_RELATIONS Relations
= NULL
, OtherRelations
= (PDEVICE_RELATIONS
)Irp
->IoStatus
.Information
;
676 PPNPROOT_DEVICE Device
= NULL
;
679 PLIST_ENTRY NextEntry
;
681 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject
, Irp
);
683 Status
= EnumerateDevices(DeviceObject
);
684 if (!NT_SUCCESS(Status
))
686 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status
);
690 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
692 Size
= FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) + sizeof(PDEVICE_OBJECT
) * DeviceExtension
->DeviceListCount
;
695 /* Another bus driver has already created a DEVICE_RELATIONS
696 * structure so we must merge this structure with our own */
698 Size
+= sizeof(PDEVICE_OBJECT
) * OtherRelations
->Count
;
700 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
703 DPRINT("ExAllocatePoolWithTag() failed\n");
704 Status
= STATUS_NO_MEMORY
;
707 RtlZeroMemory(Relations
, Size
);
710 Relations
->Count
= OtherRelations
->Count
;
711 RtlCopyMemory(Relations
->Objects
, OtherRelations
->Objects
, sizeof(PDEVICE_OBJECT
) * OtherRelations
->Count
);
714 KeAcquireGuardedMutex(&DeviceExtension
->DeviceListLock
);
717 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
718 NextEntry
!= &DeviceExtension
->DeviceListHead
;
719 NextEntry
= NextEntry
->Flink
)
722 Device
= CONTAINING_RECORD(NextEntry
, PNPROOT_DEVICE
, ListEntry
);
726 /* Create a physical device object for the
727 * device as it does not already have one */
728 Status
= IoCreateDevice(
729 DeviceObject
->DriverObject
,
730 sizeof(PNPROOT_PDO_DEVICE_EXTENSION
),
732 FILE_DEVICE_CONTROLLER
,
733 FILE_AUTOGENERATED_DEVICE_NAME
,
736 if (!NT_SUCCESS(Status
))
738 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
742 PdoDeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
743 RtlZeroMemory(PdoDeviceExtension
, sizeof(PNPROOT_PDO_DEVICE_EXTENSION
));
744 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
745 PdoDeviceExtension
->DeviceInfo
= Device
;
747 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
748 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
751 /* Reference the physical device object. The PnP manager
752 will dereference it again when it is no longer needed */
753 ObReferenceObject(Device
->Pdo
);
755 Relations
->Objects
[Relations
->Count
++] = Device
->Pdo
;
757 KeReleaseGuardedMutex(&DeviceExtension
->DeviceListLock
);
759 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
762 if (!NT_SUCCESS(Status
))
765 ExFreePool(OtherRelations
);
767 ExFreePool(Relations
);
768 if (Device
&& Device
->Pdo
)
770 IoDeleteDevice(Device
->Pdo
);
779 * FUNCTION: Handle Plug and Play IRPs for the root bus device object
781 * DeviceObject = Pointer to functional device object of the root bus driver
782 * Irp = Pointer to IRP that should be handled
787 PnpRootFdoPnpControl(
788 IN PDEVICE_OBJECT DeviceObject
,
791 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
792 PIO_STACK_LOCATION IrpSp
;
795 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
796 Status
= Irp
->IoStatus
.Status
;
797 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
799 switch (IrpSp
->MinorFunction
)
801 case IRP_MN_QUERY_DEVICE_RELATIONS
:
802 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
803 Status
= PnpRootQueryDeviceRelations(DeviceObject
, Irp
);
806 case IRP_MN_START_DEVICE
:
807 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
808 if (!IoForwardIrpSynchronously(DeviceExtension
->Ldo
, Irp
))
809 Status
= STATUS_UNSUCCESSFUL
;
812 Status
= Irp
->IoStatus
.Status
;
813 if (NT_SUCCESS(Status
))
814 DeviceExtension
->State
= dsStarted
;
817 Irp
->IoStatus
.Status
= Status
;
818 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
821 case IRP_MN_STOP_DEVICE
:
822 DPRINT("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
823 /* Root device cannot be stopped */
824 Irp
->IoStatus
.Status
= Status
= STATUS_INVALID_DEVICE_REQUEST
;
825 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
829 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp
->MinorFunction
);
833 if (Status
!= STATUS_PENDING
)
835 Irp
->IoStatus
.Status
= Status
;
836 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
843 PdoQueryDeviceRelations(
844 IN PDEVICE_OBJECT DeviceObject
,
846 IN PIO_STACK_LOCATION IrpSp
)
848 PDEVICE_RELATIONS Relations
;
849 NTSTATUS Status
= Irp
->IoStatus
.Status
;
851 if (IrpSp
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
854 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
855 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, sizeof(DEVICE_RELATIONS
));
858 DPRINT("ExAllocatePoolWithTag() failed\n");
859 Status
= STATUS_NO_MEMORY
;
863 ObReferenceObject(DeviceObject
);
864 Relations
->Count
= 1;
865 Relations
->Objects
[0] = DeviceObject
;
866 Status
= STATUS_SUCCESS
;
867 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
874 PdoQueryCapabilities(
875 IN PDEVICE_OBJECT DeviceObject
,
877 IN PIO_STACK_LOCATION IrpSp
)
879 PDEVICE_CAPABILITIES DeviceCapabilities
;
881 DeviceCapabilities
= IrpSp
->Parameters
.DeviceCapabilities
.Capabilities
;
883 if (DeviceCapabilities
->Version
!= 1)
884 return STATUS_REVISION_MISMATCH
;
886 DeviceCapabilities
->UniqueID
= TRUE
;
887 /* FIXME: Fill other fields */
889 return STATUS_SUCCESS
;
894 IN PDEVICE_OBJECT DeviceObject
,
896 IN PIO_STACK_LOCATION IrpSp
)
898 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
899 PCM_RESOURCE_LIST ResourceList
;
901 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
903 if (DeviceExtension
->DeviceInfo
->ResourceList
)
905 /* Copy existing resource requirement list */
906 ResourceList
= ExAllocatePool(
908 DeviceExtension
->DeviceInfo
->ResourceListSize
);
910 return STATUS_NO_MEMORY
;
914 DeviceExtension
->DeviceInfo
->ResourceList
,
915 DeviceExtension
->DeviceInfo
->ResourceListSize
);
917 Irp
->IoStatus
.Information
= (ULONG_PTR
)ResourceList
;
919 return STATUS_SUCCESS
;
923 /* No resources so just return without changing the status */
924 return Irp
->IoStatus
.Status
;
929 PdoQueryResourceRequirements(
930 IN PDEVICE_OBJECT DeviceObject
,
932 IN PIO_STACK_LOCATION IrpSp
)
934 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
935 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList
;
937 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
939 if (DeviceExtension
->DeviceInfo
->ResourceRequirementsList
)
941 /* Copy existing resource requirement list */
942 ResourceList
= ExAllocatePool(PagedPool
, DeviceExtension
->DeviceInfo
->ResourceRequirementsList
->ListSize
);
944 return STATUS_NO_MEMORY
;
948 DeviceExtension
->DeviceInfo
->ResourceRequirementsList
,
949 DeviceExtension
->DeviceInfo
->ResourceRequirementsList
->ListSize
);
951 Irp
->IoStatus
.Information
= (ULONG_PTR
)ResourceList
;
953 return STATUS_SUCCESS
;
957 /* No resource requirements so just return without changing the status */
958 return Irp
->IoStatus
.Status
;
964 IN PDEVICE_OBJECT DeviceObject
,
966 IN PIO_STACK_LOCATION IrpSp
)
968 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
969 DEVICE_TEXT_TYPE DeviceTextType
;
970 NTSTATUS Status
= Irp
->IoStatus
.Status
;
972 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
973 DeviceTextType
= IrpSp
->Parameters
.QueryDeviceText
.DeviceTextType
;
975 switch (DeviceTextType
)
977 case DeviceTextDescription
:
979 UNICODE_STRING String
;
980 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
982 if (DeviceExtension
->DeviceInfo
->DeviceDescription
.Buffer
!= NULL
)
984 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
985 &DeviceExtension
->DeviceInfo
->DeviceDescription
,
987 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
992 case DeviceTextLocationInformation
:
994 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
1000 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType
);
1009 IN PDEVICE_OBJECT DeviceObject
,
1011 IN PIO_STACK_LOCATION IrpSp
)
1013 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
1014 BUS_QUERY_ID_TYPE IdType
;
1015 NTSTATUS Status
= Irp
->IoStatus
.Status
;
1017 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1018 IdType
= IrpSp
->Parameters
.QueryId
.IdType
;
1022 case BusQueryDeviceID
:
1024 UNICODE_STRING String
;
1025 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
1027 Status
= RtlDuplicateUnicodeString(
1028 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1029 &DeviceExtension
->DeviceInfo
->DeviceID
,
1031 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
1035 case BusQueryHardwareIDs
:
1036 case BusQueryCompatibleIDs
:
1038 /* Optional, do nothing */
1042 case BusQueryInstanceID
:
1044 UNICODE_STRING String
;
1045 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
1047 Status
= RtlDuplicateUnicodeString(
1048 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1049 &DeviceExtension
->DeviceInfo
->InstanceID
,
1051 Irp
->IoStatus
.Information
= (ULONG_PTR
)String
.Buffer
;
1057 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType
);
1065 PdoQueryBusInformation(
1066 IN PDEVICE_OBJECT DeviceObject
,
1068 IN PIO_STACK_LOCATION IrpSp
)
1070 PPNP_BUS_INFORMATION BusInfo
;
1073 BusInfo
= (PPNP_BUS_INFORMATION
)ExAllocatePoolWithTag(PagedPool
, sizeof(PNP_BUS_INFORMATION
), TAG_PNP_ROOT
);
1075 Status
= STATUS_NO_MEMORY
;
1079 &BusInfo
->BusTypeGuid
,
1080 &GUID_BUS_TYPE_INTERNAL
,
1081 sizeof(BusInfo
->BusTypeGuid
));
1082 BusInfo
->LegacyBusType
= PNPBus
;
1083 /* We're the only root bus enumerator on the computer */
1084 BusInfo
->BusNumber
= 0;
1085 Irp
->IoStatus
.Information
= (ULONG_PTR
)BusInfo
;
1086 Status
= STATUS_SUCCESS
;
1093 * FUNCTION: Handle Plug and Play IRPs for the child device
1095 * DeviceObject = Pointer to physical device object of the child device
1096 * Irp = Pointer to IRP that should be handled
1101 PnpRootPdoPnpControl(
1102 IN PDEVICE_OBJECT DeviceObject
,
1105 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension
;
1106 PPNPROOT_FDO_DEVICE_EXTENSION FdoDeviceExtension
;
1107 PIO_STACK_LOCATION IrpSp
;
1110 DeviceExtension
= (PPNPROOT_PDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1111 FdoDeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)PnpRootDeviceObject
->DeviceExtension
;
1112 Status
= Irp
->IoStatus
.Status
;
1113 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1115 switch (IrpSp
->MinorFunction
)
1117 case IRP_MN_START_DEVICE
: /* 0x00 */
1118 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1119 Status
= STATUS_SUCCESS
;
1122 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* 0x07 */
1123 Status
= PdoQueryDeviceRelations(DeviceObject
, Irp
, IrpSp
);
1126 case IRP_MN_QUERY_CAPABILITIES
: /* 0x09 */
1127 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
1128 Status
= PdoQueryCapabilities(DeviceObject
, Irp
, IrpSp
);
1131 case IRP_MN_QUERY_RESOURCES
: /* 0x0a */
1132 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
1133 Status
= PdoQueryResources(DeviceObject
, Irp
, IrpSp
);
1136 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
: /* 0x0b */
1137 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1138 Status
= PdoQueryResourceRequirements(DeviceObject
, Irp
, IrpSp
);
1141 case IRP_MN_QUERY_DEVICE_TEXT
: /* 0x0c */
1142 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1143 Status
= PdoQueryDeviceText(DeviceObject
, Irp
, IrpSp
);
1146 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
: /* 0x0d */
1147 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1150 case IRP_MN_REMOVE_DEVICE
:
1151 /* Remove the device from the device list and decrement the device count*/
1152 KeAcquireGuardedMutex(&FdoDeviceExtension
->DeviceListLock
);
1153 RemoveEntryList(&DeviceExtension
->DeviceInfo
->ListEntry
);
1154 FdoDeviceExtension
->DeviceListCount
--;
1155 KeReleaseGuardedMutex(&FdoDeviceExtension
->DeviceListLock
);
1157 /* Free some strings we created */
1158 RtlFreeUnicodeString(&DeviceExtension
->DeviceInfo
->DeviceDescription
);
1159 RtlFreeUnicodeString(&DeviceExtension
->DeviceInfo
->DeviceID
);
1160 RtlFreeUnicodeString(&DeviceExtension
->DeviceInfo
->InstanceID
);
1162 /* Free the resource requirements list */
1163 if (DeviceExtension
->DeviceInfo
->ResourceRequirementsList
!= NULL
)
1164 ExFreePool(DeviceExtension
->DeviceInfo
->ResourceRequirementsList
);
1166 /* Free the boot resources list */
1167 if (DeviceExtension
->DeviceInfo
->ResourceList
!= NULL
)
1168 ExFreePool(DeviceExtension
->DeviceInfo
->ResourceList
);
1170 /* Free the device info */
1171 ExFreePool(DeviceExtension
->DeviceInfo
);
1173 /* Finally, delete the device object */
1174 IoDeleteDevice(DeviceObject
);
1176 /* Return success */
1177 Status
= STATUS_SUCCESS
;
1180 case IRP_MN_QUERY_ID
: /* 0x13 */
1181 Status
= PdoQueryId(DeviceObject
, Irp
, IrpSp
);
1184 case IRP_MN_QUERY_BUS_INFORMATION
: /* 0x15 */
1185 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
1186 Status
= PdoQueryBusInformation(DeviceObject
, Irp
, IrpSp
);
1190 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp
->MinorFunction
);
1194 if (Status
!= STATUS_PENDING
)
1196 Irp
->IoStatus
.Status
= Status
;
1197 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1204 * FUNCTION: Handle Plug and Play IRPs
1206 * DeviceObject = Pointer to PDO or FDO
1207 * Irp = Pointer to IRP that should be handled
1211 static NTSTATUS NTAPI
1213 IN PDEVICE_OBJECT DeviceObject
,
1216 PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension
;
1219 DeviceExtension
= (PPNPROOT_COMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1221 if (DeviceExtension
->IsFDO
)
1222 Status
= PnpRootFdoPnpControl(DeviceObject
, Irp
);
1224 Status
= PnpRootPdoPnpControl(DeviceObject
, Irp
);
1232 IN PDRIVER_OBJECT DriverObject
,
1233 IN PDEVICE_OBJECT PhysicalDeviceObject
)
1235 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension
;
1238 DPRINT("PnpRootAddDevice(DriverObject %p, Pdo %p)\n", DriverObject
, PhysicalDeviceObject
);
1240 if (!PhysicalDeviceObject
)
1242 DPRINT("PhysicalDeviceObject 0x%p\n", PhysicalDeviceObject
);
1243 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1244 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1247 Status
= IoCreateDevice(
1249 sizeof(PNPROOT_FDO_DEVICE_EXTENSION
),
1251 FILE_DEVICE_BUS_EXTENDER
,
1252 FILE_DEVICE_SECURE_OPEN
,
1254 &PnpRootDeviceObject
);
1255 if (!NT_SUCCESS(Status
))
1257 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
1258 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1260 DPRINT("Created FDO %p\n", PnpRootDeviceObject
);
1262 DeviceExtension
= (PPNPROOT_FDO_DEVICE_EXTENSION
)PnpRootDeviceObject
->DeviceExtension
;
1263 RtlZeroMemory(DeviceExtension
, sizeof(PNPROOT_FDO_DEVICE_EXTENSION
));
1265 DeviceExtension
->Common
.IsFDO
= TRUE
;
1266 DeviceExtension
->State
= dsStopped
;
1267 InitializeListHead(&DeviceExtension
->DeviceListHead
);
1268 DeviceExtension
->DeviceListCount
= 0;
1269 KeInitializeGuardedMutex(&DeviceExtension
->DeviceListLock
);
1271 Status
= IoAttachDeviceToDeviceStackSafe(
1272 PnpRootDeviceObject
,
1273 PhysicalDeviceObject
,
1274 &DeviceExtension
->Ldo
);
1275 if (!NT_SUCCESS(Status
))
1277 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
1278 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED
, Status
, 0, 0, 0);
1281 PnpRootDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1283 DPRINT("Done AddDevice()\n");
1285 return STATUS_SUCCESS
;
1290 IN PDRIVER_OBJECT DriverObject
,
1291 IN PUNICODE_STRING RegistryPath
)
1293 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject
, RegistryPath
);
1295 IopRootDriverObject
= DriverObject
;
1297 DriverObject
->DriverExtension
->AddDevice
= PnpRootAddDevice
;
1299 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = PnpRootPnpControl
;
1300 //DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
1302 return STATUS_SUCCESS
;