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