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