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