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