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