[REACTOS]
[reactos.git] / reactos / 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 = INVALID_HANDLE_VALUE, 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 != INVALID_HANDLE_VALUE)
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 = INVALID_HANDLE_VALUE;
451 HANDLE SubKeyHandle = INVALID_HANDLE_VALUE;
452 HANDLE DeviceKeyHandle = INVALID_HANDLE_VALUE;
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 with status 0x%08lx\n", Status);
529 break;
530 }
531
532 /* Enumerate the sub-keys */
533 Index2 = 0;
534 while (TRUE)
535 {
536 Status = ZwEnumerateKey(
537 SubKeyHandle,
538 Index2,
539 KeyBasicInformation,
540 SubKeyInfo,
541 BufferSize,
542 &ResultSize);
543 if (Status == STATUS_NO_MORE_ENTRIES)
544 break;
545 else if (!NT_SUCCESS(Status))
546 {
547 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
548 break;
549 }
550
551 /* Terminate the string */
552 SubKeyInfo->Name[SubKeyInfo->NameLength / sizeof(WCHAR)] = 0;
553
554 _snwprintf(DevicePath, sizeof(DevicePath) / sizeof(WCHAR),
555 L"%s\\%s", REGSTR_KEY_ROOTENUM, KeyInfo->Name);
556 DPRINT("Found device %S\\%s!\n", DevicePath, SubKeyInfo->Name);
557 if (LocateChildDevice(DeviceExtension, DevicePath, SubKeyInfo->Name, &Device) == STATUS_NO_SUCH_DEVICE)
558 {
559 /* Create a PPNPROOT_DEVICE object, and add if in the list of known devices */
560 Device = (PPNPROOT_DEVICE)ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
561 if (!Device)
562 {
563 DPRINT("ExAllocatePoolWithTag() failed\n");
564 Status = STATUS_NO_MEMORY;
565 goto cleanup;
566 }
567 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
568
569 /* Fill device ID and instance ID */
570 if (!RtlCreateUnicodeString(&Device->DeviceID, DevicePath))
571 {
572 DPRINT1("RtlCreateUnicodeString() failed\n");
573 Status = STATUS_NO_MEMORY;
574 goto cleanup;
575 }
576
577 if (!RtlCreateUnicodeString(&Device->InstanceID, SubKeyInfo->Name))
578 {
579 DPRINT1("RtlCreateUnicodeString() failed\n");
580 Status = STATUS_NO_MEMORY;
581 goto cleanup;
582 }
583
584 /* Open registry key to fill other informations */
585 Status = IopOpenRegistryKeyEx(&DeviceKeyHandle, SubKeyHandle, &Device->InstanceID, KEY_READ);
586 if (!NT_SUCCESS(Status))
587 {
588 DPRINT1("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status);
589 break;
590 }
591
592 /* Fill information from the device instance key */
593 RtlZeroMemory(QueryTable, sizeof(QueryTable));
594 QueryTable[0].QueryRoutine = QueryStringCallback;
595 QueryTable[0].Name = L"DeviceDesc";
596 QueryTable[0].EntryContext = &Device->DeviceDescription;
597
598 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
599 (PCWSTR)DeviceKeyHandle,
600 QueryTable,
601 NULL,
602 NULL);
603
604 /* Fill information from the LogConf subkey */
605 Buffer1.Data = (PVOID *)&Device->ResourceRequirementsList;
606 Buffer1.Length = NULL;
607 Buffer2.Data = (PVOID *)&Device->ResourceList;
608 Buffer2.Length = &Device->ResourceListSize;
609 RtlZeroMemory(QueryTable, sizeof(QueryTable));
610 QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
611 QueryTable[0].Name = L"LogConf";
612 QueryTable[1].QueryRoutine = QueryBinaryValueCallback;
613 QueryTable[1].Name = L"BasicConfigVector";
614 QueryTable[1].EntryContext = &Buffer1;
615 QueryTable[2].QueryRoutine = QueryBinaryValueCallback;
616 QueryTable[2].Name = L"BootConfig";
617 QueryTable[2].EntryContext = &Buffer2;
618
619 if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
620 (PCWSTR)DeviceKeyHandle,
621 QueryTable,
622 NULL,
623 NULL)))
624 {
625 /* Non-fatal error */
626 DPRINT1("Failed to read the LogConf key for %S\\%S\n", DevicePath, SubKeyInfo->Name);
627 }
628
629 ZwClose(DeviceKeyHandle);
630 DeviceKeyHandle = INVALID_HANDLE_VALUE;
631
632 /* Insert the newly created device into the list */
633 InsertTailList(
634 &DeviceExtension->DeviceListHead,
635 &Device->ListEntry);
636 DeviceExtension->DeviceListCount++;
637 }
638 Device = NULL;
639
640 Index2++;
641 }
642
643 ZwClose(SubKeyHandle);
644 SubKeyHandle = INVALID_HANDLE_VALUE;
645 Index1++;
646 }
647
648 cleanup:
649 if (Device)
650 {
651 /* We have a device that has not been added to device list. We need to clean it up */
652 /* FIXME */
653 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
654 }
655 if (DeviceKeyHandle != INVALID_HANDLE_VALUE)
656 ZwClose(DeviceKeyHandle);
657 if (SubKeyHandle != INVALID_HANDLE_VALUE)
658 ZwClose(SubKeyHandle);
659 if (KeyHandle != INVALID_HANDLE_VALUE)
660 ZwClose(KeyHandle);
661 if (KeyInfo)
662 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
663 if (SubKeyInfo)
664 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
665 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
666 return Status;
667 }
668
669 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
670 * ARGUMENTS:
671 * DeviceObject = Pointer to functional device object of the root bus driver
672 * Irp = Pointer to IRP that should be handled
673 * RETURNS:
674 * Status
675 */
676 static NTSTATUS
677 PnpRootQueryDeviceRelations(
678 IN PDEVICE_OBJECT DeviceObject,
679 IN PIRP Irp)
680 {
681 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
682 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
683 PDEVICE_RELATIONS Relations = NULL, OtherRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
684 PPNPROOT_DEVICE Device = NULL;
685 ULONG Size;
686 NTSTATUS Status;
687 PLIST_ENTRY NextEntry;
688
689 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject, Irp);
690
691 Status = EnumerateDevices(DeviceObject);
692 if (!NT_SUCCESS(Status))
693 {
694 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status);
695 return Status;
696 }
697
698 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
699
700 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * DeviceExtension->DeviceListCount;
701 if (OtherRelations)
702 {
703 /* Another bus driver has already created a DEVICE_RELATIONS
704 * structure so we must merge this structure with our own */
705
706 Size += sizeof(PDEVICE_OBJECT) * OtherRelations->Count;
707 }
708 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
709 if (!Relations)
710 {
711 DPRINT("ExAllocatePoolWithTag() failed\n");
712 Status = STATUS_NO_MEMORY;
713 goto cleanup;
714 }
715 RtlZeroMemory(Relations, Size);
716 if (OtherRelations)
717 {
718 Relations->Count = OtherRelations->Count;
719 RtlCopyMemory(Relations->Objects, OtherRelations->Objects, sizeof(PDEVICE_OBJECT) * OtherRelations->Count);
720 }
721
722 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
723
724 /* Start looping */
725 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
726 NextEntry != &DeviceExtension->DeviceListHead;
727 NextEntry = NextEntry->Flink)
728 {
729 /* Get the entry */
730 Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry);
731
732 if (!Device->Pdo)
733 {
734 /* Create a physical device object for the
735 * device as it does not already have one */
736 Status = IoCreateDevice(
737 DeviceObject->DriverObject,
738 sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
739 NULL,
740 FILE_DEVICE_CONTROLLER,
741 FILE_AUTOGENERATED_DEVICE_NAME,
742 FALSE,
743 &Device->Pdo);
744 if (!NT_SUCCESS(Status))
745 {
746 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
747 break;
748 }
749
750 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
751 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
752 PdoDeviceExtension->Common.IsFDO = FALSE;
753 PdoDeviceExtension->DeviceInfo = Device;
754
755 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
756 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
757 }
758
759 /* Reference the physical device object. The PnP manager
760 will dereference it again when it is no longer needed */
761 ObReferenceObject(Device->Pdo);
762
763 Relations->Objects[Relations->Count++] = Device->Pdo;
764 }
765 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
766
767 Irp->IoStatus.Information = (ULONG_PTR)Relations;
768
769 cleanup:
770 if (!NT_SUCCESS(Status))
771 {
772 if (OtherRelations)
773 ExFreePool(OtherRelations);
774 if (Relations)
775 ExFreePool(Relations);
776 if (Device && Device->Pdo)
777 {
778 IoDeleteDevice(Device->Pdo);
779 Device->Pdo = NULL;
780 }
781 }
782
783 return Status;
784 }
785
786 /*
787 * FUNCTION: Handle Plug and Play IRPs for the root bus device object
788 * ARGUMENTS:
789 * DeviceObject = Pointer to functional device object of the root bus driver
790 * Irp = Pointer to IRP that should be handled
791 * RETURNS:
792 * Status
793 */
794 static NTSTATUS
795 PnpRootFdoPnpControl(
796 IN PDEVICE_OBJECT DeviceObject,
797 IN PIRP Irp)
798 {
799 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
800 PIO_STACK_LOCATION IrpSp;
801 NTSTATUS Status;
802
803 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
804 Status = Irp->IoStatus.Status;
805 IrpSp = IoGetCurrentIrpStackLocation(Irp);
806
807 switch (IrpSp->MinorFunction)
808 {
809 case IRP_MN_QUERY_DEVICE_RELATIONS:
810 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
811 Status = PnpRootQueryDeviceRelations(DeviceObject, Irp);
812 break;
813
814 case IRP_MN_START_DEVICE:
815 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
816 if (!IoForwardIrpSynchronously(DeviceExtension->Ldo, Irp))
817 Status = STATUS_UNSUCCESSFUL;
818 else
819 {
820 Status = Irp->IoStatus.Status;
821 if (NT_SUCCESS(Status))
822 DeviceExtension->State = dsStarted;
823 }
824
825 Irp->IoStatus.Status = Status;
826 IoCompleteRequest(Irp, IO_NO_INCREMENT);
827 return Status;
828
829 case IRP_MN_STOP_DEVICE:
830 DPRINT("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
831 /* Root device cannot be stopped */
832 Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST;
833 IoCompleteRequest(Irp, IO_NO_INCREMENT);
834 return Status;
835
836 default:
837 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
838 break;
839 }
840
841 if (Status != STATUS_PENDING)
842 {
843 Irp->IoStatus.Status = Status;
844 IoCompleteRequest(Irp, IO_NO_INCREMENT);
845 }
846
847 return Status;
848 }
849
850 static NTSTATUS
851 PdoQueryDeviceRelations(
852 IN PDEVICE_OBJECT DeviceObject,
853 IN PIRP Irp,
854 IN PIO_STACK_LOCATION IrpSp)
855 {
856 PDEVICE_RELATIONS Relations;
857 NTSTATUS Status = Irp->IoStatus.Status;
858
859 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
860 return Status;
861
862 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
863 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
864 if (!Relations)
865 {
866 DPRINT("ExAllocatePoolWithTag() failed\n");
867 Status = STATUS_NO_MEMORY;
868 }
869 else
870 {
871 ObReferenceObject(DeviceObject);
872 Relations->Count = 1;
873 Relations->Objects[0] = DeviceObject;
874 Status = STATUS_SUCCESS;
875 Irp->IoStatus.Information = (ULONG_PTR)Relations;
876 }
877
878 return Status;
879 }
880
881 static NTSTATUS
882 PdoQueryCapabilities(
883 IN PDEVICE_OBJECT DeviceObject,
884 IN PIRP Irp,
885 IN PIO_STACK_LOCATION IrpSp)
886 {
887 PDEVICE_CAPABILITIES DeviceCapabilities;
888
889 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
890
891 if (DeviceCapabilities->Version != 1)
892 return STATUS_REVISION_MISMATCH;
893
894 DeviceCapabilities->UniqueID = TRUE;
895 /* FIXME: Fill other fields */
896
897 return STATUS_SUCCESS;
898 }
899
900 static NTSTATUS
901 PdoQueryResources(
902 IN PDEVICE_OBJECT DeviceObject,
903 IN PIRP Irp,
904 IN PIO_STACK_LOCATION IrpSp)
905 {
906 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
907 PCM_RESOURCE_LIST ResourceList;
908
909 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
910
911 if (DeviceExtension->DeviceInfo->ResourceList)
912 {
913 /* Copy existing resource requirement list */
914 ResourceList = ExAllocatePool(
915 PagedPool,
916 DeviceExtension->DeviceInfo->ResourceListSize);
917 if (!ResourceList)
918 return STATUS_NO_MEMORY;
919
920 RtlCopyMemory(
921 ResourceList,
922 DeviceExtension->DeviceInfo->ResourceList,
923 DeviceExtension->DeviceInfo->ResourceListSize);
924
925 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
926
927 return STATUS_SUCCESS;
928 }
929 else
930 {
931 /* No resources so just return without changing the status */
932 return Irp->IoStatus.Status;
933 }
934 }
935
936 static NTSTATUS
937 PdoQueryResourceRequirements(
938 IN PDEVICE_OBJECT DeviceObject,
939 IN PIRP Irp,
940 IN PIO_STACK_LOCATION IrpSp)
941 {
942 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
943 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
944
945 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
946
947 if (DeviceExtension->DeviceInfo->ResourceRequirementsList)
948 {
949 /* Copy existing resource requirement list */
950 ResourceList = ExAllocatePool(PagedPool, DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
951 if (!ResourceList)
952 return STATUS_NO_MEMORY;
953
954 RtlCopyMemory(
955 ResourceList,
956 DeviceExtension->DeviceInfo->ResourceRequirementsList,
957 DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
958
959 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
960
961 return STATUS_SUCCESS;
962 }
963 else
964 {
965 /* No resource requirements so just return without changing the status */
966 return Irp->IoStatus.Status;
967 }
968 }
969
970 static NTSTATUS
971 PdoQueryDeviceText(
972 IN PDEVICE_OBJECT DeviceObject,
973 IN PIRP Irp,
974 IN PIO_STACK_LOCATION IrpSp)
975 {
976 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
977 DEVICE_TEXT_TYPE DeviceTextType;
978 NTSTATUS Status = Irp->IoStatus.Status;
979
980 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
981 DeviceTextType = IrpSp->Parameters.QueryDeviceText.DeviceTextType;
982
983 switch (DeviceTextType)
984 {
985 case DeviceTextDescription:
986 {
987 UNICODE_STRING String;
988 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
989
990 if (DeviceExtension->DeviceInfo->DeviceDescription.Buffer != NULL)
991 {
992 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
993 &DeviceExtension->DeviceInfo->DeviceDescription,
994 &String);
995 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
996 }
997 break;
998 }
999
1000 case DeviceTextLocationInformation:
1001 {
1002 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
1003 break;
1004 }
1005
1006 default:
1007 {
1008 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType);
1009 }
1010 }
1011
1012 return Status;
1013 }
1014
1015 static NTSTATUS
1016 PdoQueryId(
1017 IN PDEVICE_OBJECT DeviceObject,
1018 IN PIRP Irp,
1019 IN PIO_STACK_LOCATION IrpSp)
1020 {
1021 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1022 BUS_QUERY_ID_TYPE IdType;
1023 NTSTATUS Status = Irp->IoStatus.Status;
1024
1025 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1026 IdType = IrpSp->Parameters.QueryId.IdType;
1027
1028 switch (IdType)
1029 {
1030 case BusQueryDeviceID:
1031 {
1032 UNICODE_STRING String;
1033 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
1034
1035 Status = RtlDuplicateUnicodeString(
1036 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1037 &DeviceExtension->DeviceInfo->DeviceID,
1038 &String);
1039 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
1040 break;
1041 }
1042
1043 case BusQueryHardwareIDs:
1044 case BusQueryCompatibleIDs:
1045 {
1046 /* Optional, do nothing */
1047 break;
1048 }
1049
1050 case BusQueryInstanceID:
1051 {
1052 UNICODE_STRING String;
1053 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
1054
1055 Status = RtlDuplicateUnicodeString(
1056 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1057 &DeviceExtension->DeviceInfo->InstanceID,
1058 &String);
1059 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
1060 break;
1061 }
1062
1063 default:
1064 {
1065 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
1066 }
1067 }
1068
1069 return Status;
1070 }
1071
1072 static NTSTATUS
1073 PdoQueryBusInformation(
1074 IN PDEVICE_OBJECT DeviceObject,
1075 IN PIRP Irp,
1076 IN PIO_STACK_LOCATION IrpSp)
1077 {
1078 PPNP_BUS_INFORMATION BusInfo;
1079 NTSTATUS Status;
1080
1081 BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PNP_ROOT);
1082 if (!BusInfo)
1083 Status = STATUS_NO_MEMORY;
1084 else
1085 {
1086 RtlCopyMemory(
1087 &BusInfo->BusTypeGuid,
1088 &GUID_BUS_TYPE_INTERNAL,
1089 sizeof(BusInfo->BusTypeGuid));
1090 BusInfo->LegacyBusType = PNPBus;
1091 /* We're the only root bus enumerator on the computer */
1092 BusInfo->BusNumber = 0;
1093 Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
1094 Status = STATUS_SUCCESS;
1095 }
1096
1097 return Status;
1098 }
1099
1100 /*
1101 * FUNCTION: Handle Plug and Play IRPs for the child device
1102 * ARGUMENTS:
1103 * DeviceObject = Pointer to physical device object of the child device
1104 * Irp = Pointer to IRP that should be handled
1105 * RETURNS:
1106 * Status
1107 */
1108 static NTSTATUS
1109 PnpRootPdoPnpControl(
1110 IN PDEVICE_OBJECT DeviceObject,
1111 IN PIRP Irp)
1112 {
1113 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
1114 PPNPROOT_FDO_DEVICE_EXTENSION FdoDeviceExtension;
1115 PIO_STACK_LOCATION IrpSp;
1116 NTSTATUS Status;
1117
1118 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1119 FdoDeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension;
1120 Status = Irp->IoStatus.Status;
1121 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1122
1123 switch (IrpSp->MinorFunction)
1124 {
1125 case IRP_MN_START_DEVICE: /* 0x00 */
1126 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
1127 Status = STATUS_SUCCESS;
1128 break;
1129
1130 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
1131 Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
1132 break;
1133
1134 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
1135 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
1136 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
1137 break;
1138
1139 case IRP_MN_QUERY_RESOURCES: /* 0x0a */
1140 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
1141 Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
1142 break;
1143
1144 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
1145 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1146 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
1147 break;
1148
1149 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
1150 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1151 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
1152 break;
1153
1154 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
1155 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1156 break;
1157
1158 case IRP_MN_REMOVE_DEVICE:
1159 /* Remove the device from the device list and decrement the device count*/
1160 KeAcquireGuardedMutex(&FdoDeviceExtension->DeviceListLock);
1161 RemoveEntryList(&DeviceExtension->DeviceInfo->ListEntry);
1162 FdoDeviceExtension->DeviceListCount--;
1163 KeReleaseGuardedMutex(&FdoDeviceExtension->DeviceListLock);
1164
1165 /* Free some strings we created */
1166 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceDescription);
1167 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceID);
1168 RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->InstanceID);
1169
1170 /* Free the resource requirements list */
1171 if (DeviceExtension->DeviceInfo->ResourceRequirementsList != NULL)
1172 ExFreePool(DeviceExtension->DeviceInfo->ResourceRequirementsList);
1173
1174 /* Free the boot resources list */
1175 if (DeviceExtension->DeviceInfo->ResourceList != NULL)
1176 ExFreePool(DeviceExtension->DeviceInfo->ResourceList);
1177
1178 /* Free the device info */
1179 ExFreePool(DeviceExtension->DeviceInfo);
1180
1181 /* Finally, delete the device object */
1182 IoDeleteDevice(DeviceObject);
1183
1184 /* Return success */
1185 Status = STATUS_SUCCESS;
1186 break;
1187
1188 case IRP_MN_QUERY_ID: /* 0x13 */
1189 Status = PdoQueryId(DeviceObject, Irp, IrpSp);
1190 break;
1191
1192 case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
1193 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
1194 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
1195 break;
1196
1197 default:
1198 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
1199 break;
1200 }
1201
1202 if (Status != STATUS_PENDING)
1203 {
1204 Irp->IoStatus.Status = Status;
1205 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1206 }
1207
1208 return Status;
1209 }
1210
1211 /*
1212 * FUNCTION: Handle Plug and Play IRPs
1213 * ARGUMENTS:
1214 * DeviceObject = Pointer to PDO or FDO
1215 * Irp = Pointer to IRP that should be handled
1216 * RETURNS:
1217 * Status
1218 */
1219 static NTSTATUS NTAPI
1220 PnpRootPnpControl(
1221 IN PDEVICE_OBJECT DeviceObject,
1222 IN PIRP Irp)
1223 {
1224 PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension;
1225 NTSTATUS Status;
1226
1227 DeviceExtension = (PPNPROOT_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1228
1229 if (DeviceExtension->IsFDO)
1230 Status = PnpRootFdoPnpControl(DeviceObject, Irp);
1231 else
1232 Status = PnpRootPdoPnpControl(DeviceObject, Irp);
1233
1234 return Status;
1235 }
1236
1237 NTSTATUS
1238 NTAPI
1239 PnpRootAddDevice(
1240 IN PDRIVER_OBJECT DriverObject,
1241 IN PDEVICE_OBJECT PhysicalDeviceObject)
1242 {
1243 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
1244 NTSTATUS Status;
1245
1246 DPRINT("PnpRootAddDevice(DriverObject %p, Pdo %p)\n", DriverObject, PhysicalDeviceObject);
1247
1248 if (!PhysicalDeviceObject)
1249 {
1250 DPRINT("PhysicalDeviceObject 0x%p\n", PhysicalDeviceObject);
1251 Status = STATUS_INSUFFICIENT_RESOURCES;
1252 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1253 }
1254
1255 Status = IoCreateDevice(
1256 DriverObject,
1257 sizeof(PNPROOT_FDO_DEVICE_EXTENSION),
1258 NULL,
1259 FILE_DEVICE_BUS_EXTENDER,
1260 FILE_DEVICE_SECURE_OPEN,
1261 TRUE,
1262 &PnpRootDeviceObject);
1263 if (!NT_SUCCESS(Status))
1264 {
1265 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
1266 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1267 }
1268 DPRINT("Created FDO %p\n", PnpRootDeviceObject);
1269
1270 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension;
1271 RtlZeroMemory(DeviceExtension, sizeof(PNPROOT_FDO_DEVICE_EXTENSION));
1272
1273 DeviceExtension->Common.IsFDO = TRUE;
1274 DeviceExtension->State = dsStopped;
1275 InitializeListHead(&DeviceExtension->DeviceListHead);
1276 DeviceExtension->DeviceListCount = 0;
1277 KeInitializeGuardedMutex(&DeviceExtension->DeviceListLock);
1278
1279 Status = IoAttachDeviceToDeviceStackSafe(
1280 PnpRootDeviceObject,
1281 PhysicalDeviceObject,
1282 &DeviceExtension->Ldo);
1283 if (!NT_SUCCESS(Status))
1284 {
1285 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
1286 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1287 }
1288
1289 PnpRootDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1290
1291 DPRINT("Done AddDevice()\n");
1292
1293 return STATUS_SUCCESS;
1294 }
1295
1296 NTSTATUS NTAPI
1297 PnpRootDriverEntry(
1298 IN PDRIVER_OBJECT DriverObject,
1299 IN PUNICODE_STRING RegistryPath)
1300 {
1301 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject, RegistryPath);
1302
1303 IopRootDriverObject = DriverObject;
1304
1305 DriverObject->DriverExtension->AddDevice = PnpRootAddDevice;
1306
1307 DriverObject->MajorFunction[IRP_MJ_PNP] = PnpRootPnpControl;
1308 //DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
1309
1310 return STATUS_SUCCESS;
1311 }