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