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