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