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