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