[HIVESYS]
[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 ExFreePool(OriginalIdBuffer);
393 ExFreePool(PartialInfo);
394 ExFreePool(BasicInfo);
395 ZwClose(InstanceKey);
396 ZwClose(ChildKeyHandle);
397 ZwClose(CriticalDeviceKey);
398
399 /* That's it */
400 return;
401 }
402
403 ExFreePool(BasicInfo);
404 }
405 else
406 {
407 /* Umm, not sure what happened here */
408 continue;
409 }
410 }
411
412 /* Advance to the next ID */
413 IdBuffer += StringLength;
414 }
415
416 ExFreePool(OriginalIdBuffer);
417 ZwClose(InstanceKey);
418 ZwClose(CriticalDeviceKey);
419 }
420
421 NTSTATUS
422 FASTCALL
423 IopInitializeDevice(PDEVICE_NODE DeviceNode,
424 PDRIVER_OBJECT DriverObject)
425 {
426 PDEVICE_OBJECT Fdo;
427 NTSTATUS Status;
428
429 if (!DriverObject)
430 {
431 /* Special case for bus driven devices */
432 DeviceNode->Flags |= DNF_ADDED;
433 return STATUS_SUCCESS;
434 }
435
436 if (!DriverObject->DriverExtension->AddDevice)
437 {
438 DeviceNode->Flags |= DNF_LEGACY_DRIVER;
439 }
440
441 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
442 {
443 DeviceNode->Flags |= DNF_ADDED + DNF_STARTED;
444 return STATUS_SUCCESS;
445 }
446
447 /* This is a Plug and Play driver */
448 DPRINT("Plug and Play driver found\n");
449 ASSERT(DeviceNode->PhysicalDeviceObject);
450
451 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
452 &DriverObject->DriverName,
453 &DeviceNode->InstancePath);
454 Status = DriverObject->DriverExtension->AddDevice(
455 DriverObject, DeviceNode->PhysicalDeviceObject);
456 if (!NT_SUCCESS(Status))
457 {
458 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
459 &DriverObject->DriverName,
460 &DeviceNode->InstancePath,
461 Status);
462 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
463 return Status;
464 }
465
466 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
467
468 /* Check if we have a ACPI device (needed for power management) */
469 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
470 {
471 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
472
473 /* There can be only one system power device */
474 if (!SystemPowerDeviceNodeCreated)
475 {
476 PopSystemPowerDeviceNode = DeviceNode;
477 ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject);
478 SystemPowerDeviceNodeCreated = TRUE;
479 }
480 }
481
482 ObDereferenceObject(Fdo);
483
484 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
485
486 return STATUS_SUCCESS;
487 }
488
489 static
490 NTSTATUS
491 NTAPI
492 IopSendEject(IN PDEVICE_OBJECT DeviceObject)
493 {
494 IO_STACK_LOCATION Stack;
495 PVOID Dummy;
496
497 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
498 Stack.MajorFunction = IRP_MJ_PNP;
499 Stack.MinorFunction = IRP_MN_EJECT;
500
501 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
502 }
503
504 static
505 VOID
506 NTAPI
507 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
508 {
509 IO_STACK_LOCATION Stack;
510 PVOID Dummy;
511
512 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
513 Stack.MajorFunction = IRP_MJ_PNP;
514 Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL;
515
516 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
517 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
518 }
519
520 static
521 NTSTATUS
522 NTAPI
523 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
524 {
525 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
526 IO_STACK_LOCATION Stack;
527 PVOID Dummy;
528 NTSTATUS Status;
529
530 ASSERT(DeviceNode);
531
532 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
533 &DeviceNode->InstancePath);
534
535 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
536 Stack.MajorFunction = IRP_MJ_PNP;
537 Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE;
538
539 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
540
541 IopNotifyPlugPlayNotification(DeviceObject,
542 EventCategoryTargetDeviceChange,
543 &GUID_TARGET_DEVICE_QUERY_REMOVE,
544 NULL,
545 NULL);
546
547 if (!NT_SUCCESS(Status))
548 {
549 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath);
550 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
551 &DeviceNode->InstancePath);
552 }
553
554 return Status;
555 }
556
557 static
558 NTSTATUS
559 NTAPI
560 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject)
561 {
562 IO_STACK_LOCATION Stack;
563 PVOID Dummy;
564
565 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
566 Stack.MajorFunction = IRP_MJ_PNP;
567 Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE;
568
569 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
570 }
571
572 static
573 VOID
574 NTAPI
575 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
576 {
577 IO_STACK_LOCATION Stack;
578 PVOID Dummy;
579
580 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
581 Stack.MajorFunction = IRP_MJ_PNP;
582 Stack.MinorFunction = IRP_MN_REMOVE_DEVICE;
583
584 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
585 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
586
587 IopNotifyPlugPlayNotification(DeviceObject,
588 EventCategoryTargetDeviceChange,
589 &GUID_TARGET_DEVICE_REMOVE_COMPLETE,
590 NULL,
591 NULL);
592 }
593
594 static
595 VOID
596 NTAPI
597 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
598 {
599 IO_STACK_LOCATION Stack;
600 PVOID Dummy;
601
602 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
603 Stack.MajorFunction = IRP_MJ_PNP;
604 Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE;
605
606 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
607 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
608
609 IopNotifyPlugPlayNotification(DeviceObject,
610 EventCategoryTargetDeviceChange,
611 &GUID_TARGET_DEVICE_REMOVE_CANCELLED,
612 NULL,
613 NULL);
614 }
615
616 static
617 VOID
618 NTAPI
619 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject)
620 {
621 IO_STACK_LOCATION Stack;
622 PVOID Dummy;
623
624 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
625 Stack.MajorFunction = IRP_MJ_PNP;
626 Stack.MinorFunction = IRP_MN_STOP_DEVICE;
627
628 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
629 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
630 }
631
632 VOID
633 NTAPI
634 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
635 {
636 IO_STACK_LOCATION Stack;
637 PDEVICE_NODE DeviceNode;
638 NTSTATUS Status;
639 PVOID Dummy;
640 DEVICE_CAPABILITIES DeviceCapabilities;
641
642 /* Get the device node */
643 DeviceNode = IopGetDeviceNode(DeviceObject);
644
645 ASSERT(!(DeviceNode->Flags & DNF_DISABLED));
646
647 /* Build the I/O stack locaiton */
648 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
649 Stack.MajorFunction = IRP_MJ_PNP;
650 Stack.MinorFunction = IRP_MN_START_DEVICE;
651
652 Stack.Parameters.StartDevice.AllocatedResources =
653 DeviceNode->ResourceList;
654 Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
655 DeviceNode->ResourceListTranslated;
656
657 /* Do the call */
658 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
659 if (!NT_SUCCESS(Status))
660 {
661 /* Send an IRP_MN_REMOVE_DEVICE request */
662 IopRemoveDevice(DeviceNode);
663
664 /* Set the appropriate flag */
665 DeviceNode->Flags |= DNF_START_FAILED;
666
667 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status);
668 return;
669 }
670
671 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
672
673 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
674 if (!NT_SUCCESS(Status))
675 {
676 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
677 }
678
679 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
680 IoInvalidateDeviceState(DeviceObject);
681
682 /* Otherwise, mark us as started */
683 DeviceNode->Flags |= DNF_STARTED;
684 DeviceNode->Flags &= ~DNF_STOPPED;
685
686 /* We now need enumeration */
687 DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
688 }
689
690 NTSTATUS
691 NTAPI
692 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
693 {
694 PDEVICE_OBJECT DeviceObject;
695 NTSTATUS Status;
696 PAGED_CODE();
697
698 /* Sanity check */
699 ASSERT((DeviceNode->Flags & DNF_ADDED));
700 ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED |
701 DNF_RESOURCE_REPORTED |
702 DNF_NO_RESOURCE_REQUIRED)));
703
704 /* Get the device object */
705 DeviceObject = DeviceNode->PhysicalDeviceObject;
706
707 /* Check if we're not started yet */
708 if (!(DeviceNode->Flags & DNF_STARTED))
709 {
710 /* Start us */
711 IopStartDevice2(DeviceObject);
712 }
713
714 /* Do we need to query IDs? This happens in the case of manual reporting */
715 #if 0
716 if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
717 {
718 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
719 /* And that case shouldn't happen yet */
720 ASSERT(FALSE);
721 }
722 #endif
723
724 /* Make sure we're started, and check if we need enumeration */
725 if ((DeviceNode->Flags & DNF_STARTED) &&
726 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY))
727 {
728 /* Enumerate us */
729 IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations);
730 Status = STATUS_SUCCESS;
731 }
732 else
733 {
734 /* Nothing to do */
735 Status = STATUS_SUCCESS;
736 }
737
738 /* Return */
739 return Status;
740 }
741
742 NTSTATUS
743 IopStopDevice(
744 PDEVICE_NODE DeviceNode)
745 {
746 NTSTATUS Status;
747
748 DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath);
749
750 Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject);
751 if (NT_SUCCESS(Status))
752 {
753 IopSendStopDevice(DeviceNode->PhysicalDeviceObject);
754
755 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
756 DeviceNode->Flags |= DNF_STOPPED;
757
758 return STATUS_SUCCESS;
759 }
760
761 return Status;
762 }
763
764 NTSTATUS
765 IopStartDevice(
766 PDEVICE_NODE DeviceNode)
767 {
768 NTSTATUS Status;
769 HANDLE InstanceHandle = INVALID_HANDLE_VALUE, ControlHandle = INVALID_HANDLE_VALUE;
770 UNICODE_STRING KeyName;
771 OBJECT_ATTRIBUTES ObjectAttributes;
772
773 if (DeviceNode->Flags & DNF_DISABLED)
774 return STATUS_SUCCESS;
775
776 Status = IopAssignDeviceResources(DeviceNode);
777 if (!NT_SUCCESS(Status))
778 goto ByeBye;
779
780 /* New PnP ABI */
781 IopStartAndEnumerateDevice(DeviceNode);
782
783 /* FIX: Should be done in new device instance code */
784 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceHandle);
785 if (!NT_SUCCESS(Status))
786 goto ByeBye;
787
788 /* FIX: Should be done in IoXxxPrepareDriverLoading */
789 // {
790 RtlInitUnicodeString(&KeyName, L"Control");
791 InitializeObjectAttributes(&ObjectAttributes,
792 &KeyName,
793 OBJ_CASE_INSENSITIVE,
794 InstanceHandle,
795 NULL);
796 Status = ZwCreateKey(&ControlHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
797 if (!NT_SUCCESS(Status))
798 goto ByeBye;
799
800 RtlInitUnicodeString(&KeyName, L"ActiveService");
801 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, DeviceNode->ServiceName.Buffer, DeviceNode->ServiceName.Length);
802 // }
803
804 ByeBye:
805 if (ControlHandle != INVALID_HANDLE_VALUE)
806 ZwClose(ControlHandle);
807
808 if (InstanceHandle != INVALID_HANDLE_VALUE)
809 ZwClose(InstanceHandle);
810
811 return Status;
812 }
813
814 NTSTATUS
815 NTAPI
816 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
817 PDEVICE_CAPABILITIES DeviceCaps)
818 {
819 IO_STATUS_BLOCK StatusBlock;
820 IO_STACK_LOCATION Stack;
821 NTSTATUS Status;
822 HANDLE InstanceKey;
823 UNICODE_STRING ValueName;
824
825 /* Set up the Header */
826 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
827 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
828 DeviceCaps->Version = 1;
829 DeviceCaps->Address = -1;
830 DeviceCaps->UINumber = -1;
831
832 /* Set up the Stack */
833 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
834 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
835
836 /* Send the IRP */
837 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
838 &StatusBlock,
839 IRP_MN_QUERY_CAPABILITIES,
840 &Stack);
841 if (!NT_SUCCESS(Status))
842 {
843 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%x\n", Status);
844 return Status;
845 }
846
847 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCaps->Version + sizeof(DeviceCaps->Version));
848
849 if (DeviceCaps->NoDisplayInUI)
850 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
851 else
852 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
853
854 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
855 if (NT_SUCCESS(Status))
856 {
857 /* Set 'Capabilities' value */
858 RtlInitUnicodeString(&ValueName, L"Capabilities");
859 Status = ZwSetValueKey(InstanceKey,
860 &ValueName,
861 0,
862 REG_DWORD,
863 (PVOID)&DeviceNode->CapabilityFlags,
864 sizeof(ULONG));
865
866 /* Set 'UINumber' value */
867 if (DeviceCaps->UINumber != MAXULONG)
868 {
869 RtlInitUnicodeString(&ValueName, L"UINumber");
870 Status = ZwSetValueKey(InstanceKey,
871 &ValueName,
872 0,
873 REG_DWORD,
874 &DeviceCaps->UINumber,
875 sizeof(ULONG));
876 }
877 }
878
879 return Status;
880 }
881
882 static VOID NTAPI
883 IopAsynchronousInvalidateDeviceRelations(
884 IN PDEVICE_OBJECT DeviceObject,
885 IN PVOID InvalidateContext)
886 {
887 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
888
889 IoSynchronousInvalidateDeviceRelations(
890 Data->DeviceObject,
891 Data->Type);
892
893 ObDereferenceObject(Data->DeviceObject);
894 IoFreeWorkItem(Data->WorkItem);
895 ExFreePool(Data);
896 }
897
898 NTSTATUS
899 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
900 {
901 KIRQL OldIrql;
902
903 if (PopSystemPowerDeviceNode)
904 {
905 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
906 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
907 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
908
909 return STATUS_SUCCESS;
910 }
911
912 return STATUS_UNSUCCESSFUL;
913 }
914
915 USHORT
916 NTAPI
917 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
918 {
919 USHORT i = 0, FoundIndex = 0xFFFF;
920 ULONG NewSize;
921 PVOID NewList;
922
923 /* Acquire the lock */
924 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
925
926 /* Loop all entries */
927 while (i < PnpBusTypeGuidList->GuidCount)
928 {
929 /* Try to find a match */
930 if (RtlCompareMemory(BusTypeGuid,
931 &PnpBusTypeGuidList->Guids[i],
932 sizeof(GUID)) == sizeof(GUID))
933 {
934 /* Found it */
935 FoundIndex = i;
936 goto Quickie;
937 }
938 i++;
939 }
940
941 /* Check if we have to grow the list */
942 if (PnpBusTypeGuidList->GuidCount)
943 {
944 /* Calculate the new size */
945 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
946 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
947
948 /* Allocate the new copy */
949 NewList = ExAllocatePool(PagedPool, NewSize);
950
951 if (!NewList) {
952 /* Fail */
953 ExFreePool(PnpBusTypeGuidList);
954 goto Quickie;
955 }
956
957 /* Now copy them, decrease the size too */
958 NewSize -= sizeof(GUID);
959 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
960
961 /* Free the old list */
962 ExFreePool(PnpBusTypeGuidList);
963
964 /* Use the new buffer */
965 PnpBusTypeGuidList = NewList;
966 }
967
968 /* Copy the new GUID */
969 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
970 BusTypeGuid,
971 sizeof(GUID));
972
973 /* The new entry is the index */
974 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
975 PnpBusTypeGuidList->GuidCount++;
976
977 Quickie:
978 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
979 return FoundIndex;
980 }
981
982 /*
983 * DESCRIPTION
984 * Creates a device node
985 *
986 * ARGUMENTS
987 * ParentNode = Pointer to parent device node
988 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
989 * to have the root device node create one
990 * (eg. for legacy drivers)
991 * DeviceNode = Pointer to storage for created device node
992 *
993 * RETURN VALUE
994 * Status
995 */
996 NTSTATUS
997 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
998 PDEVICE_OBJECT PhysicalDeviceObject,
999 PUNICODE_STRING ServiceName,
1000 PDEVICE_NODE *DeviceNode)
1001 {
1002 PDEVICE_NODE Node;
1003 NTSTATUS Status;
1004 KIRQL OldIrql;
1005 UNICODE_STRING FullServiceName;
1006 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
1007 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
1008 UNICODE_STRING KeyName, ClassName;
1009 PUNICODE_STRING ServiceName1;
1010 ULONG LegacyValue;
1011 #if 0
1012 UNICODE_STRING ClassGUID;
1013 #endif
1014 HANDLE InstanceHandle;
1015
1016 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1017 ParentNode, PhysicalDeviceObject, ServiceName);
1018
1019 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
1020 if (!Node)
1021 {
1022 return STATUS_INSUFFICIENT_RESOURCES;
1023 }
1024
1025 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
1026
1027 if (!ServiceName)
1028 ServiceName1 = &UnknownDeviceName;
1029 else
1030 ServiceName1 = ServiceName;
1031
1032 if (!PhysicalDeviceObject)
1033 {
1034 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length;
1035 FullServiceName.Length = 0;
1036 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
1037 if (!FullServiceName.Buffer)
1038 {
1039 ExFreePool(Node);
1040 return STATUS_INSUFFICIENT_RESOURCES;
1041 }
1042
1043 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
1044 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
1045
1046 Status = PnpRootCreateDevice(&FullServiceName, NULL, &PhysicalDeviceObject, &Node->InstancePath);
1047 if (!NT_SUCCESS(Status))
1048 {
1049 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
1050 ExFreePool(Node);
1051 return Status;
1052 }
1053
1054 /* Create the device key for legacy drivers */
1055 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
1056 if (!NT_SUCCESS(Status))
1057 {
1058 ZwClose(InstanceHandle);
1059 ExFreePool(Node);
1060 ExFreePool(FullServiceName.Buffer);
1061 return Status;
1062 }
1063
1064 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, ServiceName1->Length);
1065 if (!Node->ServiceName.Buffer)
1066 {
1067 ZwClose(InstanceHandle);
1068 ExFreePool(Node);
1069 ExFreePool(FullServiceName.Buffer);
1070 return Status;
1071 }
1072
1073 Node->ServiceName.MaximumLength = ServiceName1->Length;
1074 Node->ServiceName.Length = 0;
1075
1076 RtlAppendUnicodeStringToString(&Node->ServiceName, ServiceName1);
1077
1078 if (ServiceName)
1079 {
1080 RtlInitUnicodeString(&KeyName, L"Service");
1081 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length);
1082 }
1083
1084 if (NT_SUCCESS(Status))
1085 {
1086 RtlInitUnicodeString(&KeyName, L"Legacy");
1087
1088 LegacyValue = 1;
1089 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
1090 if (NT_SUCCESS(Status))
1091 {
1092 RtlInitUnicodeString(&KeyName, L"Class");
1093
1094 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
1095 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length);
1096 #if 0
1097 if (NT_SUCCESS(Status))
1098 {
1099 RtlInitUnicodeString(&KeyName, L"ClassGUID");
1100
1101 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
1102 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length);
1103 }
1104 #endif
1105 }
1106 }
1107
1108 ZwClose(InstanceHandle);
1109 ExFreePool(FullServiceName.Buffer);
1110
1111 if (!NT_SUCCESS(Status))
1112 {
1113 ExFreePool(Node);
1114 return Status;
1115 }
1116
1117 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
1118 IopDeviceNodeSetFlag(Node, DNF_PROCESSED);
1119 IopDeviceNodeSetFlag(Node, DNF_ADDED);
1120 IopDeviceNodeSetFlag(Node, DNF_STARTED);
1121 }
1122
1123 Node->PhysicalDeviceObject = PhysicalDeviceObject;
1124
1125 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
1126
1127 if (ParentNode)
1128 {
1129 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1130 Node->Parent = ParentNode;
1131 Node->Sibling = ParentNode->Child;
1132 ParentNode->Child = Node;
1133 if (ParentNode->LastChild == NULL)
1134 ParentNode->LastChild = Node;
1135 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1136 Node->Level = ParentNode->Level + 1;
1137 }
1138
1139 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1140
1141 *DeviceNode = Node;
1142
1143 return STATUS_SUCCESS;
1144 }
1145
1146 NTSTATUS
1147 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
1148 {
1149 KIRQL OldIrql;
1150 PDEVICE_NODE PrevSibling = NULL;
1151
1152 /* All children must be deleted before a parent is deleted */
1153 ASSERT(!DeviceNode->Child);
1154
1155 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1156
1157 ASSERT(DeviceNode->PhysicalDeviceObject);
1158
1159 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
1160
1161 /* Get previous sibling */
1162 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
1163 {
1164 PrevSibling = DeviceNode->Parent->Child;
1165 while (PrevSibling->Sibling != DeviceNode)
1166 PrevSibling = PrevSibling->Sibling;
1167 }
1168
1169 /* Unlink from parent if it exists */
1170 if (DeviceNode->Parent)
1171 {
1172 if (DeviceNode->Parent->LastChild == DeviceNode)
1173 {
1174 DeviceNode->Parent->LastChild = PrevSibling;
1175 if (PrevSibling)
1176 PrevSibling->Sibling = NULL;
1177 }
1178 if (DeviceNode->Parent->Child == DeviceNode)
1179 DeviceNode->Parent->Child = DeviceNode->Sibling;
1180 }
1181
1182 /* Unlink from sibling list */
1183 if (PrevSibling)
1184 PrevSibling->Sibling = DeviceNode->Sibling;
1185
1186 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1187
1188 RtlFreeUnicodeString(&DeviceNode->InstancePath);
1189
1190 RtlFreeUnicodeString(&DeviceNode->ServiceName);
1191
1192 if (DeviceNode->ResourceList)
1193 {
1194 ExFreePool(DeviceNode->ResourceList);
1195 }
1196
1197 if (DeviceNode->ResourceListTranslated)
1198 {
1199 ExFreePool(DeviceNode->ResourceListTranslated);
1200 }
1201
1202 if (DeviceNode->ResourceRequirements)
1203 {
1204 ExFreePool(DeviceNode->ResourceRequirements);
1205 }
1206
1207 if (DeviceNode->BootResources)
1208 {
1209 ExFreePool(DeviceNode->BootResources);
1210 }
1211
1212 ExFreePool(DeviceNode);
1213
1214 return STATUS_SUCCESS;
1215 }
1216
1217 NTSTATUS
1218 NTAPI
1219 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
1220 IN PIO_STACK_LOCATION IoStackLocation,
1221 OUT PVOID *Information)
1222 {
1223 PIRP Irp;
1224 PIO_STACK_LOCATION IrpStack;
1225 IO_STATUS_BLOCK IoStatusBlock;
1226 KEVENT Event;
1227 NTSTATUS Status;
1228 PDEVICE_OBJECT TopDeviceObject;
1229 PAGED_CODE();
1230
1231 /* Call the top of the device stack */
1232 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
1233
1234 /* Allocate an IRP */
1235 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
1236 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1237
1238 /* Initialize to failure */
1239 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
1240 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
1241
1242 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1243 if (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
1244 {
1245 /* Copy the resource requirements list into the IOSB */
1246 Irp->IoStatus.Information =
1247 IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
1248 }
1249
1250 /* Initialize the event */
1251 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1252
1253 /* Set them up */
1254 Irp->UserIosb = &IoStatusBlock;
1255 Irp->UserEvent = &Event;
1256
1257 /* Queue the IRP */
1258 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1259 IoQueueThreadIrp(Irp);
1260
1261 /* Copy-in the stack */
1262 IrpStack = IoGetNextIrpStackLocation(Irp);
1263 *IrpStack = *IoStackLocation;
1264
1265 /* Call the driver */
1266 Status = IoCallDriver(TopDeviceObject, Irp);
1267 if (Status == STATUS_PENDING)
1268 {
1269 /* Wait for it */
1270 KeWaitForSingleObject(&Event,
1271 Executive,
1272 KernelMode,
1273 FALSE,
1274 NULL);
1275 Status = IoStatusBlock.Status;
1276 }
1277
1278 /* Return the information */
1279 *Information = (PVOID)IoStatusBlock.Information;
1280 return Status;
1281 }
1282
1283 NTSTATUS
1284 NTAPI
1285 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
1286 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
1287 IN UCHAR MinorFunction,
1288 IN PIO_STACK_LOCATION Stack OPTIONAL)
1289 {
1290 IO_STACK_LOCATION IoStackLocation;
1291
1292 /* Fill out the stack information */
1293 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
1294 IoStackLocation.MajorFunction = IRP_MJ_PNP;
1295 IoStackLocation.MinorFunction = MinorFunction;
1296 if (Stack)
1297 {
1298 /* Copy the rest */
1299 RtlCopyMemory(&IoStackLocation.Parameters,
1300 &Stack->Parameters,
1301 sizeof(Stack->Parameters));
1302 }
1303
1304 /* Do the PnP call */
1305 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
1306 &IoStackLocation,
1307 (PVOID)&IoStatusBlock->Information);
1308 return IoStatusBlock->Status;
1309 }
1310
1311 NTSTATUS
1312 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
1313 {
1314 PDEVICE_NODE ParentDeviceNode;
1315 PDEVICE_NODE ChildDeviceNode;
1316 NTSTATUS Status;
1317
1318 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1319 ParentDeviceNode = Context->DeviceNode;
1320
1321 /* Call the action routine */
1322 Status = (Context->Action)(ParentDeviceNode, Context->Context);
1323 if (!NT_SUCCESS(Status))
1324 {
1325 return Status;
1326 }
1327
1328 /* Traversal of all children nodes */
1329 for (ChildDeviceNode = ParentDeviceNode->Child;
1330 ChildDeviceNode != NULL;
1331 ChildDeviceNode = ChildDeviceNode->Sibling)
1332 {
1333 /* Pass the current device node to the action routine */
1334 Context->DeviceNode = ChildDeviceNode;
1335
1336 Status = IopTraverseDeviceTreeNode(Context);
1337 if (!NT_SUCCESS(Status))
1338 {
1339 return Status;
1340 }
1341 }
1342
1343 return Status;
1344 }
1345
1346
1347 NTSTATUS
1348 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
1349 {
1350 NTSTATUS Status;
1351
1352 DPRINT("Context 0x%p\n", Context);
1353
1354 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
1355 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
1356
1357 /* Start from the specified device node */
1358 Context->DeviceNode = Context->FirstDeviceNode;
1359
1360 /* Recursively traverse the device tree */
1361 Status = IopTraverseDeviceTreeNode(Context);
1362 if (Status == STATUS_UNSUCCESSFUL)
1363 {
1364 /* The action routine just wanted to terminate the traversal with status
1365 code STATUS_SUCCESS */
1366 Status = STATUS_SUCCESS;
1367 }
1368
1369 return Status;
1370 }
1371
1372
1373 /*
1374 * IopCreateDeviceKeyPath
1375 *
1376 * Creates a registry key
1377 *
1378 * Parameters
1379 * RegistryPath
1380 * Name of the key to be created.
1381 * Handle
1382 * Handle to the newly created key
1383 *
1384 * Remarks
1385 * This method can create nested trees, so parent of RegistryPath can
1386 * be not existant, and will be created if needed.
1387 */
1388 NTSTATUS
1389 NTAPI
1390 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
1391 IN ULONG CreateOptions,
1392 OUT PHANDLE Handle)
1393 {
1394 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
1395 HANDLE hParent = NULL, hKey;
1396 OBJECT_ATTRIBUTES ObjectAttributes;
1397 UNICODE_STRING KeyName;
1398 LPCWSTR Current, Last;
1399 USHORT Length;
1400 NTSTATUS Status;
1401
1402 /* Assume failure */
1403 *Handle = NULL;
1404
1405 /* Create a volatile device tree in 1st stage so we have a clean slate
1406 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1407 if (ExpInTextModeSetup) CreateOptions |= REG_OPTION_VOLATILE;
1408
1409 /* Open root key for device instances */
1410 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
1411 if (!NT_SUCCESS(Status))
1412 {
1413 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
1414 return Status;
1415 }
1416
1417 Current = KeyName.Buffer = RegistryPath->Buffer;
1418 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
1419
1420 /* Go up to the end of the string */
1421 while (Current <= Last)
1422 {
1423 if (Current != Last && *Current != '\\')
1424 {
1425 /* Not the end of the string and not a separator */
1426 Current++;
1427 continue;
1428 }
1429
1430 /* Prepare relative key name */
1431 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
1432 KeyName.MaximumLength = KeyName.Length = Length;
1433 DPRINT("Create '%wZ'\n", &KeyName);
1434
1435 /* Open key */
1436 InitializeObjectAttributes(&ObjectAttributes,
1437 &KeyName,
1438 OBJ_CASE_INSENSITIVE,
1439 hParent,
1440 NULL);
1441 Status = ZwCreateKey(&hKey,
1442 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
1443 &ObjectAttributes,
1444 0,
1445 NULL,
1446 CreateOptions,
1447 NULL);
1448
1449 /* Close parent key handle, we don't need it anymore */
1450 if (hParent)
1451 ZwClose(hParent);
1452
1453 /* Key opening/creating failed? */
1454 if (!NT_SUCCESS(Status))
1455 {
1456 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
1457 return Status;
1458 }
1459
1460 /* Check if it is the end of the string */
1461 if (Current == Last)
1462 {
1463 /* Yes, return success */
1464 *Handle = hKey;
1465 return STATUS_SUCCESS;
1466 }
1467
1468 /* Start with this new parent key */
1469 hParent = hKey;
1470 Current++;
1471 KeyName.Buffer = (LPWSTR)Current;
1472 }
1473
1474 return STATUS_UNSUCCESSFUL;
1475 }
1476
1477 NTSTATUS
1478 IopSetDeviceInstanceData(HANDLE InstanceKey,
1479 PDEVICE_NODE DeviceNode)
1480 {
1481 OBJECT_ATTRIBUTES ObjectAttributes;
1482 UNICODE_STRING KeyName;
1483 HANDLE LogConfKey;
1484 ULONG ResCount;
1485 ULONG ResultLength;
1486 NTSTATUS Status;
1487 HANDLE ControlHandle;
1488
1489 DPRINT("IopSetDeviceInstanceData() called\n");
1490
1491 /* Create the 'LogConf' key */
1492 RtlInitUnicodeString(&KeyName, L"LogConf");
1493 InitializeObjectAttributes(&ObjectAttributes,
1494 &KeyName,
1495 OBJ_CASE_INSENSITIVE,
1496 InstanceKey,
1497 NULL);
1498 Status = ZwCreateKey(&LogConfKey,
1499 KEY_ALL_ACCESS,
1500 &ObjectAttributes,
1501 0,
1502 NULL,
1503 REG_OPTION_VOLATILE,
1504 NULL);
1505 if (NT_SUCCESS(Status))
1506 {
1507 /* Set 'BootConfig' value */
1508 if (DeviceNode->BootResources != NULL)
1509 {
1510 ResCount = DeviceNode->BootResources->Count;
1511 if (ResCount != 0)
1512 {
1513 RtlInitUnicodeString(&KeyName, L"BootConfig");
1514 Status = ZwSetValueKey(LogConfKey,
1515 &KeyName,
1516 0,
1517 REG_RESOURCE_LIST,
1518 DeviceNode->BootResources,
1519 PnpDetermineResourceListSize(DeviceNode->BootResources));
1520 }
1521 }
1522
1523 /* Set 'BasicConfigVector' value */
1524 if (DeviceNode->ResourceRequirements != NULL &&
1525 DeviceNode->ResourceRequirements->ListSize != 0)
1526 {
1527 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1528 Status = ZwSetValueKey(LogConfKey,
1529 &KeyName,
1530 0,
1531 REG_RESOURCE_REQUIREMENTS_LIST,
1532 DeviceNode->ResourceRequirements,
1533 DeviceNode->ResourceRequirements->ListSize);
1534 }
1535
1536 ZwClose(LogConfKey);
1537 }
1538
1539 /* Set the 'ConfigFlags' value */
1540 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1541 Status = ZwQueryValueKey(InstanceKey,
1542 &KeyName,
1543 KeyValueBasicInformation,
1544 NULL,
1545 0,
1546 &ResultLength);
1547 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1548 {
1549 /* Write the default value */
1550 ULONG DefaultConfigFlags = 0;
1551 Status = ZwSetValueKey(InstanceKey,
1552 &KeyName,
1553 0,
1554 REG_DWORD,
1555 &DefaultConfigFlags,
1556 sizeof(DefaultConfigFlags));
1557 }
1558
1559 /* Create the 'Control' key */
1560 RtlInitUnicodeString(&KeyName, L"Control");
1561 InitializeObjectAttributes(&ObjectAttributes,
1562 &KeyName,
1563 OBJ_CASE_INSENSITIVE,
1564 InstanceKey,
1565 NULL);
1566 Status = ZwCreateKey(&ControlHandle, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
1567
1568 if (NT_SUCCESS(Status))
1569 ZwClose(ControlHandle);
1570
1571 DPRINT("IopSetDeviceInstanceData() done\n");
1572
1573 return Status;
1574 }
1575
1576 /*
1577 * IopGetParentIdPrefix
1578 *
1579 * Retrieve (or create) a string which identifies a device.
1580 *
1581 * Parameters
1582 * DeviceNode
1583 * Pointer to device node.
1584 * ParentIdPrefix
1585 * Pointer to the string where is returned the parent node identifier
1586 *
1587 * Remarks
1588 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1589 * valid and its Buffer field is NULL-terminated. The caller needs to
1590 * to free the string with RtlFreeUnicodeString when it is no longer
1591 * needed.
1592 */
1593
1594 NTSTATUS
1595 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1596 PUNICODE_STRING ParentIdPrefix)
1597 {
1598 ULONG KeyNameBufferLength;
1599 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1600 UNICODE_STRING KeyName = {0, 0, NULL};
1601 UNICODE_STRING KeyValue;
1602 UNICODE_STRING ValueName;
1603 HANDLE hKey = NULL;
1604 ULONG crc32;
1605 NTSTATUS Status;
1606
1607 /* HACK: As long as some devices have a NULL device
1608 * instance path, the following test is required :(
1609 */
1610 if (DeviceNode->Parent->InstancePath.Length == 0)
1611 {
1612 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1613 &DeviceNode->InstancePath);
1614 return STATUS_UNSUCCESSFUL;
1615 }
1616
1617 /* 1. Try to retrieve ParentIdPrefix from registry */
1618 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1619 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
1620 if (!ParentIdPrefixInformation)
1621 {
1622 return STATUS_INSUFFICIENT_RESOURCES;
1623 }
1624
1625 KeyName.Buffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
1626 if (!KeyName.Buffer)
1627 {
1628 Status = STATUS_INSUFFICIENT_RESOURCES;
1629 goto cleanup;
1630 }
1631 KeyName.Length = 0;
1632 KeyName.MaximumLength = (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length;
1633
1634 RtlAppendUnicodeToString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1635 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1636
1637 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
1638 if (!NT_SUCCESS(Status))
1639 goto cleanup;
1640 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1641 Status = ZwQueryValueKey(
1642 hKey, &ValueName,
1643 KeyValuePartialInformation, ParentIdPrefixInformation,
1644 KeyNameBufferLength, &KeyNameBufferLength);
1645 if (NT_SUCCESS(Status))
1646 {
1647 if (ParentIdPrefixInformation->Type != REG_SZ)
1648 Status = STATUS_UNSUCCESSFUL;
1649 else
1650 {
1651 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1652 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1653 }
1654 goto cleanup;
1655 }
1656 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1657 {
1658 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1659 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1660 goto cleanup;
1661 }
1662
1663 /* 2. Create the ParentIdPrefix value */
1664 crc32 = RtlComputeCrc32(0,
1665 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1666 DeviceNode->Parent->InstancePath.Length);
1667
1668 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
1669 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
1670
1671 /* 3. Try to write the ParentIdPrefix to registry */
1672 Status = ZwSetValueKey(hKey,
1673 &ValueName,
1674 0,
1675 REG_SZ,
1676 (PVOID)KeyValue.Buffer,
1677 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1678
1679 cleanup:
1680 if (NT_SUCCESS(Status))
1681 {
1682 /* Duplicate the string to return it */
1683 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
1684 }
1685 ExFreePool(ParentIdPrefixInformation);
1686 RtlFreeUnicodeString(&KeyName);
1687 if (hKey != NULL)
1688 ZwClose(hKey);
1689 return Status;
1690 }
1691
1692 NTSTATUS
1693 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
1694 HANDLE InstanceKey)
1695 {
1696 IO_STACK_LOCATION Stack;
1697 IO_STATUS_BLOCK IoStatusBlock;
1698 PWSTR Ptr;
1699 UNICODE_STRING ValueName;
1700 NTSTATUS Status;
1701 ULONG Length, TotalLength;
1702
1703 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1704
1705 RtlZeroMemory(&Stack, sizeof(Stack));
1706 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1707 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1708 &IoStatusBlock,
1709 IRP_MN_QUERY_ID,
1710 &Stack);
1711 if (NT_SUCCESS(Status))
1712 {
1713 /*
1714 * FIXME: Check for valid characters, if there is invalid characters
1715 * then bugcheck.
1716 */
1717 TotalLength = 0;
1718 Ptr = (PWSTR)IoStatusBlock.Information;
1719 DPRINT("Hardware IDs:\n");
1720 while (*Ptr)
1721 {
1722 DPRINT(" %S\n", Ptr);
1723 Length = (ULONG)wcslen(Ptr) + 1;
1724
1725 Ptr += Length;
1726 TotalLength += Length;
1727 }
1728 DPRINT("TotalLength: %hu\n", TotalLength);
1729 DPRINT("\n");
1730
1731 RtlInitUnicodeString(&ValueName, L"HardwareID");
1732 Status = ZwSetValueKey(InstanceKey,
1733 &ValueName,
1734 0,
1735 REG_MULTI_SZ,
1736 (PVOID)IoStatusBlock.Information,
1737 (TotalLength + 1) * sizeof(WCHAR));
1738 if (!NT_SUCCESS(Status))
1739 {
1740 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1741 }
1742 }
1743 else
1744 {
1745 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1746 }
1747
1748 return Status;
1749 }
1750
1751 NTSTATUS
1752 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
1753 HANDLE InstanceKey)
1754 {
1755 IO_STACK_LOCATION Stack;
1756 IO_STATUS_BLOCK IoStatusBlock;
1757 PWSTR Ptr;
1758 UNICODE_STRING ValueName;
1759 NTSTATUS Status;
1760 ULONG Length, TotalLength;
1761
1762 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1763
1764 RtlZeroMemory(&Stack, sizeof(Stack));
1765 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1766 Status = IopInitiatePnpIrp(
1767 DeviceNode->PhysicalDeviceObject,
1768 &IoStatusBlock,
1769 IRP_MN_QUERY_ID,
1770 &Stack);
1771 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1772 {
1773 /*
1774 * FIXME: Check for valid characters, if there is invalid characters
1775 * then bugcheck.
1776 */
1777 TotalLength = 0;
1778 Ptr = (PWSTR)IoStatusBlock.Information;
1779 DPRINT("Compatible IDs:\n");
1780 while (*Ptr)
1781 {
1782 DPRINT(" %S\n", Ptr);
1783 Length = (ULONG)wcslen(Ptr) + 1;
1784
1785 Ptr += Length;
1786 TotalLength += Length;
1787 }
1788 DPRINT("TotalLength: %hu\n", TotalLength);
1789 DPRINT("\n");
1790
1791 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1792 Status = ZwSetValueKey(InstanceKey,
1793 &ValueName,
1794 0,
1795 REG_MULTI_SZ,
1796 (PVOID)IoStatusBlock.Information,
1797 (TotalLength + 1) * sizeof(WCHAR));
1798 if (!NT_SUCCESS(Status))
1799 {
1800 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1801 }
1802 }
1803 else
1804 {
1805 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1806 }
1807
1808 return Status;
1809 }
1810
1811
1812 /*
1813 * IopActionInterrogateDeviceStack
1814 *
1815 * Retrieve information for all (direct) child nodes of a parent node.
1816 *
1817 * Parameters
1818 * DeviceNode
1819 * Pointer to device node.
1820 * Context
1821 * Pointer to parent node to retrieve child node information for.
1822 *
1823 * Remarks
1824 * Any errors that occur are logged instead so that all child services have a chance
1825 * of being interrogated.
1826 */
1827
1828 NTSTATUS
1829 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
1830 PVOID Context)
1831 {
1832 IO_STATUS_BLOCK IoStatusBlock;
1833 PDEVICE_NODE ParentDeviceNode;
1834 WCHAR InstancePath[MAX_PATH];
1835 IO_STACK_LOCATION Stack;
1836 NTSTATUS Status;
1837 ULONG RequiredLength;
1838 LCID LocaleId;
1839 HANDLE InstanceKey = NULL;
1840 UNICODE_STRING ValueName;
1841 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
1842 DEVICE_CAPABILITIES DeviceCapabilities;
1843
1844 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1845 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1846
1847 ParentDeviceNode = (PDEVICE_NODE)Context;
1848
1849 /*
1850 * We are called for the parent too, but we don't need to do special
1851 * handling for this node
1852 */
1853
1854 if (DeviceNode == ParentDeviceNode)
1855 {
1856 DPRINT("Success\n");
1857 return STATUS_SUCCESS;
1858 }
1859
1860 /*
1861 * Make sure this device node is a direct child of the parent device node
1862 * that is given as an argument
1863 */
1864
1865 if (DeviceNode->Parent != ParentDeviceNode)
1866 {
1867 DPRINT("Skipping 2+ level child\n");
1868 return STATUS_SUCCESS;
1869 }
1870
1871 /* Skip processing if it was already completed before */
1872 if (DeviceNode->Flags & DNF_PROCESSED)
1873 {
1874 /* Nothing to do */
1875 return STATUS_SUCCESS;
1876 }
1877
1878 /* Get Locale ID */
1879 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
1880 if (!NT_SUCCESS(Status))
1881 {
1882 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
1883 return Status;
1884 }
1885
1886 /*
1887 * FIXME: For critical errors, cleanup and disable device, but always
1888 * return STATUS_SUCCESS.
1889 */
1890
1891 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1892
1893 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1894 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1895 &IoStatusBlock,
1896 IRP_MN_QUERY_ID,
1897 &Stack);
1898 if (NT_SUCCESS(Status))
1899 {
1900 /* Copy the device id string */
1901 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
1902
1903 /*
1904 * FIXME: Check for valid characters, if there is invalid characters
1905 * then bugcheck.
1906 */
1907 }
1908 else
1909 {
1910 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1911
1912 /* We have to return success otherwise we abort the traverse operation */
1913 return STATUS_SUCCESS;
1914 }
1915
1916 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1917
1918 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1919 if (!NT_SUCCESS(Status))
1920 {
1921 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1922
1923 /* We have to return success otherwise we abort the traverse operation */
1924 return STATUS_SUCCESS;
1925 }
1926
1927 /* This bit is only check after enumeration */
1928 if (DeviceCapabilities.HardwareDisabled)
1929 {
1930 /* FIXME: Cleanup device */
1931 DeviceNode->Flags |= DNF_DISABLED;
1932 return STATUS_SUCCESS;
1933 }
1934 else
1935 DeviceNode->Flags &= ~DNF_DISABLED;
1936
1937 if (!DeviceCapabilities.UniqueID)
1938 {
1939 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1940 DPRINT("Instance ID is not unique\n");
1941 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1942 if (!NT_SUCCESS(Status))
1943 {
1944 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1945
1946 /* We have to return success otherwise we abort the traverse operation */
1947 return STATUS_SUCCESS;
1948 }
1949 }
1950
1951 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1952
1953 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1954 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1955 &IoStatusBlock,
1956 IRP_MN_QUERY_ID,
1957 &Stack);
1958 if (NT_SUCCESS(Status))
1959 {
1960 /* Append the instance id string */
1961 wcscat(InstancePath, L"\\");
1962 if (ParentIdPrefix.Length > 0)
1963 {
1964 /* Add information from parent bus device to InstancePath */
1965 wcscat(InstancePath, ParentIdPrefix.Buffer);
1966 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
1967 wcscat(InstancePath, L"&");
1968 }
1969 if (IoStatusBlock.Information)
1970 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1971
1972 /*
1973 * FIXME: Check for valid characters, if there is invalid characters
1974 * then bugcheck
1975 */
1976 }
1977 else
1978 {
1979 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1980 }
1981 RtlFreeUnicodeString(&ParentIdPrefix);
1982
1983 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
1984 {
1985 DPRINT("No resources\n");
1986 /* FIXME: Cleanup and disable device */
1987 }
1988
1989 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1990
1991 /*
1992 * Create registry key for the instance id, if it doesn't exist yet
1993 */
1994 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
1995 if (!NT_SUCCESS(Status))
1996 {
1997 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1998
1999 /* We have to return success otherwise we abort the traverse operation */
2000 return STATUS_SUCCESS;
2001 }
2002
2003 IopQueryHardwareIds(DeviceNode, InstanceKey);
2004
2005 IopQueryCompatibleIds(DeviceNode, InstanceKey);
2006
2007 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2008
2009 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2010 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2011 Status = IopInitiatePnpIrp(
2012 DeviceNode->PhysicalDeviceObject,
2013 &IoStatusBlock,
2014 IRP_MN_QUERY_DEVICE_TEXT,
2015 &Stack);
2016 /* This key is mandatory, so even if the Irp fails, we still write it */
2017 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2018 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2019 {
2020 if (NT_SUCCESS(Status) &&
2021 IoStatusBlock.Information &&
2022 (*(PWSTR)IoStatusBlock.Information != 0))
2023 {
2024 /* This key is overriden when a driver is installed. Don't write the
2025 * new description if another one already exists */
2026 Status = ZwSetValueKey(InstanceKey,
2027 &ValueName,
2028 0,
2029 REG_SZ,
2030 (PVOID)IoStatusBlock.Information,
2031 ((ULONG)wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2032 }
2033 else
2034 {
2035 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2036 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2037
2038 Status = ZwSetValueKey(InstanceKey,
2039 &ValueName,
2040 0,
2041 REG_SZ,
2042 DeviceDesc.Buffer,
2043 DeviceDesc.MaximumLength);
2044
2045 if (!NT_SUCCESS(Status))
2046 {
2047 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2048 }
2049
2050 }
2051 }
2052
2053 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2054
2055 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2056 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2057 Status = IopInitiatePnpIrp(
2058 DeviceNode->PhysicalDeviceObject,
2059 &IoStatusBlock,
2060 IRP_MN_QUERY_DEVICE_TEXT,
2061 &Stack);
2062 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2063 {
2064 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
2065 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2066 Status = ZwSetValueKey(InstanceKey,
2067 &ValueName,
2068 0,
2069 REG_SZ,
2070 (PVOID)IoStatusBlock.Information,
2071 ((ULONG)wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2072 if (!NT_SUCCESS(Status))
2073 {
2074 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2075 }
2076 }
2077 else
2078 {
2079 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2080 }
2081
2082 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2083
2084 Status = IopInitiatePnpIrp(
2085 DeviceNode->PhysicalDeviceObject,
2086 &IoStatusBlock,
2087 IRP_MN_QUERY_BUS_INFORMATION,
2088 NULL);
2089 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2090 {
2091 PPNP_BUS_INFORMATION BusInformation =
2092 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2093
2094 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2095 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2096 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2097 ExFreePool(BusInformation);
2098 }
2099 else
2100 {
2101 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2102
2103 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2104 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2105 DeviceNode->ChildBusTypeIndex = -1;
2106 }
2107
2108 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2109
2110 Status = IopInitiatePnpIrp(
2111 DeviceNode->PhysicalDeviceObject,
2112 &IoStatusBlock,
2113 IRP_MN_QUERY_RESOURCES,
2114 NULL);
2115 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2116 {
2117 DeviceNode->BootResources =
2118 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2119 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2120 }
2121 else
2122 {
2123 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2124 DeviceNode->BootResources = NULL;
2125 }
2126
2127 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2128
2129 Status = IopInitiatePnpIrp(
2130 DeviceNode->PhysicalDeviceObject,
2131 &IoStatusBlock,
2132 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2133 NULL);
2134 if (NT_SUCCESS(Status))
2135 {
2136 DeviceNode->ResourceRequirements =
2137 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2138 }
2139 else
2140 {
2141 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2142 DeviceNode->ResourceRequirements = NULL;
2143 }
2144
2145 if (InstanceKey != NULL)
2146 {
2147 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2148 }
2149
2150 ZwClose(InstanceKey);
2151
2152 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2153
2154 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2155 {
2156 /* Report the device to the user-mode pnp manager */
2157 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2158 &DeviceNode->InstancePath);
2159 }
2160
2161 return STATUS_SUCCESS;
2162 }
2163
2164 static
2165 VOID
2166 IopHandleDeviceRemoval(
2167 IN PDEVICE_NODE DeviceNode,
2168 IN PDEVICE_RELATIONS DeviceRelations)
2169 {
2170 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2171 ULONG i;
2172 BOOLEAN Found;
2173
2174 if (DeviceNode == IopRootDeviceNode)
2175 return;
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 return STATUS_SUCCESS;
2557
2558 if (DeviceNode->ServiceName.Buffer == NULL)
2559 {
2560 /* We don't need to worry about loading the driver because we're
2561 * being driven in raw mode so our parent must be loaded to get here */
2562 Status = IopInitializeDevice(DeviceNode, NULL);
2563 if (NT_SUCCESS(Status))
2564 {
2565 Status = IopStartDevice(DeviceNode);
2566 if (!NT_SUCCESS(Status))
2567 {
2568 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2569 &DeviceNode->InstancePath, Status);
2570 }
2571 }
2572 }
2573 else
2574 {
2575 PLDR_DATA_TABLE_ENTRY ModuleObject;
2576 PDRIVER_OBJECT DriverObject;
2577
2578 /* Get existing DriverObject pointer (in case the driver has
2579 already been loaded and initialized) */
2580 Status = IopGetDriverObject(
2581 &DriverObject,
2582 &DeviceNode->ServiceName,
2583 FALSE);
2584
2585 if (!NT_SUCCESS(Status))
2586 {
2587 /* Driver is not initialized, try to load it */
2588 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2589
2590 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2591 {
2592 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2593 was loaded by the bootloader */
2594 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
2595 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
2596 {
2597 /* Initialize the driver */
2598 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2599 &DeviceNode->ServiceName, FALSE, &DriverObject);
2600 }
2601 else
2602 {
2603 Status = STATUS_SUCCESS;
2604 }
2605 }
2606 else
2607 {
2608 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2609 &DeviceNode->ServiceName, Status);
2610 }
2611 }
2612
2613 /* Driver is loaded and initialized at this point */
2614 if (NT_SUCCESS(Status))
2615 {
2616 /* Initialize the device, including all filters */
2617 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2618 }
2619 else
2620 {
2621 /*
2622 * Don't disable when trying to load only boot drivers
2623 */
2624 if (!BootDrivers)
2625 {
2626 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2627 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2628 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2629 DPRINT1("Initialization of service %S failed (Status %x)\n",
2630 DeviceNode->ServiceName.Buffer, Status);
2631 }
2632 }
2633 }
2634
2635 return STATUS_SUCCESS;
2636 }
2637
2638 /*
2639 * IopInitializePnpServices
2640 *
2641 * Initialize services for discovered children
2642 *
2643 * Parameters
2644 * DeviceNode
2645 * Top device node to start initializing services.
2646 *
2647 * Return Value
2648 * Status
2649 */
2650 NTSTATUS
2651 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2652 {
2653 DEVICETREE_TRAVERSE_CONTEXT Context;
2654
2655 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2656
2657 IopInitDeviceTreeTraverseContext(
2658 &Context,
2659 DeviceNode,
2660 IopActionInitChildServices,
2661 DeviceNode);
2662
2663 return IopTraverseDeviceTree(&Context);
2664 }
2665
2666 static NTSTATUS INIT_FUNCTION
2667 IopEnumerateDetectedDevices(
2668 IN HANDLE hBaseKey,
2669 IN PUNICODE_STRING RelativePath OPTIONAL,
2670 IN HANDLE hRootKey,
2671 IN BOOLEAN EnumerateSubKeys,
2672 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2673 IN ULONG ParentBootResourcesLength)
2674 {
2675 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2676 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2677 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2678 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2679 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2680 OBJECT_ATTRIBUTES ObjectAttributes;
2681 HANDLE hDevicesKey = NULL;
2682 HANDLE hDeviceKey = NULL;
2683 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2684 UNICODE_STRING Level2NameU;
2685 WCHAR Level2Name[5];
2686 ULONG IndexDevice = 0;
2687 ULONG IndexSubKey;
2688 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2689 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2690 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2691 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2692 UNICODE_STRING DeviceName, ValueName;
2693 ULONG RequiredSize;
2694 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2695 ULONG BootResourcesLength;
2696 NTSTATUS Status;
2697
2698 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
2699 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
2700 static ULONG DeviceIndexPci = 0;
2701 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2702 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2703 static ULONG DeviceIndexSerial = 0;
2704 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2705 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2706 static ULONG DeviceIndexKeyboard = 0;
2707 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2708 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2709 static ULONG DeviceIndexMouse = 0;
2710 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2711 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2712 static ULONG DeviceIndexParallel = 0;
2713 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2714 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2715 static ULONG DeviceIndexFloppy = 0;
2716 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
2717 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
2718 static ULONG DeviceIndexIsa = 0;
2719 UNICODE_STRING HardwareIdKey;
2720 PUNICODE_STRING pHardwareId;
2721 ULONG DeviceIndex = 0;
2722 PUCHAR CmResourceList;
2723 ULONG ListCount;
2724
2725 if (RelativePath)
2726 {
2727 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2728 if (!NT_SUCCESS(Status))
2729 {
2730 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2731 goto cleanup;
2732 }
2733 }
2734 else
2735 hDevicesKey = hBaseKey;
2736
2737 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2738 if (!pDeviceInformation)
2739 {
2740 DPRINT("ExAllocatePool() failed\n");
2741 Status = STATUS_NO_MEMORY;
2742 goto cleanup;
2743 }
2744
2745 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2746 if (!pValueInformation)
2747 {
2748 DPRINT("ExAllocatePool() failed\n");
2749 Status = STATUS_NO_MEMORY;
2750 goto cleanup;
2751 }
2752
2753 while (TRUE)
2754 {
2755 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2756 if (Status == STATUS_NO_MORE_ENTRIES)
2757 break;
2758 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2759 {
2760 ExFreePool(pDeviceInformation);
2761 DeviceInfoLength = RequiredSize;
2762 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2763 if (!pDeviceInformation)
2764 {
2765 DPRINT("ExAllocatePool() failed\n");
2766 Status = STATUS_NO_MEMORY;
2767 goto cleanup;
2768 }
2769 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2770 }
2771 if (!NT_SUCCESS(Status))
2772 {
2773 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2774 goto cleanup;
2775 }
2776 IndexDevice++;
2777
2778 /* Open device key */
2779 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2780 DeviceName.Buffer = pDeviceInformation->Name;
2781
2782 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
2783 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
2784 if (!NT_SUCCESS(Status))
2785 {
2786 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2787 goto cleanup;
2788 }
2789
2790 /* Read boot resources, and add then to parent ones */
2791 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2792 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2793 {
2794 ExFreePool(pValueInformation);
2795 ValueInfoLength = RequiredSize;
2796 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2797 if (!pValueInformation)
2798 {
2799 DPRINT("ExAllocatePool() failed\n");
2800 ZwDeleteKey(hLevel2Key);
2801 Status = STATUS_NO_MEMORY;
2802 goto cleanup;
2803 }
2804 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2805 }
2806 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2807 {
2808 BootResources = ParentBootResources;
2809 BootResourcesLength = ParentBootResourcesLength;
2810 }
2811 else if (!NT_SUCCESS(Status))
2812 {
2813 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2814 goto nextdevice;
2815 }
2816 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2817 {
2818 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2819 goto nextdevice;
2820 }
2821 else
2822 {
2823 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2824
2825 /* Concatenate current resources and parent ones */
2826 if (ParentBootResourcesLength == 0)
2827 BootResourcesLength = pValueInformation->DataLength;
2828 else
2829 BootResourcesLength = ParentBootResourcesLength
2830 + pValueInformation->DataLength
2831 - Header;
2832 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2833 if (!BootResources)
2834 {
2835 DPRINT("ExAllocatePool() failed\n");
2836 goto nextdevice;
2837 }
2838 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2839 {
2840 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2841 }
2842 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2843 {
2844 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2845 RtlCopyMemory(
2846 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2847 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2848 ParentBootResourcesLength - Header);
2849 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2850 }
2851 else
2852 {
2853 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2854 RtlCopyMemory(
2855 (PVOID)((ULONG_PTR)BootResources + Header),
2856 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2857 ParentBootResourcesLength - Header);
2858 RtlCopyMemory(
2859 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2860 pValueInformation->Data + Header,
2861 pValueInformation->DataLength - Header);
2862 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2863 }
2864 }
2865
2866 if (EnumerateSubKeys)
2867 {
2868 IndexSubKey = 0;
2869 while (TRUE)
2870 {
2871 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2872 if (Status == STATUS_NO_MORE_ENTRIES)
2873 break;
2874 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2875 {
2876 ExFreePool(pDeviceInformation);
2877 DeviceInfoLength = RequiredSize;
2878 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2879 if (!pDeviceInformation)
2880 {
2881 DPRINT("ExAllocatePool() failed\n");
2882 Status = STATUS_NO_MEMORY;
2883 goto cleanup;
2884 }
2885 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2886 }
2887 if (!NT_SUCCESS(Status))
2888 {
2889 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2890 goto cleanup;
2891 }
2892 IndexSubKey++;
2893 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2894 DeviceName.Buffer = pDeviceInformation->Name;
2895
2896 Status = IopEnumerateDetectedDevices(
2897 hDeviceKey,
2898 &DeviceName,
2899 hRootKey,
2900 TRUE,
2901 BootResources,
2902 BootResourcesLength);
2903 if (!NT_SUCCESS(Status))
2904 goto cleanup;
2905 }
2906 }
2907
2908 /* Read identifier */
2909 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2910 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2911 {
2912 ExFreePool(pValueInformation);
2913 ValueInfoLength = RequiredSize;
2914 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2915 if (!pValueInformation)
2916 {
2917 DPRINT("ExAllocatePool() failed\n");
2918 Status = STATUS_NO_MEMORY;
2919 goto cleanup;
2920 }
2921 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2922 }
2923 if (!NT_SUCCESS(Status))
2924 {
2925 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2926 {
2927 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2928 goto nextdevice;
2929 }
2930 ValueName.Length = ValueName.MaximumLength = 0;
2931 }
2932 else if (pValueInformation->Type != REG_SZ)
2933 {
2934 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2935 goto nextdevice;
2936 }
2937 else
2938 {
2939 /* Assign hardware id to this device */
2940 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
2941 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2942 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2943 ValueName.Length -= sizeof(WCHAR);
2944 }
2945
2946 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
2947 {
2948 pHardwareId = &HardwareIdSerial;
2949 DeviceIndex = DeviceIndexSerial++;
2950 }
2951 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
2952 {
2953 pHardwareId = &HardwareIdKeyboard;
2954 DeviceIndex = DeviceIndexKeyboard++;
2955 }
2956 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
2957 {
2958 pHardwareId = &HardwareIdMouse;
2959 DeviceIndex = DeviceIndexMouse++;
2960 }
2961 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
2962 {
2963 pHardwareId = &HardwareIdParallel;
2964 DeviceIndex = DeviceIndexParallel++;
2965 }
2966 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
2967 {
2968 pHardwareId = &HardwareIdFloppy;
2969 DeviceIndex = DeviceIndexFloppy++;
2970 }
2971 else if (NT_SUCCESS(Status))
2972 {
2973 /* Try to also match the device identifier */
2974 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
2975 {
2976 pHardwareId = &HardwareIdPci;
2977 DeviceIndex = DeviceIndexPci++;
2978 }
2979 else if (RtlCompareUnicodeString(&ValueName, &IdentifierIsa, FALSE) == 0)
2980 {
2981 pHardwareId = &HardwareIdIsa;
2982 DeviceIndex = DeviceIndexIsa++;
2983 }
2984 else
2985 {
2986 DPRINT("Unknown device '%wZ'\n", &ValueName);
2987 goto nextdevice;
2988 }
2989 }
2990 else
2991 {
2992 /* Unknown key path */
2993 DPRINT("Unknown key path '%wZ'\n", RelativePath);
2994 goto nextdevice;
2995 }
2996
2997 /* Prepare hardware id key (hardware id value without final \0) */
2998 HardwareIdKey = *pHardwareId;
2999 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3000
3001 /* Add the detected device to Root key */
3002 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3003 Status = ZwCreateKey(
3004 &hLevel1Key,
3005 KEY_CREATE_SUB_KEY,
3006 &ObjectAttributes,
3007 0,
3008 NULL,
3009 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3010 NULL);
3011 if (!NT_SUCCESS(Status))
3012 {
3013 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3014 goto nextdevice;
3015 }
3016 swprintf(Level2Name, L"%04lu", DeviceIndex);
3017 RtlInitUnicodeString(&Level2NameU, Level2Name);
3018 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3019 Status = ZwCreateKey(
3020 &hLevel2Key,
3021 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3022 &ObjectAttributes,
3023 0,
3024 NULL,
3025 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3026 NULL);
3027 ZwClose(hLevel1Key);
3028 if (!NT_SUCCESS(Status))
3029 {
3030 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3031 goto nextdevice;
3032 }
3033 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3034 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3035 if (!NT_SUCCESS(Status))
3036 {
3037 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3038 ZwDeleteKey(hLevel2Key);
3039 goto nextdevice;
3040 }
3041 /* Create 'LogConf' subkey */
3042 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3043 Status = ZwCreateKey(
3044 &hLogConf,
3045 KEY_SET_VALUE,
3046 &ObjectAttributes,
3047 0,
3048 NULL,
3049 REG_OPTION_VOLATILE,
3050 NULL);
3051 if (!NT_SUCCESS(Status))
3052 {
3053 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3054 ZwDeleteKey(hLevel2Key);
3055 goto nextdevice;
3056 }
3057 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3058 {
3059 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3060 if (!CmResourceList)
3061 {
3062 ZwClose(hLogConf);
3063 ZwDeleteKey(hLevel2Key);
3064 goto nextdevice;
3065 }
3066
3067 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3068 ListCount = 1;
3069 RtlCopyMemory(CmResourceList,
3070 &ListCount,
3071 sizeof(ULONG));
3072
3073 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3074 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3075 BootResources,
3076 BootResourcesLength);
3077
3078 /* Save boot resources to 'LogConf\BootConfig' */
3079 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3080 if (!NT_SUCCESS(Status))
3081 {
3082 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3083 ZwClose(hLogConf);
3084 ZwDeleteKey(hLevel2Key);
3085 goto nextdevice;
3086 }
3087 }
3088 ZwClose(hLogConf);
3089
3090 nextdevice:
3091 if (BootResources && BootResources != ParentBootResources)
3092 {
3093 ExFreePool(BootResources);
3094 BootResources = NULL;
3095 }
3096 if (hLevel2Key)
3097 {
3098 ZwClose(hLevel2Key);
3099 hLevel2Key = NULL;
3100 }
3101 if (hDeviceKey)
3102 {
3103 ZwClose(hDeviceKey);
3104 hDeviceKey = NULL;
3105 }
3106 }
3107
3108 Status = STATUS_SUCCESS;
3109
3110 cleanup:
3111 if (hDevicesKey && hDevicesKey != hBaseKey)
3112 ZwClose(hDevicesKey);
3113 if (hDeviceKey)
3114 ZwClose(hDeviceKey);
3115 if (pDeviceInformation)
3116 ExFreePool(pDeviceInformation);
3117 if (pValueInformation)
3118 ExFreePool(pValueInformation);
3119 return Status;
3120 }
3121
3122 static BOOLEAN INIT_FUNCTION
3123 IopIsFirmwareMapperDisabled(VOID)
3124 {
3125 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3126 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3127 OBJECT_ATTRIBUTES ObjectAttributes;
3128 HANDLE hPnpKey;
3129 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3130 ULONG DesiredLength, Length;
3131 ULONG KeyValue = 0;
3132 NTSTATUS Status;
3133
3134 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3135 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3136 if (NT_SUCCESS(Status))
3137 {
3138 Status = ZwQueryValueKey(hPnpKey,
3139 &KeyNameU,
3140 KeyValuePartialInformation,
3141 NULL,
3142 0,
3143 &DesiredLength);
3144 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3145 (Status == STATUS_BUFFER_OVERFLOW))
3146 {
3147 Length = DesiredLength;
3148 KeyInformation = ExAllocatePool(PagedPool, Length);
3149 if (KeyInformation)
3150 {
3151 Status = ZwQueryValueKey(hPnpKey,
3152 &KeyNameU,
3153 KeyValuePartialInformation,
3154 KeyInformation,
3155 Length,
3156 &DesiredLength);
3157 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3158 {
3159 KeyValue = (ULONG)(*KeyInformation->Data);
3160 }
3161 else
3162 {
3163 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3164 }
3165
3166 ExFreePool(KeyInformation);
3167 }
3168 else
3169 {
3170 DPRINT1("Failed to allocate memory for registry query\n");
3171 }
3172 }
3173 else
3174 {
3175 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3176 }
3177
3178 ZwClose(hPnpKey);
3179 }
3180 else
3181 {
3182 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3183 }
3184
3185 DPRINT1("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3186
3187 return (KeyValue != 0) ? TRUE : FALSE;
3188 }
3189
3190 NTSTATUS
3191 NTAPI
3192 INIT_FUNCTION
3193 IopUpdateRootKey(VOID)
3194 {
3195 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3196 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3197 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3198 OBJECT_ATTRIBUTES ObjectAttributes;
3199 HANDLE hEnum, hRoot;
3200 NTSTATUS Status;
3201
3202 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3203 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3204 if (!NT_SUCCESS(Status))
3205 {
3206 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3207 return Status;
3208 }
3209
3210 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3211 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3212 ZwClose(hEnum);
3213 if (!NT_SUCCESS(Status))
3214 {
3215 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3216 return Status;
3217 }
3218
3219 if (!IopIsFirmwareMapperDisabled())
3220 {
3221 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3222 if (!NT_SUCCESS(Status))
3223 {
3224 /* Nothing to do, don't return with an error status */
3225 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3226 ZwClose(hRoot);
3227 return STATUS_SUCCESS;
3228 }
3229 Status = IopEnumerateDetectedDevices(
3230 hEnum,
3231 NULL,
3232 hRoot,
3233 TRUE,
3234 NULL,
3235 0);
3236 ZwClose(hEnum);
3237 }
3238 else
3239 {
3240 /* Enumeration is disabled */
3241 Status = STATUS_SUCCESS;
3242 }
3243
3244 ZwClose(hRoot);
3245
3246 return Status;
3247 }
3248
3249 NTSTATUS
3250 NTAPI
3251 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3252 HANDLE ParentKey,
3253 PUNICODE_STRING Name,
3254 ACCESS_MASK DesiredAccess)
3255 {
3256 OBJECT_ATTRIBUTES ObjectAttributes;
3257 NTSTATUS Status;
3258
3259 PAGED_CODE();
3260
3261 *KeyHandle = NULL;
3262
3263 InitializeObjectAttributes(&ObjectAttributes,
3264 Name,
3265 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3266 ParentKey,
3267 NULL);
3268
3269 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3270
3271 return Status;
3272 }
3273
3274 NTSTATUS
3275 NTAPI
3276 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3277 IN HANDLE RootHandle OPTIONAL,
3278 IN PUNICODE_STRING KeyName,
3279 IN ACCESS_MASK DesiredAccess,
3280 IN ULONG CreateOptions,
3281 OUT PULONG Disposition OPTIONAL)
3282 {
3283 OBJECT_ATTRIBUTES ObjectAttributes;
3284 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3285 USHORT Length;
3286 HANDLE HandleArray[2];
3287 BOOLEAN Recursing = TRUE;
3288 PWCHAR pp, p, p1;
3289 UNICODE_STRING KeyString;
3290 NTSTATUS Status = STATUS_SUCCESS;
3291 PAGED_CODE();
3292
3293 /* P1 is start, pp is end */
3294 p1 = KeyName->Buffer;
3295 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3296
3297 /* Create the target key */
3298 InitializeObjectAttributes(&ObjectAttributes,
3299 KeyName,
3300 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3301 RootHandle,
3302 NULL);
3303 Status = ZwCreateKey(&HandleArray[i],
3304 DesiredAccess,
3305 &ObjectAttributes,
3306 0,
3307 NULL,
3308 CreateOptions,
3309 &KeyDisposition);
3310
3311 /* Now we check if this failed */
3312 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3313 {
3314 /* Target key failed, so we'll need to create its parent. Setup array */
3315 HandleArray[0] = NULL;
3316 HandleArray[1] = RootHandle;
3317
3318 /* Keep recursing for each missing parent */
3319 while (Recursing)
3320 {
3321 /* And if we're deep enough, close the last handle */
3322 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3323
3324 /* We're setup to ping-pong between the two handle array entries */
3325 RootHandleIndex = i;
3326 i = (i + 1) & 1;
3327
3328 /* Clear the one we're attempting to open now */
3329 HandleArray[i] = NULL;
3330
3331 /* Process the parent key name */
3332 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3333 Length = (USHORT)(p - p1) * sizeof(WCHAR);
3334
3335 /* Is there a parent name? */
3336 if (Length)
3337 {
3338 /* Build the unicode string for it */
3339 KeyString.Buffer = p1;
3340 KeyString.Length = KeyString.MaximumLength = Length;
3341
3342 /* Now try opening the parent */
3343 InitializeObjectAttributes(&ObjectAttributes,
3344 &KeyString,
3345 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3346 HandleArray[RootHandleIndex],
3347 NULL);
3348 Status = ZwCreateKey(&HandleArray[i],
3349 DesiredAccess,
3350 &ObjectAttributes,
3351 0,
3352 NULL,
3353 CreateOptions,
3354 &KeyDisposition);
3355 if (NT_SUCCESS(Status))
3356 {
3357 /* It worked, we have one more handle */
3358 NestedCloseLevel++;
3359 }
3360 else
3361 {
3362 /* Parent key creation failed, abandon loop */
3363 Recursing = FALSE;
3364 continue;
3365 }