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