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