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