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