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