1 /*
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)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 #define ENUM_NAME_ROOT L"Root"
19
20 /* DATA **********************************************************************/
21
22 typedef struct _PNPROOT_DEVICE
23 {
24 // Entry on device list
25 LIST_ENTRY ListEntry;
26 // Physical Device Object of device
27 PDEVICE_OBJECT Pdo;
28 // Device ID
29 UNICODE_STRING DeviceID;
30 // Instance ID
31 UNICODE_STRING InstanceID;
32 // Device description
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;
40
41 /* Physical Device Object device extension for a child device */
42 typedef struct _PNPROOT_PDO_DEVICE_EXTENSION
43 {
44 // Informations about the device
45 PPNPROOT_DEVICE DeviceInfo;
46 } PNPROOT_PDO_DEVICE_EXTENSION, *PPNPROOT_PDO_DEVICE_EXTENSION;
47
48 /* Physical Device Object device extension for the Root bus device object */
49 typedef struct _PNPROOT_FDO_DEVICE_EXTENSION
50 {
51 // Namespace device list
52 LIST_ENTRY DeviceListHead;
53 // Number of (not removed) devices in device list
54 ULONG DeviceListCount;
55 // Lock for namespace device list
56 KGUARDED_MUTEX DeviceListLock;
57 } PNPROOT_FDO_DEVICE_EXTENSION, *PPNPROOT_FDO_DEVICE_EXTENSION;
58
59 typedef struct _BUFFER
60 {
61 PVOID *Data;
62 PULONG Length;
63 } BUFFER, *PBUFFER;
64
65 static PNPROOT_FDO_DEVICE_EXTENSION PnpRootDOExtension;
66
67 /* FUNCTIONS *****************************************************************/
68
69 static NTSTATUS
LocateChildDevice(IN PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,IN PCUNICODE_STRING DeviceId,IN PCWSTR InstanceId,OUT PPNPROOT_DEVICE * ChildDevice OPTIONAL)70 LocateChildDevice(
71 IN PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,
72 IN PCUNICODE_STRING DeviceId,
73 IN PCWSTR InstanceId,
74 OUT PPNPROOT_DEVICE* ChildDevice OPTIONAL)
75 {
76 PPNPROOT_DEVICE Device;
77 UNICODE_STRING InstanceIdU;
78 PLIST_ENTRY NextEntry;
79
80 /* Initialize the string to compare */
81 RtlInitUnicodeString(&InstanceIdU, InstanceId);
82
83 /* Start looping */
84 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
85 NextEntry != &DeviceExtension->DeviceListHead;
86 NextEntry = NextEntry->Flink)
87 {
88 /* Get the entry */
89 Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry);
90
91 /* See if the strings match */
92 if (RtlEqualUnicodeString(DeviceId, &Device->DeviceID, TRUE) &&
93 RtlEqualUnicodeString(&InstanceIdU, &Device->InstanceID, TRUE))
94 {
95 /* They do, so set the pointer and return success */
96 if (ChildDevice)
97 *ChildDevice = Device;
98 return STATUS_SUCCESS;
99 }
100 }
101
102 /* No device found */
103 return STATUS_NO_SUCH_DEVICE;
104 }
105
106 NTSTATUS
PnpRootRegisterDevice(IN PDEVICE_OBJECT DeviceObject)107 PnpRootRegisterDevice(
108 IN PDEVICE_OBJECT DeviceObject)
109 {
110 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension = &PnpRootDOExtension;
111 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
112 PPNPROOT_DEVICE Device;
113 PDEVICE_NODE DeviceNode;
114 PWSTR InstancePath;
115 UNICODE_STRING InstancePathCopy;
116
117 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
118 if (!Device) return STATUS_NO_MEMORY;
119
120 DeviceNode = IopGetDeviceNode(DeviceObject);
121 if (!RtlCreateUnicodeString(&InstancePathCopy, DeviceNode->InstancePath.Buffer))
122 {
123 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
124 return STATUS_NO_MEMORY;
125 }
126
127 InstancePath = wcsrchr(InstancePathCopy.Buffer, L'\\');
128 ASSERT(InstancePath);
129
130 if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath + 1))
131 {
132 RtlFreeUnicodeString(&InstancePathCopy);
133 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
134 return STATUS_NO_MEMORY;
135 }
136
137 InstancePath[0] = UNICODE_NULL;
138
139 if (!RtlCreateUnicodeString(&Device->DeviceID, InstancePathCopy.Buffer))
140 {
141 RtlFreeUnicodeString(&InstancePathCopy);
142 RtlFreeUnicodeString(&Device->InstanceID);
143 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
144 return STATUS_NO_MEMORY;
145 }
146
147 InstancePath[0] = L'\\';
148
149 Device->Pdo = DeviceObject;
150
151 PdoDeviceExtension = DeviceObject->DeviceExtension;
152 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
153 PdoDeviceExtension->DeviceInfo = Device;
154
155 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
156 InsertTailList(&DeviceExtension->DeviceListHead,
157 &Device->ListEntry);
158 DeviceExtension->DeviceListCount++;
159 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
160
161 RtlFreeUnicodeString(&InstancePathCopy);
162
163 return STATUS_SUCCESS;
164 }
165
166 NTSTATUS
PnpRootCreateDeviceObject(OUT PDEVICE_OBJECT * DeviceObject)167 PnpRootCreateDeviceObject(
168 OUT PDEVICE_OBJECT *DeviceObject)
169 {
170 NTSTATUS status = IoCreateDevice(
171 IopRootDriverObject,
172 sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
173 NULL,
174 FILE_DEVICE_CONTROLLER,
175 FILE_AUTOGENERATED_DEVICE_NAME,
176 FALSE,
177 DeviceObject);
178
179 return status;
180 }
181
182 /* Creates a new PnP device for a legacy driver */
183 NTSTATUS
PnpRootCreateDevice(IN PUNICODE_STRING ServiceName,OUT PDEVICE_OBJECT * PhysicalDeviceObject,OUT PUNICODE_STRING FullInstancePath)184 PnpRootCreateDevice(
185 IN PUNICODE_STRING ServiceName,
186 OUT PDEVICE_OBJECT *PhysicalDeviceObject,
187 OUT PUNICODE_STRING FullInstancePath)
188 {
189 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
190 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
191 UNICODE_STRING DevicePath;
192 WCHAR InstancePath[5];
193 PPNPROOT_DEVICE Device = NULL;
194 NTSTATUS Status;
195 ULONG NextInstance;
196 UNICODE_STRING EnumKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM);
197 HANDLE EnumHandle, DeviceKeyHandle = NULL, InstanceKeyHandle;
198 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
199 OBJECT_ATTRIBUTES ObjectAttributes;
200
201 DeviceExtension = &PnpRootDOExtension;
202 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
203
204 DPRINT("Creating a PnP root device for service '%wZ'\n", ServiceName);
205
206 DevicePath.Length = 0;
207 DevicePath.MaximumLength = sizeof(REGSTR_KEY_ROOTENUM) + sizeof(L'\\') + ServiceName->Length;
208 DevicePath.Buffer = ExAllocatePoolWithTag(PagedPool,
209 DevicePath.MaximumLength,
210 TAG_PNP_ROOT);
211 if (DevicePath.Buffer == NULL)
212 {
213 DPRINT1("ExAllocatePoolWithTag() failed\n");
214 Status = STATUS_NO_MEMORY;
215 goto cleanup;
216 }
217 RtlAppendUnicodeToString(&DevicePath, REGSTR_KEY_ROOTENUM L"\\");
218 RtlAppendUnicodeStringToString(&DevicePath, ServiceName);
219
220 /* Initialize a PNPROOT_DEVICE structure */
221 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
222 if (!Device)
223 {
224 DPRINT("ExAllocatePoolWithTag() failed\n");
225 Status = STATUS_NO_MEMORY;
226 goto cleanup;
227 }
228 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
229 Device->DeviceID = DevicePath; // "Root\<service_name>"
230 RtlInitEmptyUnicodeString(&DevicePath, NULL, 0);
231
232 Status = IopOpenRegistryKeyEx(&EnumHandle, NULL, &EnumKeyName, KEY_READ);
233 if (NT_SUCCESS(Status))
234 {
235 InitializeObjectAttributes(&ObjectAttributes,
236 &Device->DeviceID,
237 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
238 EnumHandle,
239 NULL);
240 Status = ZwCreateKey(&DeviceKeyHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
241 ObCloseHandle(EnumHandle, KernelMode);
242 }
243
244 if (!NT_SUCCESS(Status))
245 {
246 DPRINT1("Failed to open registry key\n");
247 goto cleanup;
248 }
249
250 tryagain:
251 RtlZeroMemory(QueryTable, sizeof(QueryTable));
252 QueryTable[0].Name = L"NextInstance";
253 QueryTable[0].EntryContext = &NextInstance;
254 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
255
256 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
257 (PWSTR)DeviceKeyHandle,
258 QueryTable,
259 NULL,
260 NULL);
261 for (NextInstance = 0; NextInstance <= 9999; NextInstance++)
262 {
263 _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", NextInstance);
264 Status = LocateChildDevice(DeviceExtension, &Device->DeviceID, InstancePath, NULL);
265 if (Status == STATUS_NO_SUCH_DEVICE)
266 break;
267 }
268
269 if (NextInstance > 9999)
270 {
271 DPRINT1("Too many legacy devices reported for service '%wZ'\n", ServiceName);
272 Status = STATUS_INSUFFICIENT_RESOURCES;
273 goto cleanup;
274 }
275
276 _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", NextInstance);
277 Status = LocateChildDevice(DeviceExtension, &Device->DeviceID, InstancePath, NULL);
278 if (Status != STATUS_NO_SUCH_DEVICE || NextInstance > 9999)
279 {
280 DPRINT1("NextInstance value is corrupt! (%lu)\n", NextInstance);
281 RtlDeleteRegistryValue(RTL_REGISTRY_HANDLE,
282 (PWSTR)DeviceKeyHandle,
283 L"NextInstance");
284 goto tryagain;
285 }
286
287 NextInstance++;
288 Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
289 (PWSTR)DeviceKeyHandle,
290 L"NextInstance",
291 REG_DWORD,
292 &NextInstance,
293 sizeof(NextInstance));
294 if (!NT_SUCCESS(Status))
295 {
296 DPRINT1("Failed to write new NextInstance value! (0x%x)\n", Status);
297 goto cleanup;
298 }
299
300 // "0000" or higher
301 if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath))
302 {
303 Status = STATUS_NO_MEMORY;
304 goto cleanup;
305 }
306
307 /* Finish creating the instance path in the registry */
308 InitializeObjectAttributes(&ObjectAttributes,
309 &Device->InstanceID,
310 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
311 DeviceKeyHandle,
312 NULL);
313 Status = ZwCreateKey(&InstanceKeyHandle, KEY_QUERY_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
314 if (!NT_SUCCESS(Status))
315 {
316 DPRINT1("Failed to create instance path (0x%x)\n", Status);
317 goto cleanup;
318 }
319
320 /* Just close the handle */
321 ObCloseHandle(InstanceKeyHandle, KernelMode);
322
323 // generate the full device instance path
324 FullInstancePath->MaximumLength = Device->DeviceID.Length + sizeof(L'\\') + Device->InstanceID.Length;
325 FullInstancePath->Length = 0;
326 FullInstancePath->Buffer = ExAllocatePool(PagedPool, FullInstancePath->MaximumLength);
327 if (!FullInstancePath->Buffer)
328 {
329 Status = STATUS_NO_MEMORY;
330 goto cleanup;
331 }
332
333 RtlAppendUnicodeStringToString(FullInstancePath, &Device->DeviceID);
334 RtlAppendUnicodeToString(FullInstancePath, L"\\");
335 RtlAppendUnicodeStringToString(FullInstancePath, &Device->InstanceID);
336
337 /* Initialize a device object */
338 Status = PnpRootCreateDeviceObject(&Device->Pdo);
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
342 Status = STATUS_NO_MEMORY;
343 goto cleanup;
344 }
345
346 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
347 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
348 PdoDeviceExtension->DeviceInfo = Device;
349
350 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
351 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
352
353 InsertTailList(
354 &DeviceExtension->DeviceListHead,
355 &Device->ListEntry);
356 DeviceExtension->DeviceListCount++;
357
358 *PhysicalDeviceObject = Device->Pdo;
359 DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject, &Device->DeviceID, &Device->InstanceID);
360 Device = NULL;
361 Status = STATUS_SUCCESS;
362
363 cleanup:
364 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
365 if (Device)
366 {
367 if (Device->Pdo)
368 IoDeleteDevice(Device->Pdo);
369 RtlFreeUnicodeString(&Device->DeviceID);
370 RtlFreeUnicodeString(&Device->InstanceID);
371 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
372 }
373 RtlFreeUnicodeString(&DevicePath);
374 if (DeviceKeyHandle != NULL)
375 ObCloseHandle(DeviceKeyHandle, KernelMode);
376 return Status;
377 }
378
379 static NTSTATUS NTAPI
QueryStringCallback(IN PWSTR ValueName,IN ULONG ValueType,IN PVOID ValueData,IN ULONG ValueLength,IN PVOID Context,IN PVOID EntryContext)380 QueryStringCallback(
381 IN PWSTR ValueName,
382 IN ULONG ValueType,
383 IN PVOID ValueData,
384 IN ULONG ValueLength,
385 IN PVOID Context,
386 IN PVOID EntryContext)
387 {
388 PUNICODE_STRING Destination = (PUNICODE_STRING)EntryContext;
389 UNICODE_STRING Source;
390
391 if (ValueType != REG_SZ || ValueLength == 0 || ValueLength % sizeof(WCHAR) != 0)
392 {
393 Destination->Length = 0;
394 Destination->MaximumLength = 0;
395 Destination->Buffer = NULL;
396 return STATUS_SUCCESS;
397 }
398
399 Source.MaximumLength = Source.Length = (USHORT)ValueLength;
400 Source.Buffer = ValueData;
401
402 return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &Source, Destination);
403 }
404
405 static NTSTATUS NTAPI
QueryBinaryValueCallback(IN PWSTR ValueName,IN ULONG ValueType,IN PVOID ValueData,IN ULONG ValueLength,IN PVOID Context,IN PVOID EntryContext)406 QueryBinaryValueCallback(
407 IN PWSTR ValueName,
408 IN ULONG ValueType,
409 IN PVOID ValueData,
410 IN ULONG ValueLength,
411 IN PVOID Context,
412 IN PVOID EntryContext)
413 {
414 PBUFFER Buffer = (PBUFFER)EntryContext;
415 PVOID BinaryValue;
416
417 if (ValueLength == 0)
418 {
419 *Buffer->Data = NULL;
420 return STATUS_SUCCESS;
421 }
422
423 BinaryValue = ExAllocatePoolWithTag(PagedPool, ValueLength, TAG_PNP_ROOT);
424 if (BinaryValue == NULL)
425 return STATUS_NO_MEMORY;
426 RtlCopyMemory(BinaryValue, ValueData, ValueLength);
427 *Buffer->Data = BinaryValue;
428 if (Buffer->Length) *Buffer->Length = ValueLength;
429 return STATUS_SUCCESS;
430 }
431
432 static
433 NTSTATUS
CreateDeviceFromRegistry(_Inout_ PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,_Inout_ PUNICODE_STRING DevicePath,_In_ PCWSTR InstanceId,_In_ HANDLE SubKeyHandle)434 CreateDeviceFromRegistry(
435 _Inout_ PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,
436 _Inout_ PUNICODE_STRING DevicePath,
437 _In_ PCWSTR InstanceId,
438 _In_ HANDLE SubKeyHandle)
439 {
440 NTSTATUS Status;
441 PPNPROOT_DEVICE Device;
442 HANDLE DeviceKeyHandle = NULL;
443 RTL_QUERY_REGISTRY_TABLE QueryTable[4];
444 BUFFER Buffer1, Buffer2;
445
446 /* If the device already exists, there's nothing to do */
447 Status = LocateChildDevice(DeviceExtension, DevicePath, InstanceId, &Device);
448 if (Status != STATUS_NO_SUCH_DEVICE)
449 {
450 return STATUS_SUCCESS;
451 }
452
453 /* Create a PPNPROOT_DEVICE object, and add it to the list of known devices */
454 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
455 if (!Device)
456 {
457 DPRINT("ExAllocatePoolWithTag() failed\n");
458 Status = STATUS_NO_MEMORY;
459 goto cleanup;
460 }
461 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
462
463 /* Fill device ID and instance ID */
464 Device->DeviceID = *DevicePath;
465 RtlInitEmptyUnicodeString(DevicePath, NULL, 0);
466 if (!RtlCreateUnicodeString(&Device->InstanceID, InstanceId))
467 {
468 DPRINT1("RtlCreateUnicodeString() failed\n");
469 Status = STATUS_NO_MEMORY;
470 goto cleanup;
471 }
472
473 /* Open registry key to fill other informations */
474 Status = IopOpenRegistryKeyEx(&DeviceKeyHandle, SubKeyHandle, &Device->InstanceID, KEY_READ);
475 if (!NT_SUCCESS(Status))
476 {
477 /* If our key disappeared, let the caller go on */
478 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
479 &Device->InstanceID, Status);
480 Status = STATUS_SUCCESS;
481 goto cleanup;
482 }
483
484 /* Fill information from the device instance key */
485 RtlZeroMemory(QueryTable, sizeof(QueryTable));
486 QueryTable[0].QueryRoutine = QueryStringCallback;
487 QueryTable[0].Name = L"DeviceDesc";
488 QueryTable[0].EntryContext = &Device->DeviceDescription;
489
490 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
491 (PCWSTR)DeviceKeyHandle,
492 QueryTable,
493 NULL,
494 NULL);
495
496 /* Fill information from the LogConf subkey */
497 Buffer1.Data = (PVOID *)&Device->ResourceRequirementsList;
498 Buffer1.Length = NULL;
499 Buffer2.Data = (PVOID *)&Device->ResourceList;
500 Buffer2.Length = &Device->ResourceListSize;
501 RtlZeroMemory(QueryTable, sizeof(QueryTable));
502 QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
503 QueryTable[0].Name = L"LogConf";
504 QueryTable[1].QueryRoutine = QueryBinaryValueCallback;
505 QueryTable[1].Name = L"BasicConfigVector";
506 QueryTable[1].EntryContext = &Buffer1;
507 QueryTable[2].QueryRoutine = QueryBinaryValueCallback;
508 QueryTable[2].Name = L"BootConfig";
509 QueryTable[2].EntryContext = &Buffer2;
510
511 if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
512 (PCWSTR)DeviceKeyHandle,
513 QueryTable,
514 NULL,
515 NULL)))
516 {
517 /* Non-fatal error */
518 DPRINT1("Failed to read the LogConf key for %wZ\\%S\n", &Device->DeviceID, InstanceId);
519 }
520
521 /* Insert the newly created device into the list */
522 InsertTailList(&DeviceExtension->DeviceListHead,
523 &Device->ListEntry);
524 DeviceExtension->DeviceListCount++;
525 Device = NULL;
526
527 cleanup:
528 if (DeviceKeyHandle != NULL)
529 {
530 ZwClose(DeviceKeyHandle);
531 }
532 if (Device != NULL)
533 {
534 /* We have a device that has not been added to device list. We need to clean it up */
535 RtlFreeUnicodeString(&Device->DeviceID);
536 RtlFreeUnicodeString(&Device->InstanceID);
537 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
538 }
539 return Status;
540 }
541
542 static NTSTATUS
IopShouldProcessDevice(IN HANDLE SubKey,IN PCWSTR InstanceID)543 IopShouldProcessDevice(
544 IN HANDLE SubKey,
545 IN PCWSTR InstanceID)
546 {
547 UNICODE_STRING DeviceReportedValue = RTL_CONSTANT_STRING(L"DeviceReported");
548 UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
549 UNICODE_STRING InstanceIDU;
550 PKEY_VALUE_FULL_INFORMATION pKeyValueFullInformation;
551 HANDLE InstanceKey, ControlKey;
552 OBJECT_ATTRIBUTES ObjectAttributes;
553 ULONG Size, DeviceReported, ResultLength;
554 NTSTATUS Status;
555
556 Size = 128;
557 pKeyValueFullInformation = ExAllocatePool(PagedPool, Size);
558 if (!pKeyValueFullInformation)
559 return STATUS_INSUFFICIENT_RESOURCES;
560
561 /* Open Instance key */
562 RtlInitUnicodeString(&InstanceIDU, InstanceID);
563 InitializeObjectAttributes(&ObjectAttributes,
564 &InstanceIDU,
565 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
566 SubKey,
567 NULL);
568 Status = ZwOpenKey(&InstanceKey,
569 KEY_QUERY_VALUE,
570 &ObjectAttributes);
571 if (!NT_SUCCESS(Status))
572 {
573 ExFreePool(pKeyValueFullInformation);
574 return Status;
575 }
576
577 /* Read 'DeviceReported' Key */
578 Status = ZwQueryValueKey(InstanceKey, &DeviceReportedValue, KeyValueFullInformation, pKeyValueFullInformation, Size, &ResultLength);
579 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
580 {
581 ZwClose(InstanceKey);
582 ExFreePool(pKeyValueFullInformation);
583 DPRINT("No 'DeviceReported' value\n");
584 return STATUS_SUCCESS;
585 }
586 else if (!NT_SUCCESS(Status))
587 {
588 ZwClose(InstanceKey);
589 ExFreePool(pKeyValueFullInformation);
590 return Status;
591 }
592 if (pKeyValueFullInformation->Type != REG_DWORD || pKeyValueFullInformation->DataLength != sizeof(DeviceReported))
593 {
594 ZwClose(InstanceKey);
595 ExFreePool(pKeyValueFullInformation);
596 return STATUS_UNSUCCESSFUL;
597 }
598 RtlCopyMemory(&DeviceReported, (PVOID)((ULONG_PTR)pKeyValueFullInformation + pKeyValueFullInformation->DataOffset), sizeof(DeviceReported));
599 /* FIXME: Check DeviceReported value? */
600 ASSERT(DeviceReported == 1);
601
602 /* Open Control key */
603 InitializeObjectAttributes(&ObjectAttributes,
604 &Control,
605 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
606 InstanceKey,
607 NULL);
608 Status = ZwOpenKey(&ControlKey,
609 KEY_QUERY_VALUE,
610 &ObjectAttributes);
611 ZwClose(InstanceKey);
612 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
613 {
614 DPRINT("No 'Control' key\n");
615 return STATUS_NO_SUCH_DEVICE;
616 }
617 else if (!NT_SUCCESS(Status))
618 {
619 ExFreePool(pKeyValueFullInformation);
620 return Status;
621 }
622
623 /* Read 'DeviceReported' Key */
624 Status = ZwQueryValueKey(ControlKey, &DeviceReportedValue, KeyValueFullInformation, pKeyValueFullInformation, Size, &ResultLength);
625 ZwClose(ControlKey);
626 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
627 {
628 ExFreePool(pKeyValueFullInformation);
629 DPRINT("No 'DeviceReported' value\n");
630 return STATUS_NO_SUCH_DEVICE;
631 }
632 else if (!NT_SUCCESS(Status))
633 {
634 ExFreePool(pKeyValueFullInformation);
635 return Status;
636 }
637 if (pKeyValueFullInformation->Type != REG_DWORD || pKeyValueFullInformation->DataLength != sizeof(DeviceReported))
638 {
639 ExFreePool(pKeyValueFullInformation);
640 return STATUS_UNSUCCESSFUL;
641 }
642 RtlCopyMemory(&DeviceReported, (PVOID)((ULONG_PTR)pKeyValueFullInformation + pKeyValueFullInformation->DataOffset), sizeof(DeviceReported));
643 /* FIXME: Check DeviceReported value? */
644 ASSERT(DeviceReported == 1);
645
646 ExFreePool(pKeyValueFullInformation);
647 return STATUS_SUCCESS;
648 }
649
650 static NTSTATUS
EnumerateDevices(IN PDEVICE_OBJECT DeviceObject)651 EnumerateDevices(
652 IN PDEVICE_OBJECT DeviceObject)
653 {
654 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
655 PKEY_BASIC_INFORMATION KeyInfo = NULL, SubKeyInfo = NULL;
656 UNICODE_STRING LegacyU = RTL_CONSTANT_STRING(L"LEGACY_");
657 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L"\\" REGSTR_KEY_ROOTENUM);
658 UNICODE_STRING SubKeyName;
659 UNICODE_STRING DevicePath;
660 HANDLE KeyHandle = NULL;
661 HANDLE SubKeyHandle = NULL;
662 ULONG KeyInfoSize, SubKeyInfoSize;
663 ULONG ResultSize;
664 ULONG Index1, Index2;
665 NTSTATUS Status = STATUS_UNSUCCESSFUL;
666
667 DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject);
668
669 DeviceExtension = &PnpRootDOExtension;
670 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
671
672 /* Should hold most key names, but we reallocate below if it's too small */
673 KeyInfoSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + 64 * sizeof(WCHAR);
674 KeyInfo = ExAllocatePoolWithTag(PagedPool,
675 KeyInfoSize + sizeof(UNICODE_NULL),
676 TAG_PNP_ROOT);
677 if (!KeyInfo)
678 {
679 DPRINT("ExAllocatePoolWithTag() failed\n");
680 Status = STATUS_NO_MEMORY;
681 goto cleanup;
682 }
683 SubKeyInfoSize = KeyInfoSize;
684 SubKeyInfo = ExAllocatePoolWithTag(PagedPool,
685 SubKeyInfoSize + sizeof(UNICODE_NULL),
686 TAG_PNP_ROOT);
687 if (!SubKeyInfo)
688 {
689 DPRINT("ExAllocatePoolWithTag() failed\n");
690 Status = STATUS_NO_MEMORY;
691 goto cleanup;
692 }
693
694 Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &KeyName, KEY_ENUMERATE_SUB_KEYS);
695 if (!NT_SUCCESS(Status))
696 {
697 DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName, Status);
698 goto cleanup;
699 }
700
701 /* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as
702 * KeyHandle. We'll first do a first enumeration to have first level keys,
703 * and an inner one to have the real devices list.
704 */
705 Index1 = 0;
706 while (TRUE)
707 {
708 Status = ZwEnumerateKey(
709 KeyHandle,
710 Index1,
711 KeyBasicInformation,
712 KeyInfo,
713 KeyInfoSize,
714 &ResultSize);
715 if (Status == STATUS_NO_MORE_ENTRIES)
716 {
717 Status = STATUS_SUCCESS;
718 break;
719 }
720 else if (Status == STATUS_BUFFER_OVERFLOW ||
721 Status == STATUS_BUFFER_TOO_SMALL)
722 {
723 ASSERT(KeyInfoSize < ResultSize);
724 KeyInfoSize = ResultSize;
725 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
726 KeyInfo = ExAllocatePoolWithTag(PagedPool,
727 KeyInfoSize + sizeof(UNICODE_NULL),
728 TAG_PNP_ROOT);
729 if (!KeyInfo)
730 {
731 DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", KeyInfoSize);
732 Status = STATUS_NO_MEMORY;
733 goto cleanup;
734 }
735 continue;
736 }
737 else if (!NT_SUCCESS(Status))
738 {
739 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
740 goto cleanup;
741 }
742
743 /* Terminate the string */
744 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
745
746 /* Check if it is a legacy driver */
747 RtlInitUnicodeString(&SubKeyName, KeyInfo->Name);
748 if (RtlPrefixUnicodeString(&LegacyU, &SubKeyName, FALSE))
749 {
750 DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName);
751 Index1++;
752 continue;
753 }
754
755 /* Open the key */
756 Status = IopOpenRegistryKeyEx(&SubKeyHandle, KeyHandle, &SubKeyName, KEY_ENUMERATE_SUB_KEYS);
757 if (!NT_SUCCESS(Status))
758 {
759 DPRINT("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
760 &SubKeyName, Status);
761 break;
762 }
763
764 /* Enumerate the sub-keys */
765 Index2 = 0;
766 while (TRUE)
767 {
768 Status = ZwEnumerateKey(
769 SubKeyHandle,
770 Index2,
771 KeyBasicInformation,
772 SubKeyInfo,
773 SubKeyInfoSize,
774 &ResultSize);
775 if (Status == STATUS_NO_MORE_ENTRIES)
776 {
777 break;
778 }
779 else if (Status == STATUS_BUFFER_OVERFLOW ||
780 Status == STATUS_BUFFER_TOO_SMALL)
781 {
782 ASSERT(SubKeyInfoSize < ResultSize);
783 SubKeyInfoSize = ResultSize;
784 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
785 SubKeyInfo = ExAllocatePoolWithTag(PagedPool,
786 SubKeyInfoSize + sizeof(UNICODE_NULL),
787 TAG_PNP_ROOT);
788 if (!SubKeyInfo)
789 {
790 DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", SubKeyInfoSize);
791 Status = STATUS_NO_MEMORY;
792 goto cleanup;
793 }
794 continue;
795 }
796 else if (!NT_SUCCESS(Status))
797 {
798 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
799 break;
800 }
801
802 /* Terminate the string */
803 SubKeyInfo->Name[SubKeyInfo->NameLength / sizeof(WCHAR)] = 0;
804
805 /* Compute device ID */
806 DevicePath.Length = 0;
807 DevicePath.MaximumLength = sizeof(REGSTR_KEY_ROOTENUM) + sizeof(L'\\') + SubKeyName.Length;
808 DevicePath.Buffer = ExAllocatePoolWithTag(PagedPool,
809 DevicePath.MaximumLength,
810 TAG_PNP_ROOT);
811 if (DevicePath.Buffer == NULL)
812 {
813 DPRINT1("ExAllocatePoolWithTag() failed\n");
814 Status = STATUS_NO_MEMORY;
815 goto cleanup;
816 }
817
818 RtlAppendUnicodeToString(&DevicePath, REGSTR_KEY_ROOTENUM L"\\");
819 RtlAppendUnicodeStringToString(&DevicePath, &SubKeyName);
820 DPRINT("Found device %wZ\\%S!\n", &DevicePath, SubKeyInfo->Name);
821
822 Status = IopShouldProcessDevice(SubKeyHandle, SubKeyInfo->Name);
823 if (NT_SUCCESS(Status))
824 {
825 Status = CreateDeviceFromRegistry(DeviceExtension,
826 &DevicePath,
827 SubKeyInfo->Name,
828 SubKeyHandle);
829
830 /* If CreateDeviceFromRegistry didn't take ownership and zero this,
831 * we need to free it
832 */
833 RtlFreeUnicodeString(&DevicePath);
834
835 if (!NT_SUCCESS(Status))
836 {
837 goto cleanup;
838 }
839 }
840 else if (Status == STATUS_NO_SUCH_DEVICE)
841 {
842 DPRINT("Skipping device %wZ\\%S (not reported yet)\n", &DevicePath, SubKeyInfo->Name);
843 }
844 else
845 {
846 goto cleanup;
847 }
848
849 Index2++;
850 }
851
852 ZwClose(SubKeyHandle);
853 SubKeyHandle = NULL;
854 Index1++;
855 }
856
857 cleanup:
858 if (SubKeyHandle != NULL)
859 ZwClose(SubKeyHandle);
860 if (KeyHandle != NULL)
861 ZwClose(KeyHandle);
862 if (KeyInfo)
863 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
864 if (SubKeyInfo)
865 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
866 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
867 return Status;
868 }
869
870 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
871 * ARGUMENTS:
872 * DeviceObject = Pointer to functional device object of the root bus driver
873 * Irp = Pointer to IRP that should be handled
874 * RETURNS:
875 * Status
876 */
877 static NTSTATUS
PnpRootQueryDeviceRelations(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)878 PnpRootQueryDeviceRelations(
879 IN PDEVICE_OBJECT DeviceObject,
880 IN PIRP Irp)
881 {
882 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
883 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
884 PDEVICE_RELATIONS Relations = NULL, OtherRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
885 PPNPROOT_DEVICE Device = NULL;
886 ULONG Size;
887 NTSTATUS Status;
888 PLIST_ENTRY NextEntry;
889
890 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject, Irp);
891
892 Status = EnumerateDevices(DeviceObject);
893 if (!NT_SUCCESS(Status))
894 {
895 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status);
896 return Status;
897 }
898
899 DeviceExtension = &PnpRootDOExtension;
900
901 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * DeviceExtension->DeviceListCount;
902 if (OtherRelations)
903 {
904 /* Another bus driver has already created a DEVICE_RELATIONS
905 * structure so we must merge this structure with our own */
906
907 Size += sizeof(PDEVICE_OBJECT) * OtherRelations->Count;
908 }
909 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
910 if (!Relations)
911 {
912 DPRINT("ExAllocatePoolWithTag() failed\n");
913 Status = STATUS_NO_MEMORY;
914 goto cleanup;
915 }
916 RtlZeroMemory(Relations, Size);
917 if (OtherRelations)
918 {
919 Relations->Count = OtherRelations->Count;
920 RtlCopyMemory(Relations->Objects, OtherRelations->Objects, sizeof(PDEVICE_OBJECT) * OtherRelations->Count);
921 }
922
923 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
924
925 /* Start looping */
926 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
927 NextEntry != &DeviceExtension->DeviceListHead;
928 NextEntry = NextEntry->Flink)
929 {
930 /* Get the entry */
931 Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry);
932
933 if (!Device->Pdo)
934 {
935 /* Create a physical device object for the
936 * device as it does not already have one */
937 Status = PnpRootCreateDeviceObject(&Device->Pdo);
938 if (!NT_SUCCESS(Status))
939 {
940 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
941 break;
942 }
943
944 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
945 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
946 PdoDeviceExtension->DeviceInfo = Device;
947
948 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
949 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
950 }
951
952 /* Reference the physical device object. The PnP manager
953 will dereference it again when it is no longer needed */
954 ObReferenceObject(Device->Pdo);
955
956 Relations->Objects[Relations->Count++] = Device->Pdo;
957 }
958 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
959
960 Irp->IoStatus.Information = (ULONG_PTR)Relations;
961
962 cleanup:
963 if (!NT_SUCCESS(Status))
964 {
965 if (OtherRelations)
966 ExFreePool(OtherRelations);
967 if (Relations)
968 ExFreePool(Relations);
969 if (Device && Device->Pdo)
970 {
971 IoDeleteDevice(Device->Pdo);
972 Device->Pdo = NULL;
973 }
974 }
975
976 return Status;
977 }
978
979 /*
980 * FUNCTION: Handle Plug and Play IRPs for the root bus device object
981 * ARGUMENTS:
982 * DeviceObject = Pointer to functional device object of the root bus driver
983 * Irp = Pointer to IRP that should be handled
984 * RETURNS:
985 * Status
986 */
987 static NTSTATUS
PnpRootFdoPnpControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)988 PnpRootFdoPnpControl(
989 IN PDEVICE_OBJECT DeviceObject,
990 IN PIRP Irp)
991 {
992 PIO_STACK_LOCATION IrpSp;
993 NTSTATUS Status;
994
995 Status = Irp->IoStatus.Status;
996 IrpSp = IoGetCurrentIrpStackLocation(Irp);
997
998 switch (IrpSp->MinorFunction)
999 {
1000 case IRP_MN_QUERY_DEVICE_RELATIONS:
1001 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
1002 Status = PnpRootQueryDeviceRelations(DeviceObject, Irp);
1003 break;
1004
1005 default:
1006 // The root device object can receive only IRP_MN_QUERY_DEVICE_RELATIONS
1007 ASSERT(FALSE);
1008 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
1009 break;
1010 }
1011
1012 if (Status != STATUS_PENDING)
1013 {
1014 Irp->IoStatus.Status = Status;
1015 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1016 }
1017
1018 return Status;
1019 }
1020
1021 static NTSTATUS
PdoQueryDeviceRelations(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)1022 PdoQueryDeviceRelations(
1023 IN PDEVICE_OBJECT DeviceObject,
1024 IN PIRP Irp,
1025 IN PIO_STACK_LOCATION IrpSp)
1026 {
1027 PDEVICE_RELATIONS Relations;
1028 NTSTATUS Status = Irp->IoStatus.Status;
1029
1030 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
1031 return Status;
1032
1033 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
1034 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
1035 if (!Relations)
1036 {
1037 DPRINT("ExAllocatePoolWithTag() failed\n");
1038 Status = STATUS_NO_MEMORY;
1039 }
1040 else
1041 {
1042 ObReferenceObject(DeviceObject);
1043 Relations->Count = 1;
1044 Relations->Objects[0] = DeviceObject;
1045 Status = STATUS_SUCCESS;
1046 Irp->IoStatus.Information = (ULONG_PTR)Relations;
1047 }
1048
1049 return Status;
1050 }
1051
1052 static NTSTATUS
PdoQueryCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)1053 PdoQueryCapabilities(
1054 IN PDEVICE_OBJECT DeviceObject,
1055 IN PIRP Irp,
1056 IN PIO_STACK_LOCATION IrpSp)
1057 {
1058 PDEVICE_CAPABILITIES DeviceCapabilities;
1059
1060 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
1061
1062 if (DeviceCapabilities->Version != 1)
1063 return STATUS_REVISION_MISMATCH;
1064
1065 DeviceCapabilities->UniqueID = TRUE;
1066 /* FIXME: Fill other fields */
1067
1068 return STATUS_SUCCESS;
1069 }
1070
1071 static NTSTATUS
PdoQueryResources(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)1072 PdoQueryResources(
1073 IN PDEVICE_OBJECT DeviceObject,
1074 IN PIRP Irp,
1075 IN PIO_STACK_LOCATION IrpSp)
1076 {
1077 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1078 PCM_RESOURCE_LIST ResourceList;
1079
1080 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1081
1082 if (DeviceExtension->DeviceInfo->ResourceList)
1083 {
1084 /* Copy existing resource requirement list */
1085 ResourceList = ExAllocatePool(
1086 PagedPool,
1087 DeviceExtension->DeviceInfo->ResourceListSize);
1088 if (!ResourceList)
1089 return STATUS_NO_MEMORY;
1090
1091 RtlCopyMemory(
1092 ResourceList,
1093 DeviceExtension->DeviceInfo->ResourceList,
1094 DeviceExtension->DeviceInfo->ResourceListSize);
1095
1096 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
1097
1098 return STATUS_SUCCESS;
1099 }
1100 else
1101 {
1102 /* No resources so just return without changing the status */
1103 return Irp->IoStatus.Status;
1104 }
1105 }
1106
1107 static NTSTATUS
PdoQueryResourceRequirements(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)1108 PdoQueryResourceRequirements(
1109 IN PDEVICE_OBJECT DeviceObject,
1110 IN PIRP Irp,
1111 IN PIO_STACK_LOCATION IrpSp)
1112 {
1113 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1114 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
1115
1116 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1117
1118 if (DeviceExtension->DeviceInfo->ResourceRequirementsList)
1119 {
1120 /* Copy existing resource requirement list */
1121 ResourceList = ExAllocatePool(PagedPool, DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
1122 if (!ResourceList)
1123 return STATUS_NO_MEMORY;
1124
1125 RtlCopyMemory(
1126 ResourceList,
1127 DeviceExtension->DeviceInfo->ResourceRequirementsList,
1128 DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
1129
1130 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
1131
1132 return STATUS_SUCCESS;
1133 }
1134 else
1135 {
1136 /* No resource requirements so just return without changing the status */
1137 return Irp->IoStatus.Status;
1138 }
1139 }
1140
1141 static NTSTATUS
PdoQueryDeviceText(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)1142 PdoQueryDeviceText(
1143 IN PDEVICE_OBJECT DeviceObject,
1144 IN PIRP Irp,
1145 IN PIO_STACK_LOCATION IrpSp)
1146 {
1147 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1148 DEVICE_TEXT_TYPE DeviceTextType;
1149 NTSTATUS Status = Irp->IoStatus.Status;
1150
1151 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1152 DeviceTextType = IrpSp->Parameters.QueryDeviceText.DeviceTextType;
1153
1154 switch (DeviceTextType)
1155 {
1156 case DeviceTextDescription:
1157 {
1158 UNICODE_STRING String;
1159 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
1160
1161 if (DeviceExtension->DeviceInfo->DeviceDescription.Buffer != NULL)
1162 {
1163 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1164 &DeviceExtension->DeviceInfo->DeviceDescription,
1165 &String);
1166 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
1167 }
1168 break;
1169 }
1170
1171 case DeviceTextLocationInformation:
1172 {
1173 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
1174 break;
1175 }
1176
1177 default:
1178 {
1179 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType);
1180 }
1181 }
1182
1183 return Status;
1184 }
1185
1186 static NTSTATUS
PdoQueryId(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)1187 PdoQueryId(
1188 IN PDEVICE_OBJECT DeviceObject,
1189 IN PIRP Irp,
1190 IN PIO_STACK_LOCATION IrpSp)
1191 {
1192 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1193 BUS_QUERY_ID_TYPE IdType;
1194 NTSTATUS Status = Irp->IoStatus.Status;
1195
1196 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1197 IdType = IrpSp->Parameters.QueryId.IdType;
1198
1199 switch (IdType)
1200 {
1201 case BusQueryDeviceID:
1202 {
1203 UNICODE_STRING String;
1204 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
1205
1206 Status = RtlDuplicateUnicodeString(
1207 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1208 &DeviceExtension->DeviceInfo->DeviceID,
1209 &String);
1210 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
1211 break;
1212 }
1213
1214 case BusQueryHardwareIDs:
1215 case BusQueryCompatibleIDs:
1216 {
1217 /* Optional, do nothing */
1218 break;
1219 }
1220
1221 case BusQueryInstanceID:
1222 {
1223 UNICODE_STRING String;
1224 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
1225
1226 Status = RtlDuplicateUnicodeString(
1227 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1228 &DeviceExtension->DeviceInfo->InstanceID,
1229 &String);
1230 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
1231 break;
1232 }
1233
1234 default:
1235 {
1236 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
1237 }
1238 }
1239
1240 return Status;
1241 }
1242
1243 static NTSTATUS
PdoQueryBusInformation(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PIO_STACK_LOCATION IrpSp)1244 PdoQueryBusInformation(
1245 IN PDEVICE_OBJECT DeviceObject,
1246 IN PIRP Irp,
1247 IN PIO_STACK_LOCATION IrpSp)
1248 {
1249 PPNP_BUS_INFORMATION BusInfo;
1250 NTSTATUS Status;
1251
1252 BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PNP_ROOT);
1253 if (!BusInfo)
1254 Status = STATUS_NO_MEMORY;
1255 else
1256 {
1257 RtlCopyMemory(
1258 &BusInfo->BusTypeGuid,
1259 &GUID_BUS_TYPE_INTERNAL,
1260 sizeof(BusInfo->BusTypeGuid));
1261 BusInfo->LegacyBusType = PNPBus;
1262 /* We're the only root bus enumerator on the computer */
1263 BusInfo->BusNumber = 0;
1264 Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
1265 Status = STATUS_SUCCESS;
1266 }
1267
1268 return Status;
1269 }
1270
1271 /*
1272 * FUNCTION: Handle Plug and Play IRPs for the child device
1273 * ARGUMENTS:
1274 * DeviceObject = Pointer to physical device object of the child device
1275 * Irp = Pointer to IRP that should be handled
1276 * RETURNS:
1277 * Status
1278 */
1279 static NTSTATUS
PnpRootPdoPnpControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1280 PnpRootPdoPnpControl(
1281 IN PDEVICE_OBJECT DeviceObject,
1282 IN PIRP Irp)
1283 {
1284 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1285 PPNPROOT_FDO_DEVICE_EXTENSION FdoDeviceExtension;
1286 PIO_STACK_LOCATION IrpSp;
1287 NTSTATUS Status;
1288
1289 DeviceExtension = DeviceObject->DeviceExtension;
1290 FdoDeviceExtension = &PnpRootDOExtension;
1291 Status = Irp->IoStatus.Status;
1292 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1293
1294 switch (IrpSp->MinorFunction)
1295 {
1296 case IRP_MN_START_DEVICE: /* 0x00 */
1297 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1298 Status = STATUS_SUCCESS;
1299 break;
1300
1301 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
1302 Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
1303 break;
1304
1305 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
1306 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
1307 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
1308 break;
1309
1310 case IRP_MN_QUERY_RESOURCES: /* 0x0a */
1311 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
1312 Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
1313 break;
1314
1315 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
1316 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1317 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
1318 break;
1319
1320 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
1321 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1322 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
1323 break;
1324
1325 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
1326 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1327 break;
1328
1329 case IRP_MN_REMOVE_DEVICE:
1330 /* Remove the device from the device list and decrement the device count*/
1331 KeAcquireGuardedMutex(&FdoDeviceExtension->DeviceListLock);
1332 RemoveEntryList(&DeviceExtension->DeviceInfo->ListEntry);
1333 FdoDeviceExtension->DeviceListCount--;
1334 KeReleaseGuardedMutex(&FdoDeviceExtension->DeviceListLock);
1335
1336 /* Free some strings we created */
1337 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceDescription);
1338 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceID);
1339 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->InstanceID);
1340
1341 /* Free the resource requirements list */
1342 if (DeviceExtension->DeviceInfo->ResourceRequirementsList != NULL)
1343 ExFreePool(DeviceExtension->DeviceInfo->ResourceRequirementsList);
1344
1345 /* Free the boot resources list */
1346 if (DeviceExtension->DeviceInfo->ResourceList != NULL)
1347 ExFreePool(DeviceExtension->DeviceInfo->ResourceList);
1348
1349 /* Free the device info */
1350 ExFreePool(DeviceExtension->DeviceInfo);
1351
1352 /* Finally, delete the device object */
1353 IoDeleteDevice(DeviceObject);
1354
1355 /* Return success */
1356 Status = STATUS_SUCCESS;
1357 break;
1358
1359 case IRP_MN_QUERY_ID: /* 0x13 */
1360 Status = PdoQueryId(DeviceObject, Irp, IrpSp);
1361 break;
1362
1363 case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
1364 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
1365 break;
1366
1367 case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
1368 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
1369 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
1370 break;
1371
1372 default:
1373 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
1374 break;
1375 }
1376
1377 if (Status != STATUS_PENDING)
1378 {
1379 Irp->IoStatus.Status = Status;
1380 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1381 }
1382
1383 return Status;
1384 }
1385
1386 /*
1387 * FUNCTION: Handle Plug and Play IRPs
1388 * ARGUMENTS:
1389 * DeviceObject = Pointer to PDO or FDO
1390 * Irp = Pointer to IRP that should be handled
1391 * RETURNS:
1392 * Status
1393 */
1394 static NTSTATUS NTAPI
PnpRootPnpControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1395 PnpRootPnpControl(
1396 IN PDEVICE_OBJECT DeviceObject,
1397 IN PIRP Irp)
1398 {
1399 NTSTATUS Status;
1400
1401 if (IopRootDeviceNode == IopGetDeviceNode(DeviceObject))
1402 Status = PnpRootFdoPnpControl(DeviceObject, Irp);
1403 else
1404 Status = PnpRootPdoPnpControl(DeviceObject, Irp);
1405
1406 return Status;
1407 }
1408
1409 /*
1410 * FUNCTION: Handle Power IRPs
1411 * ARGUMENTS:
1412 * DeviceObject = Pointer to PDO or FDO
1413 * Irp = Pointer to IRP that should be handled
1414 * RETURNS:
1415 * Status
1416 */
1417 static NTSTATUS NTAPI
PnpRootPowerControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1418 PnpRootPowerControl(
1419 IN PDEVICE_OBJECT DeviceObject,
1420 IN PIRP Irp)
1421 {
1422 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
1423 NTSTATUS Status = Irp->IoStatus.Status;
1424
1425 switch (IrpSp->MinorFunction)
1426 {
1427 case IRP_MN_QUERY_POWER:
1428 case IRP_MN_SET_POWER:
1429 Status = STATUS_SUCCESS;
1430 break;
1431 }
1432 Irp->IoStatus.Status = Status;
1433 PoStartNextPowerIrp(Irp);
1434 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1435
1436 return Status;
1437 }
1438
1439 VOID
PnpRootInitializeDevExtension(VOID)1440 PnpRootInitializeDevExtension(VOID)
1441 {
1442 PnpRootDOExtension.DeviceListCount = 0;
1443 InitializeListHead(&PnpRootDOExtension.DeviceListHead);
1444 KeInitializeGuardedMutex(&PnpRootDOExtension.DeviceListLock);
1445 }
1446
1447 NTSTATUS
1448 NTAPI
PnpRootAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)1449 PnpRootAddDevice(
1450 IN PDRIVER_OBJECT DriverObject,
1451 IN PDEVICE_OBJECT PhysicalDeviceObject)
1452 {
1453 // AddDevice must never be called for the root driver
1454 ASSERT(FALSE);
1455 return STATUS_SUCCESS;
1456 }
1457
1458 #if MI_TRACE_PFNS
1459 PDEVICE_OBJECT IopPfnDumpDeviceObject;
1460
1461 NTSTATUS NTAPI
PnpRootCreateClose(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)1462 PnpRootCreateClose(
1463 _In_ PDEVICE_OBJECT DeviceObject,
1464 _In_ PIRP Irp)
1465 {
1466 PIO_STACK_LOCATION IoStack;
1467
1468 if (DeviceObject != IopPfnDumpDeviceObject)
1469 {
1470 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1471 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1472 return STATUS_INVALID_DEVICE_REQUEST;
1473 }
1474
1475 IoStack = IoGetCurrentIrpStackLocation(Irp);
1476 if (IoStack->MajorFunction == IRP_MJ_CREATE)
1477 {
1478 MmDumpArmPfnDatabase(TRUE);
1479 }
1480
1481 Irp->IoStatus.Status = STATUS_SUCCESS;
1482 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1483 return STATUS_SUCCESS;
1484 }
1485 #endif
1486
1487 NTSTATUS NTAPI
PnpRootDriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)1488 PnpRootDriverEntry(
1489 IN PDRIVER_OBJECT DriverObject,
1490 IN PUNICODE_STRING RegistryPath)
1491 {
1492 #if MI_TRACE_PFNS
1493 NTSTATUS Status;
1494 UNICODE_STRING PfnDumpDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PfnDump");
1495 #endif
1496
1497 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject, RegistryPath);
1498
1499 IopRootDriverObject = DriverObject;
1500
1501 DriverObject->DriverExtension->AddDevice = PnpRootAddDevice;
1502
1503 #if MI_TRACE_PFNS
1504 DriverObject->MajorFunction[IRP_MJ_CREATE] = PnpRootCreateClose;
1505 DriverObject->MajorFunction[IRP_MJ_CLOSE] = PnpRootCreateClose;
1506 #endif
1507 DriverObject->MajorFunction[IRP_MJ_PNP] = PnpRootPnpControl;
1508 DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
1509
1510 #if MI_TRACE_PFNS
1511 Status = IoCreateDevice(DriverObject,
1512 0,
1513 &PfnDumpDeviceName,
1514 FILE_DEVICE_UNKNOWN,
1515 0,
1516 FALSE,
1517 &IopPfnDumpDeviceObject);
1518 if (!NT_SUCCESS(Status))
1519 {
1520 DPRINT1("Creating PFN Dump device failed with %lx\n", Status);
1521 }
1522 else
1523 {
1524 IopPfnDumpDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1525 }
1526 #endif
1527
1528 return STATUS_SUCCESS;
1529 }
1530