[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
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 //#define ENABLE_ACPI
17
18 /* GLOBALS *******************************************************************/
19
20 PDEVICE_NODE IopRootDeviceNode;
21 KSPIN_LOCK IopDeviceTreeLock;
22 ERESOURCE PpRegistryDeviceResource;
23 KGUARDED_MUTEX PpDeviceReferenceTableLock;
24 RTL_AVL_TABLE PpDeviceReferenceTable;
25
26 extern ULONG ExpInitializationPhase;
27 extern BOOLEAN PnpSystemInit;
28
29 /* DATA **********************************************************************/
30
31 PDRIVER_OBJECT IopRootDriverObject;
32 FAST_MUTEX IopBusTypeGuidListLock;
33 PIO_BUS_TYPE_GUID_LIST IopBusTypeGuidList = NULL;
34
35 #if defined (ALLOC_PRAGMA)
36 #pragma alloc_text(INIT, PnpInit)
37 #pragma alloc_text(INIT, PnpInit2)
38 #endif
39
40 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
41 {
42 PDEVICE_OBJECT DeviceObject;
43 DEVICE_RELATION_TYPE Type;
44 PIO_WORKITEM WorkItem;
45 } INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
46
47 /* FUNCTIONS *****************************************************************/
48
49 NTSTATUS
50 IopAssignDeviceResources(
51 IN PDEVICE_NODE DeviceNode,
52 OUT ULONG *pRequiredSize);
53
54 NTSTATUS
55 IopTranslateDeviceResources(
56 IN PDEVICE_NODE DeviceNode,
57 IN ULONG RequiredSize);
58
59 NTSTATUS
60 IopUpdateResourceMapForPnPDevice(
61 IN PDEVICE_NODE DeviceNode);
62
63 NTSTATUS
64 NTAPI
65 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
66 OUT PHANDLE Handle);
67
68 PDEVICE_NODE
69 FASTCALL
70 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
71 {
72 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
73 }
74
75 NTSTATUS
76 FASTCALL
77 IopInitializeDevice(PDEVICE_NODE DeviceNode,
78 PDRIVER_OBJECT DriverObject)
79 {
80 PDEVICE_OBJECT Fdo;
81 NTSTATUS Status;
82
83 if (!DriverObject->DriverExtension->AddDevice)
84 return STATUS_SUCCESS;
85
86 /* This is a Plug and Play driver */
87 DPRINT("Plug and Play driver found\n");
88 ASSERT(DeviceNode->PhysicalDeviceObject);
89
90 /* Check if this plug-and-play driver is used as a legacy one for this device node */
91 if (IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
92 {
93 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
94 return STATUS_SUCCESS;
95 }
96
97 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
98 &DriverObject->DriverName,
99 &DeviceNode->InstancePath);
100 Status = DriverObject->DriverExtension->AddDevice(
101 DriverObject, DeviceNode->PhysicalDeviceObject);
102 if (!NT_SUCCESS(Status))
103 {
104 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
105 return Status;
106 }
107
108 /* Check if driver added a FDO above the PDO */
109 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
110 if (Fdo == DeviceNode->PhysicalDeviceObject)
111 {
112 /* FIXME: What do we do? Unload the driver or just disable the device? */
113 DPRINT1("An FDO was not attached\n");
114 ObDereferenceObject(Fdo);
115 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
116 return STATUS_UNSUCCESSFUL;
117 }
118
119 /* Check if we have a ACPI device (needed for power management) */
120 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
121 {
122 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
123
124 /* There can be only one system power device */
125 if (!SystemPowerDeviceNodeCreated)
126 {
127 PopSystemPowerDeviceNode = DeviceNode;
128 ObReferenceObject(PopSystemPowerDeviceNode);
129 SystemPowerDeviceNodeCreated = TRUE;
130 }
131 }
132
133 ObDereferenceObject(Fdo);
134
135 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
136 IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
137
138 return STATUS_SUCCESS;
139 }
140
141 NTSTATUS
142 IopStartDevice(
143 PDEVICE_NODE DeviceNode)
144 {
145 IO_STATUS_BLOCK IoStatusBlock;
146 IO_STACK_LOCATION Stack;
147 ULONG RequiredLength;
148 NTSTATUS Status;
149 HANDLE InstanceHandle, ControlHandle;
150 UNICODE_STRING KeyName;
151 OBJECT_ATTRIBUTES ObjectAttributes;
152
153 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
154 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
155 Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
156 Status = IopInitiatePnpIrp(
157 DeviceNode->PhysicalDeviceObject,
158 &IoStatusBlock,
159 IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
160 &Stack);
161 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
162 {
163 DPRINT("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
164 return Status;
165 }
166 else if (NT_SUCCESS(Status))
167 {
168 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
169 }
170
171 Status = IopAssignDeviceResources(DeviceNode, &RequiredLength);
172 if (NT_SUCCESS(Status))
173 {
174 Status = IopTranslateDeviceResources(DeviceNode, RequiredLength);
175 if (NT_SUCCESS(Status))
176 {
177 Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT("IopUpdateResourceMap() failed (Status 0x%08lx)\n", Status);
181 }
182 }
183 else
184 {
185 DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)\n", Status);
186 }
187 }
188 else
189 {
190 DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)\n", Status);
191 }
192 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
193
194 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
195 Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList;
196 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated;
197
198 /*
199 * Windows NT Drivers receive IRP_MN_START_DEVICE in a critical region and
200 * actually _depend_ on this!. This is because NT will lock the Device Node
201 * with an ERESOURCE, which of course requires APCs to be disabled.
202 */
203 KeEnterCriticalRegion();
204
205 Status = IopInitiatePnpIrp(
206 DeviceNode->PhysicalDeviceObject,
207 &IoStatusBlock,
208 IRP_MN_START_DEVICE,
209 &Stack);
210
211 KeLeaveCriticalRegion();
212
213 if (!NT_SUCCESS(Status))
214 {
215 DPRINT("IopInitiatePnpIrp() failed\n");
216 }
217 else
218 {
219 if (IopDeviceNodeHasFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY))
220 {
221 DPRINT("Device needs enumeration, invalidating bus relations\n");
222 /* Invalidate device relations synchronously
223 (otherwise there will be dirty read of DeviceNode) */
224 IopEnumerateDevice(DeviceNode->PhysicalDeviceObject);
225 IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
226 }
227 }
228
229 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, &InstanceHandle);
230 if (!NT_SUCCESS(Status))
231 return Status;
232
233 RtlInitUnicodeString(&KeyName, L"Control");
234 InitializeObjectAttributes(&ObjectAttributes,
235 &KeyName,
236 OBJ_CASE_INSENSITIVE,
237 InstanceHandle,
238 NULL);
239 Status = ZwCreateKey(&ControlHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
240 if (!NT_SUCCESS(Status))
241 {
242 ZwClose(InstanceHandle);
243 return Status;
244 }
245
246 RtlInitUnicodeString(&KeyName, L"ActiveService");
247 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, DeviceNode->ServiceName.Buffer, DeviceNode->ServiceName.Length);
248
249 if (NT_SUCCESS(Status) && DeviceNode->ResourceList)
250 {
251 RtlInitUnicodeString(&KeyName, L"AllocConfig");
252 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_RESOURCE_LIST,
253 DeviceNode->ResourceList, CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceList));
254 }
255
256 if (NT_SUCCESS(Status))
257 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
258
259 ZwClose(ControlHandle);
260 ZwClose(InstanceHandle);
261
262 return Status;
263 }
264
265 NTSTATUS
266 NTAPI
267 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
268 PDEVICE_CAPABILITIES DeviceCaps)
269 {
270 IO_STATUS_BLOCK StatusBlock;
271 IO_STACK_LOCATION Stack;
272
273 /* Set up the Header */
274 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
275 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
276 DeviceCaps->Version = 1;
277 DeviceCaps->Address = -1;
278 DeviceCaps->UINumber = -1;
279
280 /* Set up the Stack */
281 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
282 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
283
284 /* Send the IRP */
285 return IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
286 &StatusBlock,
287 IRP_MN_QUERY_CAPABILITIES,
288 &Stack);
289 }
290
291 static VOID NTAPI
292 IopAsynchronousInvalidateDeviceRelations(
293 IN PDEVICE_OBJECT DeviceObject,
294 IN PVOID InvalidateContext)
295 {
296 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
297
298 IoSynchronousInvalidateDeviceRelations(
299 Data->DeviceObject,
300 Data->Type);
301
302 ObDereferenceObject(Data->DeviceObject);
303 IoFreeWorkItem(Data->WorkItem);
304 ExFreePool(Data);
305 }
306
307 NTSTATUS
308 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
309 {
310 KIRQL OldIrql;
311
312 if (PopSystemPowerDeviceNode)
313 {
314 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
315 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
316 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
317
318 return STATUS_SUCCESS;
319 }
320
321 return STATUS_UNSUCCESSFUL;
322 }
323
324 USHORT
325 NTAPI
326 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
327 {
328 USHORT i = 0, FoundIndex = 0xFFFF;
329 ULONG NewSize;
330 PVOID NewList;
331
332 /* Acquire the lock */
333 ExAcquireFastMutex(&IopBusTypeGuidListLock);
334
335 /* Loop all entries */
336 while (i < IopBusTypeGuidList->GuidCount)
337 {
338 /* Try to find a match */
339 if (RtlCompareMemory(BusTypeGuid,
340 &IopBusTypeGuidList->Guids[i],
341 sizeof(GUID)) == sizeof(GUID))
342 {
343 /* Found it */
344 FoundIndex = i;
345 goto Quickie;
346 }
347 i++;
348 }
349
350 /* Check if we have to grow the list */
351 if (IopBusTypeGuidList->GuidCount)
352 {
353 /* Calculate the new size */
354 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
355 (sizeof(GUID) * IopBusTypeGuidList->GuidCount);
356
357 /* Allocate the new copy */
358 NewList = ExAllocatePool(PagedPool, NewSize);
359
360 if (!NewList) {
361 /* Fail */
362 ExFreePool(IopBusTypeGuidList);
363 goto Quickie;
364 }
365
366 /* Now copy them, decrease the size too */
367 NewSize -= sizeof(GUID);
368 RtlCopyMemory(NewList, IopBusTypeGuidList, NewSize);
369
370 /* Free the old list */
371 ExFreePool(IopBusTypeGuidList);
372
373 /* Use the new buffer */
374 IopBusTypeGuidList = NewList;
375 }
376
377 /* Copy the new GUID */
378 RtlCopyMemory(&IopBusTypeGuidList->Guids[IopBusTypeGuidList->GuidCount],
379 BusTypeGuid,
380 sizeof(GUID));
381
382 /* The new entry is the index */
383 FoundIndex = (USHORT)IopBusTypeGuidList->GuidCount;
384 IopBusTypeGuidList->GuidCount++;
385
386 Quickie:
387 ExReleaseFastMutex(&IopBusTypeGuidListLock);
388 return FoundIndex;
389 }
390
391 /*
392 * DESCRIPTION
393 * Creates a device node
394 *
395 * ARGUMENTS
396 * ParentNode = Pointer to parent device node
397 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
398 * to have the root device node create one
399 * (eg. for legacy drivers)
400 * DeviceNode = Pointer to storage for created device node
401 *
402 * RETURN VALUE
403 * Status
404 */
405 NTSTATUS
406 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
407 PDEVICE_OBJECT PhysicalDeviceObject,
408 PUNICODE_STRING ServiceName,
409 PDEVICE_NODE *DeviceNode)
410 {
411 PDEVICE_NODE Node;
412 NTSTATUS Status;
413 KIRQL OldIrql;
414 UNICODE_STRING FullServiceName;
415 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
416 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
417 UNICODE_STRING KeyName, ClassName, ClassGUID;
418 PUNICODE_STRING ServiceName1;
419 ULONG LegacyValue;
420 HANDLE InstanceHandle;
421
422 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
423 ParentNode, PhysicalDeviceObject, ServiceName);
424
425 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
426 if (!Node)
427 {
428 return STATUS_INSUFFICIENT_RESOURCES;
429 }
430
431 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
432
433 if (!ServiceName)
434 ServiceName1 = &UnknownDeviceName;
435 else
436 ServiceName1 = ServiceName;
437
438 if (!PhysicalDeviceObject)
439 {
440 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length;
441 FullServiceName.Length = 0;
442 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
443 if (!FullServiceName.Buffer)
444 {
445 ExFreePool(Node);
446 return STATUS_INSUFFICIENT_RESOURCES;
447 }
448
449 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
450 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
451
452 Status = PnpRootCreateDevice(&FullServiceName, &PhysicalDeviceObject, &Node->InstancePath);
453 if (!NT_SUCCESS(Status))
454 {
455 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
456 ExFreePool(Node);
457 return Status;
458 }
459
460 /* Create the device key for legacy drivers */
461 Status = IopCreateDeviceKeyPath(&Node->InstancePath, &InstanceHandle);
462 if (!NT_SUCCESS(Status))
463 {
464 ZwClose(InstanceHandle);
465 ExFreePool(Node);
466 ExFreePool(FullServiceName.Buffer);
467 return Status;
468 }
469
470 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, ServiceName1->Length);
471 if (!Node->ServiceName.Buffer)
472 {
473 ZwClose(InstanceHandle);
474 ExFreePool(Node);
475 ExFreePool(FullServiceName.Buffer);
476 return Status;
477 }
478
479 Node->ServiceName.MaximumLength = ServiceName1->Length;
480 Node->ServiceName.Length = 0;
481
482 RtlAppendUnicodeStringToString(&Node->ServiceName, ServiceName1);
483
484 if (ServiceName)
485 {
486 RtlInitUnicodeString(&KeyName, L"Service");
487 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length);
488 }
489
490 if (NT_SUCCESS(Status))
491 {
492 RtlInitUnicodeString(&KeyName, L"Legacy");
493
494 LegacyValue = 1;
495 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
496 if (NT_SUCCESS(Status))
497 {
498 RtlInitUnicodeString(&KeyName, L"Class");
499
500 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
501 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length);
502 if (NT_SUCCESS(Status))
503 {
504 RtlInitUnicodeString(&KeyName, L"ClassGUID");
505
506 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
507 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length);
508 }
509 }
510 }
511
512 ZwClose(InstanceHandle);
513 ExFreePool(FullServiceName.Buffer);
514
515 if (!NT_SUCCESS(Status))
516 {
517 ExFreePool(Node);
518 return Status;
519 }
520
521 /* This is for drivers passed on the command line to ntoskrnl.exe */
522 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
523 }
524
525 Node->PhysicalDeviceObject = PhysicalDeviceObject;
526
527 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
528
529 if (ParentNode)
530 {
531 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
532 Node->Parent = ParentNode;
533 Node->Sibling = ParentNode->Child;
534 ParentNode->Child = Node;
535 if (ParentNode->LastChild == NULL)
536 ParentNode->LastChild = Node;
537 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
538 Node->Level = ParentNode->Level + 1;
539 }
540
541 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
542
543 *DeviceNode = Node;
544
545 return STATUS_SUCCESS;
546 }
547
548 NTSTATUS
549 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
550 {
551 KIRQL OldIrql;
552 PDEVICE_NODE PrevSibling = NULL;
553
554 /* All children must be deleted before a parent is deleted */
555 ASSERT(!DeviceNode->Child);
556
557 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
558
559 ASSERT(DeviceNode->PhysicalDeviceObject);
560
561 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
562
563 /* Get previous sibling */
564 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
565 {
566 PrevSibling = DeviceNode->Parent->Child;
567 while (PrevSibling->Sibling != DeviceNode)
568 PrevSibling = PrevSibling->Sibling;
569 }
570
571 /* Unlink from parent if it exists */
572 if (DeviceNode->Parent)
573 {
574 if (DeviceNode->Parent->LastChild == DeviceNode)
575 {
576 DeviceNode->Parent->LastChild = PrevSibling;
577 if (PrevSibling)
578 PrevSibling->Sibling = NULL;
579 }
580 if (DeviceNode->Parent->Child == DeviceNode)
581 DeviceNode->Parent->Child = DeviceNode->Sibling;
582 }
583
584 /* Unlink from sibling list */
585 if (PrevSibling)
586 PrevSibling->Sibling = DeviceNode->Sibling;
587
588 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
589
590 RtlFreeUnicodeString(&DeviceNode->InstancePath);
591
592 RtlFreeUnicodeString(&DeviceNode->ServiceName);
593
594 if (DeviceNode->ResourceList)
595 {
596 ExFreePool(DeviceNode->ResourceList);
597 }
598
599 if (DeviceNode->ResourceListTranslated)
600 {
601 ExFreePool(DeviceNode->ResourceListTranslated);
602 }
603
604 if (DeviceNode->ResourceRequirements)
605 {
606 ExFreePool(DeviceNode->ResourceRequirements);
607 }
608
609 if (DeviceNode->BootResources)
610 {
611 ExFreePool(DeviceNode->BootResources);
612 }
613
614 ExFreePool(DeviceNode);
615
616 return STATUS_SUCCESS;
617 }
618
619 NTSTATUS
620 IopInitiatePnpIrp(PDEVICE_OBJECT DeviceObject,
621 PIO_STATUS_BLOCK IoStatusBlock,
622 ULONG MinorFunction,
623 PIO_STACK_LOCATION Stack OPTIONAL)
624 {
625 PDEVICE_OBJECT TopDeviceObject;
626 PIO_STACK_LOCATION IrpSp;
627 NTSTATUS Status;
628 KEVENT Event;
629 PIRP Irp;
630
631 /* Always call the top of the device stack */
632 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
633
634 KeInitializeEvent(
635 &Event,
636 NotificationEvent,
637 FALSE);
638
639 Irp = IoBuildSynchronousFsdRequest(
640 IRP_MJ_PNP,
641 TopDeviceObject,
642 NULL,
643 0,
644 NULL,
645 &Event,
646 IoStatusBlock);
647
648 /* PNP IRPs are initialized with a status code of STATUS_NOT_SUPPORTED */
649 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
650 Irp->IoStatus.Information = 0;
651
652 if (MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
653 {
654 Irp->IoStatus.Information = (ULONG_PTR)Stack->Parameters.FilterResourceRequirements.IoResourceRequirementList;
655 }
656
657 IrpSp = IoGetNextIrpStackLocation(Irp);
658 IrpSp->MinorFunction = (UCHAR)MinorFunction;
659
660 if (Stack)
661 {
662 RtlCopyMemory(&IrpSp->Parameters,
663 &Stack->Parameters,
664 sizeof(Stack->Parameters));
665 }
666
667 Status = IoCallDriver(TopDeviceObject, Irp);
668 if (Status == STATUS_PENDING)
669 {
670 KeWaitForSingleObject(&Event,
671 Executive,
672 KernelMode,
673 FALSE,
674 NULL);
675 Status = IoStatusBlock->Status;
676 }
677
678 ObDereferenceObject(TopDeviceObject);
679
680 return Status;
681 }
682
683
684 NTSTATUS
685 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
686 {
687 PDEVICE_NODE ParentDeviceNode;
688 PDEVICE_NODE ChildDeviceNode;
689 NTSTATUS Status;
690
691 /* Copy context data so we don't overwrite it in subsequent calls to this function */
692 ParentDeviceNode = Context->DeviceNode;
693
694 /* Call the action routine */
695 Status = (Context->Action)(ParentDeviceNode, Context->Context);
696 if (!NT_SUCCESS(Status))
697 {
698 return Status;
699 }
700
701 /* Traversal of all children nodes */
702 for (ChildDeviceNode = ParentDeviceNode->Child;
703 ChildDeviceNode != NULL;
704 ChildDeviceNode = ChildDeviceNode->Sibling)
705 {
706 /* Pass the current device node to the action routine */
707 Context->DeviceNode = ChildDeviceNode;
708
709 Status = IopTraverseDeviceTreeNode(Context);
710 if (!NT_SUCCESS(Status))
711 {
712 return Status;
713 }
714 }
715
716 return Status;
717 }
718
719
720 NTSTATUS
721 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
722 {
723 NTSTATUS Status;
724
725 DPRINT("Context 0x%p\n", Context);
726
727 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
728 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
729
730 /* Start from the specified device node */
731 Context->DeviceNode = Context->FirstDeviceNode;
732
733 /* Recursively traverse the device tree */
734 Status = IopTraverseDeviceTreeNode(Context);
735 if (Status == STATUS_UNSUCCESSFUL)
736 {
737 /* The action routine just wanted to terminate the traversal with status
738 code STATUS_SUCCESS */
739 Status = STATUS_SUCCESS;
740 }
741
742 return Status;
743 }
744
745
746 /*
747 * IopCreateDeviceKeyPath
748 *
749 * Creates a registry key
750 *
751 * Parameters
752 * RegistryPath
753 * Name of the key to be created.
754 * Handle
755 * Handle to the newly created key
756 *
757 * Remarks
758 * This method can create nested trees, so parent of RegistryPath can
759 * be not existant, and will be created if needed.
760 */
761 NTSTATUS
762 NTAPI
763 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
764 OUT PHANDLE Handle)
765 {
766 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
767 HANDLE hParent = NULL, hKey;
768 OBJECT_ATTRIBUTES ObjectAttributes;
769 UNICODE_STRING KeyName;
770 LPCWSTR Current, Last;
771 ULONG dwLength;
772 NTSTATUS Status;
773
774 /* Assume failure */
775 *Handle = NULL;
776
777 /* Open root key for device instances */
778 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
779 if (!NT_SUCCESS(Status))
780 {
781 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
782 return Status;
783 }
784
785 Current = KeyName.Buffer = RegistryPath->Buffer;
786 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
787
788 /* Go up to the end of the string */
789 while (Current <= Last)
790 {
791 if (Current != Last && *Current != '\\')
792 {
793 /* Not the end of the string and not a separator */
794 Current++;
795 continue;
796 }
797
798 /* Prepare relative key name */
799 dwLength = (ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer;
800 KeyName.MaximumLength = KeyName.Length = dwLength;
801 DPRINT("Create '%wZ'\n", &KeyName);
802
803 /* Open key */
804 InitializeObjectAttributes(&ObjectAttributes,
805 &KeyName,
806 OBJ_CASE_INSENSITIVE,
807 hParent,
808 NULL);
809 Status = ZwCreateKey(&hKey,
810 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
811 &ObjectAttributes,
812 0,
813 NULL,
814 0,
815 NULL);
816
817 /* Close parent key handle, we don't need it anymore */
818 if (hParent)
819 ZwClose(hParent);
820
821 /* Key opening/creating failed? */
822 if (!NT_SUCCESS(Status))
823 {
824 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
825 return Status;
826 }
827
828 /* Check if it is the end of the string */
829 if (Current == Last)
830 {
831 /* Yes, return success */
832 *Handle = hKey;
833 return STATUS_SUCCESS;
834 }
835
836 /* Start with this new parent key */
837 hParent = hKey;
838 Current++;
839 KeyName.Buffer = (LPWSTR)Current;
840 }
841
842 return STATUS_UNSUCCESSFUL;
843 }
844
845 NTSTATUS
846 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode, PWCHAR Level1Key, PWCHAR Level2Key)
847 {
848 NTSTATUS Status;
849 ULONG Disposition;
850 HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey;
851 UNICODE_STRING KeyName;
852 OBJECT_ATTRIBUTES ObjectAttributes;
853
854 RtlInitUnicodeString(&KeyName,
855 L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
856 InitializeObjectAttributes(&ObjectAttributes,
857 &KeyName,
858 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
859 0,
860 NULL);
861 Status = ZwCreateKey(&ResourceMapKey,
862 KEY_ALL_ACCESS,
863 &ObjectAttributes,
864 0,
865 NULL,
866 REG_OPTION_VOLATILE,
867 &Disposition);
868 if (!NT_SUCCESS(Status))
869 return Status;
870
871 RtlInitUnicodeString(&KeyName, Level1Key);
872 InitializeObjectAttributes(&ObjectAttributes,
873 &KeyName,
874 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
875 ResourceMapKey,
876 NULL);
877 Status = ZwCreateKey(&PnpMgrLevel1,
878 KEY_ALL_ACCESS,
879 &ObjectAttributes,
880 0,
881 NULL,
882 REG_OPTION_VOLATILE,
883 &Disposition);
884 ZwClose(ResourceMapKey);
885 if (!NT_SUCCESS(Status))
886 return Status;
887
888 RtlInitUnicodeString(&KeyName, Level2Key);
889 InitializeObjectAttributes(&ObjectAttributes,
890 &KeyName,
891 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
892 PnpMgrLevel1,
893 NULL);
894 Status = ZwCreateKey(&PnpMgrLevel2,
895 KEY_ALL_ACCESS,
896 &ObjectAttributes,
897 0,
898 NULL,
899 REG_OPTION_VOLATILE,
900 &Disposition);
901 ZwClose(PnpMgrLevel1);
902 if (!NT_SUCCESS(Status))
903 return Status;
904
905 if (DeviceNode->ResourceList)
906 {
907 WCHAR NameBuff[256];
908 UNICODE_STRING NameU;
909 UNICODE_STRING Suffix;
910 ULONG OldLength;
911
912 ASSERT(DeviceNode->ResourceListTranslated);
913
914 NameU.Buffer = NameBuff;
915 NameU.Length = 0;
916 NameU.MaximumLength = 256 * sizeof(WCHAR);
917
918 Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
919 DevicePropertyPhysicalDeviceObjectName,
920 NameU.MaximumLength,
921 NameU.Buffer,
922 &OldLength);
923 ASSERT(Status == STATUS_SUCCESS);
924
925 NameU.Length = (USHORT)OldLength;
926
927 RtlInitUnicodeString(&Suffix, L".Raw");
928 RtlAppendUnicodeStringToString(&NameU, &Suffix);
929
930 Status = ZwSetValueKey(PnpMgrLevel2,
931 &NameU,
932 0,
933 REG_RESOURCE_LIST,
934 DeviceNode->ResourceList,
935 CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceList));
936 if (!NT_SUCCESS(Status))
937 {
938 ZwClose(PnpMgrLevel2);
939 return Status;
940 }
941
942 /* "Remove" the suffix by setting the length back to what it used to be */
943 NameU.Length = (USHORT)OldLength;
944
945 RtlInitUnicodeString(&Suffix, L".Translated");
946 RtlAppendUnicodeStringToString(&NameU, &Suffix);
947
948 Status = ZwSetValueKey(PnpMgrLevel2,
949 &NameU,
950 0,
951 REG_RESOURCE_LIST,
952 DeviceNode->ResourceListTranslated,
953 CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceListTranslated));
954 ZwClose(PnpMgrLevel2);
955 if (!NT_SUCCESS(Status))
956 return Status;
957 }
958 else
959 {
960 ZwClose(PnpMgrLevel2);
961 }
962
963 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
964
965 return STATUS_SUCCESS;
966 }
967
968 NTSTATUS
969 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode)
970 {
971 return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager");
972 }
973
974 NTSTATUS
975 IopSetDeviceInstanceData(HANDLE InstanceKey,
976 PDEVICE_NODE DeviceNode)
977 {
978 OBJECT_ATTRIBUTES ObjectAttributes;
979 UNICODE_STRING KeyName;
980 HANDLE LogConfKey;
981 ULONG ResCount;
982 ULONG ListSize, ResultLength;
983 NTSTATUS Status;
984 HANDLE ControlHandle;
985
986 DPRINT("IopSetDeviceInstanceData() called\n");
987
988 /* Create the 'LogConf' key */
989 RtlInitUnicodeString(&KeyName, L"LogConf");
990 InitializeObjectAttributes(&ObjectAttributes,
991 &KeyName,
992 OBJ_CASE_INSENSITIVE,
993 InstanceKey,
994 NULL);
995 Status = ZwCreateKey(&LogConfKey,
996 KEY_ALL_ACCESS,
997 &ObjectAttributes,
998 0,
999 NULL,
1000 0,
1001 NULL);
1002 if (NT_SUCCESS(Status))
1003 {
1004 /* Set 'BootConfig' value */
1005 if (DeviceNode->BootResources != NULL)
1006 {
1007 ResCount = DeviceNode->BootResources->Count;
1008 if (ResCount != 0)
1009 {
1010 ListSize = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
1011
1012 RtlInitUnicodeString(&KeyName, L"BootConfig");
1013 Status = ZwSetValueKey(LogConfKey,
1014 &KeyName,
1015 0,
1016 REG_RESOURCE_LIST,
1017 DeviceNode->BootResources,
1018 ListSize);
1019 }
1020 }
1021
1022 /* Set 'BasicConfigVector' value */
1023 if (DeviceNode->ResourceRequirements != NULL &&
1024 DeviceNode->ResourceRequirements->ListSize != 0)
1025 {
1026 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1027 Status = ZwSetValueKey(LogConfKey,
1028 &KeyName,
1029 0,
1030 REG_RESOURCE_REQUIREMENTS_LIST,
1031 DeviceNode->ResourceRequirements,
1032 DeviceNode->ResourceRequirements->ListSize);
1033 }
1034
1035 ZwClose(LogConfKey);
1036 }
1037
1038 /* Set the 'ConfigFlags' value */
1039 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1040 Status = ZwQueryValueKey(InstanceKey,
1041 &KeyName,
1042 KeyValueBasicInformation,
1043 NULL,
1044 0,
1045 &ResultLength);
1046 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1047 {
1048 /* Write the default value */
1049 ULONG DefaultConfigFlags = 0;
1050 Status = ZwSetValueKey(InstanceKey,
1051 &KeyName,
1052 0,
1053 REG_DWORD,
1054 &DefaultConfigFlags,
1055 sizeof(DefaultConfigFlags));
1056 }
1057
1058 /* Create the 'Control' key */
1059 RtlInitUnicodeString(&KeyName, L"Control");
1060 InitializeObjectAttributes(&ObjectAttributes,
1061 &KeyName,
1062 OBJ_CASE_INSENSITIVE,
1063 InstanceKey,
1064 NULL);
1065 Status = ZwCreateKey(&ControlHandle, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
1066
1067 if (NT_SUCCESS(Status))
1068 ZwClose(ControlHandle);
1069
1070 DPRINT("IopSetDeviceInstanceData() done\n");
1071
1072 return Status;
1073 }
1074
1075 BOOLEAN
1076 IopCheckResourceDescriptor(
1077 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc,
1078 IN PCM_RESOURCE_LIST ResourceList,
1079 IN BOOLEAN Silent,
1080 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1081 {
1082 ULONG i, ii;
1083 BOOLEAN Result = FALSE;
1084
1085 if (ResDesc->ShareDisposition == CmResourceShareShared)
1086 return FALSE;
1087
1088 for (i = 0; i < ResourceList->Count; i++)
1089 {
1090 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList->List[i].PartialResourceList;
1091 for (ii = 0; ii < ResList->Count; ii++)
1092 {
1093 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList->PartialDescriptors[ii];
1094
1095 /* We don't care about shared resources */
1096 if (ResDesc->ShareDisposition == CmResourceShareShared &&
1097 ResDesc2->ShareDisposition == CmResourceShareShared)
1098 continue;
1099
1100 /* Make sure we're comparing the same types */
1101 if (ResDesc->Type != ResDesc2->Type)
1102 continue;
1103
1104 switch (ResDesc->Type)
1105 {
1106 case CmResourceTypeMemory:
1107 if ((ResDesc->u.Memory.Start.QuadPart < ResDesc2->u.Memory.Start.QuadPart &&
1108 ResDesc->u.Memory.Start.QuadPart + ResDesc->u.Memory.Length >
1109 ResDesc2->u.Memory.Start.QuadPart) || (ResDesc2->u.Memory.Start.QuadPart <
1110 ResDesc->u.Memory.Start.QuadPart && ResDesc2->u.Memory.Start.QuadPart +
1111 ResDesc2->u.Memory.Length > ResDesc->u.Memory.Start.QuadPart))
1112 {
1113 if (!Silent)
1114 {
1115 DPRINT1("Resource conflict: Memory (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1116 ResDesc->u.Memory.Start.QuadPart, ResDesc->u.Memory.Start.QuadPart +
1117 ResDesc->u.Memory.Length, ResDesc2->u.Memory.Start.QuadPart,
1118 ResDesc2->u.Memory.Start.QuadPart + ResDesc2->u.Memory.Length);
1119 }
1120
1121 Result = TRUE;
1122
1123 goto ByeBye;
1124 }
1125 break;
1126
1127 case CmResourceTypePort:
1128 if ((ResDesc->u.Port.Start.QuadPart < ResDesc2->u.Port.Start.QuadPart &&
1129 ResDesc->u.Port.Start.QuadPart + ResDesc->u.Port.Length >
1130 ResDesc2->u.Port.Start.QuadPart) || (ResDesc2->u.Port.Start.QuadPart <
1131 ResDesc->u.Port.Start.QuadPart && ResDesc2->u.Port.Start.QuadPart +
1132 ResDesc2->u.Port.Length > ResDesc->u.Port.Start.QuadPart))
1133 {
1134 if (!Silent)
1135 {
1136 DPRINT1("Resource conflict: Port (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1137 ResDesc->u.Port.Start.QuadPart, ResDesc->u.Port.Start.QuadPart +
1138 ResDesc->u.Port.Length, ResDesc2->u.Port.Start.QuadPart,
1139 ResDesc2->u.Port.Start.QuadPart + ResDesc2->u.Port.Length);
1140 }
1141
1142 Result = TRUE;
1143
1144 goto ByeBye;
1145 }
1146 break;
1147
1148 case CmResourceTypeInterrupt:
1149 if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector)
1150 {
1151 if (!Silent)
1152 {
1153 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
1154 ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level,
1155 ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level);
1156 }
1157
1158 Result = TRUE;
1159
1160 goto ByeBye;
1161 }
1162 break;
1163
1164 case CmResourceTypeBusNumber:
1165 if ((ResDesc->u.BusNumber.Start < ResDesc2->u.BusNumber.Start &&
1166 ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length >
1167 ResDesc2->u.BusNumber.Start) || (ResDesc2->u.BusNumber.Start <
1168 ResDesc->u.BusNumber.Start && ResDesc2->u.BusNumber.Start +
1169 ResDesc2->u.BusNumber.Length > ResDesc->u.BusNumber.Start))
1170 {
1171 if (!Silent)
1172 {
1173 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1174 ResDesc->u.BusNumber.Start, ResDesc->u.BusNumber.Start +
1175 ResDesc->u.BusNumber.Length, ResDesc2->u.BusNumber.Start,
1176 ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length);
1177 }
1178
1179 Result = TRUE;
1180
1181 goto ByeBye;
1182 }
1183 break;
1184
1185 case CmResourceTypeDma:
1186 if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel)
1187 {
1188 if (!Silent)
1189 {
1190 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
1191 ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port,
1192 ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port);
1193 }
1194
1195 Result = TRUE;
1196
1197 goto ByeBye;
1198 }
1199 break;
1200 }
1201 }
1202 }
1203
1204 ByeBye:
1205
1206 if (Result && ConflictingDescriptor)
1207 {
1208 RtlCopyMemory(ConflictingDescriptor,
1209 ResDesc,
1210 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1211 }
1212
1213 return Result;
1214 }
1215
1216
1217 BOOLEAN
1218 IopCheckForResourceConflict(
1219 IN PCM_RESOURCE_LIST ResourceList1,
1220 IN PCM_RESOURCE_LIST ResourceList2,
1221 IN BOOLEAN Silent,
1222 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1223 {
1224 ULONG i, ii;
1225 BOOLEAN Result = FALSE;
1226
1227 for (i = 0; i < ResourceList1->Count; i++)
1228 {
1229 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList1->List[i].PartialResourceList;
1230 for (ii = 0; ii < ResList->Count; ii++)
1231 {
1232 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
1233
1234 Result = IopCheckResourceDescriptor(ResDesc,
1235 ResourceList2,
1236 Silent,
1237 ConflictingDescriptor);
1238 if (Result) goto ByeBye;
1239 }
1240 }
1241
1242
1243 ByeBye:
1244
1245 return Result;
1246 }
1247
1248 NTSTATUS
1249 IopDetectResourceConflict(
1250 IN PCM_RESOURCE_LIST ResourceList,
1251 IN BOOLEAN Silent,
1252 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1253 {
1254 OBJECT_ATTRIBUTES ObjectAttributes;
1255 UNICODE_STRING KeyName;
1256 HANDLE ResourceMapKey = INVALID_HANDLE_VALUE, ChildKey2 = INVALID_HANDLE_VALUE, ChildKey3 = INVALID_HANDLE_VALUE;
1257 ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
1258 PKEY_BASIC_INFORMATION KeyInformation;
1259 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
1260 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
1261 ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0;
1262 NTSTATUS Status;
1263
1264 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1265 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL);
1266 Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1267 if (!NT_SUCCESS(Status))
1268 {
1269 /* The key is missing which means we are the first device */
1270 return STATUS_SUCCESS;
1271 }
1272
1273 while (TRUE)
1274 {
1275 Status = ZwEnumerateKey(ResourceMapKey,
1276 ChildKeyIndex1,
1277 KeyBasicInformation,
1278 NULL,
1279 0,
1280 &RequiredLength);
1281 if (Status == STATUS_NO_MORE_ENTRIES)
1282 break;
1283 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1284 {
1285 KeyInformationLength = RequiredLength;
1286 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1287 if (!KeyInformation)
1288 {
1289 Status = STATUS_INSUFFICIENT_RESOURCES;
1290 goto cleanup;
1291 }
1292
1293 Status = ZwEnumerateKey(ResourceMapKey,
1294 ChildKeyIndex1,
1295 KeyBasicInformation,
1296 KeyInformation,
1297 KeyInformationLength,
1298 &RequiredLength);
1299 }
1300 else
1301 goto cleanup;
1302 ChildKeyIndex1++;
1303 if (!NT_SUCCESS(Status))
1304 goto cleanup;
1305
1306 KeyName.Buffer = KeyInformation->Name;
1307 KeyName.MaximumLength = KeyName.Length = KeyInformation->NameLength;
1308 InitializeObjectAttributes(&ObjectAttributes,
1309 &KeyName,
1310 OBJ_CASE_INSENSITIVE,
1311 ResourceMapKey,
1312 NULL);
1313 Status = ZwOpenKey(&ChildKey2, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1314 ExFreePool(KeyInformation);
1315 if (!NT_SUCCESS(Status))
1316 goto cleanup;
1317
1318 while (TRUE)
1319 {
1320 Status = ZwEnumerateKey(ChildKey2,
1321 ChildKeyIndex2,
1322 KeyBasicInformation,
1323 NULL,
1324 0,
1325 &RequiredLength);
1326 if (Status == STATUS_NO_MORE_ENTRIES)
1327 break;
1328 else if (Status == STATUS_BUFFER_TOO_SMALL)
1329 {
1330 KeyInformationLength = RequiredLength;
1331 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1332 if (!KeyInformation)
1333 {
1334 Status = STATUS_INSUFFICIENT_RESOURCES;
1335 goto cleanup;
1336 }
1337
1338 Status = ZwEnumerateKey(ChildKey2,
1339 ChildKeyIndex2,
1340 KeyBasicInformation,
1341 KeyInformation,
1342 KeyInformationLength,
1343 &RequiredLength);
1344 }
1345 else
1346 goto cleanup;
1347 ChildKeyIndex2++;
1348 if (!NT_SUCCESS(Status))
1349 goto cleanup;
1350
1351 KeyName.Buffer = KeyInformation->Name;
1352 KeyName.MaximumLength = KeyName.Length = KeyInformation->NameLength;
1353 InitializeObjectAttributes(&ObjectAttributes,
1354 &KeyName,
1355 OBJ_CASE_INSENSITIVE,
1356 ChildKey2,
1357 NULL);
1358 Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
1359 ExFreePool(KeyInformation);
1360 if (!NT_SUCCESS(Status))
1361 goto cleanup;
1362
1363 while (TRUE)
1364 {
1365 Status = ZwEnumerateValueKey(ChildKey3,
1366 ChildKeyIndex3,
1367 KeyValuePartialInformation,
1368 NULL,
1369 0,
1370 &RequiredLength);
1371 if (Status == STATUS_NO_MORE_ENTRIES)
1372 break;
1373 else if (Status == STATUS_BUFFER_TOO_SMALL)
1374 {
1375 KeyValueInformationLength = RequiredLength;
1376 KeyValueInformation = ExAllocatePool(PagedPool, KeyValueInformationLength);
1377 if (!KeyValueInformation)
1378 {
1379 Status = STATUS_INSUFFICIENT_RESOURCES;
1380 goto cleanup;
1381 }
1382
1383 Status = ZwEnumerateValueKey(ChildKey3,
1384 ChildKeyIndex3,
1385 KeyValuePartialInformation,
1386 KeyValueInformation,
1387 KeyValueInformationLength,
1388 &RequiredLength);
1389 }
1390 else
1391 goto cleanup;
1392 if (!NT_SUCCESS(Status))
1393 goto cleanup;
1394
1395 Status = ZwEnumerateValueKey(ChildKey3,
1396 ChildKeyIndex3,
1397 KeyValueBasicInformation,
1398 NULL,
1399 0,
1400 &RequiredLength);
1401 if (Status == STATUS_BUFFER_TOO_SMALL)
1402 {
1403 KeyNameInformationLength = RequiredLength;
1404 KeyNameInformation = ExAllocatePool(PagedPool, KeyNameInformationLength + sizeof(WCHAR));
1405 if (!KeyNameInformation)
1406 {
1407 Status = STATUS_INSUFFICIENT_RESOURCES;
1408 goto cleanup;
1409 }
1410
1411 Status = ZwEnumerateValueKey(ChildKey3,
1412 ChildKeyIndex3,
1413 KeyValueBasicInformation,
1414 KeyNameInformation,
1415 KeyNameInformationLength,
1416 &RequiredLength);
1417 }
1418 else
1419 goto cleanup;
1420
1421 ChildKeyIndex3++;
1422
1423 if (!NT_SUCCESS(Status))
1424 goto cleanup;
1425
1426 KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
1427
1428 /* Skip translated entries */
1429 if (wcsstr(KeyNameInformation->Name, L".Translated"))
1430 {
1431 ExFreePool(KeyNameInformation);
1432 continue;
1433 }
1434
1435 ExFreePool(KeyNameInformation);
1436
1437 if (IopCheckForResourceConflict(ResourceList,
1438 (PCM_RESOURCE_LIST)KeyValueInformation->Data,
1439 Silent,
1440 ConflictingDescriptor))
1441 {
1442 ExFreePool(KeyValueInformation);
1443 Status = STATUS_CONFLICTING_ADDRESSES;
1444 goto cleanup;
1445 }
1446
1447 ExFreePool(KeyValueInformation);
1448 }
1449 }
1450 }
1451
1452 cleanup:
1453 if (ResourceMapKey != INVALID_HANDLE_VALUE)
1454 ZwClose(ResourceMapKey);
1455 if (ChildKey2 != INVALID_HANDLE_VALUE)
1456 ZwClose(ChildKey2);
1457 if (ChildKey3 != INVALID_HANDLE_VALUE)
1458 ZwClose(ChildKey3);
1459
1460 if (Status == STATUS_NO_MORE_ENTRIES)
1461 Status = STATUS_SUCCESS;
1462
1463 return Status;
1464 }
1465
1466 BOOLEAN
1467 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1468 {
1469 CM_RESOURCE_LIST CmList;
1470 NTSTATUS Status;
1471
1472 CmList.Count = 1;
1473 CmList.List[0].InterfaceType = InterfaceTypeUndefined;
1474 CmList.List[0].BusNumber = 0;
1475 CmList.List[0].PartialResourceList.Version = 1;
1476 CmList.List[0].PartialResourceList.Revision = 1;
1477 CmList.List[0].PartialResourceList.Count = 1;
1478 CmList.List[0].PartialResourceList.PartialDescriptors[0] = *CmDesc;
1479
1480 Status = IopDetectResourceConflict(&CmList, TRUE, ConflictingDescriptor);
1481 if (Status == STATUS_CONFLICTING_ADDRESSES)
1482 return TRUE;
1483
1484 return FALSE;
1485 }
1486
1487 BOOLEAN
1488 IopFindBusNumberResource(
1489 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1490 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1491 {
1492 ULONG Start;
1493 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1494
1495 ASSERT(IoDesc->Type == CmDesc->Type);
1496 ASSERT(IoDesc->Type == CmResourceTypeBusNumber);
1497
1498 for (Start = IoDesc->u.BusNumber.MinBusNumber;
1499 Start < IoDesc->u.BusNumber.MaxBusNumber;
1500 Start++)
1501 {
1502 CmDesc->u.BusNumber.Length = IoDesc->u.BusNumber.Length;
1503 CmDesc->u.BusNumber.Start = Start;
1504
1505 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1506 {
1507 Start += ConflictingDesc.u.BusNumber.Start + ConflictingDesc.u.BusNumber.Length;
1508 }
1509 else
1510 {
1511 return TRUE;
1512 }
1513 }
1514
1515 return FALSE;
1516 }
1517
1518 BOOLEAN
1519 IopFindMemoryResource(
1520 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1521 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1522 {
1523 ULONGLONG Start;
1524 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1525
1526 ASSERT(IoDesc->Type == CmDesc->Type);
1527 ASSERT(IoDesc->Type == CmResourceTypeMemory);
1528
1529 for (Start = IoDesc->u.Memory.MinimumAddress.QuadPart;
1530 Start < IoDesc->u.Memory.MaximumAddress.QuadPart;
1531 Start++)
1532 {
1533 CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
1534 CmDesc->u.Memory.Start.QuadPart = Start;
1535
1536 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1537 {
1538 Start += ConflictingDesc.u.Memory.Start.QuadPart + ConflictingDesc.u.Memory.Length;
1539 }
1540 else
1541 {
1542 return TRUE;
1543 }
1544 }
1545
1546 return FALSE;
1547 }
1548
1549 BOOLEAN
1550 IopFindPortResource(
1551 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1552 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1553 {
1554 ULONGLONG Start;
1555 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1556
1557 ASSERT(IoDesc->Type == CmDesc->Type);
1558 ASSERT(IoDesc->Type == CmResourceTypePort);
1559
1560 for (Start = IoDesc->u.Port.MinimumAddress.QuadPart;
1561 Start < IoDesc->u.Port.MaximumAddress.QuadPart;
1562 Start++)
1563 {
1564 CmDesc->u.Port.Length = IoDesc->u.Port.Length;
1565 CmDesc->u.Port.Start.QuadPart = Start;
1566
1567 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1568 {
1569 Start += ConflictingDesc.u.Port.Start.QuadPart + ConflictingDesc.u.Port.Length;
1570 }
1571 else
1572 {
1573 return TRUE;
1574 }
1575 }
1576
1577 return FALSE;
1578 }
1579
1580 BOOLEAN
1581 IopFindDmaResource(
1582 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1583 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1584 {
1585 ULONG Channel;
1586
1587 ASSERT(IoDesc->Type == CmDesc->Type);
1588 ASSERT(IoDesc->Type == CmResourceTypeDma);
1589
1590 for (Channel = IoDesc->u.Dma.MinimumChannel;
1591 Channel < IoDesc->u.Dma.MaximumChannel;
1592 Channel++)
1593 {
1594 CmDesc->u.Dma.Channel = Channel;
1595 CmDesc->u.Dma.Port = 0;
1596
1597 if (!IopCheckDescriptorForConflict(CmDesc, NULL))
1598 return TRUE;
1599 }
1600
1601 return FALSE;
1602 }
1603
1604 BOOLEAN
1605 IopFindInterruptResource(
1606 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1607 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1608 {
1609 ULONG Vector;
1610
1611 ASSERT(IoDesc->Type == CmDesc->Type);
1612 ASSERT(IoDesc->Type == CmResourceTypeInterrupt);
1613
1614 for (Vector = IoDesc->u.Interrupt.MinimumVector;
1615 Vector < IoDesc->u.Interrupt.MaximumVector;
1616 Vector++)
1617 {
1618 CmDesc->u.Interrupt.Vector = Vector;
1619 CmDesc->u.Interrupt.Level = Vector;
1620 CmDesc->u.Interrupt.Affinity = (KAFFINITY)-1;
1621
1622 if (!IopCheckDescriptorForConflict(CmDesc, NULL))
1623 return TRUE;
1624 }
1625
1626 return FALSE;
1627 }
1628
1629 NTSTATUS
1630 IopCreateResourceListFromRequirements(
1631 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList,
1632 OUT PCM_RESOURCE_LIST *ResourceList)
1633 {
1634 ULONG i, ii, Size;
1635 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc;
1636
1637 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1638 for (i = 0; i < RequirementsList->AlternativeLists; i++)
1639 {
1640 PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
1641 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
1642 + ResList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1643 }
1644
1645 *ResourceList = ExAllocatePool(PagedPool, Size);
1646 if (!*ResourceList)
1647 return STATUS_INSUFFICIENT_RESOURCES;
1648
1649 (*ResourceList)->Count = 1;
1650 (*ResourceList)->List[0].BusNumber = RequirementsList->BusNumber;
1651 (*ResourceList)->List[0].InterfaceType = RequirementsList->InterfaceType;
1652 (*ResourceList)->List[0].PartialResourceList.Version = 1;
1653 (*ResourceList)->List[0].PartialResourceList.Revision = 1;
1654 (*ResourceList)->List[0].PartialResourceList.Count = 0;
1655
1656 ResDesc = &(*ResourceList)->List[0].PartialResourceList.PartialDescriptors[0];
1657
1658 for (i = 0; i < RequirementsList->AlternativeLists; i++)
1659 {
1660 PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
1661 for (ii = 0; ii < ResList->Count; ii++)
1662 {
1663 PIO_RESOURCE_DESCRIPTOR ReqDesc = &ResList->Descriptors[ii];
1664
1665 /* FIXME: Handle alternate ranges */
1666 if (ReqDesc->Option == IO_RESOURCE_ALTERNATIVE)
1667 continue;
1668
1669 ResDesc->Type = ReqDesc->Type;
1670 ResDesc->Flags = ReqDesc->Flags;
1671 ResDesc->ShareDisposition = ReqDesc->ShareDisposition;
1672
1673 switch (ReqDesc->Type)
1674 {
1675 case CmResourceTypeInterrupt:
1676 if (!IopFindInterruptResource(ReqDesc, ResDesc))
1677 {
1678 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
1679 ReqDesc->u.Interrupt.MinimumVector, ReqDesc->u.Interrupt.MaximumVector);
1680
1681 if (ReqDesc->Option == 0)
1682 {
1683 ExFreePool(*ResourceList);
1684 return STATUS_CONFLICTING_ADDRESSES;
1685 }
1686 }
1687 break;
1688
1689 case CmResourceTypePort:
1690 if (!IopFindPortResource(ReqDesc, ResDesc))
1691 {
1692 DPRINT1("Failed to find an available port resource (0x%x to 0x%x length: 0x%x)\n",
1693 ReqDesc->u.Port.MinimumAddress.QuadPart, ReqDesc->u.Port.MaximumAddress.QuadPart,
1694 ReqDesc->u.Port.Length);
1695
1696 if (ReqDesc->Option == 0)
1697 {
1698 ExFreePool(*ResourceList);
1699 return STATUS_CONFLICTING_ADDRESSES;
1700 }
1701 }
1702 break;
1703
1704 case CmResourceTypeMemory:
1705 if (!IopFindMemoryResource(ReqDesc, ResDesc))
1706 {
1707 DPRINT1("Failed to find an available memory resource (0x%x to 0x%x length: 0x%x)\n",
1708 ReqDesc->u.Memory.MinimumAddress.QuadPart, ReqDesc->u.Memory.MaximumAddress.QuadPart,
1709 ReqDesc->u.Memory.Length);
1710
1711 if (ReqDesc->Option == 0)
1712 {
1713 ExFreePool(*ResourceList);
1714 return STATUS_CONFLICTING_ADDRESSES;
1715 }
1716 }
1717 break;
1718
1719 case CmResourceTypeBusNumber:
1720 if (!IopFindBusNumberResource(ReqDesc, ResDesc))
1721 {
1722 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
1723 ReqDesc->u.BusNumber.MinBusNumber, ReqDesc->u.BusNumber.MaxBusNumber,
1724 ReqDesc->u.BusNumber.Length);
1725
1726 if (ReqDesc->Option == 0)
1727 {
1728 ExFreePool(*ResourceList);
1729 return STATUS_CONFLICTING_ADDRESSES;
1730 }
1731 }
1732 break;
1733
1734 case CmResourceTypeDma:
1735 if (!IopFindDmaResource(ReqDesc, ResDesc))
1736 {
1737 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
1738 ReqDesc->u.Dma.MinimumChannel, ReqDesc->u.Dma.MaximumChannel);
1739
1740 if (ReqDesc->Option == 0)
1741 {
1742 ExFreePool(*ResourceList);
1743 return STATUS_CONFLICTING_ADDRESSES;
1744 }
1745 }
1746 break;
1747
1748 default:
1749 DPRINT1("Unsupported resource type: %x\n", ReqDesc->Type);
1750 break;
1751 }
1752
1753 (*ResourceList)->List[0].PartialResourceList.Count++;
1754 ResDesc++;
1755 }
1756 }
1757
1758 return STATUS_SUCCESS;
1759 }
1760
1761 NTSTATUS
1762 IopAssignDeviceResources(
1763 IN PDEVICE_NODE DeviceNode,
1764 OUT ULONG *pRequiredSize)
1765 {
1766 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1767 ULONG Size;
1768 ULONG i;
1769 ULONG j;
1770 NTSTATUS Status;
1771
1772 if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
1773 {
1774 /* No resource needed for this device */
1775 DeviceNode->ResourceList = NULL;
1776 *pRequiredSize = 0;
1777 return STATUS_SUCCESS;
1778 }
1779
1780 /* Fill DeviceNode->ResourceList
1781 * FIXME: the PnP arbiter should go there!
1782 * Actually, use the BootResources if provided, else the resource requirements
1783 */
1784
1785 if (DeviceNode->BootResources)
1786 {
1787 /* Browse the boot resources to know if we have some custom structures */
1788 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1789 for (i = 0; i < DeviceNode->BootResources->Count; i++)
1790 {
1791 pPartialResourceList = &DeviceNode->BootResources->List[i].PartialResourceList;
1792 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
1793 + pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1794 for (j = 0; j < pPartialResourceList->Count; j++)
1795 {
1796 if (pPartialResourceList->PartialDescriptors[j].Type == CmResourceTypeDeviceSpecific)
1797 Size += pPartialResourceList->PartialDescriptors[j].u.DeviceSpecificData.DataSize;
1798 }
1799 }
1800
1801 DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
1802 if (!DeviceNode->ResourceList)
1803 {
1804 Status = STATUS_NO_MEMORY;
1805 goto ByeBye;
1806 }
1807 RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, Size);
1808
1809 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1810 if (NT_SUCCESS(Status) || !DeviceNode->ResourceRequirements)
1811 {
1812 if (!NT_SUCCESS(Status) && !DeviceNode->ResourceRequirements)
1813 {
1814 DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
1815 }
1816
1817 *pRequiredSize = Size;
1818 return STATUS_SUCCESS;
1819 }
1820 else
1821 {
1822 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
1823 ExFreePool(DeviceNode->ResourceList);
1824 }
1825 }
1826
1827 Status = IopCreateResourceListFromRequirements(DeviceNode->ResourceRequirements,
1828 &DeviceNode->ResourceList);
1829 if (!NT_SUCCESS(Status))
1830 goto ByeBye;
1831
1832 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1833 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
1834 {
1835 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
1836 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
1837 + pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1838 }
1839
1840 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1841 if (!NT_SUCCESS(Status))
1842 goto ByeBye;
1843
1844 *pRequiredSize = Size;
1845 return STATUS_SUCCESS;
1846
1847 ByeBye:
1848 if (DeviceNode->ResourceList)
1849 {
1850 ExFreePool(DeviceNode->ResourceList);
1851 DeviceNode->ResourceList = NULL;
1852 }
1853 *pRequiredSize = 0;
1854 return Status;
1855 }
1856
1857
1858 NTSTATUS
1859 IopTranslateDeviceResources(
1860 IN PDEVICE_NODE DeviceNode,
1861 IN ULONG RequiredSize)
1862 {
1863 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1864 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
1865 ULONG i, j;
1866 NTSTATUS Status;
1867
1868 if (!DeviceNode->ResourceList)
1869 {
1870 DeviceNode->ResourceListTranslated = NULL;
1871 return STATUS_SUCCESS;
1872 }
1873
1874 /* That's easy to translate a resource list. Just copy the
1875 * untranslated one and change few fields in the copy
1876 */
1877 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, RequiredSize);
1878 if (!DeviceNode->ResourceListTranslated)
1879 {
1880 Status =STATUS_NO_MEMORY;
1881 goto cleanup;
1882 }
1883 RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, RequiredSize);
1884
1885 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
1886 {
1887 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
1888 for (j = 0; j < pPartialResourceList->Count; j++)
1889 {
1890 DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
1891 DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
1892 switch (DescriptorRaw->Type)
1893 {
1894 case CmResourceTypePort:
1895 {
1896 ULONG AddressSpace = 1; /* IO space */
1897 if (!HalTranslateBusAddress(
1898 DeviceNode->ResourceList->List[i].InterfaceType,
1899 DeviceNode->ResourceList->List[i].BusNumber,
1900 DescriptorRaw->u.Port.Start,
1901 &AddressSpace,
1902 &DescriptorTranslated->u.Port.Start))
1903 {
1904 Status = STATUS_UNSUCCESSFUL;
1905 goto cleanup;
1906 }
1907 break;
1908 }
1909 case CmResourceTypeInterrupt:
1910 {
1911 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
1912 DeviceNode->ResourceList->List[i].InterfaceType,
1913 DeviceNode->ResourceList->List[i].BusNumber,
1914 DescriptorRaw->u.Interrupt.Level,
1915 DescriptorRaw->u.Interrupt.Vector,
1916 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
1917 &DescriptorRaw->u.Interrupt.Affinity);
1918 break;
1919 }
1920 case CmResourceTypeMemory:
1921 {
1922 ULONG AddressSpace = 0; /* Memory space */
1923 if (!HalTranslateBusAddress(
1924 DeviceNode->ResourceList->List[i].InterfaceType,
1925 DeviceNode->ResourceList->List[i].BusNumber,
1926 DescriptorRaw->u.Memory.Start,
1927 &AddressSpace,
1928 &DescriptorTranslated->u.Memory.Start))
1929 {
1930 Status = STATUS_UNSUCCESSFUL;
1931 goto cleanup;
1932 }
1933 }
1934
1935 case CmResourceTypeDma:
1936 case CmResourceTypeBusNumber:
1937 case CmResourceTypeDeviceSpecific:
1938 /* Nothing to do */
1939 break;
1940 default:
1941 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
1942 Status = STATUS_NOT_IMPLEMENTED;
1943 goto cleanup;
1944 }
1945 }
1946 }
1947 return STATUS_SUCCESS;
1948
1949 cleanup:
1950 /* Yes! Also delete ResourceList because ResourceList and
1951 * ResourceListTranslated should be a pair! */
1952 ExFreePool(DeviceNode->ResourceList);
1953 DeviceNode->ResourceList = NULL;
1954 if (DeviceNode->ResourceListTranslated)
1955 {
1956 ExFreePool(DeviceNode->ResourceListTranslated);
1957 DeviceNode->ResourceList = NULL;
1958 }
1959 return Status;
1960 }
1961
1962
1963 /*
1964 * IopGetParentIdPrefix
1965 *
1966 * Retrieve (or create) a string which identifies a device.
1967 *
1968 * Parameters
1969 * DeviceNode
1970 * Pointer to device node.
1971 * ParentIdPrefix
1972 * Pointer to the string where is returned the parent node identifier
1973 *
1974 * Remarks
1975 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1976 * valid and its Buffer field is NULL-terminated. The caller needs to
1977 * to free the string with RtlFreeUnicodeString when it is no longer
1978 * needed.
1979 */
1980
1981 NTSTATUS
1982 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1983 PUNICODE_STRING ParentIdPrefix)
1984 {
1985 ULONG KeyNameBufferLength;
1986 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1987 UNICODE_STRING KeyName;
1988 UNICODE_STRING KeyValue;
1989 UNICODE_STRING ValueName;
1990 HANDLE hKey = NULL;
1991 ULONG crc32;
1992 NTSTATUS Status;
1993
1994 /* HACK: As long as some devices have a NULL device
1995 * instance path, the following test is required :(
1996 */
1997 if (DeviceNode->Parent->InstancePath.Length == 0)
1998 {
1999 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
2000 &DeviceNode->InstancePath);
2001 return STATUS_UNSUCCESSFUL;
2002 }
2003
2004 /* 1. Try to retrieve ParentIdPrefix from registry */
2005 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
2006 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
2007 if (!ParentIdPrefixInformation)
2008 {
2009 Status = STATUS_INSUFFICIENT_RESOURCES;
2010 goto cleanup;
2011 }
2012
2013
2014 KeyName.Buffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
2015 if (!KeyName.Buffer)
2016 {
2017 Status = STATUS_INSUFFICIENT_RESOURCES;
2018 goto cleanup;
2019 }
2020 KeyName.Length = 0;
2021 KeyName.MaximumLength = (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length;
2022
2023 RtlAppendUnicodeToString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2024 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
2025
2026 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
2027 if (!NT_SUCCESS(Status))
2028 goto cleanup;
2029 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
2030 Status = ZwQueryValueKey(
2031 hKey, &ValueName,
2032 KeyValuePartialInformation, ParentIdPrefixInformation,
2033 KeyNameBufferLength, &KeyNameBufferLength);
2034 if (NT_SUCCESS(Status))
2035 {
2036 if (ParentIdPrefixInformation->Type != REG_SZ)
2037 Status = STATUS_UNSUCCESSFUL;
2038 else
2039 {
2040 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
2041 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
2042 }
2043 goto cleanup;
2044 }
2045 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2046 {
2047 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
2048 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
2049 goto cleanup;
2050 }
2051
2052 /* 2. Create the ParentIdPrefix value */
2053 crc32 = RtlComputeCrc32(0,
2054 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
2055 DeviceNode->Parent->InstancePath.Length);
2056
2057 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
2058 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
2059
2060 /* 3. Try to write the ParentIdPrefix to registry */
2061 Status = ZwSetValueKey(hKey,
2062 &ValueName,
2063 0,
2064 REG_SZ,
2065 (PVOID)KeyValue.Buffer,
2066 (wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
2067
2068 cleanup:
2069 if (NT_SUCCESS(Status))
2070 {
2071 /* Duplicate the string to return it */
2072 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
2073 }
2074 ExFreePool(ParentIdPrefixInformation);
2075 RtlFreeUnicodeString(&KeyName);
2076 if (hKey != NULL)
2077 ZwClose(hKey);
2078 return Status;
2079 }
2080
2081
2082 /*
2083 * IopActionInterrogateDeviceStack
2084 *
2085 * Retrieve information for all (direct) child nodes of a parent node.
2086 *
2087 * Parameters
2088 * DeviceNode
2089 * Pointer to device node.
2090 * Context
2091 * Pointer to parent node to retrieve child node information for.
2092 *
2093 * Remarks
2094 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2095 * when we reach a device node which is not a direct child of the device
2096 * node for which we retrieve information of child nodes for. Any errors
2097 * that occur is logged instead so that all child services have a chance
2098 * of being interrogated.
2099 */
2100
2101 NTSTATUS
2102 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
2103 PVOID Context)
2104 {
2105 IO_STATUS_BLOCK IoStatusBlock;
2106 PDEVICE_NODE ParentDeviceNode;
2107 WCHAR InstancePath[MAX_PATH];
2108 IO_STACK_LOCATION Stack;
2109 NTSTATUS Status;
2110 PWSTR Ptr;
2111 USHORT Length;
2112 USHORT TotalLength;
2113 ULONG RequiredLength;
2114 LCID LocaleId;
2115 HANDLE InstanceKey = NULL;
2116 UNICODE_STRING ValueName;
2117 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
2118 DEVICE_CAPABILITIES DeviceCapabilities;
2119
2120 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2121 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2122
2123 ParentDeviceNode = (PDEVICE_NODE)Context;
2124
2125 /*
2126 * We are called for the parent too, but we don't need to do special
2127 * handling for this node
2128 */
2129
2130 if (DeviceNode == ParentDeviceNode)
2131 {
2132 DPRINT("Success\n");
2133 return STATUS_SUCCESS;
2134 }
2135
2136 /*
2137 * Make sure this device node is a direct child of the parent device node
2138 * that is given as an argument
2139 */
2140
2141 if (DeviceNode->Parent != ParentDeviceNode)
2142 {
2143 /* Stop the traversal immediately and indicate successful operation */
2144 DPRINT("Stop\n");
2145 return STATUS_UNSUCCESSFUL;
2146 }
2147
2148 /* Get Locale ID */
2149 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2150 if (!NT_SUCCESS(Status))
2151 {
2152 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2153 return Status;
2154 }
2155
2156 /*
2157 * FIXME: For critical errors, cleanup and disable device, but always
2158 * return STATUS_SUCCESS.
2159 */
2160
2161 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2162
2163 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
2164 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2165 &IoStatusBlock,
2166 IRP_MN_QUERY_ID,
2167 &Stack);
2168 if (NT_SUCCESS(Status))
2169 {
2170 /* Copy the device id string */
2171 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
2172
2173 /*
2174 * FIXME: Check for valid characters, if there is invalid characters
2175 * then bugcheck.
2176 */
2177 }
2178 else
2179 {
2180 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2181 }
2182
2183 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
2184
2185 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
2186 if (!NT_SUCCESS(Status))
2187 {
2188 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
2189 }
2190
2191 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
2192
2193 if (!DeviceCapabilities.UniqueID)
2194 {
2195 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2196 DPRINT("Instance ID is not unique\n");
2197 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
2198 if (!NT_SUCCESS(Status))
2199 {
2200 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
2201 }
2202 }
2203
2204 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2205
2206 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
2207 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2208 &IoStatusBlock,
2209 IRP_MN_QUERY_ID,
2210 &Stack);
2211 if (NT_SUCCESS(Status))
2212 {
2213 /* Append the instance id string */
2214 wcscat(InstancePath, L"\\");
2215 if (ParentIdPrefix.Length > 0)
2216 {
2217 /* Add information from parent bus device to InstancePath */
2218 wcscat(InstancePath, ParentIdPrefix.Buffer);
2219 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
2220 wcscat(InstancePath, L"&");
2221 }
2222 if (IoStatusBlock.Information)
2223 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
2224
2225 /*
2226 * FIXME: Check for valid characters, if there is invalid characters
2227 * then bugcheck
2228 */
2229 }
2230 else
2231 {
2232 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2233 }
2234 RtlFreeUnicodeString(&ParentIdPrefix);
2235
2236 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
2237 {
2238 DPRINT("No resources\n");
2239 /* FIXME: Cleanup and disable device */
2240 }
2241
2242 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2243
2244 /*
2245 * Create registry key for the instance id, if it doesn't exist yet
2246 */
2247 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, &InstanceKey);
2248 if (!NT_SUCCESS(Status))
2249 {
2250 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2251 }
2252
2253 {
2254 /* Set 'Capabilities' value */
2255 RtlInitUnicodeString(&ValueName, L"Capabilities");
2256 Status = ZwSetValueKey(InstanceKey,
2257 &ValueName,
2258 0,
2259 REG_DWORD,
2260 (PVOID)&DeviceNode->CapabilityFlags,
2261 sizeof(ULONG));
2262
2263 /* Set 'UINumber' value */
2264 if (DeviceCapabilities.UINumber != MAXULONG)
2265 {
2266 RtlInitUnicodeString(&ValueName, L"UINumber");
2267 Status = ZwSetValueKey(InstanceKey,
2268 &ValueName,
2269 0,
2270 REG_DWORD,
2271 &DeviceCapabilities.UINumber,
2272 sizeof(ULONG));
2273 }
2274 }
2275
2276 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2277
2278 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
2279 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2280 &IoStatusBlock,
2281 IRP_MN_QUERY_ID,
2282 &Stack);
2283 if (NT_SUCCESS(Status))
2284 {
2285 /*
2286 * FIXME: Check for valid characters, if there is invalid characters
2287 * then bugcheck.
2288 */
2289 TotalLength = 0;
2290 Ptr = (PWSTR)IoStatusBlock.Information;
2291 DPRINT("Hardware IDs:\n");
2292 while (*Ptr)
2293 {
2294 DPRINT(" %S\n", Ptr);
2295 Length = wcslen(Ptr) + 1;
2296
2297 Ptr += Length;
2298 TotalLength += Length;
2299 }
2300 DPRINT("TotalLength: %hu\n", TotalLength);
2301 DPRINT("\n");
2302
2303 RtlInitUnicodeString(&ValueName, L"HardwareID");
2304 Status = ZwSetValueKey(InstanceKey,
2305 &ValueName,
2306 0,
2307 REG_MULTI_SZ,
2308 (PVOID)IoStatusBlock.Information,
2309 (TotalLength + 1) * sizeof(WCHAR));
2310 if (!NT_SUCCESS(Status))
2311 {
2312 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2313 }
2314 }
2315 else
2316 {
2317 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2318 }
2319
2320 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2321
2322 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
2323 Status = IopInitiatePnpIrp(
2324 DeviceNode->PhysicalDeviceObject,
2325 &IoStatusBlock,
2326 IRP_MN_QUERY_ID,
2327 &Stack);
2328 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2329 {
2330 /*
2331 * FIXME: Check for valid characters, if there is invalid characters
2332 * then bugcheck.
2333 */
2334 TotalLength = 0;
2335 Ptr = (PWSTR)IoStatusBlock.Information;
2336 DPRINT("Compatible IDs:\n");
2337 while (*Ptr)
2338 {
2339 DPRINT(" %S\n", Ptr);
2340 Length = wcslen(Ptr) + 1;
2341
2342 Ptr += Length;
2343 TotalLength += Length;
2344 }
2345 DPRINT("TotalLength: %hu\n", TotalLength);
2346 DPRINT("\n");
2347
2348 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
2349 Status = ZwSetValueKey(InstanceKey,
2350 &ValueName,
2351 0,
2352 REG_MULTI_SZ,
2353 (PVOID)IoStatusBlock.Information,
2354 (TotalLength + 1) * sizeof(WCHAR));
2355 if (!NT_SUCCESS(Status))
2356 {
2357 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
2358 }
2359 }
2360 else
2361 {
2362 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2363 }
2364
2365 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2366
2367 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2368 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2369 Status = IopInitiatePnpIrp(
2370 DeviceNode->PhysicalDeviceObject,
2371 &IoStatusBlock,
2372 IRP_MN_QUERY_DEVICE_TEXT,
2373 &Stack);
2374 /* This key is mandatory, so even if the Irp fails, we still write it */
2375 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2376 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2377 {
2378 if (NT_SUCCESS(Status) &&
2379 IoStatusBlock.Information &&
2380 (*(PWSTR)IoStatusBlock.Information != 0))
2381 {
2382 /* This key is overriden when a driver is installed. Don't write the
2383 * new description if another one already exists */
2384 Status = ZwSetValueKey(InstanceKey,
2385 &ValueName,
2386 0,
2387 REG_SZ,
2388 (PVOID)IoStatusBlock.Information,
2389 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2390 }
2391 else
2392 {
2393 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2394 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2395
2396 Status = ZwSetValueKey(InstanceKey,
2397 &ValueName,
2398 0,
2399 REG_SZ,
2400 DeviceDesc.Buffer,
2401 DeviceDesc.MaximumLength);
2402
2403 if (!NT_SUCCESS(Status))
2404 {
2405 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2406 }
2407
2408 }
2409 }
2410
2411 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2412
2413 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2414 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2415 Status = IopInitiatePnpIrp(
2416 DeviceNode->PhysicalDeviceObject,
2417 &IoStatusBlock,
2418 IRP_MN_QUERY_DEVICE_TEXT,
2419 &Stack);
2420 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2421 {
2422 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
2423 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2424 Status = ZwSetValueKey(InstanceKey,
2425 &ValueName,
2426 0,
2427 REG_SZ,
2428 (PVOID)IoStatusBlock.Information,
2429 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2430 if (!NT_SUCCESS(Status))
2431 {
2432 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2433 }
2434 }
2435 else
2436 {
2437 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2438 }
2439
2440 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2441
2442 Status = IopInitiatePnpIrp(
2443 DeviceNode->PhysicalDeviceObject,
2444 &IoStatusBlock,
2445 IRP_MN_QUERY_BUS_INFORMATION,
2446 NULL);
2447 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2448 {
2449 PPNP_BUS_INFORMATION BusInformation =
2450 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2451
2452 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2453 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2454 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2455 ExFreePool(BusInformation);
2456 }
2457 else
2458 {
2459 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2460
2461 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2462 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2463 DeviceNode->ChildBusTypeIndex = -1;
2464 }
2465
2466 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2467
2468 Status = IopInitiatePnpIrp(
2469 DeviceNode->PhysicalDeviceObject,
2470 &IoStatusBlock,
2471 IRP_MN_QUERY_RESOURCES,
2472 NULL);
2473 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2474 {
2475 DeviceNode->BootResources =
2476 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2477 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
2478 }
2479 else
2480 {
2481 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2482 DeviceNode->BootResources = NULL;
2483 }
2484
2485 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2486
2487 Status = IopInitiatePnpIrp(
2488 DeviceNode->PhysicalDeviceObject,
2489 &IoStatusBlock,
2490 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2491 NULL);
2492 if (NT_SUCCESS(Status))
2493 {
2494 DeviceNode->ResourceRequirements =
2495 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2496 if (IoStatusBlock.Information)
2497 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_REPORTED);
2498 else
2499 IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED);
2500 }
2501 else
2502 {
2503 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2504 DeviceNode->ResourceRequirements = NULL;
2505 }
2506
2507
2508 if (InstanceKey != NULL)
2509 {
2510 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2511 }
2512
2513 ZwClose(InstanceKey);
2514
2515 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2516
2517 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2518 {
2519 /* Report the device to the user-mode pnp manager */
2520 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2521 &DeviceNode->InstancePath);
2522 }
2523
2524 return STATUS_SUCCESS;
2525 }
2526
2527
2528 NTSTATUS
2529 IopEnumerateDevice(
2530 IN PDEVICE_OBJECT DeviceObject)
2531 {
2532 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2533 DEVICETREE_TRAVERSE_CONTEXT Context;
2534 PDEVICE_RELATIONS DeviceRelations;
2535 PDEVICE_OBJECT ChildDeviceObject;
2536 IO_STATUS_BLOCK IoStatusBlock;
2537 PDEVICE_NODE ChildDeviceNode;
2538 IO_STACK_LOCATION Stack;
2539 NTSTATUS Status;
2540 ULONG i;
2541
2542 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2543
2544 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2545
2546 /* Report the device to the user-mode pnp manager */
2547 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2548 &DeviceNode->InstancePath);
2549
2550 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2551
2552 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2553
2554 Status = IopInitiatePnpIrp(
2555 DeviceObject,
2556 &IoStatusBlock,
2557 IRP_MN_QUERY_DEVICE_RELATIONS,
2558 &Stack);
2559 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2560 {
2561 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2562 return Status;
2563 }
2564
2565 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2566
2567 if (!DeviceRelations)
2568 {
2569 DPRINT("No PDOs\n");
2570 return STATUS_UNSUCCESSFUL;
2571 }
2572
2573 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2574
2575 /*
2576 * Create device nodes for all discovered devices
2577 */
2578 for (i = 0; i < DeviceRelations->Count; i++)
2579 {
2580 ChildDeviceObject = DeviceRelations->Objects[i];
2581 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2582
2583 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2584 if (!ChildDeviceNode)
2585 {
2586 /* One doesn't exist, create it */
2587 Status = IopCreateDeviceNode(
2588 DeviceNode,
2589 ChildDeviceObject,
2590 NULL,
2591 &ChildDeviceNode);
2592 if (NT_SUCCESS(Status))
2593 {
2594 /* Mark the node as enumerated */
2595 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2596
2597 /* Mark the DO as bus enumerated */
2598 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2599 }
2600 else
2601 {
2602 /* Ignore this DO */
2603 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2604 ObDereferenceObject(ChildDeviceNode);
2605 }
2606 }
2607 else
2608 {
2609 /* Mark it as enumerated */
2610 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2611 ObDereferenceObject(ChildDeviceObject);
2612 }
2613 }
2614 ExFreePool(DeviceRelations);
2615
2616 /*
2617 * Retrieve information about all discovered children from the bus driver
2618 */
2619 IopInitDeviceTreeTraverseContext(
2620 &Context,
2621 DeviceNode,
2622 IopActionInterrogateDeviceStack,
2623 DeviceNode);
2624
2625 Status = IopTraverseDeviceTree(&Context);
2626 if (!NT_SUCCESS(Status))
2627 {
2628 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2629 return Status;
2630 }
2631
2632 /*
2633 * Retrieve configuration from the registry for discovered children
2634 */
2635 IopInitDeviceTreeTraverseContext(
2636 &Context,
2637 DeviceNode,
2638 IopActionConfigureChildServices,
2639 DeviceNode);
2640
2641 Status = IopTraverseDeviceTree(&Context);
2642 if (!NT_SUCCESS(Status))
2643 {
2644 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2645 return Status;
2646 }
2647
2648 /*
2649 * Initialize services for discovered children.
2650 */
2651 Status = IopInitializePnpServices(DeviceNode);
2652 if (!NT_SUCCESS(Status))
2653 {
2654 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2655 return Status;
2656 }
2657
2658 DPRINT("IopEnumerateDevice() finished\n");
2659 return STATUS_SUCCESS;
2660 }
2661
2662
2663 /*
2664 * IopActionConfigureChildServices
2665 *
2666 * Retrieve configuration for all (direct) child nodes of a parent node.
2667 *
2668 * Parameters
2669 * DeviceNode
2670 * Pointer to device node.
2671 * Context
2672 * Pointer to parent node to retrieve child node configuration for.
2673 *
2674 * Remarks
2675 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2676 * when we reach a device node which is not a direct child of the device
2677 * node for which we configure child services for. Any errors that occur is
2678 * logged instead so that all child services have a chance of beeing
2679 * configured.
2680 */
2681
2682 NTSTATUS
2683 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2684 PVOID Context)
2685 {
2686 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2687 PDEVICE_NODE ParentDeviceNode;
2688 PUNICODE_STRING Service;
2689 UNICODE_STRING ClassGUID;
2690 NTSTATUS Status;
2691 DEVICE_CAPABILITIES DeviceCaps;
2692
2693 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2694
2695 ParentDeviceNode = (PDEVICE_NODE)Context;
2696
2697 /*
2698 * We are called for the parent too, but we don't need to do special
2699 * handling for this node
2700 */
2701 if (DeviceNode == ParentDeviceNode)
2702 {
2703 DPRINT("Success\n");
2704 return STATUS_SUCCESS;
2705 }
2706
2707 /*
2708 * Make sure this device node is a direct child of the parent device node
2709 * that is given as an argument
2710 */
2711 if (DeviceNode->Parent != ParentDeviceNode)
2712 {
2713 /* Stop the traversal immediately and indicate successful operation */
2714 DPRINT("Stop\n");
2715 return STATUS_UNSUCCESSFUL;
2716 }
2717
2718 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2719 {
2720 WCHAR RegKeyBuffer[MAX_PATH];
2721 UNICODE_STRING RegKey;
2722
2723 RegKey.Length = 0;
2724 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2725 RegKey.Buffer = RegKeyBuffer;
2726
2727 /*
2728 * Retrieve configuration from Enum key
2729 */
2730
2731 Service = &DeviceNode->ServiceName;
2732
2733 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2734 RtlInitUnicodeString(Service, NULL);
2735 RtlInitUnicodeString(&ClassGUID, NULL);
2736
2737 QueryTable[0].Name = L"Service";
2738 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2739 QueryTable[0].EntryContext = Service;
2740
2741 QueryTable[1].Name = L"ClassGUID";
2742 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2743 QueryTable[1].EntryContext = &ClassGUID;
2744 QueryTable[1].DefaultType = REG_SZ;
2745 QueryTable[1].DefaultData = L"";
2746 QueryTable[1].DefaultLength = 0;
2747
2748 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2749 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2750
2751 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2752 RegKey.Buffer, QueryTable, NULL, NULL);
2753
2754 if (!NT_SUCCESS(Status))
2755 {
2756 /* FIXME: Log the error */
2757 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2758 &DeviceNode->InstancePath, Status);
2759 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2760 return STATUS_SUCCESS;
2761 }
2762
2763 if (Service->Buffer == NULL)
2764 {
2765 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2766 DeviceCaps.RawDeviceOK)
2767 {
2768 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2769
2770 DeviceNode->ServiceName.Length = 0;
2771 DeviceNode->ServiceName.MaximumLength = 0;
2772 DeviceNode->ServiceName.Buffer = NULL;
2773 }
2774 else if (ClassGUID.Length != 0)
2775 {
2776 /* Device has a ClassGUID value, but no Service value.
2777 * Suppose it is using the NULL driver, so state the
2778 * device is started */
2779 DPRINT1("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2780 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2781 }
2782 else
2783 {
2784 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2785 }
2786 return STATUS_SUCCESS;
2787 }
2788
2789 DPRINT("Got Service %S\n", Service->Buffer);
2790 }
2791
2792 return STATUS_SUCCESS;
2793 }
2794
2795 /*
2796 * IopActionInitChildServices
2797 *
2798 * Initialize the service for all (direct) child nodes of a parent node
2799 *
2800 * Parameters
2801 * DeviceNode
2802 * Pointer to device node.
2803 * Context
2804 * Pointer to parent node to initialize child node services for.
2805 *
2806 * Remarks
2807 * If the driver image for a service is not loaded and initialized
2808 * it is done here too. We only return a status code indicating an
2809 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2810 * not a direct child of the device node for which we initialize
2811 * child services for. Any errors that occur is logged instead so
2812 * that all child services have a chance of being initialized.
2813 */
2814
2815 NTSTATUS
2816 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2817 PVOID Context)
2818 {
2819 PDEVICE_NODE ParentDeviceNode;
2820 NTSTATUS Status;
2821 BOOLEAN BootDrivers = !PnpSystemInit;
2822
2823 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2824
2825 ParentDeviceNode = (PDEVICE_NODE)Context;
2826
2827 /*
2828 * We are called for the parent too, but we don't need to do special
2829 * handling for this node
2830 */
2831 if (DeviceNode == ParentDeviceNode)
2832 {
2833 DPRINT("Success\n");
2834 return STATUS_SUCCESS;
2835 }
2836
2837 /*
2838 * Make sure this device node is a direct child of the parent device node
2839 * that is given as an argument
2840 */
2841 #if 0
2842 if (DeviceNode->Parent != ParentDeviceNode)
2843 {
2844 /*
2845 * Stop the traversal immediately and indicate unsuccessful operation
2846 */
2847 DPRINT("Stop\n");
2848 return STATUS_UNSUCCESSFUL;
2849 }
2850 #endif
2851 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2852 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2853 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2854 return STATUS_SUCCESS;
2855
2856 if (DeviceNode->ServiceName.Buffer == NULL)
2857 {
2858 /* We don't need to worry about loading the driver because we're
2859 * being driven in raw mode so our parent must be loaded to get here */
2860 Status = IopStartDevice(DeviceNode);
2861 if (!NT_SUCCESS(Status))
2862 {
2863 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2864 &DeviceNode->InstancePath, Status);
2865 }
2866 }
2867 else
2868 {
2869 PLDR_DATA_TABLE_ENTRY ModuleObject;
2870 PDRIVER_OBJECT DriverObject;
2871
2872 /* Get existing DriverObject pointer (in case the driver has
2873 already been loaded and initialized) */
2874 Status = IopGetDriverObject(
2875 &DriverObject,
2876 &DeviceNode->ServiceName,
2877 FALSE);
2878
2879 if (!NT_SUCCESS(Status))
2880 {
2881 /* Driver is not initialized, try to load it */
2882 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2883
2884 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2885 {
2886 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2887 was loaded by the bootloader */
2888 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
2889 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
2890 {
2891 /* Initialize the driver */
2892 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2893 &DeviceNode->ServiceName, FALSE, &DriverObject);
2894 }
2895 else
2896 {
2897 Status = STATUS_SUCCESS;
2898 }
2899 }
2900 else
2901 {
2902 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2903 &DeviceNode->ServiceName, Status);
2904 }
2905 }
2906
2907 /* Driver is loaded and initialized at this point */
2908 if (NT_SUCCESS(Status))
2909 {
2910 /* Attach lower level filter drivers. */
2911 IopAttachFilterDrivers(DeviceNode, TRUE);
2912
2913 /* Initialize the function driver for the device node */
2914 Status = IopInitializeDevice(DeviceNode, DriverObject);
2915
2916 if (NT_SUCCESS(Status))
2917 {
2918 /* Attach upper level filter drivers. */
2919 IopAttachFilterDrivers(DeviceNode, FALSE);
2920
2921 Status = IopStartDevice(DeviceNode);
2922 if (!NT_SUCCESS(Status))
2923 {
2924 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2925 &DeviceNode->InstancePath, Status);
2926 }
2927 }
2928 else
2929 {
2930 DPRINT1("IopInitializeDevice(%wZ) failed with status 0x%08x\n",
2931 &DeviceNode->InstancePath, Status);
2932 }
2933 }
2934 else
2935 {
2936 /*
2937 * Don't disable when trying to load only boot drivers
2938 */
2939 if (!BootDrivers)
2940 {
2941 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2942 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2943 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2944 DPRINT1("Initialization of service %S failed (Status %x)\n",
2945 DeviceNode->ServiceName.Buffer, Status);
2946 }
2947 }
2948 }
2949
2950 return STATUS_SUCCESS;
2951 }
2952
2953 /*
2954 * IopInitializePnpServices
2955 *
2956 * Initialize services for discovered children
2957 *
2958 * Parameters
2959 * DeviceNode
2960 * Top device node to start initializing services.
2961 *
2962 * Return Value
2963 * Status
2964 */
2965 NTSTATUS
2966 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2967 {
2968 DEVICETREE_TRAVERSE_CONTEXT Context;
2969
2970 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2971
2972 IopInitDeviceTreeTraverseContext(
2973 &Context,
2974 DeviceNode,
2975 IopActionInitChildServices,
2976 DeviceNode);
2977
2978 return IopTraverseDeviceTree(&Context);
2979 }
2980
2981 static NTSTATUS INIT_FUNCTION
2982 IopEnumerateDetectedDevices(
2983 IN HANDLE hBaseKey,
2984 IN PUNICODE_STRING RelativePath OPTIONAL,
2985 IN HANDLE hRootKey,
2986 IN BOOLEAN EnumerateSubKeys,
2987 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2988 IN ULONG ParentBootResourcesLength)
2989 {
2990 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2991 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2992 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2993 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2994 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2995 OBJECT_ATTRIBUTES ObjectAttributes;
2996 HANDLE hDevicesKey = NULL;
2997 HANDLE hDeviceKey = NULL;
2998 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2999 UNICODE_STRING Level2NameU;
3000 WCHAR Level2Name[5];
3001 ULONG IndexDevice = 0;
3002 ULONG IndexSubKey;
3003 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3004 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3005 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3006 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3007 UNICODE_STRING DeviceName, ValueName;
3008 ULONG RequiredSize;
3009 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
3010 ULONG BootResourcesLength;
3011 NTSTATUS Status;
3012
3013 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
3014 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
3015 static ULONG DeviceIndexPci = 0;
3016 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
3017 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
3018 static ULONG DeviceIndexSerial = 0;
3019 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
3020 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
3021 static ULONG DeviceIndexKeyboard = 0;
3022 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
3023 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
3024 static ULONG DeviceIndexMouse = 0;
3025 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
3026 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
3027 static ULONG DeviceIndexParallel = 0;
3028 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
3029 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
3030 static ULONG DeviceIndexFloppy = 0;
3031 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
3032 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
3033 static ULONG DeviceIndexIsa = 0;
3034 UNICODE_STRING HardwareIdKey;
3035 PUNICODE_STRING pHardwareId;
3036 ULONG DeviceIndex = 0;
3037 PUCHAR CmResourceList;
3038 ULONG ListCount;
3039
3040 if (RelativePath)
3041 {
3042 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
3043 if (!NT_SUCCESS(Status))
3044 {
3045 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3046 goto cleanup;
3047 }
3048 }
3049 else
3050 hDevicesKey = hBaseKey;
3051
3052 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3053 if (!pDeviceInformation)
3054 {
3055 DPRINT("ExAllocatePool() failed\n");
3056 Status = STATUS_NO_MEMORY;
3057 goto cleanup;
3058 }
3059
3060 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3061 if (!pValueInformation)
3062 {
3063 DPRINT("ExAllocatePool() failed\n");
3064 Status = STATUS_NO_MEMORY;
3065 goto cleanup;
3066 }
3067
3068 while (TRUE)
3069 {
3070 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3071 if (Status == STATUS_NO_MORE_ENTRIES)
3072 break;
3073 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3074 {
3075 ExFreePool(pDeviceInformation);
3076 DeviceInfoLength = RequiredSize;
3077 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3078 if (!pDeviceInformation)
3079 {
3080 DPRINT("ExAllocatePool() failed\n");
3081 Status = STATUS_NO_MEMORY;
3082 goto cleanup;
3083 }
3084 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3085 }
3086 if (!NT_SUCCESS(Status))
3087 {
3088 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3089 goto cleanup;
3090 }
3091 IndexDevice++;
3092
3093 /* Open device key */
3094 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3095 DeviceName.Buffer = pDeviceInformation->Name;
3096
3097 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3098 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3099 if (!NT_SUCCESS(Status))
3100 {
3101 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3102 goto cleanup;
3103 }
3104
3105 /* Read boot resources, and add then to parent ones */
3106 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3107 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3108 {
3109 ExFreePool(pValueInformation);
3110 ValueInfoLength = RequiredSize;
3111 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3112 if (!pValueInformation)
3113 {
3114 DPRINT("ExAllocatePool() failed\n");
3115 ZwDeleteKey(hLevel2Key);
3116 Status = STATUS_NO_MEMORY;
3117 goto cleanup;
3118 }
3119 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3120 }
3121 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3122 {
3123 BootResources = ParentBootResources;
3124 BootResourcesLength = ParentBootResourcesLength;
3125 }
3126 else if (!NT_SUCCESS(Status))
3127 {
3128 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3129 goto nextdevice;
3130 }
3131 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3132 {
3133 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3134 goto nextdevice;
3135 }
3136 else
3137 {
3138 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3139
3140 /* Concatenate current resources and parent ones */
3141 if (ParentBootResourcesLength == 0)
3142 BootResourcesLength = pValueInformation->DataLength;
3143 else
3144 BootResourcesLength = ParentBootResourcesLength
3145 + pValueInformation->DataLength
3146 - Header;
3147 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3148 if (!BootResources)
3149 {
3150 DPRINT("ExAllocatePool() failed\n");
3151 goto nextdevice;
3152 }
3153 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3154 {
3155 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3156 }
3157 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3158 {
3159 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3160 RtlCopyMemory(
3161 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3162 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3163 ParentBootResourcesLength - Header);
3164 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3165 }
3166 else
3167 {
3168 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3169 RtlCopyMemory(
3170 (PVOID)((ULONG_PTR)BootResources + Header),
3171 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3172 ParentBootResourcesLength - Header);
3173 RtlCopyMemory(
3174 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3175 pValueInformation->Data + Header,
3176 pValueInformation->DataLength - Header);
3177 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3178 }
3179 }
3180
3181 if (EnumerateSubKeys)
3182 {
3183 IndexSubKey = 0;
3184 while (TRUE)
3185 {
3186 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3187 if (Status == STATUS_NO_MORE_ENTRIES)
3188 break;
3189 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3190 {
3191 ExFreePool(pDeviceInformation);
3192 DeviceInfoLength = RequiredSize;
3193 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3194 if (!pDeviceInformation)
3195 {
3196 DPRINT("ExAllocatePool() failed\n");
3197 Status = STATUS_NO_MEMORY;
3198 goto cleanup;
3199 }
3200 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3201 }
3202 if (!NT_SUCCESS(Status))
3203 {
3204 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3205 goto cleanup;
3206 }
3207 IndexSubKey++;
3208 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3209 DeviceName.Buffer = pDeviceInformation->Name;
3210
3211 Status = IopEnumerateDetectedDevices(
3212 hDeviceKey,
3213 &DeviceName,
3214 hRootKey,
3215 TRUE,
3216 BootResources,
3217 BootResourcesLength);
3218 if (!NT_SUCCESS(Status))
3219 goto cleanup;
3220 }
3221 }
3222
3223 /* Read identifier */
3224 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3225 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3226 {
3227 ExFreePool(pValueInformation);
3228 ValueInfoLength = RequiredSize;
3229 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3230 if (!pValueInformation)
3231 {
3232 DPRINT("ExAllocatePool() failed\n");
3233 Status = STATUS_NO_MEMORY;
3234 goto cleanup;
3235 }
3236 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3237 }
3238 if (!NT_SUCCESS(Status))
3239 {
3240 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
3241 {
3242 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);