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