9d20b971ff0c12363b7fccdad6789412e9bd1321
[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 && !(Child->Flags & DNF_WILL_BE_REMOVED))
1828 {
1829 /* Send removal IRPs to all of its children */
1830 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
1831
1832 /* Send the surprise removal IRP */
1833 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
1834
1835 /* Tell the user-mode PnP manager that a device was removed */
1836 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
1837 &Child->InstancePath);
1838
1839 /* Send the remove device IRP */
1840 IopSendRemoveDevice(Child->PhysicalDeviceObject);
1841 }
1842
1843 Child = NextChild;
1844 }
1845 }
1846
1847 NTSTATUS
1848 IopEnumerateDevice(
1849 IN PDEVICE_OBJECT DeviceObject)
1850 {
1851 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1852 DEVICETREE_TRAVERSE_CONTEXT Context;
1853 PDEVICE_RELATIONS DeviceRelations;
1854 PDEVICE_OBJECT ChildDeviceObject;
1855 IO_STATUS_BLOCK IoStatusBlock;
1856 PDEVICE_NODE ChildDeviceNode;
1857 IO_STACK_LOCATION Stack;
1858 NTSTATUS Status;
1859 ULONG i;
1860
1861 DPRINT("DeviceObject 0x%p\n", DeviceObject);
1862
1863 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
1864 {
1865 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
1866
1867 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
1868 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
1869 &DeviceNode->InstancePath);
1870 }
1871
1872 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1873
1874 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
1875
1876 Status = IopInitiatePnpIrp(
1877 DeviceObject,
1878 &IoStatusBlock,
1879 IRP_MN_QUERY_DEVICE_RELATIONS,
1880 &Stack);
1881 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1882 {
1883 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
1884 return Status;
1885 }
1886
1887 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1888
1889 /*
1890 * Send removal IRPs for devices that have disappeared
1891 * NOTE: This code handles the case where no relations are specified
1892 */
1893 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
1894
1895 /* Now we bail if nothing was returned */
1896 if (!DeviceRelations)
1897 {
1898 /* We're all done */
1899 DPRINT("No PDOs\n");
1900 return STATUS_SUCCESS;
1901 }
1902
1903 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
1904
1905 /*
1906 * Create device nodes for all discovered devices
1907 */
1908 for (i = 0; i < DeviceRelations->Count; i++)
1909 {
1910 ChildDeviceObject = DeviceRelations->Objects[i];
1911 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
1912
1913 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
1914 if (!ChildDeviceNode)
1915 {
1916 /* One doesn't exist, create it */
1917 Status = IopCreateDeviceNode(
1918 DeviceNode,
1919 ChildDeviceObject,
1920 NULL,
1921 &ChildDeviceNode);
1922 if (NT_SUCCESS(Status))
1923 {
1924 /* Mark the node as enumerated */
1925 ChildDeviceNode->Flags |= DNF_ENUMERATED;
1926
1927 /* Mark the DO as bus enumerated */
1928 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
1929 }
1930 else
1931 {
1932 /* Ignore this DO */
1933 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
1934 ObDereferenceObject(ChildDeviceObject);
1935 }
1936 }
1937 else
1938 {
1939 /* Mark it as enumerated */
1940 ChildDeviceNode->Flags |= DNF_ENUMERATED;
1941 ObDereferenceObject(ChildDeviceObject);
1942 }
1943 }
1944 ExFreePool(DeviceRelations);
1945
1946 /*
1947 * Retrieve information about all discovered children from the bus driver
1948 */
1949 IopInitDeviceTreeTraverseContext(
1950 &Context,
1951 DeviceNode,
1952 IopActionInterrogateDeviceStack,
1953 DeviceNode);
1954
1955 Status = IopTraverseDeviceTree(&Context);
1956 if (!NT_SUCCESS(Status))
1957 {
1958 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
1959 return Status;
1960 }
1961
1962 /*
1963 * Retrieve configuration from the registry for discovered children
1964 */
1965 IopInitDeviceTreeTraverseContext(
1966 &Context,
1967 DeviceNode,
1968 IopActionConfigureChildServices,
1969 DeviceNode);
1970
1971 Status = IopTraverseDeviceTree(&Context);
1972 if (!NT_SUCCESS(Status))
1973 {
1974 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
1975 return Status;
1976 }
1977
1978 /*
1979 * Initialize services for discovered children.
1980 */
1981 Status = IopInitializePnpServices(DeviceNode);
1982 if (!NT_SUCCESS(Status))
1983 {
1984 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
1985 return Status;
1986 }
1987
1988 DPRINT("IopEnumerateDevice() finished\n");
1989 return STATUS_SUCCESS;
1990 }
1991
1992
1993 /*
1994 * IopActionConfigureChildServices
1995 *
1996 * Retrieve configuration for all (direct) child nodes of a parent node.
1997 *
1998 * Parameters
1999 * DeviceNode
2000 * Pointer to device node.
2001 * Context
2002 * Pointer to parent node to retrieve child node configuration for.
2003 *
2004 * Remarks
2005 * Any errors that occur are logged instead so that all child services have a chance of beeing
2006 * configured.
2007 */
2008
2009 NTSTATUS
2010 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2011 PVOID Context)
2012 {
2013 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2014 PDEVICE_NODE ParentDeviceNode;
2015 PUNICODE_STRING Service;
2016 UNICODE_STRING ClassGUID;
2017 NTSTATUS Status;
2018 DEVICE_CAPABILITIES DeviceCaps;
2019
2020 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2021
2022 ParentDeviceNode = (PDEVICE_NODE)Context;
2023
2024 /*
2025 * We are called for the parent too, but we don't need to do special
2026 * handling for this node
2027 */
2028 if (DeviceNode == ParentDeviceNode)
2029 {
2030 DPRINT("Success\n");
2031 return STATUS_SUCCESS;
2032 }
2033
2034 /*
2035 * Make sure this device node is a direct child of the parent device node
2036 * that is given as an argument
2037 */
2038
2039 if (DeviceNode->Parent != ParentDeviceNode)
2040 {
2041 DPRINT("Skipping 2+ level child\n");
2042 return STATUS_SUCCESS;
2043 }
2044
2045 if (!(DeviceNode->Flags & DNF_PROCESSED))
2046 {
2047 DPRINT1("Child not ready to be configured\n");
2048 return STATUS_SUCCESS;
2049 }
2050
2051 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2052 {
2053 WCHAR RegKeyBuffer[MAX_PATH];
2054 UNICODE_STRING RegKey;
2055
2056 RegKey.Length = 0;
2057 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2058 RegKey.Buffer = RegKeyBuffer;
2059
2060 /*
2061 * Retrieve configuration from Enum key
2062 */
2063
2064 Service = &DeviceNode->ServiceName;
2065
2066 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2067 RtlInitUnicodeString(Service, NULL);
2068 RtlInitUnicodeString(&ClassGUID, NULL);
2069
2070 QueryTable[0].Name = L"Service";
2071 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2072 QueryTable[0].EntryContext = Service;
2073
2074 QueryTable[1].Name = L"ClassGUID";
2075 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2076 QueryTable[1].EntryContext = &ClassGUID;
2077 QueryTable[1].DefaultType = REG_SZ;
2078 QueryTable[1].DefaultData = L"";
2079 QueryTable[1].DefaultLength = 0;
2080
2081 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2082 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2083
2084 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2085 RegKey.Buffer, QueryTable, NULL, NULL);
2086
2087 if (!NT_SUCCESS(Status))
2088 {
2089 /* FIXME: Log the error */
2090 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2091 &DeviceNode->InstancePath, Status);
2092 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2093 return STATUS_SUCCESS;
2094 }
2095
2096 if (Service->Buffer == NULL)
2097 {
2098 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2099 DeviceCaps.RawDeviceOK)
2100 {
2101 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2102
2103 DeviceNode->ServiceName.Length = 0;
2104 DeviceNode->ServiceName.MaximumLength = 0;
2105 DeviceNode->ServiceName.Buffer = NULL;
2106 }
2107 else if (ClassGUID.Length != 0)
2108 {
2109 /* Device has a ClassGUID value, but no Service value.
2110 * Suppose it is using the NULL driver, so state the
2111 * device is started */
2112 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2113 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2114 }
2115 else
2116 {
2117 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2118 }
2119 return STATUS_SUCCESS;
2120 }
2121
2122 DPRINT("Got Service %S\n", Service->Buffer);
2123 }
2124
2125 return STATUS_SUCCESS;
2126 }
2127
2128 /*
2129 * IopActionInitChildServices
2130 *
2131 * Initialize the service for all (direct) child nodes of a parent node
2132 *
2133 * Parameters
2134 * DeviceNode
2135 * Pointer to device node.
2136 * Context
2137 * Pointer to parent node to initialize child node services for.
2138 *
2139 * Remarks
2140 * If the driver image for a service is not loaded and initialized
2141 * it is done here too. Any errors that occur are logged instead so
2142 * that all child services have a chance of being initialized.
2143 */
2144
2145 NTSTATUS
2146 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2147 PVOID Context)
2148 {
2149 PDEVICE_NODE ParentDeviceNode;
2150 NTSTATUS Status;
2151 BOOLEAN BootDrivers = !PnpSystemInit;
2152
2153 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2154
2155 ParentDeviceNode = (PDEVICE_NODE)Context;
2156
2157 /*
2158 * We are called for the parent too, but we don't need to do special
2159 * handling for this node
2160 */
2161 if (DeviceNode == ParentDeviceNode)
2162 {
2163 DPRINT("Success\n");
2164 return STATUS_SUCCESS;
2165 }
2166
2167 /*
2168 * Make sure this device node is a direct child of the parent device node
2169 * that is given as an argument
2170 */
2171
2172 if (DeviceNode->Parent != ParentDeviceNode)
2173 {
2174 DPRINT("Skipping 2+ level child\n");
2175 return STATUS_SUCCESS;
2176 }
2177
2178 if (!(DeviceNode->Flags & DNF_PROCESSED))
2179 {
2180 DPRINT1("Child not ready to be added\n");
2181 return STATUS_SUCCESS;
2182 }
2183
2184 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2185 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2186 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2187 return STATUS_SUCCESS;
2188
2189 if (DeviceNode->ServiceName.Buffer == NULL)
2190 {
2191 /* We don't need to worry about loading the driver because we're
2192 * being driven in raw mode so our parent must be loaded to get here */
2193 Status = IopInitializeDevice(DeviceNode, NULL);
2194 if (NT_SUCCESS(Status))
2195 {
2196 Status = IopStartDevice(DeviceNode);
2197 if (!NT_SUCCESS(Status))
2198 {
2199 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2200 &DeviceNode->InstancePath, Status);
2201 }
2202 }
2203 }
2204 else
2205 {
2206 PLDR_DATA_TABLE_ENTRY ModuleObject;
2207 PDRIVER_OBJECT DriverObject;
2208
2209 /* Get existing DriverObject pointer (in case the driver has
2210 already been loaded and initialized) */
2211 Status = IopGetDriverObject(
2212 &DriverObject,
2213 &DeviceNode->ServiceName,
2214 FALSE);
2215
2216 if (!NT_SUCCESS(Status))
2217 {
2218 /* Driver is not initialized, try to load it */
2219 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2220
2221 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2222 {
2223 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2224 was loaded by the bootloader */
2225 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
2226 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
2227 {
2228 /* Initialize the driver */
2229 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2230 &DeviceNode->ServiceName, FALSE, &DriverObject);
2231 }
2232 else
2233 {
2234 Status = STATUS_SUCCESS;
2235 }
2236 }
2237 else
2238 {
2239 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2240 &DeviceNode->ServiceName, Status);
2241 }
2242 }
2243
2244 /* Driver is loaded and initialized at this point */
2245 if (NT_SUCCESS(Status))
2246 {
2247 /* Initialize the device, including all filters */
2248 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2249 }
2250 else
2251 {
2252 /*
2253 * Don't disable when trying to load only boot drivers
2254 */
2255 if (!BootDrivers)
2256 {
2257 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2258 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2259 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2260 DPRINT1("Initialization of service %S failed (Status %x)\n",
2261 DeviceNode->ServiceName.Buffer, Status);
2262 }
2263 }
2264 }
2265
2266 return STATUS_SUCCESS;
2267 }
2268
2269 /*
2270 * IopInitializePnpServices
2271 *
2272 * Initialize services for discovered children
2273 *
2274 * Parameters
2275 * DeviceNode
2276 * Top device node to start initializing services.
2277 *
2278 * Return Value
2279 * Status
2280 */
2281 NTSTATUS
2282 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2283 {
2284 DEVICETREE_TRAVERSE_CONTEXT Context;
2285
2286 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2287
2288 IopInitDeviceTreeTraverseContext(
2289 &Context,
2290 DeviceNode,
2291 IopActionInitChildServices,
2292 DeviceNode);
2293
2294 return IopTraverseDeviceTree(&Context);
2295 }
2296
2297 static NTSTATUS INIT_FUNCTION
2298 IopEnumerateDetectedDevices(
2299 IN HANDLE hBaseKey,
2300 IN PUNICODE_STRING RelativePath OPTIONAL,
2301 IN HANDLE hRootKey,
2302 IN BOOLEAN EnumerateSubKeys,
2303 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2304 IN ULONG ParentBootResourcesLength)
2305 {
2306 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2307 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2308 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2309 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2310 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2311 OBJECT_ATTRIBUTES ObjectAttributes;
2312 HANDLE hDevicesKey = NULL;
2313 HANDLE hDeviceKey = NULL;
2314 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2315 UNICODE_STRING Level2NameU;
2316 WCHAR Level2Name[5];
2317 ULONG IndexDevice = 0;
2318 ULONG IndexSubKey;
2319 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2320 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2321 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2322 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2323 UNICODE_STRING DeviceName, ValueName;
2324 ULONG RequiredSize;
2325 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2326 ULONG BootResourcesLength;
2327 NTSTATUS Status;
2328
2329 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
2330 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
2331 static ULONG DeviceIndexPci = 0;
2332 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2333 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2334 static ULONG DeviceIndexSerial = 0;
2335 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2336 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2337 static ULONG DeviceIndexKeyboard = 0;
2338 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2339 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2340 static ULONG DeviceIndexMouse = 0;
2341 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2342 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2343 static ULONG DeviceIndexParallel = 0;
2344 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2345 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2346 static ULONG DeviceIndexFloppy = 0;
2347 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
2348 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
2349 static ULONG DeviceIndexIsa = 0;
2350 UNICODE_STRING HardwareIdKey;
2351 PUNICODE_STRING pHardwareId;
2352 ULONG DeviceIndex = 0;
2353 PUCHAR CmResourceList;
2354 ULONG ListCount;
2355
2356 if (RelativePath)
2357 {
2358 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2359 if (!NT_SUCCESS(Status))
2360 {
2361 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2362 goto cleanup;
2363 }
2364 }
2365 else
2366 hDevicesKey = hBaseKey;
2367
2368 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2369 if (!pDeviceInformation)
2370 {
2371 DPRINT("ExAllocatePool() failed\n");
2372 Status = STATUS_NO_MEMORY;
2373 goto cleanup;
2374 }
2375
2376 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2377 if (!pValueInformation)
2378 {
2379 DPRINT("ExAllocatePool() failed\n");
2380 Status = STATUS_NO_MEMORY;
2381 goto cleanup;
2382 }
2383
2384 while (TRUE)
2385 {
2386 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2387 if (Status == STATUS_NO_MORE_ENTRIES)
2388 break;
2389 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2390 {
2391 ExFreePool(pDeviceInformation);
2392 DeviceInfoLength = RequiredSize;
2393 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2394 if (!pDeviceInformation)
2395 {
2396 DPRINT("ExAllocatePool() failed\n");
2397 Status = STATUS_NO_MEMORY;
2398 goto cleanup;
2399 }
2400 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2401 }
2402 if (!NT_SUCCESS(Status))
2403 {
2404 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2405 goto cleanup;
2406 }
2407 IndexDevice++;
2408
2409 /* Open device key */
2410 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2411 DeviceName.Buffer = pDeviceInformation->Name;
2412
2413 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
2414 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
2415 if (!NT_SUCCESS(Status))
2416 {
2417 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2418 goto cleanup;
2419 }
2420
2421 /* Read boot resources, and add then to parent ones */
2422 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2423 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2424 {
2425 ExFreePool(pValueInformation);
2426 ValueInfoLength = RequiredSize;
2427 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2428 if (!pValueInformation)
2429 {
2430 DPRINT("ExAllocatePool() failed\n");
2431 ZwDeleteKey(hLevel2Key);
2432 Status = STATUS_NO_MEMORY;
2433 goto cleanup;
2434 }
2435 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2436 }
2437 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2438 {
2439 BootResources = ParentBootResources;
2440 BootResourcesLength = ParentBootResourcesLength;
2441 }
2442 else if (!NT_SUCCESS(Status))
2443 {
2444 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2445 goto nextdevice;
2446 }
2447 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2448 {
2449 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2450 goto nextdevice;
2451 }
2452 else
2453 {
2454 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2455
2456 /* Concatenate current resources and parent ones */
2457 if (ParentBootResourcesLength == 0)
2458 BootResourcesLength = pValueInformation->DataLength;
2459 else
2460 BootResourcesLength = ParentBootResourcesLength
2461 + pValueInformation->DataLength
2462 - Header;
2463 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2464 if (!BootResources)
2465 {
2466 DPRINT("ExAllocatePool() failed\n");
2467 goto nextdevice;
2468 }
2469 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2470 {
2471 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2472 }
2473 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2474 {
2475 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2476 RtlCopyMemory(
2477 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2478 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2479 ParentBootResourcesLength - Header);
2480 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2481 }
2482 else
2483 {
2484 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2485 RtlCopyMemory(
2486 (PVOID)((ULONG_PTR)BootResources + Header),
2487 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2488 ParentBootResourcesLength - Header);
2489 RtlCopyMemory(
2490 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2491 pValueInformation->Data + Header,
2492 pValueInformation->DataLength - Header);
2493 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2494 }
2495 }
2496
2497 if (EnumerateSubKeys)
2498 {
2499 IndexSubKey = 0;
2500 while (TRUE)
2501 {
2502 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2503 if (Status == STATUS_NO_MORE_ENTRIES)
2504 break;
2505 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2506 {
2507 ExFreePool(pDeviceInformation);
2508 DeviceInfoLength = RequiredSize;
2509 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2510 if (!pDeviceInformation)
2511 {
2512 DPRINT("ExAllocatePool() failed\n");
2513 Status = STATUS_NO_MEMORY;
2514 goto cleanup;
2515 }
2516 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2517 }
2518 if (!NT_SUCCESS(Status))
2519 {
2520 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2521 goto cleanup;
2522 }
2523 IndexSubKey++;
2524 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2525 DeviceName.Buffer = pDeviceInformation->Name;
2526
2527 Status = IopEnumerateDetectedDevices(
2528 hDeviceKey,
2529 &DeviceName,
2530 hRootKey,
2531 TRUE,
2532 BootResources,
2533 BootResourcesLength);
2534 if (!NT_SUCCESS(Status))
2535 goto cleanup;
2536 }
2537 }
2538
2539 /* Read identifier */
2540 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2541 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2542 {
2543 ExFreePool(pValueInformation);
2544 ValueInfoLength = RequiredSize;
2545 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2546 if (!pValueInformation)
2547 {
2548 DPRINT("ExAllocatePool() failed\n");
2549 Status = STATUS_NO_MEMORY;
2550 goto cleanup;
2551 }
2552 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2553 }
2554 if (!NT_SUCCESS(Status))
2555 {
2556 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2557 {
2558 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2559 goto nextdevice;
2560 }
2561 ValueName.Length = ValueName.MaximumLength = 0;
2562 }
2563 else if (pValueInformation->Type != REG_SZ)
2564 {
2565 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2566 goto nextdevice;
2567 }
2568 else
2569 {
2570 /* Assign hardware id to this device */
2571 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
2572 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2573 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2574 ValueName.Length -= sizeof(WCHAR);
2575 }
2576
2577 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
2578 {
2579 pHardwareId = &HardwareIdSerial;
2580 DeviceIndex = DeviceIndexSerial++;
2581 }
2582 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
2583 {
2584 pHardwareId = &HardwareIdKeyboard;
2585 DeviceIndex = DeviceIndexKeyboard++;
2586 }
2587 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
2588 {
2589 pHardwareId = &HardwareIdMouse;
2590 DeviceIndex = DeviceIndexMouse++;
2591 }
2592 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
2593 {
2594 pHardwareId = &HardwareIdParallel;
2595 DeviceIndex = DeviceIndexParallel++;
2596 }
2597 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
2598 {
2599 pHardwareId = &HardwareIdFloppy;
2600 DeviceIndex = DeviceIndexFloppy++;
2601 }
2602 else if (NT_SUCCESS(Status))
2603 {
2604 /* Try to also match the device identifier */
2605 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
2606 {
2607 pHardwareId = &HardwareIdPci;
2608 DeviceIndex = DeviceIndexPci++;
2609 }
2610 else if (RtlCompareUnicodeString(&ValueName, &IdentifierIsa, FALSE) == 0)
2611 {
2612 pHardwareId = &HardwareIdIsa;
2613 DeviceIndex = DeviceIndexIsa++;
2614 }
2615 else
2616 {
2617 DPRINT("Unknown device '%wZ'\n", &ValueName);
2618 goto nextdevice;
2619 }
2620 }
2621 else
2622 {
2623 /* Unknown key path */
2624 DPRINT("Unknown key path '%wZ'\n", RelativePath);
2625 goto nextdevice;
2626 }
2627
2628 /* Prepare hardware id key (hardware id value without final \0) */
2629 HardwareIdKey = *pHardwareId;
2630 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
2631
2632 /* Add the detected device to Root key */
2633 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
2634 Status = ZwCreateKey(
2635 &hLevel1Key,
2636 KEY_CREATE_SUB_KEY,
2637 &ObjectAttributes,
2638 0,
2639 NULL,
2640 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
2641 NULL);
2642 if (!NT_SUCCESS(Status))
2643 {
2644 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2645 goto nextdevice;
2646 }
2647 swprintf(Level2Name, L"%04lu", DeviceIndex);
2648 RtlInitUnicodeString(&Level2NameU, Level2Name);
2649 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
2650 Status = ZwCreateKey(
2651 &hLevel2Key,
2652 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
2653 &ObjectAttributes,
2654 0,
2655 NULL,
2656 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
2657 NULL);
2658 ZwClose(hLevel1Key);
2659 if (!NT_SUCCESS(Status))
2660 {
2661 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2662 goto nextdevice;
2663 }
2664 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
2665 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
2666 if (!NT_SUCCESS(Status))
2667 {
2668 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2669 ZwDeleteKey(hLevel2Key);
2670 goto nextdevice;
2671 }
2672 /* Create 'LogConf' subkey */
2673 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
2674 Status = ZwCreateKey(
2675 &hLogConf,
2676 KEY_SET_VALUE,
2677 &ObjectAttributes,
2678 0,
2679 NULL,
2680 REG_OPTION_VOLATILE,
2681 NULL);
2682 if (!NT_SUCCESS(Status))
2683 {
2684 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2685 ZwDeleteKey(hLevel2Key);
2686 goto nextdevice;
2687 }
2688 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2689 {
2690 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
2691 if (!CmResourceList)
2692 {
2693 ZwClose(hLogConf);
2694 ZwDeleteKey(hLevel2Key);
2695 goto nextdevice;
2696 }
2697
2698 /* Add the list count (1st member of CM_RESOURCE_LIST) */
2699 ListCount = 1;
2700 RtlCopyMemory(CmResourceList,
2701 &ListCount,
2702 sizeof(ULONG));
2703
2704 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
2705 RtlCopyMemory(CmResourceList + sizeof(ULONG),
2706 BootResources,
2707 BootResourcesLength);
2708
2709 /* Save boot resources to 'LogConf\BootConfig' */
2710 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
2711 if (!NT_SUCCESS(Status))
2712 {
2713 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2714 ZwClose(hLogConf);
2715 ZwDeleteKey(hLevel2Key);
2716 goto nextdevice;
2717 }
2718 }
2719 ZwClose(hLogConf);
2720
2721 nextdevice:
2722 if (BootResources && BootResources != ParentBootResources)
2723 {
2724 ExFreePool(BootResources);
2725 BootResources = NULL;
2726 }
2727 if (hLevel2Key)
2728 {
2729 ZwClose(hLevel2Key);
2730 hLevel2Key = NULL;
2731 }
2732 if (hDeviceKey)
2733 {
2734 ZwClose(hDeviceKey);
2735 hDeviceKey = NULL;
2736 }
2737 }
2738
2739 Status = STATUS_SUCCESS;
2740
2741 cleanup:
2742 if (hDevicesKey && hDevicesKey != hBaseKey)
2743 ZwClose(hDevicesKey);
2744 if (hDeviceKey)
2745 ZwClose(hDeviceKey);
2746 if (pDeviceInformation)
2747 ExFreePool(pDeviceInformation);
2748 if (pValueInformation)
2749 ExFreePool(pValueInformation);
2750 return Status;
2751 }
2752
2753 static BOOLEAN INIT_FUNCTION
2754 IopIsFirmwareMapperDisabled(VOID)
2755 {
2756 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
2757 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
2758 OBJECT_ATTRIBUTES ObjectAttributes;
2759 HANDLE hPnpKey;
2760 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
2761 ULONG DesiredLength, Length;
2762 ULONG KeyValue = 0;
2763 NTSTATUS Status;
2764
2765 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2766 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
2767 if (NT_SUCCESS(Status))
2768 {
2769 Status = ZwQueryValueKey(hPnpKey,
2770 &KeyNameU,
2771 KeyValuePartialInformation,
2772 NULL,
2773 0,
2774 &DesiredLength);
2775 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
2776 (Status == STATUS_BUFFER_OVERFLOW))
2777 {
2778 Length = DesiredLength;
2779 KeyInformation = ExAllocatePool(PagedPool, Length);
2780 if (KeyInformation)
2781 {
2782 Status = ZwQueryValueKey(hPnpKey,
2783 &KeyNameU,
2784 KeyValuePartialInformation,
2785 KeyInformation,
2786 Length,
2787 &DesiredLength);
2788 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
2789 {
2790 KeyValue = (ULONG)(*KeyInformation->Data);
2791 }
2792 else
2793 {
2794 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
2795 }
2796
2797 ExFreePool(KeyInformation);
2798 }
2799 else
2800 {
2801 DPRINT1("Failed to allocate memory for registry query\n");
2802 }
2803 }
2804 else
2805 {
2806 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
2807 }
2808
2809 ZwClose(hPnpKey);
2810 }
2811 else
2812 {
2813 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
2814 }
2815
2816 DPRINT1("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
2817
2818 return (KeyValue != 0) ? TRUE : FALSE;
2819 }
2820
2821 NTSTATUS
2822 NTAPI
2823 INIT_FUNCTION
2824 IopUpdateRootKey(VOID)
2825 {
2826 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
2827 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
2828 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2829 OBJECT_ATTRIBUTES ObjectAttributes;
2830 HANDLE hEnum, hRoot;
2831 NTSTATUS Status;
2832
2833 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2834 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2835 if (!NT_SUCCESS(Status))
2836 {
2837 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
2838 return Status;
2839 }
2840
2841 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
2842 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2843 ZwClose(hEnum);
2844 if (!NT_SUCCESS(Status))
2845 {
2846 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
2847 return Status;
2848 }
2849
2850 if (!IopIsFirmwareMapperDisabled())
2851 {
2852 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
2853 if (!NT_SUCCESS(Status))
2854 {
2855 /* Nothing to do, don't return with an error status */
2856 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2857 ZwClose(hRoot);
2858 return STATUS_SUCCESS;
2859 }
2860 Status = IopEnumerateDetectedDevices(
2861 hEnum,
2862 NULL,
2863 hRoot,
2864 TRUE,
2865 NULL,
2866 0);
2867 ZwClose(hEnum);
2868 }
2869 else
2870 {
2871 /* Enumeration is disabled */
2872 Status = STATUS_SUCCESS;
2873 }
2874
2875 ZwClose(hRoot);
2876
2877 return Status;
2878 }
2879
2880 NTSTATUS
2881 NTAPI
2882 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
2883 HANDLE ParentKey,
2884 PUNICODE_STRING Name,
2885 ACCESS_MASK DesiredAccess)
2886 {
2887 OBJECT_ATTRIBUTES ObjectAttributes;
2888 NTSTATUS Status;
2889
2890 PAGED_CODE();
2891
2892 *KeyHandle = NULL;
2893
2894 InitializeObjectAttributes(&ObjectAttributes,
2895 Name,
2896 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2897 ParentKey,
2898 NULL);
2899
2900 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
2901
2902 return Status;
2903 }
2904
2905 NTSTATUS
2906 NTAPI
2907 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
2908 IN HANDLE RootHandle OPTIONAL,
2909 IN PUNICODE_STRING KeyName,
2910 IN ACCESS_MASK DesiredAccess,
2911 IN ULONG CreateOptions,
2912 OUT PULONG Disposition OPTIONAL)
2913 {
2914 OBJECT_ATTRIBUTES ObjectAttributes;
2915 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
2916 USHORT Length;
2917 HANDLE HandleArray[2];
2918 BOOLEAN Recursing = TRUE;
2919 PWCHAR pp, p, p1;
2920 UNICODE_STRING KeyString;
2921 NTSTATUS Status = STATUS_SUCCESS;
2922 PAGED_CODE();
2923
2924 /* P1 is start, pp is end */
2925 p1 = KeyName->Buffer;
2926 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
2927
2928 /* Create the target key */
2929 InitializeObjectAttributes(&ObjectAttributes,
2930 KeyName,
2931 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2932 RootHandle,
2933 NULL);
2934 Status = ZwCreateKey(&HandleArray[i],
2935 DesiredAccess,
2936 &ObjectAttributes,
2937 0,
2938 NULL,
2939 CreateOptions,
2940 &KeyDisposition);
2941
2942 /* Now we check if this failed */
2943 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
2944 {
2945 /* Target key failed, so we'll need to create its parent. Setup array */
2946 HandleArray[0] = NULL;
2947 HandleArray[1] = RootHandle;
2948
2949 /* Keep recursing for each missing parent */
2950 while (Recursing)
2951 {
2952 /* And if we're deep enough, close the last handle */
2953 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
2954
2955 /* We're setup to ping-pong between the two handle array entries */
2956 RootHandleIndex = i;
2957 i = (i + 1) & 1;
2958
2959 /* Clear the one we're attempting to open now */
2960 HandleArray[i] = NULL;
2961
2962 /* Process the parent key name */
2963 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
2964 Length = (USHORT)(p - p1) * sizeof(WCHAR);
2965
2966 /* Is there a parent name? */
2967 if (Length)
2968 {
2969 /* Build the unicode string for it */
2970 KeyString.Buffer = p1;
2971 KeyString.Length = KeyString.MaximumLength = Length;
2972
2973 /* Now try opening the parent */
2974 InitializeObjectAttributes(&ObjectAttributes,
2975 &KeyString,
2976 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2977 HandleArray[RootHandleIndex],
2978 NULL);
2979 Status = ZwCreateKey(&HandleArray[i],
2980 DesiredAccess,
2981 &ObjectAttributes,
2982 0,
2983 NULL,
2984 CreateOptions,
2985 &KeyDisposition);
2986 if (NT_SUCCESS(Status))
2987 {
2988 /* It worked, we have one more handle */
2989 NestedCloseLevel++;
2990 }
2991 else
2992 {
2993 /* Parent key creation failed, abandon loop */
2994 Recursing = FALSE;
2995 continue;
2996 }
2997 }
2998 else
2999 {
3000 /* We don't have a parent name, probably corrupted key name */
3001 Status = STATUS_INVALID_PARAMETER;
3002 Recursing = FALSE;
3003 continue;
3004 }
3005
3006 /* Now see if there's more parents to create */
3007 p1 = p + 1;
3008 if ((p == pp) || (p1 == pp))
3009 {
3010 /* We're done, hopefully successfully, so stop */
3011 Recursing = FALSE;
3012 }
3013 }
3014
3015 /* Outer loop check for handle nesting that requires closing the top handle */
3016 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3017 }
3018
3019 /* Check if we broke out of the loop due to success */
3020 if (NT_SUCCESS(Status))
3021 {
3022 /* Return the target handle (we closed all the parent ones) and disposition */
3023 *Handle = HandleArray[i];
3024 if (Disposition) *Disposition = KeyDisposition;
3025 }
3026
3027 /* Return the success state */
3028 return Status;
3029 }
3030
3031 NTSTATUS
3032 NTAPI
3033 IopGetRegistryValue(IN HANDLE Handle,
3034 IN PWSTR ValueName,
3035 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3036 {
3037 UNICODE_STRING ValueString;
3038 NTSTATUS Status;
3039 PKEY_VALUE_FULL_INFORMATION FullInformation;
3040 ULONG Size;
3041 PAGED_CODE();
3042
3043 RtlInitUnicodeString(&ValueString, ValueName);
3044
3045 Status = ZwQueryValueKey(Handle,
3046 &ValueString,
3047 KeyValueFullInformation,
3048 NULL,
3049 0,
3050 &Size);
3051 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3052 (Status != STATUS_BUFFER_TOO_SMALL))
3053 {
3054 return Status;
3055 }
3056
3057 FullInformation = ExAllocatePool(NonPagedPool, Size);
3058 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3059
3060 Status = ZwQueryValueKey(Handle,
3061 &ValueString,
3062 KeyValueFullInformation,
3063 FullInformation,
3064 Size,
3065 &Size);
3066 if (!NT_SUCCESS(Status))
3067 {
3068 ExFreePool(FullInformation);
3069 return Status;
3070 }
3071
3072 *Information = FullInformation;
3073 return STATUS_SUCCESS;
3074 }
3075
3076 RTL_GENERIC_COMPARE_RESULTS
3077 NTAPI
3078 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3079 IN PVOID FirstStruct,
3080 IN PVOID SecondStruct)
3081 {
3082 /* FIXME: TODO */
3083 ASSERT(FALSE);
3084 return 0;
3085 }
3086
3087 //
3088 // The allocation function is called by the generic table package whenever
3089 // it needs to allocate memory for the table.
3090 //
3091
3092 PVOID
3093 NTAPI
3094 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3095 IN CLONG ByteSize)
3096 {
3097 /* FIXME: TODO */
3098 ASSERT(FALSE);
3099 return NULL;
3100 }
3101
3102 VOID
3103 NTAPI
3104 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3105 IN PVOID Buffer)
3106 {
3107 /* FIXME: TODO */
3108 ASSERT(FALSE);
3109 }
3110
3111 VOID
3112 NTAPI
3113 PpInitializeDeviceReferenceTable(VOID)
3114 {
3115 /* Setup the guarded mutex and AVL table */
3116 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3117 RtlInitializeGenericTableAvl(
3118 &PpDeviceReferenceTable,
3119 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3120 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3121 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3122 NULL);
3123 }
3124
3125 BOOLEAN
3126 NTAPI
3127 PiInitPhase0(VOID)
3128 {
3129 /* Initialize the resource when accessing device registry data */
3130 ExInitializeResourceLite(&PpRegistryDeviceResource);
3131
3132 /* Setup the device reference AVL table */
3133 PpInitializeDeviceReferenceTable();
3134 return TRUE;
3135 }
3136
3137 BOOLEAN
3138 NTAPI
3139 PpInitSystem(VOID)
3140 {
3141 /* Check the initialization phase */
3142 switch (ExpInitializationPhase)
3143 {
3144 case 0:
3145
3146 /* Do Phase 0 */
3147 return PiInitPhase0();
3148
3149 case 1:
3150
3151 /* Do Phase 1 */
3152 return TRUE;
3153 //return PiInitPhase1();
3154
3155 default:
3156
3157 /* Don't know any other phase! Bugcheck! */
3158 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3159 return FALSE;
3160 }
3161 }
3162
3163 LONG IopNumberDeviceNodes;
3164
3165 PDEVICE_NODE
3166 NTAPI
3167 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
3168 {
3169 PDEVICE_NODE DeviceNode;
3170 PAGED_CODE();
3171
3172 /* Allocate it */
3173 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), 'donD');
3174 if (!DeviceNode) return DeviceNode;
3175
3176 /* Statistics */
3177 InterlockedIncrement(&IopNumberDeviceNodes);
3178
3179 /* Set it up */
3180 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3181 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3182 DeviceNode->BusNumber = -1;
3183 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3184 DeviceNode->ChildBusNumber = -1;
3185 DeviceNode->ChildBusTypeIndex = -1;
3186 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3187 InitializeListHead(&DeviceNode->DeviceArbiterList);
3188 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3189 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3190 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3191 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3192
3193 /* Check if there is a PDO */
3194 if (PhysicalDeviceObject)
3195 {
3196 /* Link it and remove the init flag */
3197 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3198 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3199 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3200 }
3201
3202 /* Return the node */
3203 return DeviceNode;
3204 }
3205
3206 /* PUBLIC FUNCTIONS **********************************************************/
3207
3208 NTSTATUS
3209 NTAPI
3210 PnpBusTypeGuidGet(IN USHORT Index,
3211 IN LPGUID BusTypeGuid)
3212 {
3213 NTSTATUS Status = STATUS_SUCCESS;
3214
3215 /* Acquire the lock */
3216 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3217
3218 /* Validate size */
3219 if (Index < PnpBusTypeGuidList->GuidCount)
3220 {
3221 /* Copy the data */
3222 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3223 }
3224 else
3225 {
3226 /* Failure path */
3227 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3228 }
3229
3230 /* Release lock and return status */
3231 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3232 return Status;
3233 }
3234
3235 NTSTATUS
3236 NTAPI
3237 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3238 IN PHANDLE DeviceInstanceHandle,
3239 IN ACCESS_MASK DesiredAccess)
3240 {
3241 NTSTATUS Status;
3242 HANDLE KeyHandle;
3243 PDEVICE_NODE DeviceNode;
3244 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3245 PAGED_CODE();
3246
3247 /* Open the enum key */
3248 Status = IopOpenRegistryKeyEx(&KeyHandle,
3249 NULL,
3250 &KeyName,
3251 KEY_READ);
3252 if (!NT_SUCCESS(Status)) return Status;
3253
3254 /* Make sure we have an instance path */
3255 DeviceNode = IopGetDeviceNode(DeviceObject);
3256 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3257 {
3258 /* Get the instance key */
3259 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3260 KeyHandle,
3261 &DeviceNode->InstancePath,
3262 DesiredAccess);
3263 }
3264 else
3265 {
3266 /* Fail */
3267 Status = STATUS_INVALID_DEVICE_REQUEST;
3268 }
3269
3270 /* Close the handle and return status */
3271 ZwClose(KeyHandle);
3272 return Status;
3273 }
3274
3275 ULONG
3276 NTAPI
3277 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3278 {
3279 ULONG FinalSize, PartialSize, EntrySize, i, j;
3280 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3281 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3282
3283 /* If we don't have one, that's easy */
3284 if (!ResourceList) return 0;
3285
3286 /* Start with the minimum size possible */
3287 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3288
3289 /* Loop each full descriptor */
3290 FullDescriptor = ResourceList->List;
3291 for (i = 0; i < ResourceList->Count; i++)
3292 {
3293 /* Start with the minimum size possible */
3294 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3295 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3296
3297 /* Loop each partial descriptor */
3298 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3299 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3300 {
3301 /* Start with the minimum size possible */
3302 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3303
3304 /* Check if there is extra data */
3305 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3306 {
3307 /* Add that data */
3308 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3309 }
3310
3311 /* The size of partial descriptors is bigger */
3312 PartialSize += EntrySize;
3313
3314 /* Go to the next partial descriptor */
3315 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3316 }
3317
3318 /* The size of full descriptors is bigger */
3319 FinalSize += PartialSize;
3320
3321 /* Go to the next full descriptor */
3322 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3323 }
3324
3325 /* Return the final size */
3326 return FinalSize;
3327 }
3328
3329 NTSTATUS
3330 NTAPI
3331 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3332 IN ULONG ValueType,
3333 IN PWSTR ValueName,
3334 IN PWSTR KeyName,
3335 OUT PVOID Buffer,
3336 IN PULONG BufferLength)
3337 {
3338 NTSTATUS Status;
3339 HANDLE KeyHandle, SubHandle;
3340 UNICODE_STRING KeyString;
3341 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3342 ULONG Length;
3343 PAGED_CODE();
3344
3345 /* Find the instance key */
3346 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3347 if (NT_SUCCESS(Status))
3348 {
3349 /* Check for name given by caller */
3350 if (KeyName)
3351 {
3352 /* Open this key */
3353 RtlInitUnicodeString(&KeyString, KeyName);
3354 Status = IopOpenRegistryKeyEx(&SubHandle,
3355 KeyHandle,
3356 &KeyString,
3357 KEY_READ);
3358 if (NT_SUCCESS(Status))
3359 {
3360 /* And use this handle instead */
3361 ZwClose(KeyHandle);
3362 KeyHandle = SubHandle;
3363 }
3364 }
3365
3366 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3367 if (NT_SUCCESS(Status))
3368 {
3369 /* Now get the size of the property */
3370 Status = IopGetRegistryValue(KeyHandle,
3371 ValueName,
3372 &KeyValueInfo);
3373 }
3374
3375 /* Close the key */
3376 ZwClose(KeyHandle);
3377 }
3378
3379 /* Fail if any of the registry operations failed */
3380 if (!NT_SUCCESS(Status)) return Status;
3381
3382 /* Check how much data we have to copy */
3383 Length = KeyValueInfo->DataLength;
3384 if (*BufferLength >= Length)
3385 {
3386 /* Check for a match in the value type */
3387 if (KeyValueInfo->Type == ValueType)
3388 {
3389 /* Copy the data */
3390 RtlCopyMemory(Buffer,
3391 (PVOID)((ULONG_PTR)KeyValueInfo +
3392 KeyValueInfo->DataOffset),
3393 Length);
3394 }
3395 else
3396 {
3397