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