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