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