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