[NTOSKRNL] Fix the indentation of some pnp manager functions.
[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 IopDeviceActionRequestList;
38 WORK_QUEUE_ITEM IopDeviceActionWorkItem;
39 BOOLEAN IopDeviceActionInProgress;
40 KSPIN_LOCK IopDeviceActionLock;
41
42 typedef struct _DEVICE_ACTION_DATA
43 {
44 LIST_ENTRY RequestListEntry;
45 PDEVICE_OBJECT DeviceObject;
46 DEVICE_RELATION_TYPE Type;
47 } DEVICE_ACTION_DATA, *PDEVICE_ACTION_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, REG_OPTION_NON_VOLATILE, &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(DriverObject,
467 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, ValueString;
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, REG_OPTION_NON_VOLATILE, &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 ValueString = DeviceNode->ServiceName;
821 if (!ValueString.Buffer)
822 RtlInitUnicodeString(&ValueString, L"");
823 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, ValueString.Buffer, ValueString.Length + sizeof(UNICODE_NULL));
824 // }
825
826 ByeBye:
827 if (ControlHandle != NULL)
828 ZwClose(ControlHandle);
829
830 if (InstanceHandle != NULL)
831 ZwClose(InstanceHandle);
832
833 return Status;
834 }
835
836 NTSTATUS
837 NTAPI
838 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
839 PDEVICE_CAPABILITIES DeviceCaps)
840 {
841 IO_STATUS_BLOCK StatusBlock;
842 IO_STACK_LOCATION Stack;
843 NTSTATUS Status;
844 HANDLE InstanceKey;
845 UNICODE_STRING ValueName;
846
847 /* Set up the Header */
848 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
849 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
850 DeviceCaps->Version = 1;
851 DeviceCaps->Address = -1;
852 DeviceCaps->UINumber = -1;
853
854 /* Set up the Stack */
855 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
856 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
857
858 /* Send the IRP */
859 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
860 &StatusBlock,
861 IRP_MN_QUERY_CAPABILITIES,
862 &Stack);
863 if (!NT_SUCCESS(Status))
864 {
865 if (Status != STATUS_NOT_SUPPORTED)
866 {
867 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status);
868 }
869 return Status;
870 }
871
872 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCaps->Version + sizeof(DeviceCaps->Version));
873
874 if (DeviceCaps->NoDisplayInUI)
875 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
876 else
877 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
878
879 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
880 if (NT_SUCCESS(Status))
881 {
882 /* Set 'Capabilities' value */
883 RtlInitUnicodeString(&ValueName, L"Capabilities");
884 Status = ZwSetValueKey(InstanceKey,
885 &ValueName,
886 0,
887 REG_DWORD,
888 &DeviceNode->CapabilityFlags,
889 sizeof(ULONG));
890
891 /* Set 'UINumber' value */
892 if (DeviceCaps->UINumber != MAXULONG)
893 {
894 RtlInitUnicodeString(&ValueName, L"UINumber");
895 Status = ZwSetValueKey(InstanceKey,
896 &ValueName,
897 0,
898 REG_DWORD,
899 &DeviceCaps->UINumber,
900 sizeof(ULONG));
901 }
902
903 ZwClose(InstanceKey);
904 }
905
906 return Status;
907 }
908
909 static
910 VOID
911 NTAPI
912 IopDeviceActionWorker(
913 _In_ PVOID Context)
914 {
915 PLIST_ENTRY ListEntry;
916 PDEVICE_ACTION_DATA Data;
917 KIRQL OldIrql;
918
919 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
920 while (!IsListEmpty(&IopDeviceActionRequestList))
921 {
922 ListEntry = RemoveHeadList(&IopDeviceActionRequestList);
923 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
924 Data = CONTAINING_RECORD(ListEntry,
925 DEVICE_ACTION_DATA,
926 RequestListEntry);
927
928 IoSynchronousInvalidateDeviceRelations(Data->DeviceObject,
929 Data->Type);
930
931 ObDereferenceObject(Data->DeviceObject);
932 ExFreePoolWithTag(Data, TAG_IO);
933 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
934 }
935 IopDeviceActionInProgress = FALSE;
936 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
937 }
938
939 NTSTATUS
940 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
941 {
942 KIRQL OldIrql;
943
944 if (PopSystemPowerDeviceNode)
945 {
946 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
947 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
948 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
949
950 return STATUS_SUCCESS;
951 }
952
953 return STATUS_UNSUCCESSFUL;
954 }
955
956 USHORT
957 NTAPI
958 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
959 {
960 USHORT i = 0, FoundIndex = 0xFFFF;
961 ULONG NewSize;
962 PVOID NewList;
963
964 /* Acquire the lock */
965 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
966
967 /* Loop all entries */
968 while (i < PnpBusTypeGuidList->GuidCount)
969 {
970 /* Try to find a match */
971 if (RtlCompareMemory(BusTypeGuid,
972 &PnpBusTypeGuidList->Guids[i],
973 sizeof(GUID)) == sizeof(GUID))
974 {
975 /* Found it */
976 FoundIndex = i;
977 goto Quickie;
978 }
979 i++;
980 }
981
982 /* Check if we have to grow the list */
983 if (PnpBusTypeGuidList->GuidCount)
984 {
985 /* Calculate the new size */
986 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
987 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
988
989 /* Allocate the new copy */
990 NewList = ExAllocatePool(PagedPool, NewSize);
991
992 if (!NewList)
993 {
994 /* Fail */
995 ExFreePool(PnpBusTypeGuidList);
996 goto Quickie;
997 }
998
999 /* Now copy them, decrease the size too */
1000 NewSize -= sizeof(GUID);
1001 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
1002
1003 /* Free the old list */
1004 ExFreePool(PnpBusTypeGuidList);
1005
1006 /* Use the new buffer */
1007 PnpBusTypeGuidList = NewList;
1008 }
1009
1010 /* Copy the new GUID */
1011 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
1012 BusTypeGuid,
1013 sizeof(GUID));
1014
1015 /* The new entry is the index */
1016 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
1017 PnpBusTypeGuidList->GuidCount++;
1018
1019 Quickie:
1020 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
1021 return FoundIndex;
1022 }
1023
1024 /*
1025 * DESCRIPTION
1026 * Creates a device node
1027 *
1028 * ARGUMENTS
1029 * ParentNode = Pointer to parent device node
1030 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
1031 * to have the root device node create one
1032 * (eg. for legacy drivers)
1033 * DeviceNode = Pointer to storage for created device node
1034 *
1035 * RETURN VALUE
1036 * Status
1037 */
1038 NTSTATUS
1039 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
1040 PDEVICE_OBJECT PhysicalDeviceObject,
1041 PUNICODE_STRING ServiceName,
1042 PDEVICE_NODE *DeviceNode)
1043 {
1044 PDEVICE_NODE Node;
1045 NTSTATUS Status;
1046 KIRQL OldIrql;
1047 UNICODE_STRING FullServiceName;
1048 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
1049 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
1050 UNICODE_STRING KeyName, ClassName;
1051 PUNICODE_STRING ServiceName1;
1052 ULONG LegacyValue;
1053 UNICODE_STRING ClassGUID;
1054 HANDLE InstanceHandle;
1055
1056 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1057 ParentNode, PhysicalDeviceObject, ServiceName);
1058
1059 Node = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE);
1060 if (!Node)
1061 {
1062 return STATUS_INSUFFICIENT_RESOURCES;
1063 }
1064
1065 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
1066
1067 if (!ServiceName)
1068 ServiceName1 = &UnknownDeviceName;
1069 else
1070 ServiceName1 = ServiceName;
1071
1072 if (!PhysicalDeviceObject)
1073 {
1074 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length + sizeof(UNICODE_NULL);
1075 FullServiceName.Length = 0;
1076 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
1077 if (!FullServiceName.Buffer)
1078 {
1079 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1080 return STATUS_INSUFFICIENT_RESOURCES;
1081 }
1082
1083 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
1084 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
1085 RtlUpcaseUnicodeString(&FullServiceName, &FullServiceName, FALSE);
1086
1087 Status = PnpRootCreateDevice(&FullServiceName, NULL, &PhysicalDeviceObject, &Node->InstancePath);
1088 if (!NT_SUCCESS(Status))
1089 {
1090 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
1091 ExFreePool(FullServiceName.Buffer);
1092 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1093 return Status;
1094 }
1095
1096 /* Create the device key for legacy drivers */
1097 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
1098 if (!NT_SUCCESS(Status))
1099 {
1100 ExFreePool(FullServiceName.Buffer);
1101 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1102 return Status;
1103 }
1104
1105 Node->ServiceName.MaximumLength = ServiceName1->Length + sizeof(UNICODE_NULL);
1106 Node->ServiceName.Length = 0;
1107 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, Node->ServiceName.MaximumLength);
1108 if (!Node->ServiceName.Buffer)
1109 {
1110 ZwClose(InstanceHandle);
1111 ExFreePool(FullServiceName.Buffer);
1112 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1113 return Status;
1114 }
1115
1116 RtlCopyUnicodeString(&Node->ServiceName, ServiceName1);
1117
1118 if (ServiceName)
1119 {
1120 RtlInitUnicodeString(&KeyName, L"Service");
1121 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length + sizeof(UNICODE_NULL));
1122 }
1123
1124 if (NT_SUCCESS(Status))
1125 {
1126 RtlInitUnicodeString(&KeyName, L"Legacy");
1127 LegacyValue = 1;
1128 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
1129
1130 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1131 LegacyValue = 0;
1132 ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
1133
1134 if (NT_SUCCESS(Status))
1135 {
1136 RtlInitUnicodeString(&KeyName, L"Class");
1137 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
1138 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length + sizeof(UNICODE_NULL));
1139 if (NT_SUCCESS(Status))
1140 {
1141 RtlInitUnicodeString(&KeyName, L"ClassGUID");
1142 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
1143 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length + sizeof(UNICODE_NULL));
1144 if (NT_SUCCESS(Status))
1145 {
1146 // FIXME: Retrieve the real "description" by looking at the "DisplayName" string
1147 // of the corresponding CurrentControlSet\Services\xxx entry for this driver.
1148 RtlInitUnicodeString(&KeyName, L"DeviceDesc");
1149 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName1->Buffer, ServiceName1->Length + sizeof(UNICODE_NULL));
1150 }
1151 }
1152 }
1153 }
1154
1155 ZwClose(InstanceHandle);
1156 ExFreePool(FullServiceName.Buffer);
1157
1158 if (!NT_SUCCESS(Status))
1159 {
1160 ExFreePool(Node->ServiceName.Buffer);
1161 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1162 return Status;
1163 }
1164
1165 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
1166 IopDeviceNodeSetFlag(Node, DNF_PROCESSED);
1167 IopDeviceNodeSetFlag(Node, DNF_ADDED);
1168 IopDeviceNodeSetFlag(Node, DNF_STARTED);
1169 }
1170
1171 Node->PhysicalDeviceObject = PhysicalDeviceObject;
1172
1173 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
1174
1175 if (ParentNode)
1176 {
1177 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1178 Node->Parent = ParentNode;
1179 Node->Sibling = NULL;
1180 if (ParentNode->LastChild == NULL)
1181 {
1182 ParentNode->Child = Node;
1183 ParentNode->LastChild = Node;
1184 }
1185 else
1186 {
1187 ParentNode->LastChild->Sibling = Node;
1188 ParentNode->LastChild = Node;
1189 }
1190 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1191 Node->Level = ParentNode->Level + 1;
1192 }
1193
1194 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1195
1196 *DeviceNode = Node;
1197
1198 return STATUS_SUCCESS;
1199 }
1200
1201 NTSTATUS
1202 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
1203 {
1204 KIRQL OldIrql;
1205 PDEVICE_NODE PrevSibling = NULL;
1206
1207 /* All children must be deleted before a parent is deleted */
1208 ASSERT(!DeviceNode->Child);
1209 ASSERT(DeviceNode->PhysicalDeviceObject);
1210
1211 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1212
1213 /* Get previous sibling */
1214 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
1215 {
1216 PrevSibling = DeviceNode->Parent->Child;
1217 while (PrevSibling->Sibling != DeviceNode)
1218 PrevSibling = PrevSibling->Sibling;
1219 }
1220
1221 /* Unlink from parent if it exists */
1222 if (DeviceNode->Parent)
1223 {
1224 if (DeviceNode->Parent->LastChild == DeviceNode)
1225 {
1226 DeviceNode->Parent->LastChild = PrevSibling;
1227 if (PrevSibling)
1228 PrevSibling->Sibling = NULL;
1229 }
1230 if (DeviceNode->Parent->Child == DeviceNode)
1231 DeviceNode->Parent->Child = DeviceNode->Sibling;
1232 }
1233
1234 /* Unlink from sibling list */
1235 if (PrevSibling)
1236 PrevSibling->Sibling = DeviceNode->Sibling;
1237
1238 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1239
1240 RtlFreeUnicodeString(&DeviceNode->InstancePath);
1241
1242 RtlFreeUnicodeString(&DeviceNode->ServiceName);
1243
1244 if (DeviceNode->ResourceList)
1245 {
1246 ExFreePool(DeviceNode->ResourceList);
1247 }
1248
1249 if (DeviceNode->ResourceListTranslated)
1250 {
1251 ExFreePool(DeviceNode->ResourceListTranslated);
1252 }
1253
1254 if (DeviceNode->ResourceRequirements)
1255 {
1256 ExFreePool(DeviceNode->ResourceRequirements);
1257 }
1258
1259 if (DeviceNode->BootResources)
1260 {
1261 ExFreePool(DeviceNode->BootResources);
1262 }
1263
1264 ((PEXTENDED_DEVOBJ_EXTENSION)DeviceNode->PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = NULL;
1265 ExFreePoolWithTag(DeviceNode, TAG_IO_DEVNODE);
1266
1267 return STATUS_SUCCESS;
1268 }
1269
1270 NTSTATUS
1271 NTAPI
1272 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
1273 IN PIO_STACK_LOCATION IoStackLocation,
1274 OUT PVOID *Information)
1275 {
1276 PIRP Irp;
1277 PIO_STACK_LOCATION IrpStack;
1278 IO_STATUS_BLOCK IoStatusBlock;
1279 KEVENT Event;
1280 NTSTATUS Status;
1281 PDEVICE_OBJECT TopDeviceObject;
1282 PAGED_CODE();
1283
1284 /* Call the top of the device stack */
1285 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
1286
1287 /* Allocate an IRP */
1288 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
1289 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1290
1291 /* Initialize to failure */
1292 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
1293 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
1294
1295 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1296 if (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
1297 {
1298 /* Copy the resource requirements list into the IOSB */
1299 Irp->IoStatus.Information =
1300 IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
1301 }
1302
1303 /* Initialize the event */
1304 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1305
1306 /* Set them up */
1307 Irp->UserIosb = &IoStatusBlock;
1308 Irp->UserEvent = &Event;
1309
1310 /* Queue the IRP */
1311 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1312 IoQueueThreadIrp(Irp);
1313
1314 /* Copy-in the stack */
1315 IrpStack = IoGetNextIrpStackLocation(Irp);
1316 *IrpStack = *IoStackLocation;
1317
1318 /* Call the driver */
1319 Status = IoCallDriver(TopDeviceObject, Irp);
1320 if (Status == STATUS_PENDING)
1321 {
1322 /* Wait for it */
1323 KeWaitForSingleObject(&Event,
1324 Executive,
1325 KernelMode,
1326 FALSE,
1327 NULL);
1328 Status = IoStatusBlock.Status;
1329 }
1330
1331 /* Remove the reference */
1332 ObDereferenceObject(TopDeviceObject);
1333
1334 /* Return the information */
1335 *Information = (PVOID)IoStatusBlock.Information;
1336 return Status;
1337 }
1338
1339 NTSTATUS
1340 NTAPI
1341 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
1342 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
1343 IN UCHAR MinorFunction,
1344 IN PIO_STACK_LOCATION Stack OPTIONAL)
1345 {
1346 IO_STACK_LOCATION IoStackLocation;
1347
1348 /* Fill out the stack information */
1349 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
1350 IoStackLocation.MajorFunction = IRP_MJ_PNP;
1351 IoStackLocation.MinorFunction = MinorFunction;
1352 if (Stack)
1353 {
1354 /* Copy the rest */
1355 RtlCopyMemory(&IoStackLocation.Parameters,
1356 &Stack->Parameters,
1357 sizeof(Stack->Parameters));
1358 }
1359
1360 /* Do the PnP call */
1361 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
1362 &IoStackLocation,
1363 (PVOID)&IoStatusBlock->Information);
1364 return IoStatusBlock->Status;
1365 }
1366
1367 NTSTATUS
1368 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
1369 {
1370 PDEVICE_NODE ParentDeviceNode;
1371 PDEVICE_NODE ChildDeviceNode;
1372 NTSTATUS Status;
1373
1374 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1375 ParentDeviceNode = Context->DeviceNode;
1376
1377 /* Call the action routine */
1378 Status = (Context->Action)(ParentDeviceNode, Context->Context);
1379 if (!NT_SUCCESS(Status))
1380 {
1381 return Status;
1382 }
1383
1384 /* Traversal of all children nodes */
1385 for (ChildDeviceNode = ParentDeviceNode->Child;
1386 ChildDeviceNode != NULL;
1387 ChildDeviceNode = ChildDeviceNode->Sibling)
1388 {
1389 /* Pass the current device node to the action routine */
1390 Context->DeviceNode = ChildDeviceNode;
1391
1392 Status = IopTraverseDeviceTreeNode(Context);
1393 if (!NT_SUCCESS(Status))
1394 {
1395 return Status;
1396 }
1397 }
1398
1399 return Status;
1400 }
1401
1402
1403 NTSTATUS
1404 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
1405 {
1406 NTSTATUS Status;
1407
1408 DPRINT("Context 0x%p\n", Context);
1409
1410 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
1411 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
1412
1413 /* Start from the specified device node */
1414 Context->DeviceNode = Context->FirstDeviceNode;
1415
1416 /* Recursively traverse the device tree */
1417 Status = IopTraverseDeviceTreeNode(Context);
1418 if (Status == STATUS_UNSUCCESSFUL)
1419 {
1420 /* The action routine just wanted to terminate the traversal with status
1421 code STATUS_SUCCESS */
1422 Status = STATUS_SUCCESS;
1423 }
1424
1425 return Status;
1426 }
1427
1428
1429 /*
1430 * IopCreateDeviceKeyPath
1431 *
1432 * Creates a registry key
1433 *
1434 * Parameters
1435 * RegistryPath
1436 * Name of the key to be created.
1437 * Handle
1438 * Handle to the newly created key
1439 *
1440 * Remarks
1441 * This method can create nested trees, so parent of RegistryPath can
1442 * be not existant, and will be created if needed.
1443 */
1444 NTSTATUS
1445 NTAPI
1446 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
1447 IN ULONG CreateOptions,
1448 OUT PHANDLE Handle)
1449 {
1450 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
1451 HANDLE hParent = NULL, hKey;
1452 OBJECT_ATTRIBUTES ObjectAttributes;
1453 UNICODE_STRING KeyName;
1454 PCWSTR Current, Last;
1455 USHORT Length;
1456 NTSTATUS Status;
1457
1458 /* Assume failure */
1459 *Handle = NULL;
1460
1461 /* Create a volatile device tree in 1st stage so we have a clean slate
1462 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1463 if (ExpInTextModeSetup) CreateOptions |= REG_OPTION_VOLATILE;
1464
1465 /* Open root key for device instances */
1466 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
1467 if (!NT_SUCCESS(Status))
1468 {
1469 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
1470 return Status;
1471 }
1472
1473 Current = KeyName.Buffer = RegistryPath->Buffer;
1474 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
1475
1476 /* Go up to the end of the string */
1477 while (Current <= Last)
1478 {
1479 if (Current != Last && *Current != L'\\')
1480 {
1481 /* Not the end of the string and not a separator */
1482 Current++;
1483 continue;
1484 }
1485
1486 /* Prepare relative key name */
1487 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
1488 KeyName.MaximumLength = KeyName.Length = Length;
1489 DPRINT("Create '%wZ'\n", &KeyName);
1490
1491 /* Open key */
1492 InitializeObjectAttributes(&ObjectAttributes,
1493 &KeyName,
1494 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1495 hParent,
1496 NULL);
1497 Status = ZwCreateKey(&hKey,
1498 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
1499 &ObjectAttributes,
1500 0,
1501 NULL,
1502 CreateOptions,
1503 NULL);
1504
1505 /* Close parent key handle, we don't need it anymore */
1506 if (hParent)
1507 ZwClose(hParent);
1508
1509 /* Key opening/creating failed? */
1510 if (!NT_SUCCESS(Status))
1511 {
1512 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
1513 return Status;
1514 }
1515
1516 /* Check if it is the end of the string */
1517 if (Current == Last)
1518 {
1519 /* Yes, return success */
1520 *Handle = hKey;
1521 return STATUS_SUCCESS;
1522 }
1523
1524 /* Start with this new parent key */
1525 hParent = hKey;
1526 Current++;
1527 KeyName.Buffer = (PWSTR)Current;
1528 }
1529
1530 return STATUS_UNSUCCESSFUL;
1531 }
1532
1533 NTSTATUS
1534 IopSetDeviceInstanceData(HANDLE InstanceKey,
1535 PDEVICE_NODE DeviceNode)
1536 {
1537 OBJECT_ATTRIBUTES ObjectAttributes;
1538 UNICODE_STRING KeyName;
1539 HANDLE LogConfKey;
1540 ULONG ResCount;
1541 ULONG ResultLength;
1542 NTSTATUS Status;
1543 HANDLE ControlHandle;
1544
1545 DPRINT("IopSetDeviceInstanceData() called\n");
1546
1547 /* Create the 'LogConf' key */
1548 RtlInitUnicodeString(&KeyName, L"LogConf");
1549 InitializeObjectAttributes(&ObjectAttributes,
1550 &KeyName,
1551 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1552 InstanceKey,
1553 NULL);
1554 Status = ZwCreateKey(&LogConfKey,
1555 KEY_ALL_ACCESS,
1556 &ObjectAttributes,
1557 0,
1558 NULL,
1559 REG_OPTION_VOLATILE,
1560 NULL);
1561 if (NT_SUCCESS(Status))
1562 {
1563 /* Set 'BootConfig' value */
1564 if (DeviceNode->BootResources != NULL)
1565 {
1566 ResCount = DeviceNode->BootResources->Count;
1567 if (ResCount != 0)
1568 {
1569 RtlInitUnicodeString(&KeyName, L"BootConfig");
1570 Status = ZwSetValueKey(LogConfKey,
1571 &KeyName,
1572 0,
1573 REG_RESOURCE_LIST,
1574 DeviceNode->BootResources,
1575 PnpDetermineResourceListSize(DeviceNode->BootResources));
1576 }
1577 }
1578
1579 /* Set 'BasicConfigVector' value */
1580 if (DeviceNode->ResourceRequirements != NULL &&
1581 DeviceNode->ResourceRequirements->ListSize != 0)
1582 {
1583 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1584 Status = ZwSetValueKey(LogConfKey,
1585 &KeyName,
1586 0,
1587 REG_RESOURCE_REQUIREMENTS_LIST,
1588 DeviceNode->ResourceRequirements,
1589 DeviceNode->ResourceRequirements->ListSize);
1590 }
1591
1592 ZwClose(LogConfKey);
1593 }
1594
1595 /* Set the 'ConfigFlags' value */
1596 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1597 Status = ZwQueryValueKey(InstanceKey,
1598 &KeyName,
1599 KeyValueBasicInformation,
1600 NULL,
1601 0,
1602 &ResultLength);
1603 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1604 {
1605 /* Write the default value */
1606 ULONG DefaultConfigFlags = 0;
1607 Status = ZwSetValueKey(InstanceKey,
1608 &KeyName,
1609 0,
1610 REG_DWORD,
1611 &DefaultConfigFlags,
1612 sizeof(DefaultConfigFlags));
1613 }
1614
1615 /* Create the 'Control' key */
1616 RtlInitUnicodeString(&KeyName, L"Control");
1617 InitializeObjectAttributes(&ObjectAttributes,
1618 &KeyName,
1619 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1620 InstanceKey,
1621 NULL);
1622 Status = ZwCreateKey(&ControlHandle, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
1623
1624 if (NT_SUCCESS(Status))
1625 ZwClose(ControlHandle);
1626
1627 DPRINT("IopSetDeviceInstanceData() done\n");
1628
1629 return Status;
1630 }
1631
1632 /*
1633 * IopGetParentIdPrefix
1634 *
1635 * Retrieve (or create) a string which identifies a device.
1636 *
1637 * Parameters
1638 * DeviceNode
1639 * Pointer to device node.
1640 * ParentIdPrefix
1641 * Pointer to the string where is returned the parent node identifier
1642 *
1643 * Remarks
1644 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1645 * valid and its Buffer field is NULL-terminated. The caller needs to
1646 * to free the string with RtlFreeUnicodeString when it is no longer
1647 * needed.
1648 */
1649
1650 NTSTATUS
1651 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1652 PUNICODE_STRING ParentIdPrefix)
1653 {
1654 const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1655 ULONG KeyNameBufferLength;
1656 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1657 UNICODE_STRING KeyName = {0, 0, NULL};
1658 UNICODE_STRING KeyValue;
1659 UNICODE_STRING ValueName;
1660 HANDLE hKey = NULL;
1661 ULONG crc32;
1662 NTSTATUS Status;
1663
1664 /* HACK: As long as some devices have a NULL device
1665 * instance path, the following test is required :(
1666 */
1667 if (DeviceNode->Parent->InstancePath.Length == 0)
1668 {
1669 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1670 &DeviceNode->InstancePath);
1671 return STATUS_UNSUCCESSFUL;
1672 }
1673
1674 /* 1. Try to retrieve ParentIdPrefix from registry */
1675 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1676 ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
1677 KeyNameBufferLength + sizeof(UNICODE_NULL),
1678 TAG_IO);
1679 if (!ParentIdPrefixInformation)
1680 {
1681 return STATUS_INSUFFICIENT_RESOURCES;
1682 }
1683
1684 KeyName.Length = 0;
1685 KeyName.MaximumLength = EnumKeyPath.Length +
1686 DeviceNode->Parent->InstancePath.Length +
1687 sizeof(UNICODE_NULL);
1688 KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1689 KeyName.MaximumLength,
1690 TAG_IO);
1691 if (!KeyName.Buffer)
1692 {
1693 Status = STATUS_INSUFFICIENT_RESOURCES;
1694 goto cleanup;
1695 }
1696
1697 RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
1698 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1699
1700 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
1701 if (!NT_SUCCESS(Status))
1702 {
1703 goto cleanup;
1704 }
1705 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1706 Status = ZwQueryValueKey(hKey,
1707 &ValueName,
1708 KeyValuePartialInformation,
1709 ParentIdPrefixInformation,
1710 KeyNameBufferLength,
1711 &KeyNameBufferLength);
1712 if (NT_SUCCESS(Status))
1713 {
1714 if (ParentIdPrefixInformation->Type != REG_SZ)
1715 {
1716 Status = STATUS_UNSUCCESSFUL;
1717 }
1718 else
1719 {
1720 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1721 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1722 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1723 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1724 }
1725 goto cleanup;
1726 }
1727 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1728 {
1729 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
1730 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1731 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1732 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1733 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1734 goto cleanup;
1735 }
1736
1737 /* 2. Create the ParentIdPrefix value */
1738 crc32 = RtlComputeCrc32(0,
1739 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1740 DeviceNode->Parent->InstancePath.Length);
1741
1742 RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
1743 KeyNameBufferLength,
1744 L"%lx&%lx",
1745 DeviceNode->Parent->Level,
1746 crc32);
1747 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
1748
1749 /* 3. Try to write the ParentIdPrefix to registry */
1750 Status = ZwSetValueKey(hKey,
1751 &ValueName,
1752 0,
1753 REG_SZ,
1754 KeyValue.Buffer,
1755 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1756
1757 cleanup:
1758 if (NT_SUCCESS(Status))
1759 {
1760 /* Duplicate the string to return it */
1761 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1762 &KeyValue,
1763 ParentIdPrefix);
1764 }
1765 ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
1766 RtlFreeUnicodeString(&KeyName);
1767 if (hKey != NULL)
1768 {
1769 ZwClose(hKey);
1770 }
1771 return Status;
1772 }
1773
1774 static
1775 BOOLEAN
1776 IopValidateID(
1777 _In_ PWCHAR Id,
1778 _In_ BUS_QUERY_ID_TYPE QueryType)
1779 {
1780 PWCHAR PtrChar;
1781 PWCHAR StringEnd;
1782 WCHAR Char;
1783 ULONG SeparatorsCount = 0;
1784 PWCHAR PtrPrevChar = NULL;
1785 ULONG MaxSeparators;
1786 BOOLEAN IsMultiSz;
1787
1788 PAGED_CODE();
1789
1790 switch (QueryType)
1791 {
1792 case BusQueryDeviceID:
1793 MaxSeparators = MAX_SEPARATORS_DEVICEID;
1794 IsMultiSz = FALSE;
1795 break;
1796 case BusQueryInstanceID:
1797 MaxSeparators = MAX_SEPARATORS_INSTANCEID;
1798 IsMultiSz = FALSE;
1799 break;
1800
1801 case BusQueryHardwareIDs:
1802 case BusQueryCompatibleIDs:
1803 MaxSeparators = MAX_SEPARATORS_DEVICEID;
1804 IsMultiSz = TRUE;
1805 break;
1806
1807 default:
1808 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
1809 return FALSE;
1810 }
1811
1812 StringEnd = Id + MAX_DEVICE_ID_LEN;
1813
1814 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
1815 {
1816 Char = *PtrChar;
1817
1818 if (Char == UNICODE_NULL)
1819 {
1820 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
1821 {
1822 if (MaxSeparators == SeparatorsCount || IsMultiSz)
1823 {
1824 return TRUE;
1825 }
1826
1827 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1828 SeparatorsCount, MaxSeparators);
1829 goto ErrorExit;
1830 }
1831
1832 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
1833 PtrPrevChar = PtrChar;
1834 SeparatorsCount = 0;
1835 }
1836 else if (Char < ' ' || Char > 0x7F || Char == ',')
1837 {
1838 DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
1839 goto ErrorExit;
1840 }
1841 else if (Char == ' ')
1842 {
1843 *PtrChar = '_';
1844 }
1845 else if (Char == '\\')
1846 {
1847 SeparatorsCount++;
1848
1849 if (SeparatorsCount > MaxSeparators)
1850 {
1851 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1852 SeparatorsCount, MaxSeparators);
1853 goto ErrorExit;
1854 }
1855 }
1856 }
1857
1858 DPRINT1("IopValidateID: Not terminated ID\n");
1859
1860 ErrorExit:
1861 // FIXME logging
1862 return FALSE;
1863 }
1864
1865 NTSTATUS
1866 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
1867 HANDLE InstanceKey)
1868 {
1869 IO_STACK_LOCATION Stack;
1870 IO_STATUS_BLOCK IoStatusBlock;
1871 PWSTR Ptr;
1872 UNICODE_STRING ValueName;
1873 NTSTATUS Status;
1874 ULONG Length, TotalLength;
1875 BOOLEAN IsValidID;
1876
1877 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1878
1879 RtlZeroMemory(&Stack, sizeof(Stack));
1880 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1881 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1882 &IoStatusBlock,
1883 IRP_MN_QUERY_ID,
1884 &Stack);
1885 if (NT_SUCCESS(Status))
1886 {
1887 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs);
1888
1889 if (!IsValidID)
1890 {
1891 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
1892 }
1893
1894 TotalLength = 0;
1895
1896 Ptr = (PWSTR)IoStatusBlock.Information;
1897 DPRINT("Hardware IDs:\n");
1898 while (*Ptr)
1899 {
1900 DPRINT(" %S\n", Ptr);
1901 Length = (ULONG)wcslen(Ptr) + 1;
1902
1903 Ptr += Length;
1904 TotalLength += Length;
1905 }
1906 DPRINT("TotalLength: %hu\n", TotalLength);
1907 DPRINT("\n");
1908
1909 RtlInitUnicodeString(&ValueName, L"HardwareID");
1910 Status = ZwSetValueKey(InstanceKey,
1911 &ValueName,
1912 0,
1913 REG_MULTI_SZ,
1914 (PVOID)IoStatusBlock.Information,
1915 (TotalLength + 1) * sizeof(WCHAR));
1916 if (!NT_SUCCESS(Status))
1917 {
1918 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1919 }
1920 }
1921 else
1922 {
1923 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1924 }
1925
1926 return Status;
1927 }
1928
1929 NTSTATUS
1930 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
1931 HANDLE InstanceKey)
1932 {
1933 IO_STACK_LOCATION Stack;
1934 IO_STATUS_BLOCK IoStatusBlock;
1935 PWSTR Ptr;
1936 UNICODE_STRING ValueName;
1937 NTSTATUS Status;
1938 ULONG Length, TotalLength;
1939 BOOLEAN IsValidID;
1940
1941 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1942
1943 RtlZeroMemory(&Stack, sizeof(Stack));
1944 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1945 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1946 &IoStatusBlock,
1947 IRP_MN_QUERY_ID,
1948 &Stack);
1949 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1950 {
1951 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs);
1952
1953 if (!IsValidID)
1954 {
1955 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
1956 }
1957
1958 TotalLength = 0;
1959
1960 Ptr = (PWSTR)IoStatusBlock.Information;
1961 DPRINT("Compatible IDs:\n");
1962 while (*Ptr)
1963 {
1964 DPRINT(" %S\n", Ptr);
1965 Length = (ULONG)wcslen(Ptr) + 1;
1966
1967 Ptr += Length;
1968 TotalLength += Length;
1969 }
1970 DPRINT("TotalLength: %hu\n", TotalLength);
1971 DPRINT("\n");
1972
1973 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1974 Status = ZwSetValueKey(InstanceKey,
1975 &ValueName,
1976 0,
1977 REG_MULTI_SZ,
1978 (PVOID)IoStatusBlock.Information,
1979 (TotalLength + 1) * sizeof(WCHAR));
1980 if (!NT_SUCCESS(Status))
1981 {
1982 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1983 }
1984 }
1985 else
1986 {
1987 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1988 }
1989
1990 return Status;
1991 }
1992
1993 NTSTATUS
1994 IopCreateDeviceInstancePath(
1995 _In_ PDEVICE_NODE DeviceNode,
1996 _Out_ PUNICODE_STRING InstancePath)
1997 {
1998 IO_STATUS_BLOCK IoStatusBlock;
1999 UNICODE_STRING DeviceId;
2000 UNICODE_STRING InstanceId;
2001 IO_STACK_LOCATION Stack;
2002 NTSTATUS Status;
2003 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
2004 DEVICE_CAPABILITIES DeviceCapabilities;
2005 BOOLEAN IsValidID;
2006
2007 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2008
2009 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
2010 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2011 &IoStatusBlock,
2012 IRP_MN_QUERY_ID,
2013 &Stack);
2014 if (!NT_SUCCESS(Status))
2015 {
2016 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
2017 return Status;
2018 }
2019
2020 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID);
2021
2022 if (!IsValidID)
2023 {
2024 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
2025 }
2026
2027 /* Save the device id string */
2028 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information);
2029
2030 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
2031
2032 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
2033 if (!NT_SUCCESS(Status))
2034 {
2035 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
2036 RtlFreeUnicodeString(&DeviceId);
2037 return Status;
2038 }
2039
2040 /* This bit is only check after enumeration */
2041 if (DeviceCapabilities.HardwareDisabled)
2042 {
2043 /* FIXME: Cleanup device */
2044 DeviceNode->Flags |= DNF_DISABLED;
2045 RtlFreeUnicodeString(&DeviceId);
2046 return STATUS_PLUGPLAY_NO_DEVICE;
2047 }
2048 else
2049 {
2050 DeviceNode->Flags &= ~DNF_DISABLED;
2051 }
2052
2053 if (!DeviceCapabilities.UniqueID)
2054 {
2055 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2056 DPRINT("Instance ID is not unique\n");
2057 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
2058 if (!NT_SUCCESS(Status))
2059 {
2060 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
2061 RtlFreeUnicodeString(&DeviceId);
2062 return Status;
2063 }
2064 }
2065
2066 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2067
2068 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
2069 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2070 &IoStatusBlock,
2071 IRP_MN_QUERY_ID,
2072 &Stack);
2073 if (!NT_SUCCESS(Status))
2074 {
2075 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
2076 ASSERT(IoStatusBlock.Information == 0);
2077 }
2078
2079 if (IoStatusBlock.Information)
2080 {
2081 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID);
2082
2083 if (!IsValidID)
2084 {
2085 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
2086 }
2087 }
2088
2089 RtlInitUnicodeString(&InstanceId,
2090 (PWSTR)IoStatusBlock.Information);
2091
2092 InstancePath->Length = 0;
2093 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
2094 ParentIdPrefix.Length +
2095 InstanceId.Length +
2096 sizeof(UNICODE_NULL);
2097 if (ParentIdPrefix.Length && InstanceId.Length)
2098 {
2099 InstancePath->MaximumLength += sizeof(WCHAR);
2100 }
2101
2102 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
2103 InstancePath->MaximumLength,
2104 TAG_IO);
2105 if (!InstancePath->Buffer)
2106 {
2107 RtlFreeUnicodeString(&InstanceId);
2108 RtlFreeUnicodeString(&ParentIdPrefix);
2109 RtlFreeUnicodeString(&DeviceId);
2110 return STATUS_INSUFFICIENT_RESOURCES;
2111 }
2112
2113 /* Start with the device id */
2114 RtlCopyUnicodeString(InstancePath, &DeviceId);
2115 RtlAppendUnicodeToString(InstancePath, L"\\");
2116
2117 /* Add information from parent bus device to InstancePath */
2118 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
2119 if (ParentIdPrefix.Length && InstanceId.Length)
2120 {
2121 RtlAppendUnicodeToString(InstancePath, L"&");
2122 }
2123
2124 /* Finally, add the id returned by the driver stack */
2125 RtlAppendUnicodeStringToString(InstancePath, &InstanceId);
2126
2127 /*
2128 * FIXME: Check for valid characters, if there is invalid characters
2129 * then bugcheck
2130 */
2131
2132 RtlFreeUnicodeString(&InstanceId);
2133 RtlFreeUnicodeString(&DeviceId);
2134 RtlFreeUnicodeString(&ParentIdPrefix);
2135
2136 return STATUS_SUCCESS;
2137 }
2138
2139 /*
2140 * IopActionInterrogateDeviceStack
2141 *
2142 * Retrieve information for all (direct) child nodes of a parent node.
2143 *
2144 * Parameters
2145 * DeviceNode
2146 * Pointer to device node.
2147 * Context
2148 * Pointer to parent node to retrieve child node information for.
2149 *
2150 * Remarks
2151 * Any errors that occur are logged instead so that all child services have a chance
2152 * of being interrogated.
2153 */
2154
2155 NTSTATUS
2156 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
2157 PVOID Context)
2158 {
2159 IO_STATUS_BLOCK IoStatusBlock;
2160 PWSTR DeviceDescription;
2161 PWSTR LocationInformation;
2162 PDEVICE_NODE ParentDeviceNode;
2163 IO_STACK_LOCATION Stack;
2164 NTSTATUS Status;
2165 ULONG RequiredLength;
2166 LCID LocaleId;
2167 HANDLE InstanceKey = NULL;
2168 UNICODE_STRING ValueName;
2169 UNICODE_STRING InstancePathU;
2170 PDEVICE_OBJECT OldDeviceObject;
2171
2172 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2173 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2174
2175 ParentDeviceNode = (PDEVICE_NODE)Context;
2176
2177 /*
2178 * We are called for the parent too, but we don't need to do special
2179 * handling for this node
2180 */
2181 if (DeviceNode == ParentDeviceNode)
2182 {
2183 DPRINT("Success\n");
2184 return STATUS_SUCCESS;
2185 }
2186
2187 /*
2188 * Make sure this device node is a direct child of the parent device node
2189 * that is given as an argument
2190 */
2191 if (DeviceNode->Parent != ParentDeviceNode)
2192 {
2193 DPRINT("Skipping 2+ level child\n");
2194 return STATUS_SUCCESS;
2195 }
2196
2197 /* Skip processing if it was already completed before */
2198 if (DeviceNode->Flags & DNF_PROCESSED)
2199 {
2200 /* Nothing to do */
2201 return STATUS_SUCCESS;
2202 }
2203
2204 /* Get Locale ID */
2205 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2206 if (!NT_SUCCESS(Status))
2207 {
2208 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2209 return Status;
2210 }
2211
2212 /*
2213 * FIXME: For critical errors, cleanup and disable device, but always
2214 * return STATUS_SUCCESS.
2215 */
2216
2217 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
2218 if (!NT_SUCCESS(Status))
2219 {
2220 if (Status != STATUS_PLUGPLAY_NO_DEVICE)
2221 {
2222 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
2223 }
2224
2225 /* We have to return success otherwise we abort the traverse operation */
2226 return STATUS_SUCCESS;
2227 }
2228
2229 /* Verify that this is not a duplicate */
2230 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
2231 if (OldDeviceObject != NULL)
2232 {
2233 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
2234
2235 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
2236 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
2237 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
2238
2239 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
2240 0x01,
2241 (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
2242 (ULONG_PTR)OldDeviceObject,
2243 0);
2244 }
2245
2246 DeviceNode->InstancePath = InstancePathU;
2247
2248 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2249
2250 /*
2251 * Create registry key for the instance id, if it doesn't exist yet
2252 */
2253 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
2254 if (!NT_SUCCESS(Status))
2255 {
2256 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2257
2258 /* We have to return success otherwise we abort the traverse operation */
2259 return STATUS_SUCCESS;
2260 }
2261
2262 IopQueryHardwareIds(DeviceNode, InstanceKey);
2263
2264 IopQueryCompatibleIds(DeviceNode, InstanceKey);
2265
2266 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2267
2268 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2269 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2270 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2271 &IoStatusBlock,
2272 IRP_MN_QUERY_DEVICE_TEXT,
2273 &Stack);
2274 DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information
2275 : NULL;
2276 /* This key is mandatory, so even if the Irp fails, we still write it */
2277 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2278 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2279 {
2280 if (DeviceDescription &&
2281 *DeviceDescription != UNICODE_NULL)
2282 {
2283 /* This key is overriden when a driver is installed. Don't write the
2284 * new description if another one already exists */
2285 Status = ZwSetValueKey(InstanceKey,
2286 &ValueName,
2287 0,
2288 REG_SZ,
2289 DeviceDescription,
2290 ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR));
2291 }
2292 else
2293 {
2294 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2295 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2296
2297 Status = ZwSetValueKey(InstanceKey,
2298 &ValueName,
2299 0,
2300 REG_SZ,
2301 DeviceDesc.Buffer,
2302 DeviceDesc.MaximumLength);
2303 if (!NT_SUCCESS(Status))
2304 {
2305 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2306 }
2307
2308 }
2309 }
2310
2311 if (DeviceDescription)
2312 {
2313 ExFreePoolWithTag(DeviceDescription, 0);
2314 }
2315
2316 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2317
2318 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2319 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2320 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2321 &IoStatusBlock,
2322 IRP_MN_QUERY_DEVICE_TEXT,
2323 &Stack);
2324 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2325 {
2326 LocationInformation = (PWSTR)IoStatusBlock.Information;
2327 DPRINT("LocationInformation: %S\n", LocationInformation);
2328 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2329 Status = ZwSetValueKey(InstanceKey,
2330 &ValueName,
2331 0,
2332 REG_SZ,
2333 LocationInformation,
2334 ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR));
2335 if (!NT_SUCCESS(Status))
2336 {
2337 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2338 }
2339
2340 ExFreePoolWithTag(LocationInformation, 0);
2341 }
2342 else
2343 {
2344 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2345 }
2346
2347 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2348
2349 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2350 &IoStatusBlock,
2351 IRP_MN_QUERY_BUS_INFORMATION,
2352 NULL);
2353 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2354 {
2355 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2356
2357 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2358 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2359 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2360 ExFreePoolWithTag(BusInformation, 0);
2361 }
2362 else
2363 {
2364 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2365
2366 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2367 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2368 DeviceNode->ChildBusTypeIndex = -1;
2369 }
2370
2371 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2372
2373 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2374 &IoStatusBlock,
2375 IRP_MN_QUERY_RESOURCES,
2376 NULL);
2377 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2378 {
2379 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2380 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2381 }
2382 else
2383 {
2384 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2385 DeviceNode->BootResources = NULL;
2386 }
2387
2388 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2389
2390 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2391 &IoStatusBlock,
2392 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2393 NULL);
2394 if (NT_SUCCESS(Status))
2395 {
2396 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2397 }
2398 else
2399 {
2400 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2401 DeviceNode->ResourceRequirements = NULL;
2402 }
2403
2404 if (InstanceKey != NULL)
2405 {
2406 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2407 }
2408
2409 ZwClose(InstanceKey);
2410
2411 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2412
2413 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2414 {
2415 /* Report the device to the user-mode pnp manager */
2416 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2417 &DeviceNode->InstancePath);
2418 }
2419
2420 return STATUS_SUCCESS;
2421 }
2422
2423 static
2424 VOID
2425 IopHandleDeviceRemoval(
2426 IN PDEVICE_NODE DeviceNode,
2427 IN PDEVICE_RELATIONS DeviceRelations)
2428 {
2429 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2430 ULONG i;
2431 BOOLEAN Found;
2432
2433 if (DeviceNode == IopRootDeviceNode)
2434 return;
2435
2436 while (Child != NULL)
2437 {
2438 NextChild = Child->Sibling;
2439 Found = FALSE;
2440
2441 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
2442 {
2443 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
2444 {
2445 Found = TRUE;
2446 break;
2447 }
2448 }
2449
2450 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
2451 {
2452 /* Send removal IRPs to all of its children */
2453 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
2454
2455 /* Send the surprise removal IRP */
2456 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
2457
2458 /* Tell the user-mode PnP manager that a device was removed */
2459 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
2460 &Child->InstancePath);
2461
2462 /* Send the remove device IRP */
2463 IopSendRemoveDevice(Child->PhysicalDeviceObject);
2464 }
2465
2466 Child = NextChild;
2467 }
2468 }
2469
2470 NTSTATUS
2471 IopEnumerateDevice(
2472 IN PDEVICE_OBJECT DeviceObject)
2473 {
2474 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2475 DEVICETREE_TRAVERSE_CONTEXT Context;
2476 PDEVICE_RELATIONS DeviceRelations;
2477 PDEVICE_OBJECT ChildDeviceObject;
2478 IO_STATUS_BLOCK IoStatusBlock;
2479 PDEVICE_NODE ChildDeviceNode;
2480 IO_STACK_LOCATION Stack;
2481 NTSTATUS Status;
2482 ULONG i;
2483
2484 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2485
2486 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
2487 {
2488 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
2489
2490 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2491 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2492 &DeviceNode->InstancePath);
2493 }
2494
2495 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2496
2497 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2498
2499 Status = IopInitiatePnpIrp(
2500 DeviceObject,
2501 &IoStatusBlock,
2502 IRP_MN_QUERY_DEVICE_RELATIONS,
2503 &Stack);
2504 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2505 {
2506 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2507 return Status;
2508 }
2509
2510 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2511
2512 /*
2513 * Send removal IRPs for devices that have disappeared
2514 * NOTE: This code handles the case where no relations are specified
2515 */
2516 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2517
2518 /* Now we bail if nothing was returned */
2519 if (!DeviceRelations)
2520 {
2521 /* We're all done */
2522 DPRINT("No PDOs\n");
2523 return STATUS_SUCCESS;
2524 }
2525
2526 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2527
2528 /*
2529 * Create device nodes for all discovered devices
2530 */
2531 for (i = 0; i < DeviceRelations->Count; i++)
2532 {
2533 ChildDeviceObject = DeviceRelations->Objects[i];
2534 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2535
2536 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2537 if (!ChildDeviceNode)
2538 {
2539 /* One doesn't exist, create it */
2540 Status = IopCreateDeviceNode(
2541 DeviceNode,
2542 ChildDeviceObject,
2543 NULL,
2544 &ChildDeviceNode);
2545 if (NT_SUCCESS(Status))
2546 {
2547 /* Mark the node as enumerated */
2548 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2549
2550 /* Mark the DO as bus enumerated */
2551 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2552 }
2553 else
2554 {
2555 /* Ignore this DO */
2556 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2557 ObDereferenceObject(ChildDeviceObject);
2558 }
2559 }
2560 else
2561 {
2562 /* Mark it as enumerated */
2563 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2564 ObDereferenceObject(ChildDeviceObject);
2565 }
2566 }
2567 ExFreePool(DeviceRelations);
2568
2569 /*
2570 * Retrieve information about all discovered children from the bus driver
2571 */
2572 IopInitDeviceTreeTraverseContext(
2573 &Context,
2574 DeviceNode,
2575 IopActionInterrogateDeviceStack,
2576 DeviceNode);
2577
2578 Status = IopTraverseDeviceTree(&Context);
2579 if (!NT_SUCCESS(Status))
2580 {
2581 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2582 return Status;
2583 }
2584
2585 /*
2586 * Retrieve configuration from the registry for discovered children
2587 */
2588 IopInitDeviceTreeTraverseContext(
2589 &Context,
2590 DeviceNode,
2591 IopActionConfigureChildServices,
2592 DeviceNode);
2593
2594 Status = IopTraverseDeviceTree(&Context);
2595 if (!NT_SUCCESS(Status))
2596 {
2597 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2598 return Status;
2599 }
2600
2601 /*
2602 * Initialize services for discovered children.
2603 */
2604 Status = IopInitializePnpServices(DeviceNode);
2605 if (!NT_SUCCESS(Status))
2606 {
2607 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2608 return Status;
2609 }
2610
2611 DPRINT("IopEnumerateDevice() finished\n");
2612 return STATUS_SUCCESS;
2613 }
2614
2615
2616 /*
2617 * IopActionConfigureChildServices
2618 *
2619 * Retrieve configuration for all (direct) child nodes of a parent node.
2620 *
2621 * Parameters
2622 * DeviceNode
2623 * Pointer to device node.
2624 * Context
2625 * Pointer to parent node to retrieve child node configuration for.
2626 *
2627 * Remarks
2628 * Any errors that occur are logged instead so that all child services have a chance of beeing
2629 * configured.
2630 */
2631
2632 NTSTATUS
2633 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2634 PVOID Context)
2635 {
2636 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2637 PDEVICE_NODE ParentDeviceNode;
2638 PUNICODE_STRING Service;
2639 UNICODE_STRING ClassGUID;
2640 NTSTATUS Status;
2641 DEVICE_CAPABILITIES DeviceCaps;
2642
2643 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2644
2645 ParentDeviceNode = (PDEVICE_NODE)Context;
2646
2647 /*
2648 * We are called for the parent too, but we don't need to do special
2649 * handling for this node
2650 */
2651 if (DeviceNode == ParentDeviceNode)
2652 {
2653 DPRINT("Success\n");
2654 return STATUS_SUCCESS;
2655 }
2656
2657 /*
2658 * Make sure this device node is a direct child of the parent device node
2659 * that is given as an argument
2660 */
2661
2662 if (DeviceNode->Parent != ParentDeviceNode)
2663 {
2664 DPRINT("Skipping 2+ level child\n");
2665 return STATUS_SUCCESS;
2666 }
2667
2668 if (!(DeviceNode->Flags & DNF_PROCESSED))
2669 {
2670 DPRINT1("Child not ready to be configured\n");
2671 return STATUS_SUCCESS;
2672 }
2673
2674 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2675 {
2676 WCHAR RegKeyBuffer[MAX_PATH];
2677 UNICODE_STRING RegKey;
2678
2679 /* Install the service for this if it's in the CDDB */
2680 IopInstallCriticalDevice(DeviceNode);
2681
2682 RegKey.Length = 0;
2683 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2684 RegKey.Buffer = RegKeyBuffer;
2685
2686 /*
2687 * Retrieve configuration from Enum key
2688 */
2689
2690 Service = &DeviceNode->ServiceName;
2691
2692 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2693 RtlInitUnicodeString(Service, NULL);
2694 RtlInitUnicodeString(&ClassGUID, NULL);
2695
2696 QueryTable[0].Name = L"Service";
2697 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2698 QueryTable[0].EntryContext = Service;
2699
2700 QueryTable[1].Name = L"ClassGUID";
2701 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2702 QueryTable[1].EntryContext = &ClassGUID;
2703 QueryTable[1].DefaultType = REG_SZ;
2704 QueryTable[1].DefaultData = L"";
2705 QueryTable[1].DefaultLength = 0;
2706
2707 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2708 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2709
2710 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2711 RegKey.Buffer, QueryTable, NULL, NULL);
2712
2713 if (!NT_SUCCESS(Status))
2714 {
2715 /* FIXME: Log the error */
2716 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2717 &DeviceNode->InstancePath, Status);
2718 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2719 return STATUS_SUCCESS;
2720 }
2721
2722 if (Service->Buffer == NULL)
2723 {
2724 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2725 DeviceCaps.RawDeviceOK)
2726 {
2727 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2728 RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0);
2729 }
2730 else if (ClassGUID.Length != 0)
2731 {
2732 /* Device has a ClassGUID value, but no Service value.
2733 * Suppose it is using the NULL driver, so state the
2734 * device is started */
2735 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2736 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2737 }
2738 else
2739 {
2740 DeviceNode->Problem = CM_PROB_FAILED_INSTALL;
2741 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2742 }
2743 return STATUS_SUCCESS;
2744 }
2745
2746 DPRINT("Got Service %S\n", Service->Buffer);
2747 }
2748
2749 return STATUS_SUCCESS;
2750 }
2751
2752 /*
2753 * IopActionInitChildServices
2754 *
2755 * Initialize the service for all (direct) child nodes of a parent node
2756 *
2757 * Parameters
2758 * DeviceNode
2759 * Pointer to device node.
2760 * Context
2761 * Pointer to parent node to initialize child node services for.
2762 *
2763 * Remarks
2764 * If the driver image for a service is not loaded and initialized
2765 * it is done here too. Any errors that occur are logged instead so
2766 * that all child services have a chance of being initialized.
2767 */
2768
2769 NTSTATUS
2770 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2771 PVOID Context)
2772 {
2773 PDEVICE_NODE ParentDeviceNode;
2774 NTSTATUS Status;
2775 BOOLEAN BootDrivers = !PnpSystemInit;
2776
2777 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2778
2779 ParentDeviceNode = Context;
2780
2781 /*
2782 * We are called for the parent too, but we don't need to do special
2783 * handling for this node
2784 */
2785 if (DeviceNode == ParentDeviceNode)
2786 {
2787 DPRINT("Success\n");
2788 return STATUS_SUCCESS;
2789 }
2790
2791 /*
2792 * We don't want to check for a direct child because
2793 * this function is called during boot to reinitialize
2794 * devices with drivers that couldn't load yet due to
2795 * stage 0 limitations (ie can't load from disk yet).
2796 */
2797
2798 if (!(DeviceNode->Flags & DNF_PROCESSED))
2799 {
2800 DPRINT1("Child not ready to be added\n");
2801 return STATUS_SUCCESS;
2802 }
2803
2804 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2805 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2806 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2807 return STATUS_SUCCESS;
2808
2809 if (DeviceNode->ServiceName.Buffer == NULL)
2810 {
2811 /* We don't need to worry about loading the driver because we're
2812 * being driven in raw mode so our parent must be loaded to get here */
2813 Status = IopInitializeDevice(DeviceNode, NULL);
2814 if (NT_SUCCESS(Status))
2815 {
2816 Status = IopStartDevice(DeviceNode);
2817 if (!NT_SUCCESS(Status))
2818 {
2819 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2820 &DeviceNode->InstancePath, Status);
2821 }
2822 }
2823 }
2824 else
2825 {
2826 PLDR_DATA_TABLE_ENTRY ModuleObject;
2827 PDRIVER_OBJECT DriverObject;
2828
2829 KeEnterCriticalRegion();
2830 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
2831 /* Get existing DriverObject pointer (in case the driver has
2832 already been loaded and initialized) */
2833 Status = IopGetDriverObject(
2834 &DriverObject,
2835 &DeviceNode->ServiceName,
2836 FALSE);
2837
2838 if (!NT_SUCCESS(Status))
2839 {
2840 /* Driver is not initialized, try to load it */
2841 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2842
2843 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2844 {
2845 /* Initialize the driver */
2846 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2847 &DeviceNode->ServiceName, FALSE, &DriverObject);
2848 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY;
2849 }
2850 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD)
2851 {
2852 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
2853 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE;
2854 }
2855 else
2856 {
2857 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2858 &DeviceNode->ServiceName, Status);
2859 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
2860 }
2861 }
2862 ExReleaseResourceLite(&IopDriverLoadResource);
2863 KeLeaveCriticalRegion();
2864
2865 /* Driver is loaded and initialized at this point */
2866 if (NT_SUCCESS(Status))
2867 {
2868 /* Initialize the device, including all filters */
2869 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2870
2871 /* Remove the extra reference */
2872 ObDereferenceObject(DriverObject);
2873 }
2874 else
2875 {
2876 /*
2877 * Don't disable when trying to load only boot drivers
2878 */
2879 if (!BootDrivers)
2880 {
2881 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2882 }
2883 }
2884 }
2885
2886 return STATUS_SUCCESS;
2887 }
2888
2889 /*
2890 * IopInitializePnpServices
2891 *
2892 * Initialize services for discovered children
2893 *
2894 * Parameters
2895 * DeviceNode
2896 * Top device node to start initializing services.
2897 *
2898 * Return Value
2899 * Status
2900 */
2901 NTSTATUS
2902 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2903 {
2904 DEVICETREE_TRAVERSE_CONTEXT Context;
2905
2906 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2907
2908 IopInitDeviceTreeTraverseContext(
2909 &Context,
2910 DeviceNode,
2911 IopActionInitChildServices,
2912 DeviceNode);
2913
2914 return IopTraverseDeviceTree(&Context);
2915 }
2916
2917 static NTSTATUS INIT_FUNCTION
2918 IopEnumerateDetectedDevices(
2919 IN HANDLE hBaseKey,
2920 IN PUNICODE_STRING RelativePath OPTIONAL,
2921 IN HANDLE hRootKey,
2922 IN BOOLEAN EnumerateSubKeys,
2923 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2924 IN ULONG ParentBootResourcesLength)
2925 {
2926 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2927 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2928 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2929 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2930 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2931 OBJECT_ATTRIBUTES ObjectAttributes;
2932 HANDLE hDevicesKey = NULL;
2933 HANDLE hDeviceKey = NULL;
2934 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2935 UNICODE_STRING Level2NameU;
2936 WCHAR Level2Name[5];
2937 ULONG IndexDevice = 0;
2938 ULONG IndexSubKey;
2939 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2940 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2941 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2942 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2943 UNICODE_STRING DeviceName, ValueName;
2944 ULONG RequiredSize;
2945 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2946 ULONG BootResourcesLength;
2947 NTSTATUS Status;
2948
2949 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2950 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2951 static ULONG DeviceIndexSerial = 0;
2952 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2953 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2954 static ULONG DeviceIndexKeyboard = 0;
2955 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2956 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2957 static ULONG DeviceIndexMouse = 0;
2958 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2959 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2960 static ULONG DeviceIndexParallel = 0;
2961 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2962 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2963 static ULONG DeviceIndexFloppy = 0;
2964 UNICODE_STRING HardwareIdKey;
2965 PUNICODE_STRING pHardwareId;
2966 ULONG DeviceIndex = 0;
2967 PUCHAR CmResourceList;
2968 ULONG ListCount;
2969
2970 if (RelativePath)
2971 {
2972 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2973 if (!NT_SUCCESS(Status))
2974 {
2975 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2976 goto cleanup;
2977 }
2978 }
2979 else
2980 hDevicesKey = hBaseKey;
2981
2982 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2983 if (!pDeviceInformation)
2984 {
2985 DPRINT("ExAllocatePool() failed\n");
2986 Status = STATUS_NO_MEMORY;
2987 goto cleanup;
2988 }
2989
2990 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2991 if (!pValueInformation)
2992 {
2993 DPRINT("ExAllocatePool() failed\n");
2994 Status = STATUS_NO_MEMORY;
2995 goto cleanup;
2996 }
2997
2998 while (TRUE)
2999 {
3000 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3001 if (Status == STATUS_NO_MORE_ENTRIES)
3002 break;
3003 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3004 {
3005 ExFreePool(pDeviceInformation);
3006 DeviceInfoLength = RequiredSize;
3007 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3008 if (!pDeviceInformation)
3009 {
3010 DPRINT("ExAllocatePool() failed\n");
3011 Status = STATUS_NO_MEMORY;
3012 goto cleanup;
3013 }
3014 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3015 }
3016 if (!NT_SUCCESS(Status))
3017 {
3018 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3019 goto cleanup;
3020 }
3021 IndexDevice++;
3022
3023 /* Open device key */
3024 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3025 DeviceName.Buffer = pDeviceInformation->Name;
3026
3027 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3028 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3029 if (!NT_SUCCESS(Status))
3030 {
3031 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3032 goto cleanup;
3033 }
3034
3035 /* Read boot resources, and add then to parent ones */
3036 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3037 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3038 {
3039 ExFreePool(pValueInformation);
3040 ValueInfoLength = RequiredSize;
3041 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3042 if (!pValueInformation)
3043 {
3044 DPRINT("ExAllocatePool() failed\n");
3045 ZwDeleteKey(hLevel2Key);
3046 Status = STATUS_NO_MEMORY;
3047 goto cleanup;
3048 }
3049 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3050 }
3051 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3052 {
3053 BootResources = ParentBootResources;
3054 BootResourcesLength = ParentBootResourcesLength;
3055 }
3056 else if (!NT_SUCCESS(Status))
3057 {
3058 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3059 goto nextdevice;
3060 }
3061 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3062 {
3063 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3064 goto nextdevice;
3065 }
3066 else
3067 {
3068 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3069
3070 /* Concatenate current resources and parent ones */
3071 if (ParentBootResourcesLength == 0)
3072 BootResourcesLength = pValueInformation->DataLength;
3073 else
3074 BootResourcesLength = ParentBootResourcesLength
3075 + pValueInformation->DataLength
3076 - Header;
3077 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3078 if (!BootResources)
3079 {
3080 DPRINT("ExAllocatePool() failed\n");
3081 goto nextdevice;
3082 }
3083 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3084 {
3085 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3086 }
3087 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3088 {
3089 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3090 RtlCopyMemory(
3091 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3092 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3093 ParentBootResourcesLength - Header);
3094 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3095 }
3096 else
3097 {
3098 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3099 RtlCopyMemory(
3100 (PVOID)((ULONG_PTR)BootResources + Header),
3101 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3102 ParentBootResourcesLength - Header);
3103 RtlCopyMemory(
3104 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3105 pValueInformation->Data + Header,
3106 pValueInformation->DataLength - Header);
3107 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3108 }
3109 }
3110
3111 if (EnumerateSubKeys)
3112 {
3113 IndexSubKey = 0;
3114 while (TRUE)
3115 {
3116 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3117 if (Status == STATUS_NO_MORE_ENTRIES)
3118 break;
3119 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3120 {
3121 ExFreePool(pDeviceInformation);
3122 DeviceInfoLength = RequiredSize;
3123 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3124 if (!pDeviceInformation)
3125 {
3126 DPRINT("ExAllocatePool() failed\n");
3127 Status = STATUS_NO_MEMORY;
3128 goto cleanup;
3129 }
3130 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3131 }
3132 if (!NT_SUCCESS(Status))
3133 {
3134 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3135 goto cleanup;
3136 }
3137 IndexSubKey++;
3138 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3139 DeviceName.Buffer = pDeviceInformation->Name;
3140
3141 Status = IopEnumerateDetectedDevices(
3142 hDeviceKey,
3143 &DeviceName,
3144 hRootKey,
3145 TRUE,
3146 BootResources,
3147 BootResourcesLength);
3148 if (!NT_SUCCESS(Status))
3149 goto cleanup;
3150 }
3151 }
3152
3153 /* Read identifier */
3154 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3155 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3156 {
3157 ExFreePool(pValueInformation);
3158 ValueInfoLength = RequiredSize;
3159 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3160 if (!pValueInformation)
3161 {
3162 DPRINT("ExAllocatePool() failed\n");
3163 Status = STATUS_NO_MEMORY;
3164 goto cleanup;
3165 }
3166 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3167 }
3168 if (!NT_SUCCESS(Status))
3169 {
3170 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
3171 {
3172 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3173 goto nextdevice;
3174 }
3175 ValueName.Length = ValueName.MaximumLength = 0;
3176 }
3177 else if (pValueInformation->Type != REG_SZ)
3178 {
3179 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3180 goto nextdevice;
3181 }
3182 else
3183 {
3184 /* Assign hardware id to this device */
3185 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3186 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3187 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3188 ValueName.Length -= sizeof(WCHAR);
3189 }
3190
3191 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3192 {
3193 pHardwareId = &HardwareIdSerial;
3194 DeviceIndex = DeviceIndexSerial++;
3195 }
3196 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3197 {
3198 pHardwareId = &HardwareIdKeyboard;
3199 DeviceIndex = DeviceIndexKeyboard++;
3200 }
3201 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3202 {
3203 pHardwareId = &HardwareIdMouse;
3204 DeviceIndex = DeviceIndexMouse++;
3205 }
3206 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3207 {
3208 pHardwareId = &HardwareIdParallel;
3209 DeviceIndex = DeviceIndexParallel++;
3210 }
3211 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3212 {
3213 pHardwareId = &HardwareIdFloppy;
3214 DeviceIndex = DeviceIndexFloppy++;
3215 }
3216 else
3217 {
3218 /* Unknown key path */
3219 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3220 goto nextdevice;
3221 }
3222
3223 /* Prepare hardware id key (hardware id value without final \0) */
3224 HardwareIdKey = *pHardwareId;
3225 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3226
3227 /* Add the detected device to Root key */
3228 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3229 Status = ZwCreateKey(
3230 &hLevel1Key,
3231 KEY_CREATE_SUB_KEY,
3232 &ObjectAttributes,
3233 0,
3234 NULL,
3235 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3236 NULL);
3237 if (!NT_SUCCESS(Status))
3238 {
3239 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3240 goto nextdevice;
3241 }
3242 swprintf(Level2Name, L"%04lu", DeviceIndex);
3243 RtlInitUnicodeString(&Level2NameU, Level2Name);
3244 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3245 Status = ZwCreateKey(
3246 &hLevel2Key,
3247 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3248 &ObjectAttributes,
3249 0,
3250 NULL,
3251 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3252 NULL);
3253 ZwClose(hLevel1Key);
3254 if (!NT_SUCCESS(Status))
3255 {
3256 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3257 goto nextdevice;
3258 }
3259 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3260 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3261 if (!NT_SUCCESS(Status))
3262 {
3263 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3264 ZwDeleteKey(hLevel2Key);
3265 goto nextdevice;
3266 }
3267 /* Create 'LogConf' subkey */
3268 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3269 Status = ZwCreateKey(
3270 &hLogConf,
3271 KEY_SET_VALUE,
3272 &ObjectAttributes,
3273 0,
3274 NULL,
3275 REG_OPTION_VOLATILE,
3276 NULL);
3277 if (!NT_SUCCESS(Status))
3278 {
3279 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3280 ZwDeleteKey(hLevel2Key);
3281 goto nextdevice;
3282 }
3283 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3284 {
3285 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3286 if (!CmResourceList)
3287 {
3288 ZwClose(hLogConf);
3289 ZwDeleteKey(hLevel2Key);
3290 goto nextdevice;
3291 }
3292
3293 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3294 ListCount = 1;
3295 RtlCopyMemory(CmResourceList,
3296 &ListCount,
3297 sizeof(ULONG));
3298
3299 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3300 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3301 BootResources,
3302 BootResourcesLength);
3303
3304 /* Save boot resources to 'LogConf\BootConfig' */
3305 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3306 if (!NT_SUCCESS(Status))
3307 {
3308 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3309 ZwClose(hLogConf);
3310 ZwDeleteKey(hLevel2Key);
3311 goto nextdevice;
3312 }
3313 }
3314 ZwClose(hLogConf);
3315
3316 nextdevice:
3317 if (BootResources && BootResources != ParentBootResources)
3318 {
3319 ExFreePool(BootResources);
3320 BootResources = NULL;
3321 }
3322 if (hLevel2Key)
3323 {
3324 ZwClose(hLevel2Key);
3325 hLevel2Key = NULL;
3326 }
3327 if (hDeviceKey)
3328 {
3329 ZwClose(hDeviceKey);
3330 hDeviceKey = NULL;
3331 }
3332 }
3333
3334 Status = STATUS_SUCCESS;
3335
3336 cleanup:
3337 if (hDevicesKey && hDevicesKey != hBaseKey)
3338 ZwClose(hDevicesKey);
3339 if (hDeviceKey)
3340 ZwClose(hDeviceKey);
3341 if (pDeviceInformation)
3342 ExFreePool(pDeviceInformation);
3343 if (pValueInformation)
3344 ExFreePool(pValueInformation);
3345 return Status;
3346 }
3347
3348 static BOOLEAN INIT_FUNCTION
3349 IopIsFirmwareMapperDisabled(VOID)
3350 {
3351 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3352 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3353 OBJECT_ATTRIBUTES ObjectAttributes;
3354 HANDLE hPnpKey;