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