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