[AUDIO-BRINGUP]
[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 IdentifierSW = RTL_CONSTANT_STRING(L"SWENUM");
2047 UNICODE_STRING HardwareIdSW= RTL_CONSTANT_STRING(L"SWENUM\0");
2048 static ULONG DeviceIndexSW = 0;
2049 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2050 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2051 static ULONG DeviceIndexSerial = 0;
2052 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2053 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2054 static ULONG DeviceIndexKeyboard = 0;
2055 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2056 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2057 static ULONG DeviceIndexMouse = 0;
2058 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2059 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2060 static ULONG DeviceIndexParallel = 0;
2061 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2062 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2063 static ULONG DeviceIndexFloppy = 0;
2064 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
2065 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
2066 static ULONG DeviceIndexIsa = 0;
2067 UNICODE_STRING HardwareIdKey;
2068 PUNICODE_STRING pHardwareId;
2069 ULONG DeviceIndex = 0;
2070 PUCHAR CmResourceList;
2071 ULONG ListCount;
2072
2073 if (RelativePath)
2074 {
2075 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2076 if (!NT_SUCCESS(Status))
2077 {
2078 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2079 goto cleanup;
2080 }
2081 }
2082 else
2083 hDevicesKey = hBaseKey;
2084
2085 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2086 if (!pDeviceInformation)
2087 {
2088 DPRINT("ExAllocatePool() failed\n");
2089 Status = STATUS_NO_MEMORY;
2090 goto cleanup;
2091 }
2092
2093 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2094 if (!pValueInformation)
2095 {
2096 DPRINT("ExAllocatePool() failed\n");
2097 Status = STATUS_NO_MEMORY;
2098 goto cleanup;
2099 }
2100
2101 while (TRUE)
2102 {
2103 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2104 if (Status == STATUS_NO_MORE_ENTRIES)
2105 break;
2106 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2107 {
2108 ExFreePool(pDeviceInformation);
2109 DeviceInfoLength = RequiredSize;
2110 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2111 if (!pDeviceInformation)
2112 {
2113 DPRINT("ExAllocatePool() failed\n");
2114 Status = STATUS_NO_MEMORY;
2115 goto cleanup;
2116 }
2117 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2118 }
2119 if (!NT_SUCCESS(Status))
2120 {
2121 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2122 goto cleanup;
2123 }
2124 IndexDevice++;
2125
2126 /* Open device key */
2127 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2128 DeviceName.Buffer = pDeviceInformation->Name;
2129
2130 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
2131 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
2132 if (!NT_SUCCESS(Status))
2133 {
2134 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2135 goto cleanup;
2136 }
2137
2138 /* Read boot resources, and add then to parent ones */
2139 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2140 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2141 {
2142 ExFreePool(pValueInformation);
2143 ValueInfoLength = RequiredSize;
2144 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2145 if (!pValueInformation)
2146 {
2147 DPRINT("ExAllocatePool() failed\n");
2148 ZwDeleteKey(hLevel2Key);
2149 Status = STATUS_NO_MEMORY;
2150 goto cleanup;
2151 }
2152 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2153 }
2154 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2155 {
2156 BootResources = ParentBootResources;
2157 BootResourcesLength = ParentBootResourcesLength;
2158 }
2159 else if (!NT_SUCCESS(Status))
2160 {
2161 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2162 goto nextdevice;
2163 }
2164 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2165 {
2166 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2167 goto nextdevice;
2168 }
2169 else
2170 {
2171 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2172
2173 /* Concatenate current resources and parent ones */
2174 if (ParentBootResourcesLength == 0)
2175 BootResourcesLength = pValueInformation->DataLength;
2176 else
2177 BootResourcesLength = ParentBootResourcesLength
2178 + pValueInformation->DataLength
2179 - Header;
2180 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2181 if (!BootResources)
2182 {
2183 DPRINT("ExAllocatePool() failed\n");
2184 goto nextdevice;
2185 }
2186 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2187 {
2188 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2189 }
2190 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2191 {
2192 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2193 RtlCopyMemory(
2194 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2195 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2196 ParentBootResourcesLength - Header);
2197 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2198 }
2199 else
2200 {
2201 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2202 RtlCopyMemory(
2203 (PVOID)((ULONG_PTR)BootResources + Header),
2204 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2205 ParentBootResourcesLength - Header);
2206 RtlCopyMemory(
2207 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2208 pValueInformation->Data + Header,
2209 pValueInformation->DataLength - Header);
2210 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2211 }
2212 }
2213
2214 if (EnumerateSubKeys)
2215 {
2216 IndexSubKey = 0;
2217 while (TRUE)
2218 {
2219 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2220 if (Status == STATUS_NO_MORE_ENTRIES)
2221 break;
2222 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2223 {
2224 ExFreePool(pDeviceInformation);
2225 DeviceInfoLength = RequiredSize;
2226 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2227 if (!pDeviceInformation)
2228 {
2229 DPRINT("ExAllocatePool() failed\n");
2230 Status = STATUS_NO_MEMORY;
2231 goto cleanup;
2232 }
2233 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2234 }
2235 if (!NT_SUCCESS(Status))
2236 {
2237 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2238 goto cleanup;
2239 }
2240 IndexSubKey++;
2241 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2242 DeviceName.Buffer = pDeviceInformation->Name;
2243
2244 Status = IopEnumerateDetectedDevices(
2245 hDeviceKey,
2246 &DeviceName,
2247 hRootKey,
2248 TRUE,
2249 BootResources,
2250 BootResourcesLength);
2251 if (!NT_SUCCESS(Status))
2252 goto cleanup;
2253 }
2254 }
2255
2256 /* Read identifier */
2257 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2258 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2259 {
2260 ExFreePool(pValueInformation);
2261 ValueInfoLength = RequiredSize;
2262 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2263 if (!pValueInformation)
2264 {
2265 DPRINT("ExAllocatePool() failed\n");
2266 Status = STATUS_NO_MEMORY;
2267 goto cleanup;
2268 }
2269 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2270 }
2271 if (!NT_SUCCESS(Status))
2272 {
2273 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2274 {
2275 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2276 goto nextdevice;
2277 }
2278 ValueName.Length = ValueName.MaximumLength = 0;
2279 }
2280 else if (pValueInformation->Type != REG_SZ)
2281 {
2282 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2283 goto nextdevice;
2284 }
2285 else
2286 {
2287 /* Assign hardware id to this device */
2288 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
2289 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2290 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2291 ValueName.Length -= sizeof(WCHAR);
2292 }
2293 DPRINT1("RelativePath %wZ\n", RelativePath);
2294 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
2295 {
2296 pHardwareId = &HardwareIdSerial;
2297 DeviceIndex = DeviceIndexSerial++;
2298 }
2299 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
2300 {
2301 pHardwareId = &HardwareIdKeyboard;
2302 DeviceIndex = DeviceIndexKeyboard++;
2303 }
2304 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
2305 {
2306 pHardwareId = &HardwareIdMouse;
2307 DeviceIndex = DeviceIndexMouse++;
2308 }
2309 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
2310 {
2311 pHardwareId = &HardwareIdParallel;
2312 DeviceIndex = DeviceIndexParallel++;
2313 }
2314 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
2315 {
2316 pHardwareId = &HardwareIdFloppy;
2317 DeviceIndex = DeviceIndexFloppy++;
2318 }
2319 else if (NT_SUCCESS(Status))
2320 {
2321 /* Try to also match the device identifier */
2322 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
2323 {
2324 pHardwareId = &HardwareIdPci;
2325 DeviceIndex = DeviceIndexPci++;
2326 }
2327 else if (RtlCompareUnicodeString(&ValueName, &IdentifierIsa, FALSE) == 0)
2328 {
2329 pHardwareId = &HardwareIdIsa;
2330 DeviceIndex = DeviceIndexIsa++;
2331 }
2332 else if (RtlCompareUnicodeString(&ValueName, &IdentifierSW, FALSE) == 0)
2333 {
2334 pHardwareId = &HardwareIdSW;
2335 DeviceIndex = DeviceIndexSW++;
2336 }
2337 else
2338 {
2339 DPRINT1("Unknown device '%wZ'\n", &ValueName);
2340 goto nextdevice;
2341 }
2342 }
2343 else
2344 {
2345 /* Unknown key path */
2346 DPRINT("Unknown key path '%wZ'\n", RelativePath);
2347 goto nextdevice;
2348 }
2349
2350 /* Prepare hardware id key (hardware id value without final \0) */
2351 HardwareIdKey = *pHardwareId;
2352 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
2353
2354 /* Add the detected device to Root key */
2355 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
2356 Status = ZwCreateKey(
2357 &hLevel1Key,
2358 KEY_CREATE_SUB_KEY,
2359 &ObjectAttributes,
2360 0,
2361 NULL,
2362 REG_OPTION_NON_VOLATILE,
2363 NULL);
2364 if (!NT_SUCCESS(Status))
2365 {
2366 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2367 goto nextdevice;
2368 }
2369 swprintf(Level2Name, L"%04lu", DeviceIndex);
2370 RtlInitUnicodeString(&Level2NameU, Level2Name);
2371 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
2372 Status = ZwCreateKey(
2373 &hLevel2Key,
2374 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
2375 &ObjectAttributes,
2376 0,
2377 NULL,
2378 REG_OPTION_NON_VOLATILE,
2379 NULL);
2380 ZwClose(hLevel1Key);
2381 if (!NT_SUCCESS(Status))
2382 {
2383 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2384 goto nextdevice;
2385 }
2386 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
2387 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
2388 if (!NT_SUCCESS(Status))
2389 {
2390 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2391 ZwDeleteKey(hLevel2Key);
2392 goto nextdevice;
2393 }
2394 /* Create 'LogConf' subkey */
2395 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
2396 Status = ZwCreateKey(
2397 &hLogConf,
2398 KEY_SET_VALUE,
2399 &ObjectAttributes,
2400 0,
2401 NULL,
2402 REG_OPTION_VOLATILE,
2403 NULL);
2404 if (!NT_SUCCESS(Status))
2405 {
2406 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2407 ZwDeleteKey(hLevel2Key);
2408 goto nextdevice;
2409 }
2410 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2411 {
2412 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
2413 if (!CmResourceList)
2414 {
2415 ZwClose(hLogConf);
2416 ZwDeleteKey(hLevel2Key);
2417 goto nextdevice;
2418 }
2419
2420 /* Add the list count (1st member of CM_RESOURCE_LIST) */
2421 ListCount = 1;
2422 RtlCopyMemory(CmResourceList,
2423 &ListCount,
2424 sizeof(ULONG));
2425
2426 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
2427 RtlCopyMemory(CmResourceList + sizeof(ULONG),
2428 BootResources,
2429 BootResourcesLength);
2430
2431 /* Save boot resources to 'LogConf\BootConfig' */
2432 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
2433 if (!NT_SUCCESS(Status))
2434 {
2435 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2436 ZwClose(hLogConf);
2437 ZwDeleteKey(hLevel2Key);
2438 goto nextdevice;
2439 }
2440 }
2441 ZwClose(hLogConf);
2442
2443 nextdevice:
2444 if (BootResources && BootResources != ParentBootResources)
2445 {
2446 ExFreePool(BootResources);
2447 BootResources = NULL;
2448 }
2449 if (hLevel2Key)
2450 {
2451 ZwClose(hLevel2Key);
2452 hLevel2Key = NULL;
2453 }
2454 if (hDeviceKey)
2455 {
2456 ZwClose(hDeviceKey);
2457 hDeviceKey = NULL;
2458 }
2459 }
2460
2461 Status = STATUS_SUCCESS;
2462
2463 cleanup:
2464 if (hDevicesKey && hDevicesKey != hBaseKey)
2465 ZwClose(hDevicesKey);
2466 if (hDeviceKey)
2467 ZwClose(hDeviceKey);
2468 if (pDeviceInformation)
2469 ExFreePool(pDeviceInformation);
2470 if (pValueInformation)
2471 ExFreePool(pValueInformation);
2472 return Status;
2473 }
2474
2475 static BOOLEAN INIT_FUNCTION
2476 IopIsAcpiComputer(VOID)
2477 {
2478 #ifndef ENABLE_ACPI
2479 return FALSE;
2480 #else
2481 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2482 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2483 UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS");
2484 OBJECT_ATTRIBUTES ObjectAttributes;
2485 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2486 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2487 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2488 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2489 ULONG RequiredSize;
2490 ULONG IndexDevice = 0;
2491 UNICODE_STRING DeviceName, ValueName;
2492 HANDLE hDevicesKey = NULL;
2493 HANDLE hDeviceKey = NULL;
2494 NTSTATUS Status;
2495 BOOLEAN ret = FALSE;
2496
2497 InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2498 Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
2499 if (!NT_SUCCESS(Status))
2500 {
2501 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2502 goto cleanup;
2503 }
2504
2505 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2506 if (!pDeviceInformation)
2507 {
2508 DPRINT("ExAllocatePool() failed\n");
2509 Status = STATUS_NO_MEMORY;
2510 goto cleanup;
2511 }
2512
2513 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2514 if (!pDeviceInformation)
2515 {
2516 DPRINT("ExAllocatePool() failed\n");
2517 Status = STATUS_NO_MEMORY;
2518 goto cleanup;
2519 }
2520
2521 while (TRUE)
2522 {
2523 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2524 if (Status == STATUS_NO_MORE_ENTRIES)
2525 break;
2526 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2527 {
2528 ExFreePool(pDeviceInformation);
2529 DeviceInfoLength = RequiredSize;
2530 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2531 if (!pDeviceInformation)
2532 {
2533 DPRINT("ExAllocatePool() failed\n");
2534 Status = STATUS_NO_MEMORY;
2535 goto cleanup;
2536 }
2537 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2538 }
2539 if (!NT_SUCCESS(Status))
2540 {
2541 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2542 goto cleanup;
2543 }
2544 IndexDevice++;
2545
2546 /* Open device key */
2547 DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
2548 DeviceName.Buffer = pDeviceInformation->Name;
2549 InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
2550 Status = ZwOpenKey(
2551 &hDeviceKey,
2552 KEY_QUERY_VALUE,
2553 &ObjectAttributes);
2554 if (!NT_SUCCESS(Status))
2555 {
2556 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2557 goto cleanup;
2558 }
2559
2560 /* Read identifier */
2561 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2562 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2563 {
2564 ExFreePool(pValueInformation);
2565 ValueInfoLength = RequiredSize;
2566 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2567 if (!pValueInformation)
2568 {
2569 DPRINT("ExAllocatePool() failed\n");
2570 Status = STATUS_NO_MEMORY;
2571 goto cleanup;
2572 }
2573 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2574 }
2575 if (!NT_SUCCESS(Status))
2576 {
2577 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2578 goto nextdevice;
2579 }
2580 else if (pValueInformation->Type != REG_SZ)
2581 {
2582 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2583 goto nextdevice;
2584 }
2585
2586 ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
2587 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2588 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2589 ValueName.Length -= sizeof(WCHAR);
2590 if (RtlCompareUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE) == 0)
2591 {
2592 DPRINT("Found ACPI BIOS\n");
2593 ret = TRUE;
2594 goto cleanup;
2595 }
2596
2597 nextdevice:
2598 ZwClose(hDeviceKey);
2599 hDeviceKey = NULL;
2600 }
2601
2602 cleanup:
2603 if (pDeviceInformation)
2604 ExFreePool(pDeviceInformation);
2605 if (pValueInformation)
2606 ExFreePool(pValueInformation);
2607 if (hDevicesKey)
2608 ZwClose(hDevicesKey);
2609 if (hDeviceKey)
2610 ZwClose(hDeviceKey);
2611 return ret;
2612 #endif
2613 }
2614
2615 NTSTATUS
2616 NTAPI
2617 IopUpdateRootKey(VOID)
2618 {
2619 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
2620 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
2621 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2622 UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
2623 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2624 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2625 UNICODE_STRING HalAcpiDevice = RTL_CONSTANT_STRING(L"ACPI_HAL");
2626 UNICODE_STRING HalAcpiId = RTL_CONSTANT_STRING(L"0000");
2627 UNICODE_STRING HalAcpiDeviceDesc = RTL_CONSTANT_STRING(L"HAL ACPI");
2628 UNICODE_STRING HalAcpiHardwareID = RTL_CONSTANT_STRING(L"*PNP0C08\0");
2629 OBJECT_ATTRIBUTES ObjectAttributes;
2630 HANDLE hEnum, hRoot, hHalAcpiDevice, hHalAcpiId, hLogConf;
2631 NTSTATUS Status;
2632 ULONG Disposition;
2633
2634 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2635 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2636 if (!NT_SUCCESS(Status))
2637 {
2638 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
2639 return Status;
2640 }
2641
2642 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
2643 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2644 ZwClose(hEnum);
2645 if (!NT_SUCCESS(Status))
2646 {
2647 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
2648 return Status;
2649 }
2650
2651 if (IopIsAcpiComputer())
2652 {
2653 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiDevice, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hRoot, NULL);
2654 Status = ZwCreateKey(&hHalAcpiDevice, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2655 ZwClose(hRoot);
2656 if (!NT_SUCCESS(Status))
2657 return Status;
2658 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiId, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiDevice, NULL);
2659 Status = ZwCreateKey(&hHalAcpiId, KEY_CREATE_SUB_KEY | KEY_SET_VALUE, &ObjectAttributes, 0, NULL, 0, &Disposition);
2660 ZwClose(hHalAcpiDevice);
2661 if (!NT_SUCCESS(Status))
2662 return Status;
2663 if (Disposition == REG_CREATED_NEW_KEY)
2664 {
2665 Status = ZwSetValueKey(hHalAcpiId, &DeviceDescU, 0, REG_SZ, HalAcpiDeviceDesc.Buffer, HalAcpiDeviceDesc.MaximumLength);
2666 if (NT_SUCCESS(Status))
2667 Status = ZwSetValueKey(hHalAcpiId, &HardwareIDU, 0, REG_MULTI_SZ, HalAcpiHardwareID.Buffer, HalAcpiHardwareID.MaximumLength);
2668 }
2669 if (NT_SUCCESS(Status))
2670 {
2671 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiId, NULL);
2672 Status = ZwCreateKey(&hLogConf, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
2673 if (NT_SUCCESS(Status))
2674 ZwClose(hLogConf);
2675 }
2676 ZwClose(hHalAcpiId);
2677 return Status;
2678 }
2679 else
2680 {
2681 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
2682 if (!NT_SUCCESS(Status))
2683 {
2684 /* Nothing to do, don't return with an error status */
2685 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2686 ZwClose(hRoot);
2687 return STATUS_SUCCESS;
2688 }
2689 Status = IopEnumerateDetectedDevices(
2690 hEnum,
2691 NULL,
2692 hRoot,
2693 TRUE,
2694 NULL,
2695 0);
2696 ZwClose(hEnum);
2697 ZwClose(hRoot);
2698 return Status;
2699 }
2700 }
2701
2702 NTSTATUS
2703 NTAPI
2704 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
2705 HANDLE ParentKey,
2706 PUNICODE_STRING Name,
2707 ACCESS_MASK DesiredAccess)
2708 {
2709 OBJECT_ATTRIBUTES ObjectAttributes;
2710 NTSTATUS Status;
2711
2712 PAGED_CODE();
2713
2714 *KeyHandle = NULL;
2715
2716 InitializeObjectAttributes(&ObjectAttributes,
2717 Name,
2718 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2719 ParentKey,
2720 NULL);
2721
2722 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
2723
2724 return Status;
2725 }
2726
2727 NTSTATUS
2728 NTAPI
2729 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
2730 IN HANDLE RootHandle OPTIONAL,
2731 IN PUNICODE_STRING KeyName,
2732 IN ACCESS_MASK DesiredAccess,
2733 IN ULONG CreateOptions,
2734 OUT PULONG Disposition OPTIONAL)
2735 {
2736 OBJECT_ATTRIBUTES ObjectAttributes;
2737 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0, Length;
2738 HANDLE HandleArray[2];
2739 BOOLEAN Recursing = TRUE;
2740 PWCHAR pp, p, p1;
2741 UNICODE_STRING KeyString;
2742 NTSTATUS Status = STATUS_SUCCESS;
2743 PAGED_CODE();
2744
2745 /* P1 is start, pp is end */
2746 p1 = KeyName->Buffer;
2747 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
2748
2749 /* Create the target key */
2750 InitializeObjectAttributes(&ObjectAttributes,
2751 KeyName,
2752 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2753 RootHandle,
2754 NULL);
2755 Status = ZwCreateKey(&HandleArray[i],
2756 DesiredAccess,
2757 &ObjectAttributes,
2758 0,
2759 NULL,
2760 CreateOptions,
2761 &KeyDisposition);
2762
2763 /* Now we check if this failed */
2764 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
2765 {
2766 /* Target key failed, so we'll need to create its parent. Setup array */
2767 HandleArray[0] = NULL;
2768 HandleArray[1] = RootHandle;
2769
2770 /* Keep recursing for each missing parent */
2771 while (Recursing)
2772 {
2773 /* And if we're deep enough, close the last handle */
2774 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
2775
2776 /* We're setup to ping-pong between the two handle array entries */
2777 RootHandleIndex = i;
2778 i = (i + 1) & 1;
2779
2780 /* Clear the one we're attempting to open now */
2781 HandleArray[i] = NULL;
2782
2783 /* Process the parent key name */
2784 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
2785 Length = (p - p1) * sizeof(WCHAR);
2786
2787 /* Is there a parent name? */
2788 if (Length)
2789 {
2790 /* Build the unicode string for it */
2791 KeyString.Buffer = p1;
2792 KeyString.Length = KeyString.MaximumLength = Length;
2793
2794 /* Now try opening the parent */
2795 InitializeObjectAttributes(&ObjectAttributes,
2796 &KeyString,
2797 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2798 HandleArray[RootHandleIndex],
2799 NULL);
2800 Status = ZwCreateKey(&HandleArray[i],
2801 DesiredAccess,
2802 &ObjectAttributes,
2803 0,
2804 NULL,
2805 CreateOptions,
2806 &KeyDisposition);
2807 if (NT_SUCCESS(Status))
2808 {
2809 /* It worked, we have one more handle */
2810 NestedCloseLevel++;
2811 }
2812 else
2813 {
2814 /* Parent key creation failed, abandon loop */
2815 Recursing = FALSE;
2816 continue;
2817 }
2818 }
2819 else
2820 {
2821 /* We don't have a parent name, probably corrupted key name */
2822 Status = STATUS_INVALID_PARAMETER;
2823 Recursing = FALSE;
2824 continue;
2825 }
2826
2827 /* Now see if there's more parents to create */
2828 p1 = p + 1;
2829 if ((p == pp) || (p1 == pp))
2830 {
2831 /* We're done, hopefully successfully, so stop */
2832 Recursing = FALSE;
2833 }
2834 }
2835
2836 /* Outer loop check for handle nesting that requires closing the top handle */
2837 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
2838 }
2839
2840 /* Check if we broke out of the loop due to success */
2841 if (NT_SUCCESS(Status))
2842 {
2843 /* Return the target handle (we closed all the parent ones) and disposition */
2844 *Handle = HandleArray[i];
2845 if (Disposition) *Disposition = KeyDisposition;
2846 }
2847
2848 /* Return the success state */
2849 return Status;
2850 }
2851
2852 NTSTATUS
2853 NTAPI
2854 IopGetRegistryValue(IN HANDLE Handle,
2855 IN PWSTR ValueName,
2856 OUT PKEY_VALUE_FULL_INFORMATION *Information)
2857 {
2858 UNICODE_STRING ValueString;
2859 NTSTATUS Status;
2860 PKEY_VALUE_FULL_INFORMATION FullInformation;
2861 ULONG Size;
2862 PAGED_CODE();
2863
2864 RtlInitUnicodeString(&ValueString, ValueName);
2865
2866 Status = ZwQueryValueKey(Handle,
2867 &ValueString,
2868 KeyValueFullInformation,
2869 NULL,
2870 0,
2871 &Size);
2872 if ((Status != STATUS_BUFFER_OVERFLOW) &&
2873 (Status != STATUS_BUFFER_TOO_SMALL))
2874 {
2875 return Status;
2876 }
2877
2878 FullInformation = ExAllocatePool(NonPagedPool, Size);
2879 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
2880
2881 Status = ZwQueryValueKey(Handle,
2882 &ValueString,
2883 KeyValueFullInformation,
2884 FullInformation,
2885 Size,
2886 &Size);
2887 if (!NT_SUCCESS(Status))
2888 {
2889 ExFreePool(FullInformation);
2890 return Status;
2891 }
2892
2893 *Information = FullInformation;
2894 return STATUS_SUCCESS;
2895 }
2896
2897 RTL_GENERIC_COMPARE_RESULTS
2898 NTAPI
2899 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
2900 IN PVOID FirstStruct,
2901 IN PVOID SecondStruct)
2902 {
2903 /* FIXME: TODO */
2904 ASSERT(FALSE);
2905 return 0;
2906 }
2907
2908 //
2909 // The allocation function is called by the generic table package whenever
2910 // it needs to allocate memory for the table.
2911 //
2912
2913 PVOID
2914 NTAPI
2915 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
2916 IN CLONG ByteSize)
2917 {
2918 /* FIXME: TODO */
2919 ASSERT(FALSE);
2920 return NULL;
2921 }
2922
2923 VOID
2924 NTAPI
2925 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
2926 IN PVOID Buffer)
2927 {
2928 /* FIXME: TODO */
2929 ASSERT(FALSE);
2930 }
2931
2932 VOID
2933 NTAPI
2934 PpInitializeDeviceReferenceTable(VOID)
2935 {
2936 /* Setup the guarded mutex and AVL table */
2937 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
2938 RtlInitializeGenericTableAvl(
2939 &PpDeviceReferenceTable,
2940 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
2941 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
2942 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
2943 NULL);
2944 }
2945
2946 BOOLEAN
2947 NTAPI
2948 PiInitPhase0(VOID)
2949 {
2950 /* Initialize the resource when accessing device registry data */
2951 ExInitializeResourceLite(&PpRegistryDeviceResource);
2952
2953 /* Setup the device reference AVL table */
2954 PpInitializeDeviceReferenceTable();
2955 return TRUE;
2956 }
2957
2958 BOOLEAN
2959 NTAPI
2960 PpInitSystem(VOID)
2961 {
2962 /* Check the initialization phase */
2963 switch (ExpInitializationPhase)
2964 {
2965 case 0:
2966
2967 /* Do Phase 0 */
2968 return PiInitPhase0();
2969
2970 case 1:
2971
2972 /* Do Phase 1 */
2973 return TRUE;
2974 //return PiInitPhase1();
2975
2976 default:
2977
2978 /* Don't know any other phase! Bugcheck! */
2979 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
2980 return FALSE;
2981 }
2982 }
2983
2984 LONG IopNumberDeviceNodes;
2985
2986 PDEVICE_NODE
2987 NTAPI
2988 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
2989 {
2990 PDEVICE_NODE DeviceNode;
2991 PAGED_CODE();
2992
2993 /* Allocate it */
2994 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), 'donD');
2995 if (!DeviceNode) return DeviceNode;
2996
2997 /* Statistics */
2998 InterlockedIncrement(&IopNumberDeviceNodes);
2999
3000 /* Set it up */
3001 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3002 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3003 DeviceNode->BusNumber = -1;
3004 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3005 DeviceNode->ChildBusNumber = -1;
3006 DeviceNode->ChildBusTypeIndex = -1;
3007 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3008 InitializeListHead(&DeviceNode->DeviceArbiterList);
3009 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3010 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3011 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3012 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3013
3014 /* Check if there is a PDO */
3015 if (PhysicalDeviceObject)
3016 {
3017 /* Link it and remove the init flag */
3018 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3019 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3020 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3021 }
3022
3023 /* Return the node */
3024 return DeviceNode;
3025 }
3026
3027 /* PUBLIC FUNCTIONS **********************************************************/
3028
3029 NTSTATUS
3030 NTAPI
3031 PnpBusTypeGuidGet(IN USHORT Index,
3032 IN LPGUID BusTypeGuid)
3033 {
3034 NTSTATUS Status = STATUS_SUCCESS;
3035
3036 /* Acquire the lock */
3037 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3038
3039 /* Validate size */
3040 if (Index < PnpBusTypeGuidList->GuidCount)
3041 {
3042 /* Copy the data */
3043 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3044 }
3045 else
3046 {
3047 /* Failure path */
3048 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3049 }
3050
3051 /* Release lock and return status */
3052 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3053 return Status;
3054 }
3055
3056 NTSTATUS
3057 NTAPI
3058 PpIrpQueryCapabilities(IN PDEVICE_OBJECT DeviceObject,
3059 OUT PDEVICE_CAPABILITIES DeviceCaps)
3060 {
3061 PVOID Dummy;
3062 IO_STACK_LOCATION Stack;
3063
3064 PAGED_CODE();
3065
3066 /* Set up the Header */
3067 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
3068 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
3069 DeviceCaps->Version = 1;
3070 DeviceCaps->Address = -1;
3071 DeviceCaps->UINumber = -1;
3072
3073 /* Set up the Stack */
3074 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
3075 Stack.MajorFunction = IRP_MJ_PNP;
3076 Stack.MinorFunction = IRP_MN_QUERY_CAPABILITIES;
3077 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
3078
3079 /* Send the IRP */
3080 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
3081 }
3082
3083 NTSTATUS
3084 NTAPI
3085 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3086 IN PHANDLE DeviceInstanceHandle,
3087 IN ACCESS_MASK DesiredAccess)
3088 {
3089 NTSTATUS Status;
3090 HANDLE KeyHandle;
3091 PDEVICE_NODE DeviceNode;
3092 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3093 PAGED_CODE();
3094
3095 /* Open the enum key */
3096 Status = IopOpenRegistryKeyEx(&KeyHandle,
3097 NULL,
3098 &KeyName,
3099 KEY_READ);
3100 if (!NT_SUCCESS(Status)) return Status;
3101
3102 /* Make sure we have an instance path */
3103 DeviceNode = IopGetDeviceNode(DeviceObject);
3104 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3105 {
3106 /* Get the instance key */
3107 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3108 KeyHandle,
3109 &DeviceNode->InstancePath,
3110 DesiredAccess);
3111 }
3112 else
3113 {
3114 /* Fail */
3115 Status = STATUS_INVALID_DEVICE_REQUEST;
3116 }
3117
3118 /* Close the handle and return status */
3119 ZwClose(KeyHandle);
3120 return Status;
3121 }
3122
3123 ULONG
3124 NTAPI
3125 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3126 {
3127 ULONG FinalSize, PartialSize, EntrySize, i, j;
3128 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3129 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3130
3131 /* If we don't have one, that's easy */
3132 if (!ResourceList) return 0;
3133
3134 /* Start with the minimum size possible */
3135 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3136
3137 /* Loop each full descriptor */
3138 FullDescriptor = ResourceList->List;
3139 for (i = 0; i < ResourceList->Count; i++)
3140 {
3141 /* Start with the minimum size possible */
3142 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3143 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3144
3145 /* Loop each partial descriptor */
3146 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3147 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3148 {
3149 /* Start with the minimum size possible */
3150 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3151
3152 /* Check if there is extra data */
3153 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3154 {
3155 /* Add that data */
3156 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3157 }
3158
3159 /* The size of partial descriptors is bigger */
3160 PartialSize += EntrySize;
3161
3162 /* Go to the next partial descriptor */
3163 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3164 }
3165
3166 /* The size of full descriptors is bigger */
3167 FinalSize += PartialSize;
3168
3169 /* Go to the next full descriptor */
3170 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3171 }
3172
3173 /* Return the final size */
3174 return FinalSize;
3175 }
3176
3177 NTSTATUS
3178 NTAPI
3179 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3180 IN ULONG ValueType,
3181 IN PWSTR ValueName,
3182 IN PWSTR KeyName,
3183 OUT PVOID Buffer,
3184 IN PULONG BufferLength)
3185 {
3186 NTSTATUS Status;
3187 HANDLE KeyHandle, SubHandle;
3188 UNICODE_STRING KeyString;
3189 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3190 ULONG Length;
3191 PAGED_CODE();
3192
3193 /* Find the instance key */
3194 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3195 if (NT_SUCCESS(Status))
3196 {
3197 /* Check for name given by caller */
3198 if (KeyName)
3199 {
3200 /* Open this key */
3201 RtlInitUnicodeString(&KeyString, KeyName);
3202 Status = IopOpenRegistryKeyEx(&SubHandle,
3203 KeyHandle,
3204 &KeyString,
3205 KEY_READ);
3206 if (NT_SUCCESS(Status))
3207 {
3208 /* And use this handle instead */
3209 ZwClose(KeyHandle);
3210 KeyHandle = SubHandle;
3211 }
3212 }
3213
3214 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3215 if (NT_SUCCESS(Status))
3216 {
3217 /* Now get the size of the property */
3218 Status = IopGetRegistryValue(KeyHandle,
3219 ValueName,
3220 &KeyValueInfo);
3221 }
3222
3223 /* Close the key */
3224 ZwClose(KeyHandle);
3225 }
3226
3227 /* Fail if any of the registry operations failed */
3228 if (!NT_SUCCESS(Status)) return Status;
3229
3230 /* Check how much data we have to copy */
3231 Length = KeyValueInfo->DataLength;
3232 if (*BufferLength >= Length)
3233 {
3234 /* Check for a match in the value type */
3235 if (KeyValueInfo->Type == ValueType)
3236 {
3237 /* Copy the data */
3238 RtlCopyMemory(Buffer,
3239 (PVOID)((ULONG_PTR)KeyValueInfo +
3240 KeyValueInfo->DataOffset),
3241 Length);
3242 }
3243 else
3244 {
3245 /* Invalid registry property type, fail */
3246 Status = STATUS_INVALID_PARAMETER_2;
3247 }
3248 }
3249 else
3250 {
3251 /* Buffer is too small to hold data */
3252 Status = STATUS_BUFFER_TOO_SMALL;
3253 }
3254
3255 /* Return the required buffer length, free the buffer, and return status */
3256 *BufferLength = Length;
3257 ExFreePool(KeyValueInfo);
3258 return Status;
3259 }
3260
3261 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3262 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3263 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED; while(TRUE); break;}
3264
3265 /*
3266 * @implemented
3267 */
3268 NTSTATUS
3269 NTAPI
3270 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
3271 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
3272 IN ULONG BufferLength,
3273 OUT PVOID PropertyBuffer,
3274 OUT PULONG ResultLength)
3275 {
3276 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
3277 DEVICE_CAPABILITIES DeviceCaps;
3278 ULONG ReturnLength = 0, Length = 0, ValueType;
3279 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
3280 PVOID Data = NULL;
3281 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
3282 GUID BusTypeGuid;
3283 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
3284 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
3285
3286 /* Assume failure */
3287 *ResultLength = 0;
3288
3289 /* Only PDOs can call this */
3290 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
3291
3292 /* Handle all properties */
3293 switch (DeviceProperty)
3294 {
3295 case DevicePropertyBusTypeGuid:
3296
3297 /* Get the GUID from the internal cache */
3298 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
3299 if (!NT_SUCCESS(Status)) return Status;
3300
3301 /* This is the format of the returned data */
3302 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
3303
3304 case DevicePropertyLegacyBusType:
3305
3306 /* Validate correct interface type */
3307 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
3308 return STATUS_OBJECT_NAME_NOT_FOUND;
3309
3310 /* This is the format of the returned data */
3311 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
3312
3313 case DevicePropertyBusNumber:
3314
3315 /* Validate correct bus number */
3316 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
3317 return STATUS_OBJECT_NAME_NOT_FOUND;
3318
3319 /* This is the format of the returned data */
3320 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
3321
3322 case DevicePropertyEnumeratorName:
3323
3324 /* Get the instance path */
3325 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
3326
3327 /* Sanity checks */
3328 ASSERT((BufferLength & 1) == 0);
3329 ASSERT(DeviceInstanceName != NULL);
3330
3331 /* Get the name from the path */
3332 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
3333 ASSERT(EnumeratorNameEnd);
3334
3335 /* This is the format of the returned data */
3336 PIP_RETURN_DATA((EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
3337 DeviceInstanceName);
3338
3339 case DevicePropertyAddress:
3340
3341 /* Query the device caps */
3342 Status = PpIrpQueryCapabilities(DeviceObject, &DeviceCaps);
3343 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
3344 return STATUS_OBJECT_NAME_NOT_FOUND;
3345
3346 /* This is the format of the returned data */
3347 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
3348
3349 case DevicePropertyBootConfigurationTranslated:
3350
3351 /* Validate we have resources */
3352 if (!DeviceNode->BootResources)
3353 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3354 {
3355 /* No resources will still fake success, but with 0 bytes */
3356 *ResultLength = 0;
3357 return STATUS_SUCCESS;
3358 }
3359
3360 /* This is the format of the returned data */
3361 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
3362 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
3363
3364 case DevicePropertyPhysicalDeviceObjectName:
3365
3366 /* Sanity check for Unicode-sized string */
3367 ASSERT((BufferLength & 1) == 0);
3368
3369 /* Allocate name buffer */
3370 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
3371 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
3372 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
3373
3374 /* Query the PDO name */
3375 Status = ObQueryNameString(DeviceObject,
3376 ObjectNameInfo,
3377 Length,
3378 ResultLength);
3379 if (Status == STATUS_INFO_LENGTH_MISMATCH)
3380 {
3381 /* It's up to the caller to try again */
3382 Status = STATUS_BUFFER_TOO_SMALL;
3383 }
3384
3385 /* Return if successful */
3386 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
3387 ObjectNameInfo->Name.Buffer);
3388
3389 /* Let the caller know how big the name is */
3390 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
3391 break;
3392
3393 /* Handle the registry-based properties */
3394 case DevicePropertyUINumber:
3395 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
3396 case DevicePropertyLocationInformation:
3397 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
3398 case DevicePropertyDeviceDescription:
3399 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
3400 case DevicePropertyHardwareID:
3401 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
3402 case DevicePropertyCompatibleIDs:
3403 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
3404 case DevicePropertyBootConfiguration:
3405 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
3406 case DevicePropertyClassName:
3407 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
3408 case DevicePropertyClassGuid:
3409 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
3410 case DevicePropertyDriverKeyName:
3411 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
3412 case DevicePropertyManufacturer:
3413 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
3414 case DevicePropertyFriendlyName:
3415 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
3416 case DevicePropertyContainerID:
3417 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3418 PIP_UNIMPLEMENTED();
3419 case DevicePropertyRemovalPolicy:
3420 PIP_UNIMPLEMENTED();
3421 case DevicePropertyInstallState:
3422 PIP_UNIMPLEMENTED();
3423 case DevicePropertyResourceRequirements:
3424 PIP_UNIMPLEMENTED();
3425 case DevicePropertyAllocatedResources:
3426 PIP_UNIMPLEMENTED();
3427 default:
3428 return STATUS_INVALID_PARAMETER_2;
3429 }
3430
3431 /* Having a registry value name implies registry data */
3432 if (ValueName)
3433 {
3434 /* We know up-front how much data to expect */
3435 *ResultLength = BufferLength;
3436
3437 /* Go get the data, use the LogConf subkey if necessary */
3438 Status = PiGetDeviceRegistryProperty(DeviceObject,
3439 ValueType,
3440 ValueName,
3441 (DeviceProperty ==
3442 DevicePropertyBootConfiguration) ?
3443 L"LogConf": NULL,
3444 PropertyBuffer,
3445 ResultLength);
3446 }
3447 else if (NT_SUCCESS(Status))
3448 {
3449 /* We know up-front how much data to expect, check the caller's buffer */
3450 *ResultLength = ReturnLength;
3451 if (ReturnLength <= BufferLength)
3452 {
3453 /* Buffer is all good, copy the data */
3454 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
3455
3456 /* Check for properties that require a null-terminated string */
3457 if ((DeviceProperty == DevicePropertyEnumeratorName) ||
3458 (DeviceProperty == DevicePropertyPhysicalDeviceObjectName))
3459 {
3460 /* Terminate the string */
3461 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
3462 }
3463
3464 /* This is the success path */
3465 Status = STATUS_SUCCESS;
3466 }
3467 else
3468 {
3469 /* Failure path */
3470 Status = STATUS_BUFFER_TOO_SMALL;
3471 }
3472 }
3473
3474 /* Free any allocation we may have made, and return the status code */
3475 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
3476 return Status;
3477 }
3478
3479 /*
3480 * @unimplemented
3481 */
3482 VOID
3483 NTAPI
3484 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
3485 {
3486 UNIMPLEMENTED;
3487 }
3488
3489 /**
3490 * @name IoOpenDeviceRegistryKey
3491 *
3492 * Open a registry key unique for a specified driver or device instance.
3493 *
3494 * @param DeviceObject Device to get the registry key for.
3495 * @param DevInstKeyType Type of the key to return.
3496 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
3497 * @param DevInstRegKey Handle to the opened registry key on
3498 * successful return.
3499 *
3500 * @return Status.
3501 *
3502 * @implemented
3503 */
3504 NTSTATUS
3505 NTAPI
3506 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
3507 IN ULONG DevInstKeyType,
3508 IN ACCESS_MASK DesiredAccess,
3509 OUT PHANDLE DevInstRegKey)
3510 {
3511 static WCHAR RootKeyName[] =
3512 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
3513 static WCHAR ProfileKeyName[] =
3514 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
3515 static WCHAR ClassKeyName[] = L"Control\\Class\\";
3516 static WCHAR EnumKeyName[] = L"Enum\\";
3517 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
3518 ULONG KeyNameLength;
3519 LPWSTR KeyNameBuffer;
3520 UNICODE_STRING KeyName;
3521 ULONG DriverKeyLength;
3522 OBJECT_ATTRIBUTES ObjectAttributes;
3523 PDEVICE_NODE DeviceNode = NULL;
3524 NTSTATUS Status;
3525
3526 DPRINT("IoOpenDeviceRegistryKey() called\n");
3527
3528 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
3529 {
3530 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
3531 return STATUS_INVALID_PARAMETER;
3532 }
3533
3534 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
3535 return STATUS_INVALID_DEVICE_REQUEST;
3536 DeviceNode = IopGetDeviceNode(DeviceObject);
3537
3538 /*
3539 * Calculate the length of the base key name. This is the full
3540 * name for driver key or the name excluding "Device Parameters"
3541 * subkey for device key.
3542 */
3543
3544 KeyNameLength = sizeof(RootKeyName);
3545 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
3546 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
3547 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3548 {
3549 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
3550 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
3551 0, NULL, &DriverKeyLength);
3552 if (Status != STATUS_BUFFER_TOO_SMALL)
3553 return Status;
3554 KeyNameLength += DriverKeyLength;
3555 }
3556 else
3557 {
3558 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
3559 DeviceNode->InstancePath.Length;
3560 }
3561
3562 /*
3563 * Now allocate the buffer for the key name...
3564 */
3565
3566 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
3567 if (KeyNameBuffer == NULL)
3568 return STATUS_INSUFFICIENT_RESOURCES;
3569
3570 KeyName.Length = 0;
3571 KeyName.MaximumLength = (USHORT)KeyNameLength;
3572 KeyName.Buffer = KeyNameBuffer;
3573
3574 /*
3575 * ...and build the key name.
3576 */
3577
3578 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
3579 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
3580
3581 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
3582 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
3583
3584 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3585 {
3586 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
3587 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
3588 DriverKeyLength, KeyNameBuffer +
3589 (KeyName.Length / sizeof(WCHAR)),
3590 &DriverKeyLength);
3591 if (!NT_SUCCESS(Status))
3592 {
3593 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
3594 ExFreePool(KeyNameBuffer);
3595 return Status;
3596 }
3597 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
3598 }
3599 else
3600 {
3601 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
3602 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
3603 if (DeviceNode->InstancePath.Length == 0)
3604 {
3605 ExFreePool(KeyNameBuffer);
3606 return Status;
3607 }
3608 }
3609
3610 /*
3611 * Open the base key.
3612 */
3613 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
3614 if (!NT_SUCCESS(Status))
3615 {
3616 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
3617 ExFreePool(KeyNameBuffer);
3618 return Status;
3619 }
3620 ExFreePool(KeyNameBuffer);
3621
3622 /*
3623 * For driver key we're done now.
3624 */
3625
3626 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3627 return Status;
3628
3629 /*
3630 * Let's go further. For device key we must open "Device Parameters"
3631 * subkey and create it if it doesn't exist yet.
3632 */
3633
3634 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
3635 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
3636 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
3637 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
3638 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
3639 ZwClose(ObjectAttributes.RootDirectory);
3640
3641 return Status;
3642 }
3643
3644 /*
3645 * @unimplemented
3646 */
3647 VOID
3648 NTAPI
3649 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
3650 {
3651 UNIMPLEMENTED;
3652 }
3653
3654 /*
3655 * @implemented
3656 */
3657 VOID
3658 NTAPI
3659 IoInvalidateDeviceRelations(
3660 IN PDEVICE_OBJECT DeviceObject,
3661 IN DEVICE_RELATION_TYPE Type)
3662 {
3663 PIO_WORKITEM WorkItem;
3664 PINVALIDATE_DEVICE_RELATION_DATA Data;
3665
3666 Data = ExAllocatePool(NonPagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
3667 if (!Data)
3668 return;
3669 WorkItem = IoAllocateWorkItem(DeviceObject);
3670 if (!WorkItem)
3671 {
3672 ExFreePool(Data);
3673 return;
3674 }
3675
3676 ObReferenceObject(DeviceObject);
3677 Data->DeviceObject = DeviceObject;
3678 Data->Type = Type;
3679 Data->WorkItem = WorkItem;
3680
3681 IoQueueWorkItem(
3682 WorkItem,
3683 IopAsynchronousInvalidateDeviceRelations,
3684 DelayedWorkQueue,
3685 Data);
3686 }
3687
3688 /*
3689 * @implemented
3690 */
3691 NTSTATUS
3692 NTAPI
3693 IoSynchronousInvalidateDeviceRelations(
3694 IN PDEVICE_OBJECT DeviceObject,
3695 IN DEVICE_RELATION_TYPE Type)
3696 {
3697 PAGED_CODE();
3698
3699 switch (Type)
3700 {
3701 case BusRelations:
3702 /* Enumerate the device */
3703 return IopEnumerateDevice(DeviceObject);
3704 case PowerRelations:
3705 /* Not handled yet */
3706 return STATUS_NOT_IMPLEMENTED;
3707 case TargetDeviceRelation:
3708 /* Nothing to do */
3709 return STATUS_SUCCESS;
3710 default:
3711 /* Ejection relations are not supported */
3712 return STATUS_NOT_SUPPORTED;
3713 }
3714 }
3715
3716 /*
3717 * @unimplemented
3718 */
3719 BOOLEAN
3720 NTAPI
3721 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
3722 IN ULONG BusNumber,
3723 IN PHYSICAL_ADDRESS BusAddress,
3724 IN OUT PULONG AddressSpace,
3725 OUT PPHYSICAL_ADDRESS TranslatedAddress)
3726 {
3727 UNIMPLEMENTED;
3728 return FALSE;
3729 }