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