[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 //#define ENABLE_ACPI
17
18 /* GLOBALS *******************************************************************/
19
20 PDEVICE_NODE IopRootDeviceNode;
21 KSPIN_LOCK IopDeviceTreeLock;
22 ERESOURCE PpRegistryDeviceResource;
23 KGUARDED_MUTEX PpDeviceReferenceTableLock;
24 RTL_AVL_TABLE PpDeviceReferenceTable;
25
26 extern ULONG ExpInitializationPhase;
27 extern BOOLEAN PnpSystemInit;
28
29 /* DATA **********************************************************************/
30
31 PDRIVER_OBJECT IopRootDriverObject;
32 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
33
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, PnpInit)
36 #pragma alloc_text(INIT, PnpInit2)
37 #endif
38
39 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
40 {
41 PDEVICE_OBJECT DeviceObject;
42 DEVICE_RELATION_TYPE Type;
43 PIO_WORKITEM WorkItem;
44 } INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
45
46 /* FUNCTIONS *****************************************************************/
47 NTSTATUS
48 NTAPI
49 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
50 IN ULONG CreateOptions,
51 OUT PHANDLE Handle);
52
53 PDEVICE_NODE
54 FASTCALL
55 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
56 {
57 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
58 }
59
60 NTSTATUS
61 FASTCALL
62 IopInitializeDevice(PDEVICE_NODE DeviceNode,
63 PDRIVER_OBJECT DriverObject)
64 {
65 PDEVICE_OBJECT Fdo;
66 NTSTATUS Status;
67
68 if (!DriverObject)
69 {
70 /* Special case for bus driven devices */
71 DeviceNode->Flags |= DNF_ADDED;
72 return STATUS_SUCCESS;
73 }
74
75 if (!DriverObject->DriverExtension->AddDevice)
76 {
77 DeviceNode->Flags |= DNF_LEGACY_DRIVER;
78 }
79
80 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
81 {
82 DeviceNode->Flags |= DNF_ADDED + DNF_STARTED;
83 return STATUS_SUCCESS;
84 }
85
86 /* This is a Plug and Play driver */
87 DPRINT("Plug and Play driver found\n");
88 ASSERT(DeviceNode->PhysicalDeviceObject);
89
90 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
91 &DriverObject->DriverName,
92 &DeviceNode->InstancePath);
93 Status = DriverObject->DriverExtension->AddDevice(
94 DriverObject, DeviceNode->PhysicalDeviceObject);
95 if (!NT_SUCCESS(Status))
96 {
97 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
98 return Status;
99 }
100
101 /* Check if driver added a FDO above the PDO */
102 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
103 if (Fdo == DeviceNode->PhysicalDeviceObject)
104 {
105 /* FIXME: What do we do? Unload the driver or just disable the device? */
106 DPRINT1("An FDO was not attached\n");
107 ObDereferenceObject(Fdo);
108 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
109 return STATUS_UNSUCCESSFUL;
110 }
111
112 /* Check if we have a ACPI device (needed for power management) */
113 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
114 {
115 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
116
117 /* There can be only one system power device */
118 if (!SystemPowerDeviceNodeCreated)
119 {
120 PopSystemPowerDeviceNode = DeviceNode;
121 ObReferenceObject(PopSystemPowerDeviceNode);
122 SystemPowerDeviceNodeCreated = TRUE;
123 }
124 }
125
126 ObDereferenceObject(Fdo);
127
128 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
129
130 return STATUS_SUCCESS;
131 }
132
133 VOID
134 NTAPI
135 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
136 {
137 IO_STACK_LOCATION Stack;
138 PVOID Dummy;
139
140 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
141 Stack.MajorFunction = IRP_MJ_PNP;
142 Stack.MinorFunction = IRP_MN_REMOVE_DEVICE;
143
144 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
145 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
146 }
147
148 VOID
149 NTAPI
150 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
151 {
152 IO_STACK_LOCATION Stack;
153 PDEVICE_NODE DeviceNode;
154 NTSTATUS Status;
155 PVOID Dummy;
156
157 /* Get the device node */
158 DeviceNode = IopGetDeviceNode(DeviceObject);
159
160 /* Build the I/O stack locaiton */
161 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
162 Stack.MajorFunction = IRP_MJ_PNP;
163 Stack.MinorFunction = IRP_MN_START_DEVICE;
164
165 /* Check if we didn't already report the resources */
166 if (!(DeviceNode->Flags & DNF_RESOURCE_REPORTED))
167 {
168 /* Report them */
169 Stack.Parameters.StartDevice.AllocatedResources =
170 DeviceNode->ResourceList;
171 Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
172 DeviceNode->ResourceListTranslated;
173 }
174
175 /* I don't think we set this flag yet */
176 ASSERT(!(DeviceNode->Flags & DNF_STOPPED));
177
178 /* Do the call */
179 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
180 if (!NT_SUCCESS(Status))
181 {
182 /* Send an IRP_MN_REMOVE_DEVICE request */
183 IopSendRemoveDevice(DeviceObject);
184
185 /* Set the appropriate flag */
186 DeviceNode->Flags |= DNF_START_FAILED;
187
188 DPRINT1("Warning: PnP Start failed (%wZ)\n", &DeviceNode->InstancePath);
189 return;
190 }
191
192 /* Otherwise, mark us as started */
193 DeviceNode->Flags |= DNF_STARTED;
194
195 /* We now need enumeration */
196 DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
197 }
198
199 NTSTATUS
200 NTAPI
201 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
202 {
203 PDEVICE_OBJECT DeviceObject;
204 NTSTATUS Status;
205 PAGED_CODE();
206
207 /* Sanity check */
208 ASSERT((DeviceNode->Flags & DNF_ADDED));
209 ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED |
210 DNF_RESOURCE_REPORTED |
211 DNF_NO_RESOURCE_REQUIRED)));
212 ASSERT((!(DeviceNode->Flags & (DNF_HAS_PROBLEM |
213 DNF_STARTED |
214 DNF_START_REQUEST_PENDING))));
215
216 /* Get the device object */
217 DeviceObject = DeviceNode->PhysicalDeviceObject;
218
219 /* Check if we're not started yet */
220 if (!(DeviceNode->Flags & DNF_STARTED))
221 {
222 /* Start us */
223 IopStartDevice2(DeviceObject);
224 }
225
226 /* Do we need to query IDs? This happens in the case of manual reporting */
227 #if 0
228 if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
229 {
230 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
231 /* And that case shouldn't happen yet */
232 ASSERT(FALSE);
233 }
234 #endif
235
236 /* Make sure we're started, and check if we need enumeration */
237 if ((DeviceNode->Flags & DNF_STARTED) &&
238 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY))
239 {
240 /* Enumerate us */
241 IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations);
242 IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
243 Status = STATUS_SUCCESS;
244 }
245 else
246 {
247 /* Nothing to do */
248 Status = STATUS_SUCCESS;
249 }
250
251 /* Return */
252 return Status;
253 }
254
255 NTSTATUS
256 IopStartDevice(
257 PDEVICE_NODE DeviceNode)
258 {
259 NTSTATUS Status;
260 HANDLE InstanceHandle = INVALID_HANDLE_VALUE, ControlHandle = INVALID_HANDLE_VALUE;
261 UNICODE_STRING KeyName;
262 OBJECT_ATTRIBUTES ObjectAttributes;
263
264 if (DeviceNode->Flags & (DNF_STARTED | DNF_START_REQUEST_PENDING))
265 {
266 /* Nothing to do here */
267 return STATUS_SUCCESS;
268 }
269
270 Status = IopAssignDeviceResources(DeviceNode);
271 if (!NT_SUCCESS(Status))
272 goto ByeBye;
273
274 /* New PnP ABI */
275 IopStartAndEnumerateDevice(DeviceNode);
276
277 /* FIX: Should be done in new device instance code */
278 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceHandle);
279 if (!NT_SUCCESS(Status))
280 goto ByeBye;
281
282 /* FIX: Should be done in IoXxxPrepareDriverLoading */
283 // {
284 RtlInitUnicodeString(&KeyName, L"Control");
285 InitializeObjectAttributes(&ObjectAttributes,
286 &KeyName,
287 OBJ_CASE_INSENSITIVE,
288 InstanceHandle,
289 NULL);
290 Status = ZwCreateKey(&ControlHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
291 if (!NT_SUCCESS(Status))
292 goto ByeBye;
293
294 RtlInitUnicodeString(&KeyName, L"ActiveService");
295 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, DeviceNode->ServiceName.Buffer, DeviceNode->ServiceName.Length);
296 // }
297
298 ByeBye:
299 if (ControlHandle != INVALID_HANDLE_VALUE)
300 ZwClose(ControlHandle);
301
302 if (InstanceHandle != INVALID_HANDLE_VALUE)
303 ZwClose(InstanceHandle);
304
305 return Status;
306 }
307
308 NTSTATUS
309 NTAPI
310 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
311 PDEVICE_CAPABILITIES DeviceCaps)
312 {
313 IO_STATUS_BLOCK StatusBlock;
314 IO_STACK_LOCATION Stack;
315
316 /* Set up the Header */
317 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
318 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
319 DeviceCaps->Version = 1;
320 DeviceCaps->Address = -1;
321 DeviceCaps->UINumber = -1;
322
323 /* Set up the Stack */
324 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
325 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
326
327 /* Send the IRP */
328 return IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
329 &StatusBlock,
330 IRP_MN_QUERY_CAPABILITIES,
331 &Stack);
332 }
333
334 static VOID NTAPI
335 IopAsynchronousInvalidateDeviceRelations(
336 IN PDEVICE_OBJECT DeviceObject,
337 IN PVOID InvalidateContext)
338 {
339 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
340
341 IoSynchronousInvalidateDeviceRelations(
342 Data->DeviceObject,
343 Data->Type);
344
345 ObDereferenceObject(Data->DeviceObject);
346 IoFreeWorkItem(Data->WorkItem);
347 ExFreePool(Data);
348 }
349
350 NTSTATUS
351 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
352 {
353 KIRQL OldIrql;
354
355 if (PopSystemPowerDeviceNode)
356 {
357 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
358 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
359 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
360
361 return STATUS_SUCCESS;
362 }
363
364 return STATUS_UNSUCCESSFUL;
365 }
366
367 USHORT
368 NTAPI
369 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
370 {
371 USHORT i = 0, FoundIndex = 0xFFFF;
372 ULONG NewSize;
373 PVOID NewList;
374
375 /* Acquire the lock */
376 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
377
378 /* Loop all entries */
379 while (i < PnpBusTypeGuidList->GuidCount)
380 {
381 /* Try to find a match */
382 if (RtlCompareMemory(BusTypeGuid,
383 &PnpBusTypeGuidList->Guids[i],
384 sizeof(GUID)) == sizeof(GUID))
385 {
386 /* Found it */
387 FoundIndex = i;
388 goto Quickie;
389 }
390 i++;
391 }
392
393 /* Check if we have to grow the list */
394 if (PnpBusTypeGuidList->GuidCount)
395 {
396 /* Calculate the new size */
397 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
398 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
399
400 /* Allocate the new copy */
401 NewList = ExAllocatePool(PagedPool, NewSize);
402
403 if (!NewList) {
404 /* Fail */
405 ExFreePool(PnpBusTypeGuidList);
406 goto Quickie;
407 }
408
409 /* Now copy them, decrease the size too */
410 NewSize -= sizeof(GUID);
411 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
412
413 /* Free the old list */
414 ExFreePool(PnpBusTypeGuidList);
415
416 /* Use the new buffer */
417 PnpBusTypeGuidList = NewList;
418 }
419
420 /* Copy the new GUID */
421 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
422 BusTypeGuid,
423 sizeof(GUID));
424
425 /* The new entry is the index */
426 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
427 PnpBusTypeGuidList->GuidCount++;
428
429 Quickie:
430 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
431 return FoundIndex;
432 }
433
434 /*
435 * DESCRIPTION
436 * Creates a device node
437 *
438 * ARGUMENTS
439 * ParentNode = Pointer to parent device node
440 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
441 * to have the root device node create one
442 * (eg. for legacy drivers)
443 * DeviceNode = Pointer to storage for created device node
444 *
445 * RETURN VALUE
446 * Status
447 */
448 NTSTATUS
449 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
450 PDEVICE_OBJECT PhysicalDeviceObject,
451 PUNICODE_STRING ServiceName,
452 PDEVICE_NODE *DeviceNode)
453 {
454 PDEVICE_NODE Node;
455 NTSTATUS Status;
456 KIRQL OldIrql;
457 UNICODE_STRING FullServiceName;
458 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
459 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
460 UNICODE_STRING KeyName, ClassName;
461 PUNICODE_STRING ServiceName1;
462 ULONG LegacyValue;
463 #if 0
464 UNICODE_STRING ClassGUID;
465 #endif
466 HANDLE InstanceHandle;
467
468 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
469 ParentNode, PhysicalDeviceObject, ServiceName);
470
471 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
472 if (!Node)
473 {
474 return STATUS_INSUFFICIENT_RESOURCES;
475 }
476
477 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
478
479 if (!ServiceName)
480 ServiceName1 = &UnknownDeviceName;
481 else
482 ServiceName1 = ServiceName;
483
484 if (!PhysicalDeviceObject)
485 {
486 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length;
487 FullServiceName.Length = 0;
488 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
489 if (!FullServiceName.Buffer)
490 {
491 ExFreePool(Node);
492 return STATUS_INSUFFICIENT_RESOURCES;
493 }
494
495 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
496 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
497
498 Status = PnpRootCreateDevice(&FullServiceName, &PhysicalDeviceObject, &Node->InstancePath);
499 if (!NT_SUCCESS(Status))
500 {
501 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
502 ExFreePool(Node);
503 return Status;
504 }
505
506 /* Create the device key for legacy drivers */
507 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
508 if (!NT_SUCCESS(Status))
509 {
510 ZwClose(InstanceHandle);
511 ExFreePool(Node);
512 ExFreePool(FullServiceName.Buffer);
513 return Status;
514 }
515
516 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, ServiceName1->Length);
517 if (!Node->ServiceName.Buffer)
518 {
519 ZwClose(InstanceHandle);
520 ExFreePool(Node);
521 ExFreePool(FullServiceName.Buffer);
522 return Status;
523 }
524
525 Node->ServiceName.MaximumLength = ServiceName1->Length;
526 Node->ServiceName.Length = 0;
527
528 RtlAppendUnicodeStringToString(&Node->ServiceName, ServiceName1);
529
530 if (ServiceName)
531 {
532 RtlInitUnicodeString(&KeyName, L"Service");
533 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length);
534 }
535
536 if (NT_SUCCESS(Status))
537 {
538 RtlInitUnicodeString(&KeyName, L"Legacy");
539
540 LegacyValue = 1;
541 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
542 if (NT_SUCCESS(Status))
543 {
544 RtlInitUnicodeString(&KeyName, L"Class");
545
546 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
547 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length);
548 #if 0
549 if (NT_SUCCESS(Status))
550 {
551 RtlInitUnicodeString(&KeyName, L"ClassGUID");
552
553 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
554 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length);
555 }
556 #endif
557 }
558 }
559
560 ZwClose(InstanceHandle);
561 ExFreePool(FullServiceName.Buffer);
562
563 if (!NT_SUCCESS(Status))
564 {
565 ExFreePool(Node);
566 return Status;
567 }
568
569 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
570 IopDeviceNodeSetFlag(Node, DNF_ADDED);
571 IopDeviceNodeSetFlag(Node, DNF_STARTED);
572 }
573
574 Node->PhysicalDeviceObject = PhysicalDeviceObject;
575
576 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
577
578 if (ParentNode)
579 {
580 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
581 Node->Parent = ParentNode;
582 Node->Sibling = ParentNode->Child;
583 ParentNode->Child = Node;
584 if (ParentNode->LastChild == NULL)
585 ParentNode->LastChild = Node;
586 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
587 Node->Level = ParentNode->Level + 1;
588 }
589
590 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
591
592 *DeviceNode = Node;
593
594 return STATUS_SUCCESS;
595 }
596
597 NTSTATUS
598 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
599 {
600 KIRQL OldIrql;
601 PDEVICE_NODE PrevSibling = NULL;
602
603 /* All children must be deleted before a parent is deleted */
604 ASSERT(!DeviceNode->Child);
605
606 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
607
608 ASSERT(DeviceNode->PhysicalDeviceObject);
609
610 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
611
612 /* Get previous sibling */
613 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
614 {
615 PrevSibling = DeviceNode->Parent->Child;
616 while (PrevSibling->Sibling != DeviceNode)
617 PrevSibling = PrevSibling->Sibling;
618 }
619
620 /* Unlink from parent if it exists */
621 if (DeviceNode->Parent)
622 {
623 if (DeviceNode->Parent->LastChild == DeviceNode)
624 {
625 DeviceNode->Parent->LastChild = PrevSibling;
626 if (PrevSibling)
627 PrevSibling->Sibling = NULL;
628 }
629 if (DeviceNode->Parent->Child == DeviceNode)
630 DeviceNode->Parent->Child = DeviceNode->Sibling;
631 }
632
633 /* Unlink from sibling list */
634 if (PrevSibling)
635 PrevSibling->Sibling = DeviceNode->Sibling;
636
637 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
638
639 RtlFreeUnicodeString(&DeviceNode->InstancePath);
640
641 RtlFreeUnicodeString(&DeviceNode->ServiceName);
642
643 if (DeviceNode->ResourceList)
644 {
645 ExFreePool(DeviceNode->ResourceList);
646 }
647
648 if (DeviceNode->ResourceListTranslated)
649 {
650 ExFreePool(DeviceNode->ResourceListTranslated);
651 }
652
653 if (DeviceNode->ResourceRequirements)
654 {
655 ExFreePool(DeviceNode->ResourceRequirements);
656 }
657
658 if (DeviceNode->BootResources)
659 {
660 ExFreePool(DeviceNode->BootResources);
661 }
662
663 ExFreePool(DeviceNode);
664
665 return STATUS_SUCCESS;
666 }
667
668 NTSTATUS
669 NTAPI
670 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
671 IN PIO_STACK_LOCATION IoStackLocation,
672 OUT PVOID *Information)
673 {
674 PIRP Irp;
675 PIO_STACK_LOCATION IrpStack;
676 IO_STATUS_BLOCK IoStatusBlock;
677 KEVENT Event;
678 NTSTATUS Status;
679 PDEVICE_OBJECT TopDeviceObject;
680 PAGED_CODE();
681
682 /* Call the top of the device stack */
683 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
684
685 /* Allocate an IRP */
686 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
687 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
688
689 /* Initialize to failure */
690 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
691 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
692
693 /* Initialize the event */
694 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
695
696 /* Set them up */
697 Irp->UserIosb = &IoStatusBlock;
698 Irp->UserEvent = &Event;
699
700 /* Queue the IRP */
701 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
702 IoQueueThreadIrp(Irp);
703
704 /* Copy-in the stack */
705 IrpStack = IoGetNextIrpStackLocation(Irp);
706 *IrpStack = *IoStackLocation;
707
708 /* Call the driver */
709 Status = IoCallDriver(TopDeviceObject, Irp);
710 if (Status == STATUS_PENDING)
711 {
712 /* Wait for it */
713 KeWaitForSingleObject(&Event,
714 Executive,
715 KernelMode,
716 FALSE,
717 NULL);
718 Status = IoStatusBlock.Status;
719 }
720
721 /* Return the information */
722 *Information = (PVOID)IoStatusBlock.Information;
723 return Status;
724 }
725
726 NTSTATUS
727 NTAPI
728 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
729 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
730 IN ULONG MinorFunction,
731 IN PIO_STACK_LOCATION Stack OPTIONAL)
732 {
733 IO_STACK_LOCATION IoStackLocation;
734
735 /* Fill out the stack information */
736 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
737 IoStackLocation.MajorFunction = IRP_MJ_PNP;
738 IoStackLocation.MinorFunction = MinorFunction;
739 if (Stack)
740 {
741 /* Copy the rest */
742 RtlCopyMemory(&IoStackLocation.Parameters,
743 &Stack->Parameters,
744 sizeof(Stack->Parameters));
745 }
746
747 /* Do the PnP call */
748 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
749 &IoStackLocation,
750 (PVOID)&IoStatusBlock->Information);
751 return IoStatusBlock->Status;
752 }
753
754 NTSTATUS
755 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
756 {
757 PDEVICE_NODE ParentDeviceNode;
758 PDEVICE_NODE ChildDeviceNode;
759 NTSTATUS Status;
760
761 /* Copy context data so we don't overwrite it in subsequent calls to this function */
762 ParentDeviceNode = Context->DeviceNode;
763
764 /* Call the action routine */
765 Status = (Context->Action)(ParentDeviceNode, Context->Context);
766 if (!NT_SUCCESS(Status))
767 {
768 return Status;
769 }
770
771 /* Traversal of all children nodes */
772 for (ChildDeviceNode = ParentDeviceNode->Child;
773 ChildDeviceNode != NULL;
774 ChildDeviceNode = ChildDeviceNode->Sibling)
775 {
776 /* Pass the current device node to the action routine */
777 Context->DeviceNode = ChildDeviceNode;
778
779 Status = IopTraverseDeviceTreeNode(Context);
780 if (!NT_SUCCESS(Status))
781 {
782 return Status;
783 }
784 }
785
786 return Status;
787 }
788
789
790 NTSTATUS
791 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
792 {
793 NTSTATUS Status;
794
795 DPRINT("Context 0x%p\n", Context);
796
797 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
798 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
799
800 /* Start from the specified device node */
801 Context->DeviceNode = Context->FirstDeviceNode;
802
803 /* Recursively traverse the device tree */
804 Status = IopTraverseDeviceTreeNode(Context);
805 if (Status == STATUS_UNSUCCESSFUL)
806 {
807 /* The action routine just wanted to terminate the traversal with status
808 code STATUS_SUCCESS */
809 Status = STATUS_SUCCESS;
810 }
811
812 return Status;
813 }
814
815
816 /*
817 * IopCreateDeviceKeyPath
818 *
819 * Creates a registry key
820 *
821 * Parameters
822 * RegistryPath
823 * Name of the key to be created.
824 * Handle
825 * Handle to the newly created key
826 *
827 * Remarks
828 * This method can create nested trees, so parent of RegistryPath can
829 * be not existant, and will be created if needed.
830 */
831 NTSTATUS
832 NTAPI
833 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
834 IN ULONG CreateOptions,
835 OUT PHANDLE Handle)
836 {
837 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
838 HANDLE hParent = NULL, hKey;
839 OBJECT_ATTRIBUTES ObjectAttributes;
840 UNICODE_STRING KeyName;
841 LPCWSTR Current, Last;
842 ULONG dwLength;
843 NTSTATUS Status;
844
845 /* Assume failure */
846 *Handle = NULL;
847
848 /* Open root key for device instances */
849 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
850 if (!NT_SUCCESS(Status))
851 {
852 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
853 return Status;
854 }
855
856 Current = KeyName.Buffer = RegistryPath->Buffer;
857 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
858
859 /* Go up to the end of the string */
860 while (Current <= Last)
861 {
862 if (Current != Last && *Current != '\\')
863 {
864 /* Not the end of the string and not a separator */
865 Current++;
866 continue;
867 }
868
869 /* Prepare relative key name */
870 dwLength = (ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer;
871 KeyName.MaximumLength = KeyName.Length = dwLength;
872 DPRINT("Create '%wZ'\n", &KeyName);
873
874 /* Open key */
875 InitializeObjectAttributes(&ObjectAttributes,
876 &KeyName,
877 OBJ_CASE_INSENSITIVE,
878 hParent,
879 NULL);
880 Status = ZwCreateKey(&hKey,
881 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
882 &ObjectAttributes,
883 0,
884 NULL,
885 CreateOptions,
886 NULL);
887
888 /* Close parent key handle, we don't need it anymore */
889 if (hParent)
890 ZwClose(hParent);
891
892 /* Key opening/creating failed? */
893 if (!NT_SUCCESS(Status))
894 {
895 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
896 return Status;
897 }
898
899 /* Check if it is the end of the string */
900 if (Current == Last)
901 {
902 /* Yes, return success */
903 *Handle = hKey;
904 return STATUS_SUCCESS;
905 }
906
907 /* Start with this new parent key */
908 hParent = hKey;
909 Current++;
910 KeyName.Buffer = (LPWSTR)Current;
911 }
912
913 return STATUS_UNSUCCESSFUL;
914 }
915
916 NTSTATUS
917 IopSetDeviceInstanceData(HANDLE InstanceKey,
918 PDEVICE_NODE DeviceNode)
919 {
920 OBJECT_ATTRIBUTES ObjectAttributes;
921 UNICODE_STRING KeyName;
922 HANDLE LogConfKey;
923 ULONG ResCount;
924 ULONG ResultLength;
925 NTSTATUS Status;
926 HANDLE ControlHandle;
927
928 DPRINT("IopSetDeviceInstanceData() called\n");
929
930 /* Create the 'LogConf' key */
931 RtlInitUnicodeString(&KeyName, L"LogConf");
932 InitializeObjectAttributes(&ObjectAttributes,
933 &KeyName,
934 OBJ_CASE_INSENSITIVE,
935 InstanceKey,
936 NULL);
937 Status = ZwCreateKey(&LogConfKey,
938 KEY_ALL_ACCESS,
939 &ObjectAttributes,
940 0,
941 NULL,
942 0,
943 NULL);
944 if (NT_SUCCESS(Status))
945 {
946 /* Set 'BootConfig' value */
947 if (DeviceNode->BootResources != NULL)
948 {
949 ResCount = DeviceNode->BootResources->Count;
950 if (ResCount != 0)
951 {
952 RtlInitUnicodeString(&KeyName, L"BootConfig");
953 Status = ZwSetValueKey(LogConfKey,
954 &KeyName,
955 0,
956 REG_RESOURCE_LIST,
957 DeviceNode->BootResources,
958 PnpDetermineResourceListSize(DeviceNode->BootResources));
959 }
960 }
961
962 /* Set 'BasicConfigVector' value */
963 if (DeviceNode->ResourceRequirements != NULL &&
964 DeviceNode->ResourceRequirements->ListSize != 0)
965 {
966 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
967 Status = ZwSetValueKey(LogConfKey,
968 &KeyName,
969 0,
970 REG_RESOURCE_REQUIREMENTS_LIST,
971 DeviceNode->ResourceRequirements,
972 DeviceNode->ResourceRequirements->ListSize);
973 }
974
975 ZwClose(LogConfKey);
976 }
977
978 /* Set the 'ConfigFlags' value */
979 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
980 Status = ZwQueryValueKey(InstanceKey,
981 &KeyName,
982 KeyValueBasicInformation,
983 NULL,
984 0,
985 &ResultLength);
986 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
987 {
988 /* Write the default value */
989 ULONG DefaultConfigFlags = 0;
990 Status = ZwSetValueKey(InstanceKey,
991 &KeyName,
992 0,
993 REG_DWORD,
994 &DefaultConfigFlags,
995 sizeof(DefaultConfigFlags));
996 }
997
998 /* Create the 'Control' key */
999 RtlInitUnicodeString(&KeyName, L"Control");
1000 InitializeObjectAttributes(&ObjectAttributes,
1001 &KeyName,
1002 OBJ_CASE_INSENSITIVE,
1003 InstanceKey,
1004 NULL);
1005 Status = ZwCreateKey(&ControlHandle, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
1006
1007 if (NT_SUCCESS(Status))
1008 ZwClose(ControlHandle);
1009
1010 DPRINT("IopSetDeviceInstanceData() done\n");
1011
1012 return Status;
1013 }
1014
1015 /*
1016 * IopGetParentIdPrefix
1017 *
1018 * Retrieve (or create) a string which identifies a device.
1019 *
1020 * Parameters
1021 * DeviceNode
1022 * Pointer to device node.
1023 * ParentIdPrefix
1024 * Pointer to the string where is returned the parent node identifier
1025 *
1026 * Remarks
1027 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1028 * valid and its Buffer field is NULL-terminated. The caller needs to
1029 * to free the string with RtlFreeUnicodeString when it is no longer
1030 * needed.
1031 */
1032
1033 NTSTATUS
1034 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1035 PUNICODE_STRING ParentIdPrefix)
1036 {
1037 ULONG KeyNameBufferLength;
1038 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1039 UNICODE_STRING KeyName;
1040 UNICODE_STRING KeyValue;
1041 UNICODE_STRING ValueName;
1042 HANDLE hKey = NULL;
1043 ULONG crc32;
1044 NTSTATUS Status;
1045
1046 /* HACK: As long as some devices have a NULL device
1047 * instance path, the following test is required :(
1048 */
1049 if (DeviceNode->Parent->InstancePath.Length == 0)
1050 {
1051 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1052 &DeviceNode->InstancePath);
1053 return STATUS_UNSUCCESSFUL;
1054 }
1055
1056 /* 1. Try to retrieve ParentIdPrefix from registry */
1057 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1058 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
1059 if (!ParentIdPrefixInformation)
1060 {
1061 Status = STATUS_INSUFFICIENT_RESOURCES;
1062 goto cleanup;
1063 }
1064
1065
1066 KeyName.Buffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
1067 if (!KeyName.Buffer)
1068 {
1069 Status = STATUS_INSUFFICIENT_RESOURCES;
1070 goto cleanup;
1071 }
1072 KeyName.Length = 0;
1073 KeyName.MaximumLength = (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length;
1074
1075 RtlAppendUnicodeToString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1076 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1077
1078 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
1079 if (!NT_SUCCESS(Status))
1080 goto cleanup;
1081 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1082 Status = ZwQueryValueKey(
1083 hKey, &ValueName,
1084 KeyValuePartialInformation, ParentIdPrefixInformation,
1085 KeyNameBufferLength, &KeyNameBufferLength);
1086 if (NT_SUCCESS(Status))
1087 {
1088 if (ParentIdPrefixInformation->Type != REG_SZ)
1089 Status = STATUS_UNSUCCESSFUL;
1090 else
1091 {
1092 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1093 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1094 }
1095 goto cleanup;
1096 }
1097 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1098 {
1099 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1100 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1101 goto cleanup;
1102 }
1103
1104 /* 2. Create the ParentIdPrefix value */
1105 crc32 = RtlComputeCrc32(0,
1106 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1107 DeviceNode->Parent->InstancePath.Length);
1108
1109 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
1110 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
1111
1112 /* 3. Try to write the ParentIdPrefix to registry */
1113 Status = ZwSetValueKey(hKey,
1114 &ValueName,
1115 0,
1116 REG_SZ,
1117 (PVOID)KeyValue.Buffer,
1118 (wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1119
1120 cleanup:
1121 if (NT_SUCCESS(Status))
1122 {
1123 /* Duplicate the string to return it */
1124 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
1125 }
1126 ExFreePool(ParentIdPrefixInformation);
1127 RtlFreeUnicodeString(&KeyName);
1128 if (hKey != NULL)
1129 ZwClose(hKey);
1130 return Status;
1131 }
1132
1133
1134 /*
1135 * IopActionInterrogateDeviceStack
1136 *
1137 * Retrieve information for all (direct) child nodes of a parent node.
1138 *
1139 * Parameters
1140 * DeviceNode
1141 * Pointer to device node.
1142 * Context
1143 * Pointer to parent node to retrieve child node information for.
1144 *
1145 * Remarks
1146 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1147 * when we reach a device node which is not a direct child of the device
1148 * node for which we retrieve information of child nodes for. Any errors
1149 * that occur is logged instead so that all child services have a chance
1150 * of being interrogated.
1151 */
1152
1153 NTSTATUS
1154 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
1155 PVOID Context)
1156 {
1157 IO_STATUS_BLOCK IoStatusBlock;
1158 PDEVICE_NODE ParentDeviceNode;
1159 WCHAR InstancePath[MAX_PATH];
1160 IO_STACK_LOCATION Stack;
1161 NTSTATUS Status;
1162 PWSTR Ptr;
1163 USHORT Length;
1164 USHORT TotalLength;
1165 ULONG RequiredLength;
1166 LCID LocaleId;
1167 HANDLE InstanceKey = NULL;
1168 UNICODE_STRING ValueName;
1169 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
1170 DEVICE_CAPABILITIES DeviceCapabilities;
1171
1172 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1173 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1174
1175 ParentDeviceNode = (PDEVICE_NODE)Context;
1176
1177 /*
1178 * We are called for the parent too, but we don't need to do special
1179 * handling for this node
1180 */
1181
1182 if (DeviceNode == ParentDeviceNode)
1183 {
1184 DPRINT("Success\n");
1185 return STATUS_SUCCESS;
1186 }
1187
1188 /*
1189 * Make sure this device node is a direct child of the parent device node
1190 * that is given as an argument
1191 */
1192
1193 if (DeviceNode->Parent != ParentDeviceNode)
1194 {
1195 /* Stop the traversal immediately and indicate successful operation */
1196 DPRINT("Stop\n");
1197 return STATUS_UNSUCCESSFUL;
1198 }
1199
1200 /* Get Locale ID */
1201 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
1202 if (!NT_SUCCESS(Status))
1203 {
1204 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
1205 return Status;
1206 }
1207
1208 /*
1209 * FIXME: For critical errors, cleanup and disable device, but always
1210 * return STATUS_SUCCESS.
1211 */
1212
1213 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1214
1215 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1216 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1217 &IoStatusBlock,
1218 IRP_MN_QUERY_ID,
1219 &Stack);
1220 if (NT_SUCCESS(Status))
1221 {
1222 /* Copy the device id string */
1223 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
1224
1225 /*
1226 * FIXME: Check for valid characters, if there is invalid characters
1227 * then bugcheck.
1228 */
1229 }
1230 else
1231 {
1232 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1233 }
1234
1235 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
1236
1237 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1238 if (!NT_SUCCESS(Status))
1239 {
1240 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1241 }
1242
1243 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
1244
1245 if (!DeviceCapabilities.UniqueID)
1246 {
1247 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1248 DPRINT("Instance ID is not unique\n");
1249 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1250 if (!NT_SUCCESS(Status))
1251 {
1252 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1253 }
1254 }
1255
1256 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1257
1258 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1259 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1260 &IoStatusBlock,
1261 IRP_MN_QUERY_ID,
1262 &Stack);
1263 if (NT_SUCCESS(Status))
1264 {
1265 /* Append the instance id string */
1266 wcscat(InstancePath, L"\\");
1267 if (ParentIdPrefix.Length > 0)
1268 {
1269 /* Add information from parent bus device to InstancePath */
1270 wcscat(InstancePath, ParentIdPrefix.Buffer);
1271 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
1272 wcscat(InstancePath, L"&");
1273 }
1274 if (IoStatusBlock.Information)
1275 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1276
1277 /*
1278 * FIXME: Check for valid characters, if there is invalid characters
1279 * then bugcheck
1280 */
1281 }
1282 else
1283 {
1284 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1285 }
1286 RtlFreeUnicodeString(&ParentIdPrefix);
1287
1288 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
1289 {
1290 DPRINT("No resources\n");
1291 /* FIXME: Cleanup and disable device */
1292 }
1293
1294 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1295
1296 /*
1297 * Create registry key for the instance id, if it doesn't exist yet
1298 */
1299 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
1300 if (!NT_SUCCESS(Status))
1301 {
1302 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1303 }
1304
1305 {
1306 /* Set 'Capabilities' value */
1307 RtlInitUnicodeString(&ValueName, L"Capabilities");
1308 Status = ZwSetValueKey(InstanceKey,
1309 &ValueName,
1310 0,
1311 REG_DWORD,
1312 (PVOID)&DeviceNode->CapabilityFlags,
1313 sizeof(ULONG));
1314
1315 /* Set 'UINumber' value */
1316 if (DeviceCapabilities.UINumber != MAXULONG)
1317 {
1318 RtlInitUnicodeString(&ValueName, L"UINumber");
1319 Status = ZwSetValueKey(InstanceKey,
1320 &ValueName,
1321 0,
1322 REG_DWORD,
1323 &DeviceCapabilities.UINumber,
1324 sizeof(ULONG));
1325 }
1326 }
1327
1328 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1329
1330 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1331 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1332 &IoStatusBlock,
1333 IRP_MN_QUERY_ID,
1334 &Stack);
1335 if (NT_SUCCESS(Status))
1336 {
1337 /*
1338 * FIXME: Check for valid characters, if there is invalid characters
1339 * then bugcheck.
1340 */
1341 TotalLength = 0;
1342 Ptr = (PWSTR)IoStatusBlock.Information;
1343 DPRINT("Hardware IDs:\n");
1344 while (*Ptr)
1345 {
1346 DPRINT(" %S\n", Ptr);
1347 Length = wcslen(Ptr) + 1;
1348
1349 Ptr += Length;
1350 TotalLength += Length;
1351 }
1352 DPRINT("TotalLength: %hu\n", TotalLength);
1353 DPRINT("\n");
1354
1355 RtlInitUnicodeString(&ValueName, L"HardwareID");
1356 Status = ZwSetValueKey(InstanceKey,
1357 &ValueName,
1358 0,
1359 REG_MULTI_SZ,
1360 (PVOID)IoStatusBlock.Information,
1361 (TotalLength + 1) * sizeof(WCHAR));
1362 if (!NT_SUCCESS(Status))
1363 {
1364 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1365 }
1366 }
1367 else
1368 {
1369 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1370 }
1371
1372 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1373
1374 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1375 Status = IopInitiatePnpIrp(
1376 DeviceNode->PhysicalDeviceObject,
1377 &IoStatusBlock,
1378 IRP_MN_QUERY_ID,
1379 &Stack);
1380 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1381 {
1382 /*
1383 * FIXME: Check for valid characters, if there is invalid characters
1384 * then bugcheck.
1385 */
1386 TotalLength = 0;
1387 Ptr = (PWSTR)IoStatusBlock.Information;
1388 DPRINT("Compatible IDs:\n");
1389 while (*Ptr)
1390 {
1391 DPRINT(" %S\n", Ptr);
1392 Length = wcslen(Ptr) + 1;
1393
1394 Ptr += Length;
1395 TotalLength += Length;
1396 }
1397 DPRINT("TotalLength: %hu\n", TotalLength);
1398 DPRINT("\n");
1399
1400 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1401 Status = ZwSetValueKey(InstanceKey,
1402 &ValueName,
1403 0,
1404 REG_MULTI_SZ,
1405 (PVOID)IoStatusBlock.Information,
1406 (TotalLength + 1) * sizeof(WCHAR));
1407 if (!NT_SUCCESS(Status))
1408 {
1409 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1410 }
1411 }
1412 else
1413 {
1414 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1415 }
1416
1417 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1418
1419 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
1420 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
1421 Status = IopInitiatePnpIrp(
1422 DeviceNode->PhysicalDeviceObject,
1423 &IoStatusBlock,
1424 IRP_MN_QUERY_DEVICE_TEXT,
1425 &Stack);
1426 /* This key is mandatory, so even if the Irp fails, we still write it */
1427 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
1428 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
1429 {
1430 if (NT_SUCCESS(Status) &&
1431 IoStatusBlock.Information &&
1432 (*(PWSTR)IoStatusBlock.Information != 0))
1433 {
1434 /* This key is overriden when a driver is installed. Don't write the
1435 * new description if another one already exists */
1436 Status = ZwSetValueKey(InstanceKey,
1437 &ValueName,
1438 0,
1439 REG_SZ,
1440 (PVOID)IoStatusBlock.Information,
1441 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1442 }
1443 else
1444 {
1445 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
1446 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
1447
1448 Status = ZwSetValueKey(InstanceKey,
1449 &ValueName,
1450 0,
1451 REG_SZ,
1452 DeviceDesc.Buffer,
1453 DeviceDesc.MaximumLength);
1454
1455 if (!NT_SUCCESS(Status))
1456 {
1457 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
1458 }
1459
1460 }
1461 }
1462
1463 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1464
1465 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
1466 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
1467 Status = IopInitiatePnpIrp(
1468 DeviceNode->PhysicalDeviceObject,
1469 &IoStatusBlock,
1470 IRP_MN_QUERY_DEVICE_TEXT,
1471 &Stack);
1472 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1473 {
1474 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
1475 RtlInitUnicodeString(&ValueName, L"LocationInformation");
1476 Status = ZwSetValueKey(InstanceKey,
1477 &ValueName,
1478 0,
1479 REG_SZ,
1480 (PVOID)IoStatusBlock.Information,
1481 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1482 if (!NT_SUCCESS(Status))
1483 {
1484 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1485 }
1486 }
1487 else
1488 {
1489 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1490 }
1491
1492 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1493
1494 Status = IopInitiatePnpIrp(
1495 DeviceNode->PhysicalDeviceObject,
1496 &IoStatusBlock,
1497 IRP_MN_QUERY_BUS_INFORMATION,
1498 NULL);
1499 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1500 {
1501 PPNP_BUS_INFORMATION BusInformation =
1502 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
1503
1504 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
1505 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
1506 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
1507 ExFreePool(BusInformation);
1508 }
1509 else
1510 {
1511 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1512
1513 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
1514 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
1515 DeviceNode->ChildBusTypeIndex = -1;
1516 }
1517
1518 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1519
1520 Status = IopInitiatePnpIrp(
1521 DeviceNode->PhysicalDeviceObject,
1522 &IoStatusBlock,
1523 IRP_MN_QUERY_RESOURCES,
1524 NULL);
1525 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1526 {
1527 DeviceNode->BootResources =
1528 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
1529 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
1530 }
1531 else
1532 {
1533 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1534 DeviceNode->BootResources = NULL;
1535 }
1536
1537 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1538
1539 Status = IopInitiatePnpIrp(
1540 DeviceNode->PhysicalDeviceObject,
1541 &IoStatusBlock,
1542 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
1543 NULL);
1544 if (NT_SUCCESS(Status))
1545 {
1546 DeviceNode->ResourceRequirements =
1547 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
1548 }
1549 else
1550 {
1551 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
1552 DeviceNode->ResourceRequirements = NULL;
1553 }
1554
1555 if (InstanceKey != NULL)
1556 {
1557 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
1558 }
1559
1560 ZwClose(InstanceKey);
1561
1562 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
1563
1564 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
1565 {
1566 /* Report the device to the user-mode pnp manager */
1567 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
1568 &DeviceNode->InstancePath);
1569 }
1570
1571 return STATUS_SUCCESS;
1572 }
1573
1574
1575 NTSTATUS
1576 IopEnumerateDevice(
1577 IN PDEVICE_OBJECT DeviceObject)
1578 {
1579 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1580 DEVICETREE_TRAVERSE_CONTEXT Context;
1581 PDEVICE_RELATIONS DeviceRelations;
1582 PDEVICE_OBJECT ChildDeviceObject;
1583 IO_STATUS_BLOCK IoStatusBlock;
1584 PDEVICE_NODE ChildDeviceNode;
1585 IO_STACK_LOCATION Stack;
1586 NTSTATUS Status;
1587 ULONG i;
1588
1589 DPRINT("DeviceObject 0x%p\n", DeviceObject);
1590
1591 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
1592
1593 /* Report the device to the user-mode pnp manager */
1594 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
1595 &DeviceNode->InstancePath);
1596
1597 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1598
1599 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
1600
1601 Status = IopInitiatePnpIrp(
1602 DeviceObject,
1603 &IoStatusBlock,
1604 IRP_MN_QUERY_DEVICE_RELATIONS,
1605 &Stack);
1606 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1607 {
1608 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
1609 return Status;
1610 }
1611
1612 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1613
1614 if (!DeviceRelations)
1615 {
1616 DPRINT("No PDOs\n");
1617 return STATUS_UNSUCCESSFUL;
1618 }
1619
1620 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
1621
1622 /*
1623 * Create device nodes for all discovered devices
1624 */
1625 for (i = 0; i < DeviceRelations->Count; i++)
1626 {
1627 ChildDeviceObject = DeviceRelations->Objects[i];
1628 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
1629
1630 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
1631 if (!ChildDeviceNode)
1632 {
1633 /* One doesn't exist, create it */
1634 Status = IopCreateDeviceNode(
1635 DeviceNode,
1636 ChildDeviceObject,
1637 NULL,
1638 &ChildDeviceNode);
1639 if (NT_SUCCESS(Status))
1640 {
1641 /* Mark the node as enumerated */
1642 ChildDeviceNode->Flags |= DNF_ENUMERATED;
1643
1644 /* Mark the DO as bus enumerated */
1645 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
1646 }
1647 else
1648 {
1649 /* Ignore this DO */
1650 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
1651 ObDereferenceObject(ChildDeviceNode);
1652 }
1653 }
1654 else
1655 {
1656 /* Mark it as enumerated */
1657 ChildDeviceNode->Flags |= DNF_ENUMERATED;
1658 ObDereferenceObject(ChildDeviceObject);
1659 }
1660 }
1661 ExFreePool(DeviceRelations);
1662
1663 /*
1664 * Retrieve information about all discovered children from the bus driver
1665 */
1666 IopInitDeviceTreeTraverseContext(
1667 &Context,
1668 DeviceNode,
1669 IopActionInterrogateDeviceStack,
1670 DeviceNode);
1671
1672 Status = IopTraverseDeviceTree(&Context);
1673 if (!NT_SUCCESS(Status))
1674 {
1675 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
1676 return Status;
1677 }
1678
1679 /*
1680 * Retrieve configuration from the registry for discovered children
1681 */
1682 IopInitDeviceTreeTraverseContext(
1683 &Context,
1684 DeviceNode,
1685 IopActionConfigureChildServices,
1686 DeviceNode);
1687
1688 Status = IopTraverseDeviceTree(&Context);
1689 if (!NT_SUCCESS(Status))
1690 {
1691 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
1692 return Status;
1693 }
1694
1695 /*
1696 * Initialize services for discovered children.
1697 */
1698 Status = IopInitializePnpServices(DeviceNode);
1699 if (!NT_SUCCESS(Status))
1700 {
1701 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
1702 return Status;
1703 }
1704
1705 DPRINT("IopEnumerateDevice() finished\n");
1706 return STATUS_SUCCESS;
1707 }
1708
1709
1710 /*
1711 * IopActionConfigureChildServices
1712 *
1713 * Retrieve configuration for all (direct) child nodes of a parent node.
1714 *
1715 * Parameters
1716 * DeviceNode
1717 * Pointer to device node.
1718 * Context
1719 * Pointer to parent node to retrieve child node configuration for.
1720 *
1721 * Remarks
1722 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1723 * when we reach a device node which is not a direct child of the device
1724 * node for which we configure child services for. Any errors that occur is
1725 * logged instead so that all child services have a chance of beeing
1726 * configured.
1727 */
1728
1729 NTSTATUS
1730 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
1731 PVOID Context)
1732 {
1733 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1734 PDEVICE_NODE ParentDeviceNode;
1735 PUNICODE_STRING Service;
1736 UNICODE_STRING ClassGUID;
1737 NTSTATUS Status;
1738 DEVICE_CAPABILITIES DeviceCaps;
1739
1740 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
1741
1742 ParentDeviceNode = (PDEVICE_NODE)Context;
1743
1744 /*
1745 * We are called for the parent too, but we don't need to do special
1746 * handling for this node
1747 */
1748 if (DeviceNode == ParentDeviceNode)
1749 {
1750 DPRINT("Success\n");
1751 return STATUS_SUCCESS;
1752 }
1753
1754 /*
1755 * Make sure this device node is a direct child of the parent device node
1756 * that is given as an argument
1757 */
1758 if (DeviceNode->Parent != ParentDeviceNode)
1759 {
1760 /* Stop the traversal immediately and indicate successful operation */
1761 DPRINT("Stop\n");
1762 return STATUS_UNSUCCESSFUL;
1763 }
1764
1765 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
1766 {
1767 WCHAR RegKeyBuffer[MAX_PATH];
1768 UNICODE_STRING RegKey;
1769
1770 RegKey.Length = 0;
1771 RegKey.MaximumLength = sizeof(RegKeyBuffer);
1772 RegKey.Buffer = RegKeyBuffer;
1773
1774 /*
1775 * Retrieve configuration from Enum key
1776 */
1777
1778 Service = &DeviceNode->ServiceName;
1779
1780 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1781 RtlInitUnicodeString(Service, NULL);
1782 RtlInitUnicodeString(&ClassGUID, NULL);
1783
1784 QueryTable[0].Name = L"Service";
1785 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1786 QueryTable[0].EntryContext = Service;
1787
1788 QueryTable[1].Name = L"ClassGUID";
1789 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1790 QueryTable[1].EntryContext = &ClassGUID;
1791 QueryTable[1].DefaultType = REG_SZ;
1792 QueryTable[1].DefaultData = L"";
1793 QueryTable[1].DefaultLength = 0;
1794
1795 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1796 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
1797
1798 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1799 RegKey.Buffer, QueryTable, NULL, NULL);
1800
1801 if (!NT_SUCCESS(Status))
1802 {
1803 /* FIXME: Log the error */
1804 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
1805 &DeviceNode->InstancePath, Status);
1806 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1807 return STATUS_SUCCESS;
1808 }
1809
1810 if (Service->Buffer == NULL)
1811 {
1812 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
1813 DeviceCaps.RawDeviceOK)
1814 {
1815 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
1816
1817 DeviceNode->ServiceName.Length = 0;
1818 DeviceNode->ServiceName.MaximumLength = 0;
1819 DeviceNode->ServiceName.Buffer = NULL;
1820 }
1821 else if (ClassGUID.Length != 0)
1822 {
1823 /* Device has a ClassGUID value, but no Service value.
1824 * Suppose it is using the NULL driver, so state the
1825 * device is started */
1826 DPRINT1("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
1827 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
1828 }
1829 else
1830 {
1831 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1832 }
1833 return STATUS_SUCCESS;
1834 }
1835
1836 DPRINT("Got Service %S\n", Service->Buffer);
1837 }
1838
1839 return STATUS_SUCCESS;
1840 }
1841
1842 /*
1843 * IopActionInitChildServices
1844 *
1845 * Initialize the service for all (direct) child nodes of a parent node
1846 *
1847 * Parameters
1848 * DeviceNode
1849 * Pointer to device node.
1850 * Context
1851 * Pointer to parent node to initialize child node services for.
1852 *
1853 * Remarks
1854 * If the driver image for a service is not loaded and initialized
1855 * it is done here too. We only return a status code indicating an
1856 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
1857 * not a direct child of the device node for which we initialize
1858 * child services for. Any errors that occur is logged instead so
1859 * that all child services have a chance of being initialized.
1860 */
1861
1862 NTSTATUS
1863 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
1864 PVOID Context)
1865 {
1866 PDEVICE_NODE ParentDeviceNode;
1867 NTSTATUS Status;
1868 BOOLEAN BootDrivers = !PnpSystemInit;
1869
1870 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
1871
1872 ParentDeviceNode = (PDEVICE_NODE)Context;
1873
1874 /*
1875 * We are called for the parent too, but we don't need to do special
1876 * handling for this node
1877 */
1878 if (DeviceNode == ParentDeviceNode)
1879 {
1880 DPRINT("Success\n");
1881 return STATUS_SUCCESS;
1882 }
1883
1884 /*
1885 * Make sure this device node is a direct child of the parent device node
1886 * that is given as an argument
1887 */
1888 #if 0
1889 if (DeviceNode->Parent != ParentDeviceNode)
1890 {
1891 /*
1892 * Stop the traversal immediately and indicate unsuccessful operation
1893 */
1894 DPRINT("Stop\n");
1895 return STATUS_UNSUCCESSFUL;
1896 }
1897 #endif
1898 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
1899 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
1900 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
1901 return STATUS_SUCCESS;
1902
1903 if (DeviceNode->ServiceName.Buffer == NULL)
1904 {
1905 /* We don't need to worry about loading the driver because we're
1906 * being driven in raw mode so our parent must be loaded to get here */
1907 Status = IopInitializeDevice(DeviceNode, NULL);
1908 if (NT_SUCCESS(Status))
1909 {
1910 Status = IopStartDevice(DeviceNode);
1911 if (!NT_SUCCESS(Status))
1912 {
1913 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
1914 &DeviceNode->InstancePath, Status);
1915 }
1916 }
1917 }
1918 else
1919 {
1920 PLDR_DATA_TABLE_ENTRY ModuleObject;
1921 PDRIVER_OBJECT DriverObject;
1922
1923 /* Get existing DriverObject pointer (in case the driver has
1924 already been loaded and initialized) */
1925 Status = IopGetDriverObject(
1926 &DriverObject,
1927 &DeviceNode->ServiceName,
1928 FALSE);
1929
1930 if (!NT_SUCCESS(Status))
1931 {
1932 /* Driver is not initialized, try to load it */
1933 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
1934
1935 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
1936 {
1937 /* STATUS_IMAGE_ALREADY_LOADED means this driver
1938 was loaded by the bootloader */
1939 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
1940 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
1941 {
1942 /* Initialize the driver */
1943 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
1944 &DeviceNode->ServiceName, FALSE, &DriverObject);
1945 }
1946 else
1947 {
1948 Status = STATUS_SUCCESS;
1949 }
1950 }
1951 else
1952 {
1953 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
1954 &DeviceNode->ServiceName, Status);
1955 }
1956 }
1957
1958 /* Driver is loaded and initialized at this point */
1959 if (NT_SUCCESS(Status))
1960 {
1961 /* Initialize the device, including all filters */
1962 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
1963 }
1964 else
1965 {
1966 /*
1967 * Don't disable when trying to load only boot drivers
1968 */
1969 if (!BootDrivers)
1970 {
1971 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1972 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
1973 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
1974 DPRINT1("Initialization of service %S failed (Status %x)\n",
1975 DeviceNode->ServiceName.Buffer, Status);
1976 }
1977 }
1978 }
1979
1980 return STATUS_SUCCESS;
1981 }
1982
1983 /*
1984 * IopInitializePnpServices
1985 *
1986 * Initialize services for discovered children
1987 *
1988 * Parameters
1989 * DeviceNode
1990 * Top device node to start initializing services.
1991 *
1992 * Return Value
1993 * Status
1994 */
1995 NTSTATUS
1996 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
1997 {
1998 DEVICETREE_TRAVERSE_CONTEXT Context;
1999
2000 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2001
2002 IopInitDeviceTreeTraverseContext(
2003 &Context,
2004 DeviceNode,
2005 IopActionInitChildServices,
2006 DeviceNode);
2007
2008 return IopTraverseDeviceTree(&Context);
2009 }
2010
2011 static NTSTATUS INIT_FUNCTION
2012 IopEnumerateDetectedDevices(
2013 IN HANDLE hBaseKey,
2014 IN PUNICODE_STRING RelativePath OPTIONAL,
2015 IN HANDLE hRootKey,
2016 IN BOOLEAN EnumerateSubKeys,
2017 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2018 IN ULONG ParentBootResourcesLength)
2019 {
2020 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2021 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2022 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2023 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2024 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2025 OBJECT_ATTRIBUTES ObjectAttributes;
2026 HANDLE hDevicesKey = NULL;
2027 HANDLE hDeviceKey = NULL;
2028 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2029 UNICODE_STRING Level2NameU;
2030 WCHAR Level2Name[5];
2031 ULONG IndexDevice = 0;
2032 ULONG IndexSubKey;
2033 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2034 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2035 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2036 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2037 UNICODE_STRING DeviceName, ValueName;
2038 ULONG RequiredSize;
2039 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2040 ULONG BootResourcesLength;
2041 NTSTATUS Status;
2042
2043 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
2044 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
2045 static ULONG DeviceIndexPci = 0;
2046 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2047 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2048 static ULONG DeviceIndexSerial = 0;
2049 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2050 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2051 static ULONG DeviceIndexKeyboard = 0;
2052 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2053 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2054 static ULONG DeviceIndexMouse = 0;
2055 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2056 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2057 static ULONG DeviceIndexParallel = 0;
2058 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2059 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2060 static ULONG DeviceIndexFloppy = 0;
2061 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
2062 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
2063 static ULONG DeviceIndexIsa = 0;
2064 UNICODE_STRING HardwareIdKey;
2065 PUNICODE_STRING pHardwareId;
2066 ULONG DeviceIndex = 0;
2067 PUCHAR CmResourceList;
2068 ULONG ListCount;
2069
2070 if (RelativePath)
2071 {
2072 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2073 if (!NT_SUCCESS(Status))
2074 {
2075 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2076 goto cleanup;
2077 }
2078 }
2079 else
2080 hDevicesKey = hBaseKey;
2081
2082 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2083 if (!pDeviceInformation)
2084 {
2085 DPRINT("ExAllocatePool() failed\n");
2086 Status = STATUS_NO_MEMORY;
2087 goto cleanup;
2088 }
2089
2090 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2091 if (!pValueInformation)
2092 {
2093 DPRINT("ExAllocatePool() failed\n");
2094 Status = STATUS_NO_MEMORY;
2095 goto cleanup;
2096 }
2097
2098 while (TRUE)
2099 {
2100 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2101 if (Status == STATUS_NO_MORE_ENTRIES)
2102 break;
2103 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2104 {
2105 ExFreePool(pDeviceInformation);
2106 DeviceInfoLength = RequiredSize;
2107 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2108 if (!pDeviceInformation)
2109 {
2110 DPRINT("ExAllocatePool() failed\n");
2111 Status = STATUS_NO_MEMORY;
2112 goto cleanup;
2113 }
2114 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2115 }
2116 if (!NT_SUCCESS(Status))
2117 {
2118 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2119 goto cleanup;
2120 }
2121 IndexDevice++;
2122
2123 /* Open device key */
2124 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2125 DeviceName.Buffer = pDeviceInformation->Name;
2126
2127 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
2128 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
2129 if (!NT_SUCCESS(Status))
2130 {
2131 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2132 goto cleanup;
2133 }
2134
2135 /* Read boot resources, and add then to parent ones */
2136 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2137 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2138 {
2139 ExFreePool(pValueInformation);
2140 ValueInfoLength = RequiredSize;
2141 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2142 if (!pValueInformation)
2143 {
2144 DPRINT("ExAllocatePool() failed\n");
2145 ZwDeleteKey(hLevel2Key);
2146 Status = STATUS_NO_MEMORY;
2147 goto cleanup;
2148 }
2149 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2150 }
2151 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2152 {
2153 BootResources = ParentBootResources;
2154 BootResourcesLength = ParentBootResourcesLength;
2155 }
2156 else if (!NT_SUCCESS(Status))
2157 {
2158 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2159 goto nextdevice;
2160 }
2161 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2162 {
2163 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2164 goto nextdevice;
2165 }
2166 else
2167 {
2168 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2169
2170 /* Concatenate current resources and parent ones */
2171 if (ParentBootResourcesLength == 0)
2172 BootResourcesLength = pValueInformation->DataLength;
2173 else
2174 BootResourcesLength = ParentBootResourcesLength
2175 + pValueInformation->DataLength
2176 - Header;
2177 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2178 if (!BootResources)
2179 {
2180 DPRINT("ExAllocatePool() failed\n");
2181 goto nextdevice;
2182 }
2183 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2184 {
2185 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2186 }
2187 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2188 {
2189 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2190 RtlCopyMemory(
2191 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2192 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2193 ParentBootResourcesLength - Header);
2194 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2195 }
2196 else
2197 {
2198 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2199 RtlCopyMemory(
2200 (PVOID)((ULONG_PTR)BootResources + Header),
2201 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2202 ParentBootResourcesLength - Header);
2203 RtlCopyMemory(
2204 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2205 pValueInformation->Data + Header,
2206 pValueInformation->DataLength - Header);
2207 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2208 }
2209 }
2210
2211 if (EnumerateSubKeys)
2212 {
2213 IndexSubKey = 0;
2214 while (TRUE)
2215 {
2216 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2217 if (Status == STATUS_NO_MORE_ENTRIES)
2218 break;
2219 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2220 {
2221 ExFreePool(pDeviceInformation);
2222 DeviceInfoLength = RequiredSize;
2223 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2224 if (!pDeviceInformation)
2225 {
2226 DPRINT("ExAllocatePool() failed\n");
2227 Status = STATUS_NO_MEMORY;
2228 goto cleanup;
2229 }
2230 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2231 }
2232 if (!NT_SUCCESS(Status))
2233 {
2234 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2235 goto cleanup;
2236 }
2237 IndexSubKey++;
2238 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2239 DeviceName.Buffer = pDeviceInformation->Name;
2240
2241 Status = IopEnumerateDetectedDevices(
2242 hDeviceKey,
2243 &DeviceName,
2244 hRootKey,
2245 TRUE,
2246 BootResources,
2247 BootResourcesLength);
2248 if (!NT_SUCCESS(Status))
2249 goto cleanup;
2250 }
2251 }
2252
2253 /* Read identifier */
2254 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2255 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2256 {
2257 ExFreePool(pValueInformation);
2258 ValueInfoLength = RequiredSize;
2259 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2260 if (!pValueInformation)
2261 {
2262 DPRINT("ExAllocatePool() failed\n");
2263 Status = STATUS_NO_MEMORY;
2264 goto cleanup;
2265 }
2266 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2267 }
2268 if (!NT_SUCCESS(Status))
2269 {
2270 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2271 {
2272 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2273 goto nextdevice;
2274 }
2275 ValueName.Length = ValueName.MaximumLength = 0;
2276 }
2277 else if (pValueInformation->Type != REG_SZ)
2278 {
2279 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2280 goto nextdevice;
2281 }
2282 else
2283 {
2284 /* Assign hardware id to this device */
2285 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
2286 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2287 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2288 ValueName.Length -= sizeof(WCHAR);
2289 }
2290
2291 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
2292 {
2293 pHardwareId = &HardwareIdSerial;
2294 DeviceIndex = DeviceIndexSerial++;
2295 }
2296 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
2297 {
2298 pHardwareId = &HardwareIdKeyboard;
2299 DeviceIndex = DeviceIndexKeyboard++;
2300 }
2301 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
2302 {
2303 pHardwareId = &HardwareIdMouse;
2304 DeviceIndex = DeviceIndexMouse++;
2305 }
2306 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
2307 {
2308 pHardwareId = &HardwareIdParallel;
2309 DeviceIndex = DeviceIndexParallel++;
2310 }
2311 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
2312 {
2313 pHardwareId = &HardwareIdFloppy;
2314 DeviceIndex = DeviceIndexFloppy++;
2315 }
2316 else if (NT_SUCCESS(Status))
2317 {
2318 /* Try to also match the device identifier */
2319 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
2320 {
2321 pHardwareId = &HardwareIdPci;
2322 DeviceIndex = DeviceIndexPci++;
2323 }
2324 else if (RtlCompareUnicodeString(&ValueName, &IdentifierIsa, FALSE) == 0)
2325 {
2326 pHardwareId = &HardwareIdIsa;
2327 DeviceIndex = DeviceIndexIsa++;
2328 }
2329 else
2330 {
2331 DPRINT("Unknown device '%wZ'\n", &ValueName);
2332 goto nextdevice;
2333 }
2334 }
2335 else
2336 {
2337 /* Unknown key path */
2338 DPRINT("Unknown key path '%wZ'\n", RelativePath);
2339 goto nextdevice;
2340 }
2341
2342 /* Prepare hardware id key (hardware id value without final \0) */
2343 HardwareIdKey = *pHardwareId;
2344 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
2345
2346 /* Add the detected device to Root key */
2347 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
2348 Status = ZwCreateKey(
2349 &hLevel1Key,
2350 KEY_CREATE_SUB_KEY,
2351 &ObjectAttributes,
2352 0,
2353 NULL,
2354 REG_OPTION_NON_VOLATILE,
2355 NULL);
2356 if (!NT_SUCCESS(Status))
2357 {
2358 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2359 goto nextdevice;
2360 }
2361 swprintf(Level2Name, L"%04lu", DeviceIndex);
2362 RtlInitUnicodeString(&Level2NameU, Level2Name);
2363 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
2364 Status = ZwCreateKey(
2365 &hLevel2Key,
2366 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
2367 &ObjectAttributes,
2368 0,
2369 NULL,
2370 REG_OPTION_NON_VOLATILE,
2371 NULL);
2372 ZwClose(hLevel1Key);
2373 if (!NT_SUCCESS(Status))
2374 {
2375 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2376 goto nextdevice;
2377 }
2378 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
2379 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
2380 if (!NT_SUCCESS(Status))
2381 {
2382 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2383 ZwDeleteKey(hLevel2Key);
2384 goto nextdevice;
2385 }
2386 /* Create 'LogConf' subkey */
2387 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
2388 Status = ZwCreateKey(
2389 &hLogConf,
2390 KEY_SET_VALUE,
2391 &ObjectAttributes,
2392 0,
2393 NULL,
2394 REG_OPTION_VOLATILE,
2395 NULL);
2396 if (!NT_SUCCESS(Status))
2397 {
2398 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2399 ZwDeleteKey(hLevel2Key);
2400 goto nextdevice;
2401 }
2402 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2403 {
2404 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
2405 if (!CmResourceList)
2406 {
2407 ZwClose(hLogConf);
2408 ZwDeleteKey(hLevel2Key);
2409 goto nextdevice;
2410 }
2411
2412 /* Add the list count (1st member of CM_RESOURCE_LIST) */
2413 ListCount = 1;
2414 RtlCopyMemory(CmResourceList,
2415 &ListCount,
2416 sizeof(ULONG));
2417
2418 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
2419 RtlCopyMemory(CmResourceList + sizeof(ULONG),
2420 BootResources,
2421 BootResourcesLength);
2422
2423 /* Save boot resources to 'LogConf\BootConfig' */
2424 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
2425 if (!NT_SUCCESS(Status))
2426 {
2427 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2428 ZwClose(hLogConf);
2429 ZwDeleteKey(hLevel2Key);
2430 goto nextdevice;
2431 }
2432 }
2433 ZwClose(hLogConf);
2434
2435 nextdevice:
2436 if (BootResources && BootResources != ParentBootResources)
2437 {
2438 ExFreePool(BootResources);
2439 BootResources = NULL;
2440 }
2441 if (hLevel2Key)
2442 {
2443 ZwClose(hLevel2Key);
2444 hLevel2Key = NULL;
2445 }
2446 if (hDeviceKey)
2447 {
2448 ZwClose(hDeviceKey);
2449 hDeviceKey = NULL;
2450 }
2451 }
2452
2453 Status = STATUS_SUCCESS;
2454
2455 cleanup:
2456 if (hDevicesKey && hDevicesKey != hBaseKey)
2457 ZwClose(hDevicesKey);
2458 if (hDeviceKey)
2459 ZwClose(hDeviceKey);
2460 if (pDeviceInformation)
2461 ExFreePool(pDeviceInformation);
2462 if (pValueInformation)
2463 ExFreePool(pValueInformation);
2464 return Status;
2465 }
2466
2467 static BOOLEAN INIT_FUNCTION
2468 IopIsAcpiComputer(VOID)
2469 {
2470 #ifndef ENABLE_ACPI
2471 return FALSE;
2472 #else
2473 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2474 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2475 UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS");
2476 OBJECT_ATTRIBUTES ObjectAttributes;
2477 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2478 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2479 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2480 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2481 ULONG RequiredSize;
2482 ULONG IndexDevice = 0;
2483 UNICODE_STRING DeviceName, ValueName;
2484 HANDLE hDevicesKey = NULL;
2485 HANDLE hDeviceKey = NULL;
2486 NTSTATUS Status;
2487 BOOLEAN ret = FALSE;
2488
2489 InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2490 Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
2491 if (!NT_SUCCESS(Status))
2492 {
2493 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2494 goto cleanup;
2495 }
2496
2497 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2498 if (!pDeviceInformation)
2499 {
2500 DPRINT("ExAllocatePool() failed\n");
2501 Status = STATUS_NO_MEMORY;
2502 goto cleanup;
2503 }
2504
2505 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2506 if (!pDeviceInformation)
2507 {
2508 DPRINT("ExAllocatePool() failed\n");
2509 Status = STATUS_NO_MEMORY;
2510 goto cleanup;
2511 }
2512
2513 while (TRUE)
2514 {
2515 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2516 if (Status == STATUS_NO_MORE_ENTRIES)
2517 break;
2518 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2519 {
2520 ExFreePool(pDeviceInformation);
2521 DeviceInfoLength = RequiredSize;
2522 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2523 if (!pDeviceInformation)
2524 {
2525 DPRINT("ExAllocatePool() failed\n");
2526 Status = STATUS_NO_MEMORY;
2527 goto cleanup;
2528 }
2529 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2530 }
2531 if (!NT_SUCCESS(Status))
2532 {
2533 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2534 goto cleanup;
2535 }
2536 IndexDevice++;
2537
2538 /* Open device key */
2539 DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
2540 DeviceName.Buffer = pDeviceInformation->Name;
2541 InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
2542 Status = ZwOpenKey(
2543 &hDeviceKey,
2544 KEY_QUERY_VALUE,
2545 &ObjectAttributes);
2546 if (!NT_SUCCESS(Status))
2547 {
2548 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2549 goto cleanup;
2550 }
2551
2552 /* Read identifier */
2553 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2554 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2555 {
2556 ExFreePool(pValueInformation);
2557 ValueInfoLength = RequiredSize;
2558 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2559 if (!pValueInformation)
2560 {
2561 DPRINT("ExAllocatePool() failed\n");
2562 Status = STATUS_NO_MEMORY;
2563 goto cleanup;
2564 }
2565 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2566 }
2567 if (!NT_SUCCESS(Status))
2568 {
2569 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2570 goto nextdevice;
2571 }
2572 else if (pValueInformation->Type != REG_SZ)
2573 {
2574 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2575 goto nextdevice;
2576 }
2577
2578 ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
2579 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2580 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2581 ValueName.Length -= sizeof(WCHAR);
2582 if (RtlCompareUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE) == 0)
2583 {
2584 DPRINT("Found ACPI BIOS\n");
2585 ret = TRUE;
2586 goto cleanup;
2587 }
2588
2589 nextdevice:
2590 ZwClose(hDeviceKey);
2591 hDeviceKey = NULL;
2592 }
2593
2594 cleanup:
2595 if (pDeviceInformation)
2596 ExFreePool(pDeviceInformation);
2597 if (pValueInformation)
2598 ExFreePool(pValueInformation);
2599 if (hDevicesKey)
2600 ZwClose(hDevicesKey);
2601 if (hDeviceKey)
2602 ZwClose(hDeviceKey);
2603 return ret;
2604 #endif
2605 }
2606
2607 NTSTATUS
2608 NTAPI
2609 IopUpdateRootKey(VOID)
2610 {
2611 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
2612 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
2613 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2614 UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
2615 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2616 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2617 UNICODE_STRING HalAcpiDevice = RTL_CONSTANT_STRING(L"ACPI_HAL");
2618 UNICODE_STRING HalAcpiId = RTL_CONSTANT_STRING(L"0000");
2619 UNICODE_STRING HalAcpiDeviceDesc = RTL_CONSTANT_STRING(L"HAL ACPI");
2620 UNICODE_STRING HalAcpiHardwareID = RTL_CONSTANT_STRING(L"*PNP0C08\0");
2621 OBJECT_ATTRIBUTES ObjectAttributes;
2622 HANDLE hEnum, hRoot, hHalAcpiDevice, hHalAcpiId, hLogConf;
2623 NTSTATUS Status;
2624
2625 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2626 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2627 if (!NT_SUCCESS(Status))
2628 {
2629 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
2630 return Status;
2631 }
2632
2633 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
2634 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2635 ZwClose(hEnum);
2636 if (!NT_SUCCESS(Status))
2637 {
2638 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
2639 return Status;
2640 }
2641
2642 if (IopIsAcpiComputer())
2643 {
2644 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiDevice, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hRoot, NULL);
2645 Status = ZwCreateKey(&hHalAcpiDevice, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2646 ZwClose(hRoot);
2647 if (!NT_SUCCESS(Status))
2648 return Status;
2649 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiId, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiDevice, NULL);
2650 Status = ZwCreateKey(&hHalAcpiId, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2651 ZwClose(hHalAcpiDevice);
2652 if (!NT_SUCCESS(Status))
2653 return Status;
2654 Status = ZwSetValueKey(hHalAcpiId, &DeviceDescU, 0, REG_SZ, HalAcpiDeviceDesc.Buffer, HalAcpiDeviceDesc.MaximumLength);
2655 if (NT_SUCCESS(Status))
2656 Status = ZwSetValueKey(hHalAcpiId, &HardwareIDU, 0, REG_MULTI_SZ, HalAcpiHardwareID.Buffer, HalAcpiHardwareID.MaximumLength);
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 /* On