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