[CMAKE]
[reactos.git] / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 //#define ENABLE_ACPI
17
18 /* GLOBALS *******************************************************************/
19
20 PDEVICE_NODE IopRootDeviceNode;
21 KSPIN_LOCK IopDeviceTreeLock;
22 ERESOURCE PpRegistryDeviceResource;
23 KGUARDED_MUTEX PpDeviceReferenceTableLock;
24 RTL_AVL_TABLE PpDeviceReferenceTable;
25
26 extern ULONG ExpInitializationPhase;
27 extern BOOLEAN PnpSystemInit;
28
29 /* DATA **********************************************************************/
30
31 PDRIVER_OBJECT IopRootDriverObject;
32 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
33
34 #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 ULONG Disposition;
2625
2626 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2627 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2628 if (!NT_SUCCESS(Status))
2629 {
2630 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
2631 return Status;
2632 }
2633
2634 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
2635 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2636 ZwClose(hEnum);
2637 if (!NT_SUCCESS(Status))
2638 {
2639 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
2640 return Status;
2641 }
2642
2643 if (IopIsAcpiComputer())
2644 {
2645 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiDevice, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hRoot, NULL);
2646 Status = ZwCreateKey(&hHalAcpiDevice, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2647 ZwClose(hRoot);
2648 if (!NT_SUCCESS(Status))
2649 return Status;
2650 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiId, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiDevice, NULL);
2651 Status = ZwCreateKey(&hHalAcpiId, KEY_CREATE_SUB_KEY | KEY_SET_VALUE, &ObjectAttributes, 0, NULL, 0, &Disposition);
2652 ZwClose(hHalAcpiDevice);
2653 if (!NT_SUCCESS(Status))
2654 return Status;
2655 if (Disposition == REG_CREATED_NEW_KEY)
2656 {
2657 Status = ZwSetValueKey(hHalAcpiId, &DeviceDescU, 0, REG_SZ, HalAcpiDeviceDesc.Buffer, HalAcpiDeviceDesc.MaximumLength);
2658 if (NT_SUCCESS(Status))
2659 Status = ZwSetValueKey(hHalAcpiId, &HardwareIDU, 0, REG_MULTI_SZ, HalAcpiHardwareID.Buffer, HalAcpiHardwareID.MaximumLength);
2660 }
2661 if (NT_SUCCESS(Status))
2662 {
2663 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiId, NULL);
2664 Status = ZwCreateKey(&hLogConf, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
2665 if (NT_SUCCESS(Status))
2666 ZwClose(hLogConf);
2667 }
2668 ZwClose(hHalAcpiId);
2669 return Status;
2670 }
2671 else
2672 {
2673 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
2674 if (!NT_SUCCESS(Status))
2675 {
2676 /* Nothing to do, don't return with an error status */
2677 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2678 ZwClose(hRoot);
2679 return STATUS_SUCCESS;
2680 }
2681 Status = IopEnumerateDetectedDevices(
2682 hEnum,
2683 NULL,
2684 hRoot,
2685 TRUE,
2686 NULL,
2687 0);
2688 ZwClose(hEnum);
2689 ZwClose(hRoot);
2690 return Status;
2691 }
2692 }
2693
2694 NTSTATUS
2695 NTAPI
2696 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
2697 HANDLE ParentKey,
2698 PUNICODE_STRING Name,
2699 ACCESS_MASK DesiredAccess)
2700 {
2701 OBJECT_ATTRIBUTES ObjectAttributes;
2702 NTSTATUS Status;
2703
2704 PAGED_CODE();
2705
2706 *KeyHandle = NULL;
2707
2708 InitializeObjectAttributes(&ObjectAttributes,
2709 Name,
2710 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2711 ParentKey,
2712 NULL);
2713
2714 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
2715
2716 return Status;
2717 }
2718
2719 NTSTATUS
2720 NTAPI
2721 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
2722 IN HANDLE RootHandle OPTIONAL,
2723 IN PUNICODE_STRING KeyName,
2724 IN ACCESS_MASK DesiredAccess,
2725 IN ULONG CreateOptions,
2726 OUT PULONG Disposition OPTIONAL)
2727 {
2728 OBJECT_ATTRIBUTES ObjectAttributes;
2729 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0, Length;
2730 HANDLE HandleArray[2];
2731 BOOLEAN Recursing = TRUE;
2732 PWCHAR pp, p, p1;
2733 UNICODE_STRING KeyString;
2734 NTSTATUS Status = STATUS_SUCCESS;
2735 PAGED_CODE();
2736
2737 /* P1 is start, pp is end */
2738 p1 = KeyName->Buffer;
2739 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
2740
2741 /* Create the target key */
2742 InitializeObjectAttributes(&ObjectAttributes,
2743 KeyName,
2744 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2745 RootHandle,
2746 NULL);
2747 Status = ZwCreateKey(&HandleArray[i],
2748 DesiredAccess,
2749 &ObjectAttributes,
2750 0,
2751 NULL,
2752 CreateOptions,
2753 &KeyDisposition);
2754
2755 /* Now we check if this failed */
2756 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
2757 {
2758 /* Target key failed, so we'll need to create its parent. Setup array */
2759 HandleArray[0] = NULL;
2760 HandleArray[1] = RootHandle;
2761
2762 /* Keep recursing for each missing parent */
2763 while (Recursing)
2764 {
2765 /* And if we're deep enough, close the last handle */
2766 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
2767
2768 /* We're setup to ping-pong between the two handle array entries */
2769 RootHandleIndex = i;
2770 i = (i + 1) & 1;
2771
2772 /* Clear the one we're attempting to open now */
2773 HandleArray[i] = NULL;
2774
2775 /* Process the parent key name */
2776 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
2777 Length = (p - p1) * sizeof(WCHAR);
2778
2779 /* Is there a parent name? */
2780 if (Length)
2781 {
2782 /* Build the unicode string for it */
2783 KeyString.Buffer = p1;
2784 KeyString.Length = KeyString.MaximumLength = Length;
2785
2786 /* Now try opening the parent */
2787 InitializeObjectAttributes(&ObjectAttributes,
2788 &KeyString,
2789 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2790 HandleArray[RootHandleIndex],
2791 NULL);
2792 Status = ZwCreateKey(&HandleArray[i],
2793 DesiredAccess,
2794 &ObjectAttributes,
2795 0,
2796 NULL,
2797 CreateOptions,
2798 &KeyDisposition);
2799 if (NT_SUCCESS(Status))
2800 {
2801 /* It worked, we have one more handle */
2802 NestedCloseLevel++;
2803 }
2804 else
2805 {
2806 /* Parent key creation failed, abandon loop */
2807 Recursing = FALSE;
2808 continue;
2809 }
2810 }
2811 else
2812 {
2813 /* We don't have a parent name, probably corrupted key name */
2814 Status = STATUS_INVALID_PARAMETER;
2815 Recursing = FALSE;
2816 continue;
2817 }
2818
2819 /* Now see if there's more parents to create */
2820 p1 = p + 1;
2821 if ((p == pp) || (p1 == pp))
2822 {
2823 /* We're done, hopefully successfully, so stop */
2824 Recursing = FALSE;
2825 }
2826 }
2827
2828 /* Outer loop check for handle nesting that requires closing the top handle */
2829 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
2830 }
2831
2832 /* Check if we broke out of the loop due to success */
2833 if (NT_SUCCESS(Status))
2834 {
2835 /* Return the target handle (we closed all the parent ones) and disposition */
2836 *Handle = HandleArray[i];
2837 if (Disposition) *Disposition = KeyDisposition;
2838 }
2839
2840 /* Return the success state */
2841 return Status;
2842 }
2843
2844 NTSTATUS
2845 NTAPI
2846 IopGetRegistryValue(IN HANDLE Handle,
2847 IN PWSTR ValueName,
2848 OUT PKEY_VALUE_FULL_INFORMATION *Information)
2849 {
2850 UNICODE_STRING ValueString;
2851 NTSTATUS Status;
2852 PKEY_VALUE_FULL_INFORMATION FullInformation;
2853 ULONG Size;
2854 PAGED_CODE();
2855
2856 RtlInitUnicodeString(&ValueString, ValueName);
2857
2858 Status = ZwQueryValueKey(Handle,
2859 &ValueString,
2860 KeyValueFullInformation,
2861 NULL,
2862 0,
2863 &Size);
2864 if ((Status != STATUS_BUFFER_OVERFLOW) &&
2865 (Status != STATUS_BUFFER_TOO_SMALL))
2866 {
2867 return Status;
2868 }
2869
2870 FullInformation = ExAllocatePool(NonPagedPool, Size);
2871 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
2872
2873 Status = ZwQueryValueKey(Handle,
2874 &ValueString,
2875 KeyValueFullInformation,
2876 FullInformation,
2877 Size,
2878 &Size);
2879 if (!NT_SUCCESS(Status))
2880 {
2881 ExFreePool(FullInformation);
2882 return Status;
2883 }
2884
2885 *Information = FullInformation;
2886 return STATUS_SUCCESS;
2887 }
2888
2889 RTL_GENERIC_COMPARE_RESULTS
2890 NTAPI
2891 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
2892 IN PVOID FirstStruct,
2893 IN PVOID SecondStruct)
2894 {
2895 /* FIXME: TODO */
2896 ASSERT(FALSE);
2897 return 0;
2898 }
2899
2900 //
2901 // The allocation function is called by the generic table package whenever
2902 // it needs to allocate memory for the table.
2903 //
2904
2905 PVOID
2906 NTAPI
2907 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
2908 IN CLONG ByteSize)
2909 {
2910 /* FIXME: TODO */
2911 ASSERT(FALSE);
2912 return NULL;
2913 }
2914
2915 VOID
2916 NTAPI
2917 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
2918 IN PVOID Buffer)
2919 {
2920 /* FIXME: TODO */
2921 ASSERT(FALSE);
2922 }
2923
2924 VOID
2925 NTAPI
2926 PpInitializeDeviceReferenceTable(VOID)
2927 {
2928 /* Setup the guarded mutex and AVL table */
2929 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
2930 RtlInitializeGenericTableAvl(
2931 &PpDeviceReferenceTable,
2932 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
2933 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
2934 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
2935 NULL);
2936 }
2937
2938 BOOLEAN
2939 NTAPI
2940 PiInitPhase0(VOID)
2941 {
2942 /* Initialize the resource when accessing device registry data */
2943 ExInitializeResourceLite(&PpRegistryDeviceResource);
2944
2945 /* Setup the device reference AVL table */
2946 PpInitializeDeviceReferenceTable();
2947 return TRUE;
2948 }
2949
2950 BOOLEAN
2951 NTAPI
2952 PpInitSystem(VOID)
2953 {
2954 /* Check the initialization phase */
2955 switch (ExpInitializationPhase)
2956 {
2957 case 0:
2958
2959 /* Do Phase 0 */
2960 return PiInitPhase0();
2961
2962 case 1:
2963
2964 /* Do Phase 1 */
2965 return TRUE;
2966 //return PiInitPhase1();
2967
2968 default:
2969
2970 /* Don't know any other phase! Bugcheck! */
2971 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
2972 return FALSE;
2973 }
2974 }
2975
2976 LONG IopNumberDeviceNodes;
2977
2978 PDEVICE_NODE
2979 NTAPI
2980 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
2981 {
2982 PDEVICE_NODE DeviceNode;
2983 PAGED_CODE();
2984
2985 /* Allocate it */
2986 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), 'donD');
2987 if (!DeviceNode) return DeviceNode;
2988
2989 /* Statistics */
2990 InterlockedIncrement(&IopNumberDeviceNodes);
2991
2992 /* Set it up */
2993 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
2994 DeviceNode->InterfaceType = InterfaceTypeUndefined;
2995 DeviceNode->BusNumber = -1;
2996 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2997 DeviceNode->ChildBusNumber = -1;
2998 DeviceNode->ChildBusTypeIndex = -1;
2999 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3000 InitializeListHead(&DeviceNode->DeviceArbiterList);
3001 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3002 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3003 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3004 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3005
3006 /* Check if there is a PDO */
3007 if (PhysicalDeviceObject)
3008 {
3009 /* Link it and remove the init flag */
3010 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3011 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3012 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3013 }
3014
3015 /* Return the node */
3016 return DeviceNode;
3017 }
3018
3019 /* PUBLIC FUNCTIONS **********************************************************/
3020
3021 NTSTATUS
3022 NTAPI
3023 PnpBusTypeGuidGet(IN USHORT Index,
3024 IN LPGUID BusTypeGuid)
3025 {
3026 NTSTATUS Status = STATUS_SUCCESS;
3027
3028 /* Acquire the lock */
3029 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3030
3031 /* Validate size */
3032 if (Index < PnpBusTypeGuidList->GuidCount)
3033 {
3034 /* Copy the data */
3035 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3036 }
3037 else
3038 {
3039 /* Failure path */
3040 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3041 }
3042
3043 /* Release lock and return status */
3044 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3045 return Status;
3046 }
3047
3048 NTSTATUS
3049 NTAPI
3050 PpIrpQueryCapabilities(IN PDEVICE_OBJECT DeviceObject,
3051 OUT PDEVICE_CAPABILITIES DeviceCaps)
3052 {
3053 PVOID Dummy;
3054 IO_STACK_LOCATION Stack;
3055
3056 PAGED_CODE();
3057
3058 /* Set up the Header */
3059 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
3060 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
3061 DeviceCaps->Version = 1;
3062 DeviceCaps->Address = -1;
3063 DeviceCaps->UINumber = -1;
3064
3065 /* Set up the Stack */
3066 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
3067 Stack.MajorFunction = IRP_MJ_PNP;
3068 Stack.MinorFunction = IRP_MN_QUERY_CAPABILITIES;
3069 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
3070
3071 /* Send the IRP */
3072 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
3073 }
3074
3075 NTSTATUS
3076 NTAPI
3077 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3078 IN PHANDLE DeviceInstanceHandle,
3079 IN ACCESS_MASK DesiredAccess)
3080 {
3081 NTSTATUS Status;
3082 HANDLE KeyHandle;
3083 PDEVICE_NODE DeviceNode;
3084 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3085 PAGED_CODE();
3086
3087 /* Open the enum key */
3088 Status = IopOpenRegistryKeyEx(&KeyHandle,
3089 NULL,
3090 &KeyName,
3091 KEY_READ);
3092 if (!NT_SUCCESS(Status)) return Status;
3093
3094 /* Make sure we have an instance path */
3095 DeviceNode = IopGetDeviceNode(DeviceObject);
3096 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3097 {
3098 /* Get the instance key */
3099 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3100 KeyHandle,
3101 &DeviceNode->InstancePath,
3102 DesiredAccess);
3103 }
3104 else
3105 {
3106 /* Fail */
3107 Status = STATUS_INVALID_DEVICE_REQUEST;
3108 }
3109
3110 /* Close the handle and return status */
3111 ZwClose(KeyHandle);
3112 return Status;
3113 }
3114
3115 ULONG
3116 NTAPI
3117 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3118 {
3119 ULONG FinalSize, PartialSize, EntrySize, i, j;
3120 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3121 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3122
3123 /* If we don't have one, that's easy */
3124 if (!ResourceList) return 0;
3125
3126 /* Start with the minimum size possible */
3127 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3128
3129 /* Loop each full descriptor */
3130 FullDescriptor = ResourceList->List;
3131 for (i = 0; i < ResourceList->Count; i++)
3132 {
3133 /* Start with the minimum size possible */
3134 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3135 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3136
3137 /* Loop each partial descriptor */
3138 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3139 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3140 {
3141 /* Start with the minimum size possible */
3142 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3143
3144 /* Check if there is extra data */
3145 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3146 {
3147 /* Add that data */
3148 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3149 }
3150
3151 /* The size of partial descriptors is bigger */
3152 PartialSize += EntrySize;
3153
3154 /* Go to the next partial descriptor */
3155 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3156 }
3157
3158 /* The size of full descriptors is bigger */
3159 FinalSize += PartialSize;
3160
3161 /* Go to the next full descriptor */
3162 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3163 }
3164
3165 /* Return the final size */
3166 return FinalSize;
3167 }
3168
3169 NTSTATUS
3170 NTAPI
3171 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3172 IN ULONG ValueType,
3173 IN PWSTR ValueName,
3174 IN PWSTR KeyName,
3175 OUT PVOID Buffer,
3176 IN PULONG BufferLength)
3177 {
3178 NTSTATUS Status;
3179 HANDLE KeyHandle, SubHandle;
3180 UNICODE_STRING KeyString;
3181 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3182 ULONG Length;
3183 PAGED_CODE();
3184
3185 /* Find the instance key */
3186 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3187 if (NT_SUCCESS(Status))
3188 {
3189 /* Check for name given by caller */
3190 if (KeyName)
3191 {
3192 /* Open this key */
3193 RtlInitUnicodeString(&KeyString, KeyName);
3194 Status = IopOpenRegistryKeyEx(&SubHandle,
3195 KeyHandle,
3196 &KeyString,
3197 KEY_READ);
3198 if (NT_SUCCESS(Status))
3199 {
3200 /* And use this handle instead */
3201 ZwClose(KeyHandle);
3202 KeyHandle = SubHandle;
3203 }
3204 }
3205
3206 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3207 if (NT_SUCCESS(Status))
3208 {
3209 /* Now get the size of the property */
3210 Status = IopGetRegistryValue(KeyHandle,
3211 ValueName,
3212 &KeyValueInfo);
3213 }
3214
3215 /* Close the key */
3216 ZwClose(KeyHandle);
3217 }
3218
3219 /* Fail if any of the registry operations failed */
3220 if (!NT_SUCCESS(Status)) return Status;
3221
3222 /* Check how much data we have to copy */
3223 Length = KeyValueInfo->DataLength;
3224 if (*BufferLength >= Length)
3225 {
3226 /* Check for a match in the value type */
3227 if (KeyValueInfo->Type == ValueType)
3228 {
3229 /* Copy the data */
3230 RtlCopyMemory(Buffer,
3231 (PVOID)((ULONG_PTR)KeyValueInfo +
3232 KeyValueInfo->DataOffset),
3233 Length);
3234 }
3235 else
3236 {
3237 /* Invalid registry property type, fail */
3238 Status = STATUS_INVALID_PARAMETER_2;
3239 }
3240 }
3241 else
3242 {
3243 /* Buffer is too small to hold data */
3244 Status = STATUS_BUFFER_TOO_SMALL;
3245 }
3246
3247 /* Return the required buffer length, free the buffer, and return status */
3248 *BufferLength = Length;
3249 ExFreePool(KeyValueInfo);
3250 return Status;
3251 }
3252
3253 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3254 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3255 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED; while(TRUE); break;}
3256
3257 /*
3258 * @implemented
3259 */
3260 NTSTATUS
3261 NTAPI
3262 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
3263 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
3264 IN ULONG BufferLength,
3265 OUT PVOID PropertyBuffer,
3266 OUT PULONG ResultLength)
3267 {
3268 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
3269 DEVICE_CAPABILITIES DeviceCaps;
3270 ULONG ReturnLength = 0, Length = 0, ValueType;
3271 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
3272 PVOID Data = NULL;
3273 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
3274 GUID BusTypeGuid;
3275 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
3276 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
3277
3278 /* Assume failure */
3279 *ResultLength = 0;
3280
3281 /* Only PDOs can call this */
3282 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
3283
3284 /* Handle all properties */
3285 switch (DeviceProperty)
3286 {
3287 case DevicePropertyBusTypeGuid:
3288
3289 /* Get the GUID from the internal cache */
3290 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
3291 if (!NT_SUCCESS(Status)) return Status;
3292
3293 /* This is the format of the returned data */
3294 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
3295
3296 case DevicePropertyLegacyBusType:
3297
3298 /* Validate correct interface type */
3299 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
3300 return STATUS_OBJECT_NAME_NOT_FOUND;
3301
3302 /* This is the format of the returned data */
3303 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
3304
3305 case DevicePropertyBusNumber:
3306
3307 /* Validate correct bus number */
3308 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
3309 return STATUS_OBJECT_NAME_NOT_FOUND;
3310
3311 /* This is the format of the returned data */
3312 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
3313
3314 case DevicePropertyEnumeratorName:
3315
3316 /* Get the instance path */
3317 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
3318
3319 /* Sanity checks */
3320 ASSERT((BufferLength & 1) == 0);
3321 ASSERT(DeviceInstanceName != NULL);
3322
3323 /* Get the name from the path */
3324 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
3325 ASSERT(EnumeratorNameEnd);
3326
3327 /* This is the format of the returned data */
3328 PIP_RETURN_DATA((EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
3329 DeviceInstanceName);
3330
3331 case DevicePropertyAddress:
3332
3333 /* Query the device caps */
3334 Status = PpIrpQueryCapabilities(DeviceObject, &DeviceCaps);
3335 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
3336 return STATUS_OBJECT_NAME_NOT_FOUND;
3337
3338 /* This is the format of the returned data */
3339 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
3340
3341 case DevicePropertyBootConfigurationTranslated:
3342
3343 /* Validate we have resources */
3344 if (!DeviceNode->BootResources)
3345 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3346 {
3347 /* No resources will still fake success, but with 0 bytes */
3348 *ResultLength = 0;
3349 return STATUS_SUCCESS;
3350 }
3351
3352 /* This is the format of the returned data */
3353 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
3354 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
3355
3356 case DevicePropertyPhysicalDeviceObjectName:
3357
3358 /* Sanity check for Unicode-sized string */
3359 ASSERT((BufferLength & 1) == 0);
3360
3361 /* Allocate name buffer */
3362 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
3363 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
3364 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
3365
3366 /* Query the PDO name */
3367 Status = ObQueryNameString(DeviceObject,
3368 ObjectNameInfo,
3369 Length,
3370 ResultLength);
3371 if (Status == STATUS_INFO_LENGTH_MISMATCH)
3372 {
3373 /* It's up to the caller to try again */
3374 Status = STATUS_BUFFER_TOO_SMALL;
3375 }
3376
3377 /* Return if successful */
3378 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
3379 ObjectNameInfo->Name.Buffer);
3380
3381 /* Let the caller know how big the name is */
3382 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
3383 break;
3384
3385 /* Handle the registry-based properties */
3386 case DevicePropertyUINumber:
3387 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
3388 case DevicePropertyLocationInformation:
3389 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
3390 case DevicePropertyDeviceDescription:
3391 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
3392 case DevicePropertyHardwareID:
3393 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
3394 case DevicePropertyCompatibleIDs:
3395 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
3396 case DevicePropertyBootConfiguration:
3397 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
3398 case DevicePropertyClassName:
3399 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
3400 case DevicePropertyClassGuid:
3401 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
3402 case DevicePropertyDriverKeyName:
3403 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
3404 case DevicePropertyManufacturer:
3405 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
3406 case DevicePropertyFriendlyName:
3407 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
3408 case DevicePropertyContainerID:
3409 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3410 PIP_UNIMPLEMENTED();
3411 case DevicePropertyRemovalPolicy:
3412 PIP_UNIMPLEMENTED();
3413 case DevicePropertyInstallState:
3414 PIP_UNIMPLEMENTED();
3415 case DevicePropertyResourceRequirements:
3416 PIP_UNIMPLEMENTED();
3417 case DevicePropertyAllocatedResources:
3418 PIP_UNIMPLEMENTED();
3419 default:
3420 return STATUS_INVALID_PARAMETER_2;
3421 }
3422
3423 /* Having a registry value name implies registry data */
3424 if (ValueName)
3425 {
3426 /* We know up-front how much data to expect */
3427 *ResultLength = BufferLength;
3428
3429 /* Go get the data, use the LogConf subkey if necessary */
3430 Status = PiGetDeviceRegistryProperty(DeviceObject,
3431 ValueType,
3432 ValueName,
3433 (DeviceProperty ==
3434 DevicePropertyBootConfiguration) ?
3435 L"LogConf": NULL,
3436 PropertyBuffer,
3437 ResultLength);
3438 }
3439 else if (NT_SUCCESS(Status))
3440 {
3441 /* We know up-front how much data to expect, check the caller's buffer */
3442 *ResultLength = ReturnLength;
3443 if (ReturnLength <= BufferLength)
3444 {
3445 /* Buffer is all good, copy the data */
3446 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
3447
3448 /* Check for properties that require a null-terminated string */
3449 if ((DeviceProperty == DevicePropertyEnumeratorName) ||
3450 (DeviceProperty == DevicePropertyPhysicalDeviceObjectName))
3451 {
3452 /* Terminate the string */
3453 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
3454 }
3455
3456 /* This is the success path */
3457 Status = STATUS_SUCCESS;
3458 }
3459 else
3460 {
3461 /* Failure path */
3462 Status = STATUS_BUFFER_TOO_SMALL;
3463 }
3464 }
3465
3466 /* Free any allocation we may have made, and return the status code */
3467 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
3468 return Status;
3469 }
3470
3471 /*
3472 * @unimplemented
3473 */
3474 VOID
3475 NTAPI
3476 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
3477 {
3478 UNIMPLEMENTED;
3479 }
3480
3481 /**
3482 * @name IoOpenDeviceRegistryKey
3483 *
3484 * Open a registry key unique for a specified driver or device instance.
3485 *
3486 * @param DeviceObject Device to get the registry key for.
3487 * @param DevInstKeyType Type of the key to return.
3488 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
3489 * @param DevInstRegKey Handle to the opened registry key on
3490 * successful return.
3491 *
3492 * @return Status.
3493 *
3494 * @implemented
3495 */
3496 NTSTATUS
3497 NTAPI
3498 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
3499 IN ULONG DevInstKeyType,
3500 IN ACCESS_MASK DesiredAccess,
3501 OUT PHANDLE DevInstRegKey)
3502 {
3503 static WCHAR RootKeyName[] =
3504 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
3505 static WCHAR ProfileKeyName[] =
3506 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
3507 static WCHAR ClassKeyName[] = L"Control\\Class\\";
3508 static WCHAR EnumKeyName[] = L"Enum\\";
3509 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
3510 ULONG KeyNameLength;
3511 LPWSTR KeyNameBuffer;
3512 UNICODE_STRING KeyName;
3513 ULONG DriverKeyLength;
3514 OBJECT_ATTRIBUTES ObjectAttributes;
3515 PDEVICE_NODE DeviceNode = NULL;
3516 NTSTATUS Status;
3517
3518 DPRINT("IoOpenDeviceRegistryKey() called\n");
3519
3520 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
3521 {
3522 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
3523 return STATUS_INVALID_PARAMETER;
3524 }
3525
3526 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
3527 return STATUS_INVALID_DEVICE_REQUEST;
3528 DeviceNode = IopGetDeviceNode(DeviceObject);
3529
3530 /*
3531 * Calculate the length of the base key name. This is the full
3532 * name for driver key or the name excluding "Device Parameters"
3533 * subkey for device key.
3534 */
3535
3536 KeyNameLength = sizeof(RootKeyName);
3537 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
3538 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
3539 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3540 {
3541 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
3542 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
3543 0, NULL, &DriverKeyLength);
3544 if (Status != STATUS_BUFFER_TOO_SMALL)
3545 return Status;
3546 KeyNameLength += DriverKeyLength;
3547 }
3548 else
3549 {
3550 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
3551 DeviceNode->InstancePath.Length;
3552 }
3553
3554 /*
3555 * Now allocate the buffer for the key name...
3556 */
3557
3558 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
3559 if (KeyNameBuffer == NULL)
3560 return STATUS_INSUFFICIENT_RESOURCES;
3561
3562 KeyName.Length = 0;
3563 KeyName.MaximumLength = (USHORT)KeyNameLength;
3564 KeyName.Buffer = KeyNameBuffer;
3565
3566 /*
3567 * ...and build the key name.
3568 */
3569
3570 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
3571 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
3572
3573 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
3574 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
3575
3576 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3577 {
3578 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
3579 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
3580 DriverKeyLength, KeyNameBuffer +
3581 (KeyName.Length / sizeof(WCHAR)),
3582 &DriverKeyLength);
3583 if (!NT_SUCCESS(Status))
3584 {
3585 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
3586 ExFreePool(KeyNameBuffer);
3587 return Status;
3588 }
3589 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
3590 }
3591 else
3592 {
3593 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
3594 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
3595 if (DeviceNode->InstancePath.Length == 0)
3596 {
3597 ExFreePool(KeyNameBuffer);
3598 return Status;
3599 }
3600 }
3601
3602 /*
3603 * Open the base key.
3604 */
3605 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
3606 if (!NT_SUCCESS(Status))
3607 {
3608 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
3609 ExFreePool(KeyNameBuffer);
3610 return Status;
3611 }
3612 ExFreePool(KeyNameBuffer);
3613
3614 /*
3615 * For driver key we're done now.
3616 */
3617
3618 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3619 return Status;
3620
3621 /*
3622 * Let's go further. For device key we must open "Device Parameters"
3623 * subkey and create it if it doesn't exist yet.
3624 */
3625
3626 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
3627 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
3628 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
3629 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
3630 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
3631 ZwClose(ObjectAttributes.RootDirectory);
3632
3633 return Status;
3634 }
3635
3636 /*
3637 * @unimplemented
3638 */
3639 VOID
3640 NTAPI
3641 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
3642 {
3643 UNIMPLEMENTED;
3644 }
3645
3646 /*
3647 * @implemented
3648 */
3649 VOID
3650 NTAPI
3651 IoInvalidateDeviceRelations(
3652 IN PDEVICE_OBJECT DeviceObject,
3653 IN DEVICE_RELATION_TYPE Type)
3654 {
3655 PIO_WORKITEM WorkItem;
3656 PINVALIDATE_DEVICE_RELATION_DATA Data;
3657
3658 Data = ExAllocatePool(NonPagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
3659 if (!Data)
3660 return;
3661 WorkItem = IoAllocateWorkItem(DeviceObject);
3662 if (!WorkItem)
3663 {
3664 ExFreePool(Data);
3665 return;
3666 }
3667
3668 ObReferenceObject(DeviceObject);
3669 Data->DeviceObject = DeviceObject;
3670 Data->Type = Type;
3671 Data->WorkItem = WorkItem;
3672
3673 IoQueueWorkItem(
3674 WorkItem,
3675 IopAsynchronousInvalidateDeviceRelations,
3676 DelayedWorkQueue,
3677 Data);
3678 }
3679
3680 /*
3681 * @implemented
3682 */
3683 NTSTATUS
3684 NTAPI
3685 IoSynchronousInvalidateDeviceRelations(
3686 IN PDEVICE_OBJECT DeviceObject,
3687 IN DEVICE_RELATION_TYPE Type)
3688 {
3689 PAGED_CODE();
3690
3691 switch (Type)
3692 {
3693 case BusRelations:
3694 /* Enumerate the device */
3695 return IopEnumerateDevice(DeviceObject);
3696 case PowerRelations:
3697 /* Not handled yet */
3698 return STATUS_NOT_IMPLEMENTED;
3699 case TargetDeviceRelation:
3700 /* Nothing to do */
3701 return STATUS_SUCCESS;
3702 default:
3703 /* Ejection relations are not supported */
3704 return STATUS_NOT_SUPPORTED;
3705 }
3706 }
3707
3708 /*
3709 * @unimplemented
3710 */
3711 BOOLEAN
3712 NTAPI
3713 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
3714 IN ULONG BusNumber,
3715 IN PHYSICAL_ADDRESS BusAddress,
3716 IN OUT PULONG AddressSpace,
3717 OUT PPHYSICAL_ADDRESS TranslatedAddress)
3718 {
3719 UNIMPLEMENTED;
3720 return FALSE;
3721 }