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