63a3dd59c706f46a5df55da9852c07c59d0e24a8
[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 /* Creates a new PnP device for a legacy driver */
130 NTSTATUS
131 PnpRootCreateDevice(
132 IN PUNICODE_STRING ServiceName,
133 OUT PDEVICE_OBJECT *PhysicalDeviceObject,
134 OUT OPTIONAL PUNICODE_STRING FullInstancePath)
135 {
136 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
137 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
138 WCHAR DevicePath[MAX_PATH + 1];
139 WCHAR InstancePath[5];
140 PPNPROOT_DEVICE Device = NULL;
141 NTSTATUS Status;
142 ULONG i;
143 UNICODE_STRING PathSep = RTL_CONSTANT_STRING(L"\\");
144
145 DeviceExtension = PnpRootDeviceObject->DeviceExtension;
146 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
147
148 DPRINT("Creating a PnP root device for service '%wZ'\n", ServiceName);
149
150 /* Search for a free instance ID */
151 _snwprintf(DevicePath, sizeof(DevicePath) / sizeof(WCHAR), L"%s\\%wZ", REGSTR_KEY_ROOTENUM, ServiceName);
152 for (i = 0; i < 9999; i++)
153 {
154 _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", i);
155 Status = LocateChildDevice(DeviceExtension, DevicePath, InstancePath, &Device);
156 if (Status == STATUS_NO_SUCH_DEVICE)
157 break;
158 }
159 if (i == 9999)
160 {
161 DPRINT1("Too much legacy devices reported for service '%wZ'\n", ServiceName);
162 Status = STATUS_INSUFFICIENT_RESOURCES;
163 goto cleanup;
164 }
165
166 /* Initialize a PNPROOT_DEVICE structure */
167 Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
168 if (!Device)
169 {
170 DPRINT("ExAllocatePoolWithTag() failed\n");
171 Status = STATUS_NO_MEMORY;
172 goto cleanup;
173 }
174 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
175 if (!RtlCreateUnicodeString(&Device->DeviceID, DevicePath))
176 {
177 Status = STATUS_NO_MEMORY;
178 goto cleanup;
179 }
180 if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath))
181 {
182 Status = STATUS_NO_MEMORY;
183 goto cleanup;
184 }
185
186 if (FullInstancePath)
187 {
188 FullInstancePath->MaximumLength = Device->DeviceID.Length + PathSep.Length + Device->InstanceID.Length;
189 FullInstancePath->Length = 0;
190 FullInstancePath->Buffer = ExAllocatePool(PagedPool, FullInstancePath->MaximumLength);
191 if (!FullInstancePath->Buffer)
192 {
193 Status = STATUS_NO_MEMORY;
194 goto cleanup;
195 }
196
197 RtlAppendUnicodeStringToString(FullInstancePath, &Device->DeviceID);
198 RtlAppendUnicodeStringToString(FullInstancePath, &PathSep);
199 RtlAppendUnicodeStringToString(FullInstancePath, &Device->InstanceID);
200 }
201
202 /* Initialize a device object */
203 Status = IoCreateDevice(
204 PnpRootDeviceObject->DriverObject,
205 sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
206 NULL,
207 FILE_DEVICE_CONTROLLER,
208 FILE_AUTOGENERATED_DEVICE_NAME,
209 FALSE,
210 &Device->Pdo);
211 if (!NT_SUCCESS(Status))
212 {
213 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
214 Status = STATUS_NO_MEMORY;
215 goto cleanup;
216 }
217
218 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
219 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
220 PdoDeviceExtension->Common.IsFDO = FALSE;
221 PdoDeviceExtension->DeviceInfo = Device;
222
223 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
224 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
225
226 InsertTailList(
227 &DeviceExtension->DeviceListHead,
228 &Device->ListEntry);
229 DeviceExtension->DeviceListCount++;
230
231 *PhysicalDeviceObject = Device->Pdo;
232 DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject, &Device->DeviceID, &Device->InstanceID);
233 Device = NULL;
234 Status = STATUS_SUCCESS;
235
236 cleanup:
237 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
238 if (Device)
239 {
240 if (Device->Pdo)
241 IoDeleteDevice(Device->Pdo);
242 RtlFreeUnicodeString(&Device->DeviceID);
243 RtlFreeUnicodeString(&Device->InstanceID);
244 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
245 }
246 return Status;
247 }
248
249 static NTSTATUS NTAPI
250 QueryStringCallback(
251 IN PWSTR ValueName,
252 IN ULONG ValueType,
253 IN PVOID ValueData,
254 IN ULONG ValueLength,
255 IN PVOID Context,
256 IN PVOID EntryContext)
257 {
258 PUNICODE_STRING Destination = (PUNICODE_STRING)EntryContext;
259 UNICODE_STRING Source;
260
261 if (ValueType != REG_SZ || ValueLength == 0 || ValueLength % sizeof(WCHAR) != 0)
262 return STATUS_SUCCESS;
263
264 Source.MaximumLength = Source.Length = ValueLength;
265 Source.Buffer = ValueData;
266 if (Source.Length > 0 && Source.Buffer[Source.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
267 Source.Length -= sizeof(WCHAR);
268 return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &Source, Destination);
269 }
270
271 static NTSTATUS NTAPI
272 QueryBinaryValueCallback(
273 IN PWSTR ValueName,
274 IN ULONG ValueType,
275 IN PVOID ValueData,
276 IN ULONG ValueLength,
277 IN PVOID Context,
278 IN PVOID EntryContext)
279 {
280 PBUFFER Buffer = (PBUFFER)EntryContext;
281 PVOID BinaryValue;
282
283 if (ValueLength == 0)
284 {
285 *Buffer->Data = NULL;
286 return STATUS_SUCCESS;
287 }
288
289 BinaryValue = ExAllocatePoolWithTag(PagedPool, ValueLength, TAG_PNP_ROOT);
290 if (BinaryValue == NULL)
291 return STATUS_NO_MEMORY;
292 RtlCopyMemory(BinaryValue, ValueData, ValueLength);
293 *Buffer->Data = BinaryValue;
294 if (Buffer->Length) *Buffer->Length = ValueLength;
295 return STATUS_SUCCESS;
296 }
297
298 static NTSTATUS
299 EnumerateDevices(
300 IN PDEVICE_OBJECT DeviceObject)
301 {
302 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
303 PKEY_BASIC_INFORMATION KeyInfo = NULL, SubKeyInfo = NULL;
304 UNICODE_STRING LegacyU = RTL_CONSTANT_STRING(L"LEGACY_");
305 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L"\\" REGSTR_KEY_ROOTENUM);
306 UNICODE_STRING SubKeyName;
307 WCHAR DevicePath[MAX_PATH + 1];
308 RTL_QUERY_REGISTRY_TABLE QueryTable[5];
309 PPNPROOT_DEVICE Device = NULL;
310 HANDLE KeyHandle = INVALID_HANDLE_VALUE;
311 HANDLE SubKeyHandle = INVALID_HANDLE_VALUE;
312 HANDLE DeviceKeyHandle = INVALID_HANDLE_VALUE;
313 ULONG BufferSize;
314 ULONG ResultSize;
315 ULONG Index1, Index2;
316 BUFFER Buffer1, Buffer2;
317 NTSTATUS Status = STATUS_UNSUCCESSFUL;
318
319 DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject);
320
321 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
322 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
323
324 BufferSize = sizeof(KEY_BASIC_INFORMATION) + (MAX_PATH + 1) * sizeof(WCHAR);
325 KeyInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_PNP_ROOT);
326 if (!KeyInfo)
327 {
328 DPRINT("ExAllocatePoolWithTag() failed\n");
329 Status = STATUS_NO_MEMORY;
330 goto cleanup;
331 }
332 SubKeyInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_PNP_ROOT);
333 if (!SubKeyInfo)
334 {
335 DPRINT("ExAllocatePoolWithTag() failed\n");
336 Status = STATUS_NO_MEMORY;
337 goto cleanup;
338 }
339
340 Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &KeyName, KEY_ENUMERATE_SUB_KEYS);
341 if (!NT_SUCCESS(Status))
342 {
343 DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName, Status);
344 goto cleanup;
345 }
346
347 /* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as
348 * KeyHandle. We'll first do a first enumeration to have first level keys,
349 * and an inner one to have the real devices list.
350 */
351 Index1 = 0;
352 while (TRUE)
353 {
354 Status = ZwEnumerateKey(
355 KeyHandle,
356 Index1,
357 KeyBasicInformation,
358 KeyInfo,
359 BufferSize,
360 &ResultSize);
361 if (Status == STATUS_NO_MORE_ENTRIES)
362 {
363 Status = STATUS_SUCCESS;
364 break;
365 }
366 else if (!NT_SUCCESS(Status))
367 {
368 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
369 goto cleanup;
370 }
371
372 /* Terminate the string */
373 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
374
375 /* Check if it is a legacy driver */
376 RtlInitUnicodeString(&SubKeyName, KeyInfo->Name);
377 if (RtlPrefixUnicodeString(&LegacyU, &SubKeyName, FALSE))
378 {
379 DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName);
380 Index1++;
381 continue;
382 }
383
384 /* Open the key */
385 Status = IopOpenRegistryKeyEx(&SubKeyHandle, KeyHandle, &SubKeyName, KEY_ENUMERATE_SUB_KEYS);
386 if (!NT_SUCCESS(Status))
387 {
388 DPRINT("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status);
389 break;
390 }
391
392 /* Enumerate the sub-keys */
393 Index2 = 0;
394 while (TRUE)
395 {
396 Status = ZwEnumerateKey(
397 SubKeyHandle,
398 Index2,
399 KeyBasicInformation,
400 SubKeyInfo,
401 BufferSize,
402 &ResultSize);
403 if (Status == STATUS_NO_MORE_ENTRIES)
404 break;
405 else if (!NT_SUCCESS(Status))
406 {
407 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
408 break;
409 }
410
411 /* Terminate the string */
412 SubKeyInfo->Name[SubKeyInfo->NameLength / sizeof(WCHAR)] = 0;
413
414 _snwprintf(
415 DevicePath,
416 sizeof(DevicePath) / sizeof(WCHAR),
417 L"%s\\%s", REGSTR_KEY_ROOTENUM, KeyInfo->Name);
418 DPRINT("Found device %S\\%s!\n", DevicePath, SubKeyInfo->Name);
419 if (LocateChildDevice(DeviceExtension, DevicePath, SubKeyInfo->Name, &Device) == STATUS_NO_SUCH_DEVICE)
420 {
421 /* Create a PPNPROOT_DEVICE object, and add if in the list of known devices */
422 Device = (PPNPROOT_DEVICE)ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
423 if (!Device)
424 {
425 DPRINT("ExAllocatePoolWithTag() failed\n");
426 Status = STATUS_NO_MEMORY;
427 goto cleanup;
428 }
429 RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
430
431 /* Fill device ID and instance ID */
432 if (!RtlCreateUnicodeString(&Device->DeviceID, DevicePath))
433 {
434 DPRINT("RtlCreateUnicodeString() failed\n");
435 Status = STATUS_NO_MEMORY;
436 goto cleanup;
437 }
438
439 if (!RtlCreateUnicodeString(&Device->InstanceID, SubKeyInfo->Name))
440 {
441 DPRINT("RtlCreateUnicodeString() failed\n");
442 Status = STATUS_NO_MEMORY;
443 goto cleanup;
444 }
445
446 /* Open registry key to fill other informations */
447 Status = IopOpenRegistryKeyEx(&DeviceKeyHandle, SubKeyHandle, &Device->InstanceID, KEY_READ);
448 if (!NT_SUCCESS(Status))
449 {
450 DPRINT("IopOpenRegistryKeyEx() failed with status 0x%08lx\n", Status);
451 break;
452 }
453
454 /* Fill other informations */
455 Buffer1.Data = (PVOID *)&Device->ResourceRequirementsList;
456 Buffer1.Length = NULL;
457 Buffer2.Data = (PVOID *)&Device->ResourceList;
458 Buffer2.Length = &Device->ResourceListSize;
459 RtlZeroMemory(QueryTable, sizeof(QueryTable));
460 QueryTable[0].QueryRoutine = QueryStringCallback;
461 QueryTable[0].Name = L"DeviceDesc";
462 QueryTable[0].EntryContext = &Device->DeviceDescription;
463 QueryTable[1].Flags = RTL_QUERY_REGISTRY_SUBKEY;
464 QueryTable[1].Name = L"LogConf";
465 QueryTable[2].QueryRoutine = QueryBinaryValueCallback;
466 QueryTable[2].Name = L"BasicConfigVector";
467 QueryTable[2].EntryContext = &Buffer1;
468 QueryTable[3].QueryRoutine = QueryBinaryValueCallback;
469 QueryTable[3].Name = L"BootConfig";
470 QueryTable[3].EntryContext = &Buffer2;
471
472 Status = RtlQueryRegistryValues(
473 RTL_REGISTRY_HANDLE,
474 (PCWSTR)DeviceKeyHandle,
475 QueryTable,
476 NULL,
477 NULL);
478 if (!NT_SUCCESS(Status))
479 {
480 DPRINT("RtlQueryRegistryValues() failed with status 0x%08lx\n", Status);
481 break;
482 }
483
484 ZwClose(DeviceKeyHandle);
485 DeviceKeyHandle = INVALID_HANDLE_VALUE;
486
487 /* Insert the newly created device into the list */
488 InsertTailList(
489 &DeviceExtension->DeviceListHead,
490 &Device->ListEntry);
491 DeviceExtension->DeviceListCount++;
492 }
493 Device = NULL;
494
495 Index2++;
496 }
497
498 ZwClose(SubKeyHandle);
499 SubKeyHandle = INVALID_HANDLE_VALUE;
500 Index1++;
501 }
502
503 cleanup:
504 if (Device)
505 {
506 /* We have a device that has not been added to device list. We need to clean it up */
507 /* FIXME */
508 ExFreePoolWithTag(Device, TAG_PNP_ROOT);
509 }
510 if (DeviceKeyHandle != INVALID_HANDLE_VALUE)
511 ZwClose(DeviceKeyHandle);
512 if (SubKeyHandle != INVALID_HANDLE_VALUE)
513 ZwClose(SubKeyHandle);
514 if (KeyHandle != INVALID_HANDLE_VALUE)
515 ZwClose(KeyHandle);
516 if (KeyInfo)
517 ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
518 if (SubKeyInfo)
519 ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
520 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
521 return Status;
522 }
523
524 /* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
525 * ARGUMENTS:
526 * DeviceObject = Pointer to functional device object of the root bus driver
527 * Irp = Pointer to IRP that should be handled
528 * RETURNS:
529 * Status
530 */
531 static NTSTATUS
532 PnpRootQueryDeviceRelations(
533 IN PDEVICE_OBJECT DeviceObject,
534 IN PIRP Irp)
535 {
536 PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
537 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
538 PDEVICE_RELATIONS Relations = NULL, OtherRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
539 PPNPROOT_DEVICE Device = NULL;
540 ULONG Size;
541 NTSTATUS Status;
542 PLIST_ENTRY NextEntry;
543
544 DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject, Irp);
545
546 Status = EnumerateDevices(DeviceObject);
547 if (!NT_SUCCESS(Status))
548 {
549 DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status);
550 return Status;
551 }
552
553 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
554
555 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * DeviceExtension->DeviceListCount;
556 if (OtherRelations)
557 {
558 /* Another bus driver has already created a DEVICE_RELATIONS
559 * structure so we must merge this structure with our own */
560
561 Size += sizeof(PDEVICE_OBJECT) * OtherRelations->Count;
562 }
563 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
564 if (!Relations)
565 {
566 DPRINT("ExAllocatePoolWithTag() failed\n");
567 Status = STATUS_NO_MEMORY;
568 goto cleanup;
569 }
570 RtlZeroMemory(Relations, Size);
571 if (OtherRelations)
572 {
573 Relations->Count = OtherRelations->Count;
574 RtlCopyMemory(Relations->Objects, OtherRelations->Objects, sizeof(PDEVICE_OBJECT) * OtherRelations->Count);
575 }
576
577 KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
578
579 /* Start looping */
580 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
581 NextEntry != &DeviceExtension->DeviceListHead;
582 NextEntry = NextEntry->Flink)
583 {
584 /* Get the entry */
585 Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry);
586
587 if (!Device->Pdo)
588 {
589 /* Create a physical device object for the
590 * device as it does not already have one */
591 Status = IoCreateDevice(
592 DeviceObject->DriverObject,
593 sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
594 NULL,
595 FILE_DEVICE_CONTROLLER,
596 FILE_AUTOGENERATED_DEVICE_NAME,
597 FALSE,
598 &Device->Pdo);
599 if (!NT_SUCCESS(Status))
600 {
601 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
602 break;
603 }
604
605 PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
606 RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
607 PdoDeviceExtension->Common.IsFDO = FALSE;
608 PdoDeviceExtension->DeviceInfo = Device;
609
610 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
611 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
612 }
613
614 /* Reference the physical device object. The PnP manager
615 will dereference it again when it is no longer needed */
616 ObReferenceObject(Device->Pdo);
617
618 Relations->Objects[Relations->Count++] = Device->Pdo;
619 }
620 KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
621
622 Irp->IoStatus.Information = (ULONG_PTR)Relations;
623
624 cleanup:
625 if (!NT_SUCCESS(Status))
626 {
627 if (OtherRelations)
628 ExFreePool(OtherRelations);
629 if (Relations)
630 ExFreePool(Relations);
631 if (Device && Device->Pdo)
632 {
633 IoDeleteDevice(Device->Pdo);
634 Device->Pdo = NULL;
635 }
636 }
637
638 return Status;
639 }
640
641 /*
642 * FUNCTION: Handle Plug and Play IRPs for the root bus device object
643 * ARGUMENTS:
644 * DeviceObject = Pointer to functional device object of the root bus driver
645 * Irp = Pointer to IRP that should be handled
646 * RETURNS:
647 * Status
648 */
649 static NTSTATUS
650 PnpRootFdoPnpControl(
651 IN PDEVICE_OBJECT DeviceObject,
652 IN PIRP Irp)
653 {
654 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
655 PIO_STACK_LOCATION IrpSp;
656 NTSTATUS Status;
657
658 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
659 Status = Irp->IoStatus.Status;
660 IrpSp = IoGetCurrentIrpStackLocation(Irp);
661
662 switch (IrpSp->MinorFunction)
663 {
664 case IRP_MN_QUERY_DEVICE_RELATIONS:
665 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
666 Status = PnpRootQueryDeviceRelations(DeviceObject, Irp);
667 break;
668
669 case IRP_MN_START_DEVICE:
670 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
671 if (!IoForwardIrpSynchronously(DeviceExtension->Ldo, Irp))
672 Status = STATUS_UNSUCCESSFUL;
673 else
674 {
675 Status = Irp->IoStatus.Status;
676 if (NT_SUCCESS(Status))
677 DeviceExtension->State = dsStarted;
678 }
679
680 Irp->IoStatus.Status = Status;
681 IoCompleteRequest(Irp, IO_NO_INCREMENT);
682 return Status;
683
684 case IRP_MN_STOP_DEVICE:
685 DPRINT("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
686 /* Root device cannot be stopped */
687 Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST;
688 IoCompleteRequest(Irp, IO_NO_INCREMENT);
689 return Status;
690
691 default:
692 DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
693 break;
694 }
695
696 if (Status != STATUS_PENDING)
697 {
698 Irp->IoStatus.Status = Status;
699 IoCompleteRequest(Irp, IO_NO_INCREMENT);
700 }
701
702 return Status;
703 }
704
705 static NTSTATUS
706 PdoQueryDeviceRelations(
707 IN PDEVICE_OBJECT DeviceObject,
708 IN PIRP Irp,
709 IN PIO_STACK_LOCATION IrpSp)
710 {
711 PDEVICE_RELATIONS Relations;
712 NTSTATUS Status = Irp->IoStatus.Status;
713
714 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
715 return Status;
716
717 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
718 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
719 if (!Relations)
720 {
721 DPRINT("ExAllocatePoolWithTag() failed\n");
722 Status = STATUS_NO_MEMORY;
723 }
724 else
725 {
726 ObReferenceObject(DeviceObject);
727 Relations->Count = 1;
728 Relations->Objects[0] = DeviceObject;
729 Status = STATUS_SUCCESS;
730 Irp->IoStatus.Information = (ULONG_PTR)Relations;
731 }
732
733 return Status;
734 }
735
736 static NTSTATUS
737 PdoQueryCapabilities(
738 IN PDEVICE_OBJECT DeviceObject,
739 IN PIRP Irp,
740 IN PIO_STACK_LOCATION IrpSp)
741 {
742 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
743 PDEVICE_CAPABILITIES DeviceCapabilities;
744
745 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
746 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
747
748 if (DeviceCapabilities->Version != 1)
749 return STATUS_REVISION_MISMATCH;
750
751 DeviceCapabilities->UniqueID = TRUE;
752 /* FIXME: Fill other fields */
753
754 return STATUS_SUCCESS;
755 }
756
757 static NTSTATUS
758 PdoQueryResources(
759 IN PDEVICE_OBJECT DeviceObject,
760 IN PIRP Irp,
761 IN PIO_STACK_LOCATION IrpSp)
762 {
763 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
764 PCM_RESOURCE_LIST ResourceList;
765
766 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
767
768 if (DeviceExtension->DeviceInfo->ResourceList)
769 {
770 /* Copy existing resource requirement list */
771 ResourceList = ExAllocatePool(
772 PagedPool,
773 DeviceExtension->DeviceInfo->ResourceListSize);
774 if (!ResourceList)
775 return STATUS_NO_MEMORY;
776
777 RtlCopyMemory(
778 ResourceList,
779 DeviceExtension->DeviceInfo->ResourceList,
780 DeviceExtension->DeviceInfo->ResourceListSize);
781
782 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
783
784 return STATUS_SUCCESS;
785 }
786 else
787 {
788 /* No resources so just return without changing the status */
789 return Irp->IoStatus.Status;
790 }
791 }
792
793 static NTSTATUS
794 PdoQueryResourceRequirements(
795 IN PDEVICE_OBJECT DeviceObject,
796 IN PIRP Irp,
797 IN PIO_STACK_LOCATION IrpSp)
798 {
799 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
800 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
801
802 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
803
804 if (DeviceExtension->DeviceInfo->ResourceRequirementsList)
805 {
806 /* Copy existing resource requirement list */
807 ResourceList = ExAllocatePool(PagedPool, DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
808 if (!ResourceList)
809 return STATUS_NO_MEMORY;
810
811 RtlCopyMemory(
812 ResourceList,
813 DeviceExtension->DeviceInfo->ResourceRequirementsList,
814 DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
815
816 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
817
818 return STATUS_SUCCESS;
819 }
820 else
821 {
822 /* No resource requirements so just return without changing the status */
823 return Irp->IoStatus.Status;
824 }
825 }
826
827 static NTSTATUS
828 PdoQueryDeviceText(
829 IN PDEVICE_OBJECT DeviceObject,
830 IN PIRP Irp,
831 IN PIO_STACK_LOCATION IrpSp)
832 {
833 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
834 DEVICE_TEXT_TYPE DeviceTextType;
835 NTSTATUS Status = Irp->IoStatus.Status;
836
837 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
838 DeviceTextType = IrpSp->Parameters.QueryDeviceText.DeviceTextType;
839
840 switch (DeviceTextType)
841 {
842 case DeviceTextDescription:
843 {
844 UNICODE_STRING String;
845 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
846
847 Status = RtlDuplicateUnicodeString(
848 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
849 &DeviceExtension->DeviceInfo->DeviceDescription,
850 &String);
851 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
852 break;
853 }
854
855 case DeviceTextLocationInformation:
856 {
857 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
858 Status = STATUS_NOT_SUPPORTED;
859 break;
860 }
861
862 default:
863 {
864 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType);
865 }
866 }
867
868 return Status;
869 }
870
871 static NTSTATUS
872 PdoQueryId(
873 IN PDEVICE_OBJECT DeviceObject,
874 IN PIRP Irp,
875 IN PIO_STACK_LOCATION IrpSp)
876 {
877 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
878 BUS_QUERY_ID_TYPE IdType;
879 NTSTATUS Status = Irp->IoStatus.Status;
880
881 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
882 IdType = IrpSp->Parameters.QueryId.IdType;
883
884 switch (IdType)
885 {
886 case BusQueryDeviceID:
887 {
888 UNICODE_STRING String;
889 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
890
891 Status = RtlDuplicateUnicodeString(
892 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
893 &DeviceExtension->DeviceInfo->DeviceID,
894 &String);
895 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
896 break;
897 }
898
899 case BusQueryHardwareIDs:
900 case BusQueryCompatibleIDs:
901 {
902 /* Optional, do nothing */
903 break;
904 }
905
906 case BusQueryInstanceID:
907 {
908 UNICODE_STRING String;
909 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
910
911 Status = RtlDuplicateUnicodeString(
912 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
913 &DeviceExtension->DeviceInfo->InstanceID,
914 &String);
915 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
916 break;
917 }
918
919 default:
920 {
921 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
922 }
923 }
924
925 return Status;
926 }
927
928 static NTSTATUS
929 PdoQueryBusInformation(
930 IN PDEVICE_OBJECT DeviceObject,
931 IN PIRP Irp,
932 IN PIO_STACK_LOCATION IrpSp)
933 {
934 PPNP_BUS_INFORMATION BusInfo;
935 NTSTATUS Status;
936
937 BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PNP_ROOT);
938 if (!BusInfo)
939 Status = STATUS_NO_MEMORY;
940 else
941 {
942 RtlCopyMemory(
943 &BusInfo->BusTypeGuid,
944 &GUID_BUS_TYPE_INTERNAL,
945 sizeof(BusInfo->BusTypeGuid));
946 BusInfo->LegacyBusType = PNPBus;
947 /* We're the only root bus enumerator on the computer */
948 BusInfo->BusNumber = 0;
949 Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
950 Status = STATUS_SUCCESS;
951 }
952
953 return Status;
954 }
955
956 /*
957 * FUNCTION: Handle Plug and Play IRPs for the child device
958 * ARGUMENTS:
959 * DeviceObject = Pointer to physical device object of the child device
960 * Irp = Pointer to IRP that should be handled
961 * RETURNS:
962 * Status
963 */
964 static NTSTATUS
965 PnpRootPdoPnpControl(
966 IN PDEVICE_OBJECT DeviceObject,
967 IN PIRP Irp)
968 {
969 PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
970 PIO_STACK_LOCATION IrpSp;
971 NTSTATUS Status;
972
973 DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
974 Status = Irp->IoStatus.Status;
975 IrpSp = IoGetCurrentIrpStackLocation(Irp);
976
977 switch (IrpSp->MinorFunction)
978 {
979 case IRP_MN_START_DEVICE: /* 0x00 */
980 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
981 Status = STATUS_SUCCESS;
982 break;
983
984 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
985 Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
986 break;
987
988 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
989 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
990 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
991 break;
992
993 case IRP_MN_QUERY_RESOURCES: /* 0x0a */
994 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
995 Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
996 break;
997
998 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
999 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1000 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
1001 break;
1002
1003 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
1004 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
1005 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
1006 break;
1007
1008 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
1009 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
1010 break;
1011
1012 case IRP_MN_QUERY_ID: /* 0x13 */
1013 Status = PdoQueryId(DeviceObject, Irp, IrpSp);
1014 break;
1015
1016 case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
1017 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
1018 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
1019 break;
1020
1021 default:
1022 DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
1023 Status = STATUS_NOT_IMPLEMENTED;
1024 break;
1025 }
1026
1027 if (Status != STATUS_PENDING)
1028 {
1029 Irp->IoStatus.Status = Status;
1030 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1031 }
1032
1033 return Status;
1034 }
1035
1036 /*
1037 * FUNCTION: Handle Plug and Play IRPs
1038 * ARGUMENTS:
1039 * DeviceObject = Pointer to PDO or FDO
1040 * Irp = Pointer to IRP that should be handled
1041 * RETURNS:
1042 * Status
1043 */
1044 static NTSTATUS NTAPI
1045 PnpRootPnpControl(
1046 IN PDEVICE_OBJECT DeviceObject,
1047 IN PIRP Irp)
1048 {
1049 PPNPROOT_COMMON_DEVICE_EXTENSION DeviceExtension;
1050 NTSTATUS Status;
1051
1052 DeviceExtension = (PPNPROOT_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1053
1054 if (DeviceExtension->IsFDO)
1055 Status = PnpRootFdoPnpControl(DeviceObject, Irp);
1056 else
1057 Status = PnpRootPdoPnpControl(DeviceObject, Irp);
1058
1059 return Status;
1060 }
1061
1062 NTSTATUS
1063 NTAPI
1064 PnpRootAddDevice(
1065 IN PDRIVER_OBJECT DriverObject,
1066 IN PDEVICE_OBJECT PhysicalDeviceObject)
1067 {
1068 PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
1069 NTSTATUS Status;
1070
1071 DPRINT("PnpRootAddDevice(DriverObject %p, Pdo %p)\n", DriverObject, PhysicalDeviceObject);
1072
1073 if (!PhysicalDeviceObject)
1074 {
1075 DPRINT("PhysicalDeviceObject 0x%p\n", PhysicalDeviceObject);
1076 Status = STATUS_INSUFFICIENT_RESOURCES;
1077 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1078 }
1079
1080 Status = IoCreateDevice(
1081 DriverObject,
1082 sizeof(PNPROOT_FDO_DEVICE_EXTENSION),
1083 NULL,
1084 FILE_DEVICE_BUS_EXTENDER,
1085 FILE_DEVICE_SECURE_OPEN,
1086 TRUE,
1087 &PnpRootDeviceObject);
1088 if (!NT_SUCCESS(Status))
1089 {
1090 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
1091 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1092 }
1093 DPRINT("Created FDO %p\n", PnpRootDeviceObject);
1094
1095 DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension;
1096 RtlZeroMemory(DeviceExtension, sizeof(PNPROOT_FDO_DEVICE_EXTENSION));
1097
1098 DeviceExtension->Common.IsFDO = TRUE;
1099 DeviceExtension->State = dsStopped;
1100 InitializeListHead(&DeviceExtension->DeviceListHead);
1101 DeviceExtension->DeviceListCount = 0;
1102 KeInitializeGuardedMutex(&DeviceExtension->DeviceListLock);
1103
1104 Status = IoAttachDeviceToDeviceStackSafe(
1105 PnpRootDeviceObject,
1106 PhysicalDeviceObject,
1107 &DeviceExtension->Ldo);
1108 if (!NT_SUCCESS(Status))
1109 {
1110 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
1111 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1112 }
1113
1114 PnpRootDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1115
1116 DPRINT("Done AddDevice()\n");
1117
1118 return STATUS_SUCCESS;
1119 }
1120
1121 NTSTATUS NTAPI
1122 PnpRootDriverEntry(
1123 IN PDRIVER_OBJECT DriverObject,
1124 IN PUNICODE_STRING RegistryPath)
1125 {
1126 DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject, RegistryPath);
1127
1128 DriverObject->DriverExtension->AddDevice = PnpRootAddDevice;
1129
1130 DriverObject->MajorFunction[IRP_MJ_PNP] = PnpRootPnpControl;
1131 //DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
1132
1133 return STATUS_SUCCESS;
1134 }